diff --git a/.editorconfig b/.editorconfig index 15d2c086..645a8f3e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,10 +1,3 @@ -# In retrospect I'm less of a fan of tabs for indentation, because -# while they're better when they work, they're worse when they don't -# work, and so many people use terrible editors when they don't work -# that everything is inconsistent... but tabs are what Shimmie went -# with back in the 90's, so that's what we use now, and we deal with -# the pain of making sure everybody configures their editor properly - # top-most EditorConfig file root = true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3f9f0889..369765aa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,44 +12,63 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 - + uses: actions/checkout@v3 - name: Set Up Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | vendor key: php-cs-fixer-${{ hashFiles('composer.lock') }} - - name: Validate composer.json and composer.lock run: composer validate - - name: Install PHP dependencies - run: composer update && composer install --prefer-dist --no-progress - + run: composer install --prefer-dist --no-progress - name: Set up PHP uses: shivammathur/setup-php@master with: - php-version: 7.4 + php-version: 8.1 + - name: Format + run: ./vendor/bin/php-cs-fixer fix && git diff --exit-code - - name: Check format - run: ./vendor/bin/php-cs-fixer fix --dry-run + static: + name: Static Analysis + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 2 + - name: Set Up Cache + uses: actions/cache@v3 + with: + path: | + vendor + key: phpstan-${{ hashFiles('composer.lock') }} + - name: Install PHP dependencies + run: composer install --prefer-dist --no-progress + - name: PHPStan + uses: php-actions/phpstan@v3 + with: + configuration: tests/phpstan.neon + memory_limit: 1G test: name: PHP ${{ matrix.php }} / DB ${{ matrix.database }} strategy: fail-fast: false matrix: - php: ['7.4', '8.0'] + php: ['8.1', '8.2'] database: ['pgsql', 'mysql', 'sqlite'] runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 + with: + fetch-depth: 2 - name: Set Up Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | vendor @@ -106,7 +125,6 @@ jobs: vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-clover=data/coverage.clover - name: Upload coverage - if: matrix.php == '7.4' + if: matrix.php == '8.1' run: | - wget https://scrutinizer-ci.com/ocular.phar - php ocular.phar code-coverage:upload --format=php-clover data/coverage.clover + vendor/bin/ocular code-coverage:upload --format=php-clover data/coverage.clover diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index f2bd1ae1..8a4d93aa 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -1,19 +1,17 @@ exclude('ext/amazon_s3/lib') ->exclude('vendor') ->exclude('data') ->in(__DIR__) ; -$config = new PhpCsFixer\Config(); -return $config->setRules([ +$_phpcs_config = new PhpCsFixer\Config(); +return $_phpcs_config->setRules([ '@PSR12' => true, //'strict_param' => true, 'array_syntax' => ['syntax' => 'short'], ]) - ->setFinder($finder) -; - -?> + ->setFinder($_phpcs_finder) +; \ No newline at end of file diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 8a3a5db6..3f425840 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -6,6 +6,7 @@ filter: excluded_paths: [ext/*/lib/*,ext/tagger/script.js,tests/*] build: + image: default-bionic nodes: analysis: tests: diff --git a/Dockerfile b/Dockerfile index 61ccbab6..944d0439 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,10 @@ +ARG PHP_VERSION=8.2 + # "Build" shimmie (composer install - done in its own stage so that we don't # need to include all the composer fluff in the final image) -FROM debian:stable AS app -RUN apt update && apt install -y composer php7.4-gd php7.4-dom php7.4-sqlite3 php-xdebug imagemagick +FROM debian:unstable AS app +RUN apt update && apt upgrade -y +RUN apt install -y composer php${PHP_VERSION}-gd php${PHP_VERSION}-xml php${PHP_VERSION}-sqlite3 php${PHP_VERSION}-xdebug imagemagick COPY composer.json composer.lock /app/ WORKDIR /app RUN composer install --no-dev @@ -10,8 +13,9 @@ COPY . /app/ # Tests in their own image. Really we should inherit from app and then # `composer install` phpunit on top of that; but for some reason # `composer install --no-dev && composer install` doesn't install dev -FROM debian:stable AS tests -RUN apt update && apt install -y composer php7.4-gd php7.4-dom php7.4-sqlite3 php-xdebug imagemagick +FROM debian:unstable AS tests +RUN apt update && apt upgrade -y +RUN apt install -y composer php${PHP_VERSION}-gd php${PHP_VERSION}-xml php${PHP_VERSION}-sqlite3 php${PHP_VERSION}-xdebug imagemagick COPY composer.json composer.lock /app/ WORKDIR /app RUN composer install @@ -25,22 +29,24 @@ RUN [ $RUN_TESTS = false ] || (\ echo '=== Cleaning ===' && rm -rf data) # Build su-exec so that our final image can be nicer -FROM debian:stable AS suexec -RUN apt-get update && apt-get install -y --no-install-recommends gcc libc-dev curl -RUN curl -k -o /usr/local/bin/su-exec.c https://raw.githubusercontent.com/ncopa/su-exec/master/su-exec.c; \ - gcc -Wall /usr/local/bin/su-exec.c -o/usr/local/bin/su-exec; \ - chown root:root /usr/local/bin/su-exec; \ - chmod 0755 /usr/local/bin/su-exec; +FROM debian:unstable AS suexec +RUN apt update && apt upgrade -y +RUN apt install -y --no-install-recommends gcc libc-dev curl +RUN curl -k -o /usr/local/bin/su-exec.c https://raw.githubusercontent.com/ncopa/su-exec/master/su-exec.c; \ + gcc -Wall /usr/local/bin/su-exec.c -o/usr/local/bin/su-exec; \ + chown root:root /usr/local/bin/su-exec; \ + chmod 0755 /usr/local/bin/su-exec; # Actually run shimmie -FROM debian:stable +FROM debian:unstable EXPOSE 8000 HEALTHCHECK --interval=1m --timeout=3s CMD curl --fail http://127.0.0.1:8000/ || exit 1 ENV UID=1000 \ GID=1000 -RUN apt update && apt install -y curl \ - php7.4-cli php7.4-gd php7.4-pgsql php7.4-mysql php7.4-sqlite3 php7.4-zip php7.4-dom php7.4-mbstring \ - imagemagick zip unzip && \ +RUN apt update && apt upgrade -y && apt install -y \ + php${PHP_VERSION}-cli php${PHP_VERSION}-gd php${PHP_VERSION}-zip php${PHP_VERSION}-xml php${PHP_VERSION}-mbstring \ + php${PHP_VERSION}-pgsql php${PHP_VERSION}-mysql php${PHP_VERSION}-sqlite3 \ + curl imagemagick ffmpeg zip unzip && \ rm -rf /var/lib/apt/lists/* COPY --from=app /app /app COPY --from=suexec /usr/local/bin/su-exec /usr/local/bin/su-exec diff --git a/composer.json b/composer.json index 1cb791ae..116bb6d8 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "config": { "platform": { - "php": "7.4.0" + "php": "8.1.0" } }, @@ -31,7 +31,7 @@ ], "require" : { - "php" : "^7.4 | ^8.0", + "php" : "^8.1", "ext-pdo": "*", "ext-json": "*", "ext-fileinfo": "*", @@ -39,28 +39,33 @@ "flexihash/flexihash" : "^2.0", "ifixit/php-akismet" : "^1.0", "google/recaptcha" : "^1.1", - "dapphp/securimage" : "^3.6", "shish/eventtracer-php" : "^2.0", "shish/ffsphp" : "^1.0", "shish/microcrud" : "^2.0", "shish/microhtml" : "^2.0", + "shish/gqla" : "dev-main", "enshrined/svg-sanitize" : "^0.15", "bower-asset/jquery" : "^1.12", "bower-asset/jquery-timeago" : "^1.5", - "bower-asset/js-cookie" : "^2.1" + "bower-asset/js-cookie" : "^2.1", + "psr/simple-cache" : "^1.0", + "sabre/cache" : "^2.0.1", + "naroga/redis-cache": "dev-master" }, "require-dev" : { "phpunit/phpunit" : "^9.0", - "friendsofphp/php-cs-fixer" : "^3.4" + "friendsofphp/php-cs-fixer" : "^3.12", + "scrutinizer/ocular": "dev-master", + "phpstan/phpstan": "1.10.x-dev" }, "suggest": { "ext-memcache": "memcache caching", "ext-memcached": "memcached caching", "ext-apc": "apc caching", + "ext-apcu": "apc caching", "ext-redis": "redis caching", - "ext-dom": "some extensions", "ext-curl": "some extensions", "ext-ctype": "some extensions", "ext-json": "some extensions", diff --git a/composer.lock b/composer.lock index b5bd335a..bf2bf72a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,14 +4,14 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7fa1634834197de7e5325d494f20278e", + "content-hash": "605e247102c97c1320a4d1984a747c50", "packages": [ { "name": "bower-asset/jquery", "version": "1.12.4", "source": { "type": "git", - "url": "https://github.com/jquery/jquery-dist.git", + "url": "git@github.com:jquery/jquery-dist.git", "reference": "5e89585e0121e72ff47de177c5ef604f3089a53d" }, "dist": { @@ -50,7 +50,7 @@ "version": "v2.2.1", "source": { "type": "git", - "url": "https://github.com/js-cookie/js-cookie.git", + "url": "git@github.com:js-cookie/js-cookie.git", "reference": "54962f884e9ae33f93e13ac903ffaf1d5a523598" }, "dist": { @@ -63,72 +63,18 @@ "MIT" ] }, - { - "name": "dapphp/securimage", - "version": "3.6.8", - "source": { - "type": "git", - "url": "https://github.com/dapphp/securimage.git", - "reference": "5fc5953c4ffba1eb214cc83100672f238c184ca4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dapphp/securimage/zipball/5fc5953c4ffba1eb214cc83100672f238c184ca4", - "reference": "5fc5953c4ffba1eb214cc83100672f238c184ca4", - "shasum": "" - }, - "require": { - "ext-gd": "*", - "php": ">=5.4" - }, - "suggest": { - "ext-pdo": "For database storage support", - "ext-pdo_mysql": "For MySQL database support", - "ext-pdo_sqlite": "For SQLite3 database support" - }, - "type": "library", - "autoload": { - "classmap": [ - "securimage.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Drew Phillips", - "email": "drew@drew-phillips.com" - } - ], - "description": "PHP CAPTCHA Library", - "homepage": "https://www.phpcaptcha.org", - "keywords": [ - "Forms", - "anti-spam", - "captcha", - "security" - ], - "support": { - "issues": "https://github.com/dapphp/securimage/issues", - "source": "https://github.com/dapphp/securimage/tree/3.6.8" - }, - "abandoned": true, - "time": "2020-05-30T09:43:22+00:00" - }, { "name": "enshrined/svg-sanitize", - "version": "0.15.0", + "version": "0.15.4", "source": { "type": "git", "url": "https://github.com/darylldoyle/svg-sanitizer.git", - "reference": "17e12ba9c2881caa6b167d0fbea555c11207fbb0" + "reference": "e50b83a2f1f296ca61394fe88fbfe3e896a84cf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/17e12ba9c2881caa6b167d0fbea555c11207fbb0", - "reference": "17e12ba9c2881caa6b167d0fbea555c11207fbb0", + "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/e50b83a2f1f296ca61394fe88fbfe3e896a84cf4", + "reference": "e50b83a2f1f296ca61394fe88fbfe3e896a84cf4", "shasum": "" }, "require": { @@ -137,7 +83,6 @@ "php": "^7.0 || ^8.0" }, "require-dev": { - "codeclimate/php-test-reporter": "^0.1.2", "phpunit/phpunit": "^6.5 || ^8.5" }, "type": "library", @@ -159,9 +104,9 @@ "description": "An SVG sanitizer for PHP", "support": { "issues": "https://github.com/darylldoyle/svg-sanitizer/issues", - "source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.15.0" + "source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.15.4" }, - "time": "2022-02-13T00:42:56+00:00" + "time": "2022-02-21T09:13:59+00:00" }, { "name": "flexihash/flexihash", @@ -226,27 +171,27 @@ "source": { "type": "git", "url": "https://github.com/google/recaptcha.git", - "reference": "ed5645e799e43afa9eb181f214dc52f22982682d" + "reference": "6ffa193021aa0e369a3c5b3909de2b4ed97ac359" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/google/recaptcha/zipball/ed5645e799e43afa9eb181f214dc52f22982682d", - "reference": "ed5645e799e43afa9eb181f214dc52f22982682d", + "url": "https://api.github.com/repos/google/recaptcha/zipball/6ffa193021aa0e369a3c5b3909de2b4ed97ac359", + "reference": "6ffa193021aa0e369a3c5b3909de2b4ed97ac359", "shasum": "" }, "require": { - "php": ">=5.5" + "php": ">=8" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.2.20|^2.15", - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^4.8.36|^5.7.27|^6.59|^7.5.11" + "friendsofphp/php-cs-fixer": "^3.14", + "php-coveralls/php-coveralls": "^2.5", + "phpunit/phpunit": "^10" }, "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { @@ -271,7 +216,7 @@ "issues": "https://github.com/google/recaptcha/issues", "source": "https://github.com/google/recaptcha" }, - "time": "2021-10-04T09:40:45+00:00" + "time": "2023-02-20T17:27:30+00:00" }, { "name": "ifixit/php-akismet", @@ -284,24 +229,257 @@ "type": "library" }, { - "name": "shish/eventtracer-php", - "version": "v2.0.1", + "name": "naroga/redis-cache", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/shish/eventtracer-php.git", - "reference": "6a17a1e29dad55558d300f0d3b1dd44628cfce55" + "url": "https://github.com/naroga/redis-cache.git", + "reference": "c32ee4ce2efcf8292cac6b6192c17c0306320d04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/shish/eventtracer-php/zipball/6a17a1e29dad55558d300f0d3b1dd44628cfce55", - "reference": "6a17a1e29dad55558d300f0d3b1dd44628cfce55", + "url": "https://api.github.com/repos/naroga/redis-cache/zipball/c32ee4ce2efcf8292cac6b6192c17c0306320d04", + "reference": "c32ee4ce2efcf8292cac6b6192c17c0306320d04", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "predis/predis": "^1.1", + "psr/simple-cache": "~1.0" + }, + "require-dev": { + "phpunit/php-code-coverage": ">=2.2.4", + "phpunit/phpunit": ">=3.7.38", + "satooshi/php-coveralls": ">=1.0.1" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "Naroga\\RedisCache\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Pedro Cordeiro", + "email": "pedro.cordeiro@sympla.com.br" + } + ], + "description": "A Redis driver that implements PSR-16 (Simple Cache)", + "support": { + "issues": "https://github.com/naroga/redis-cache/issues", + "source": "https://github.com/naroga/redis-cache/tree/1.2" + }, + "time": "2021-01-25T13:15:08+00:00" + }, + { + "name": "predis/predis", + "version": "v1.x-dev", + "source": { + "type": "git", + "url": "https://github.com/predis/predis.git", + "reference": "bb8cce7bcf0d790dd17dde01922230d411efb99b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/predis/predis/zipball/bb8cce7bcf0d790dd17dde01922230d411efb99b", + "reference": "bb8cce7bcf0d790dd17dde01922230d411efb99b", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "ext-curl": "Allows access to Webdis when paired with phpiredis", + "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" + }, + "type": "library", + "autoload": { + "psr-4": { + "Predis\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniele Alessandri", + "email": "suppakilla@gmail.com", + "homepage": "http://clorophilla.net", + "role": "Creator & Maintainer" + }, + { + "name": "Till Krüss", + "homepage": "https://till.im", + "role": "Maintainer" + } + ], + "description": "Flexible and feature-complete Redis client for PHP and HHVM", + "homepage": "http://github.com/predis/predis", + "keywords": [ + "nosql", + "predis", + "redis" + ], + "support": { + "issues": "https://github.com/predis/predis/issues", + "source": "https://github.com/predis/predis/tree/v1.x" + }, + "funding": [ + { + "url": "https://github.com/sponsors/tillkruss", + "type": "github" + } + ], + "time": "2023-01-10T16:48:39+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "sabre/cache", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/cache.git", + "reference": "a843741b85025d8674bf4713121cae60172e6f86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/cache/zipball/a843741b85025d8674bf4713121cae60172e6f86", + "reference": "a843741b85025d8674bf4713121cae60172e6f86", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "psr/simple-cache": "^1.0" + }, + "provide": { + "psr/simple-cache-implementation": "~1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.14.0", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-phpunit": "^1.3", + "phpstan/phpstan-strict-rules": "^1.4", + "phpunit/phpunit": "^9.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Sabre\\Cache\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "https://evertpot.com/", + "role": "Developer" + } + ], + "description": "Simple cache abstraction layer implementing PSR-16", + "homepage": "http://sabre.io/dav/", + "keywords": [ + "apc", + "apcu", + "cache", + "memcache", + "memcached", + "psr-16", + "sabre", + "simple-cache" + ], + "support": { + "forum": "https://groups.google.com/group/sabredav-discuss", + "issues": "https://github.com/sabre-io/cache/issues", + "source": "https://github.com/fruux/sabre-skel" + }, + "time": "2023-02-09T23:47:10+00:00" + }, + { + "name": "shish/eventtracer-php", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/shish/eventtracer-php.git", + "reference": "5dfe2c090c8b7df772e982520c36f44b33ead035" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/shish/eventtracer-php/zipball/5dfe2c090c8b7df772e982520c36f44b33ead035", + "reference": "5dfe2c090c8b7df772e982520c36f44b33ead035", "shasum": "" }, "require": { "ext-json": "*", - "php": "^7.3 | ^8.0" + "php": "^8.0" }, "require-dev": { + "friendsofphp/php-cs-fixer": "^3.12", + "phpstan/phpstan": "^1.9", "phpunit/phpunit": "^9.0" }, "type": "library", @@ -326,29 +504,31 @@ "homepage": "https://github.com/shish/eventtracer-php", "support": { "issues": "https://github.com/shish/eventtracer-php/issues", - "source": "https://github.com/shish/eventtracer-php/tree/v2.0.1" + "source": "https://github.com/shish/eventtracer-php/tree/v2.1.0" }, - "time": "2020-10-24T14:53:38+00:00" + "time": "2023-02-04T12:26:41+00:00" }, { "name": "shish/ffsphp", - "version": "v1.0.5", + "version": "v1.1.0", "source": { "type": "git", "url": "https://github.com/shish/ffsphp.git", - "reference": "76d30da4a0b1cf87ead53564ffdebefecc76385e" + "reference": "47d7e96a129502275fb8a4ae0c4f36bd3f59e95b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/shish/ffsphp/zipball/76d30da4a0b1cf87ead53564ffdebefecc76385e", - "reference": "76d30da4a0b1cf87ead53564ffdebefecc76385e", + "url": "https://api.github.com/repos/shish/ffsphp/zipball/47d7e96a129502275fb8a4ae0c4f36bd3f59e95b", + "reference": "47d7e96a129502275fb8a4ae0c4f36bd3f59e95b", "shasum": "" }, "require": { "ext-pdo": "*", - "php": "^7.3 | ^8.0" + "php": "^8.0" }, "require-dev": { + "friendsofphp/php-cs-fixer": "^3.12", + "phpstan/phpstan": "^1.9", "phpunit/phpunit": "^9.0" }, "type": "library", @@ -373,31 +553,86 @@ "homepage": "https://github.com/shish/ffsphp", "support": { "issues": "https://github.com/shish/ffsphp/issues", - "source": "https://github.com/shish/ffsphp/tree/v1.0.5" + "source": "https://github.com/shish/ffsphp/tree/v1.1.0" }, - "time": "2021-12-13T21:26:41+00:00" + "time": "2023-02-04T12:34:44+00:00" }, { - "name": "shish/microcrud", - "version": "v2.0.4", + "name": "shish/gqla", + "version": "dev-main", "source": { "type": "git", - "url": "https://github.com/shish/microcrud.git", - "reference": "c4be2183bb336c8c222d1badc81069ec0334b649" + "url": "https://github.com/shish/gqla.git", + "reference": "26bf0405445f4e32e68cd7f1ea2256e81c6c42cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/shish/microcrud/zipball/c4be2183bb336c8c222d1badc81069ec0334b649", - "reference": "c4be2183bb336c8c222d1badc81069ec0334b649", + "url": "https://api.github.com/repos/shish/gqla/zipball/26bf0405445f4e32e68cd7f1ea2256e81c6c42cb", + "reference": "26bf0405445f4e32e68cd7f1ea2256e81c6c42cb", + "shasum": "" + }, + "require": { + "php": "^8.1", + "webonyx/graphql-php": "^15.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.12", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^9.0" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "GQLA\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Shish", + "email": "webmaster@shishnet.org", + "homepage": "https://shish.io", + "role": "Developer" + } + ], + "description": "A set of annotations for generating graphql APIs", + "homepage": "https://github.com/shish/gqla", + "keywords": [ + "graphql" + ], + "support": { + "issues": "https://github.com/shish/gqla/issues", + "source": "https://github.com/shish/gqla/tree/main" + }, + "time": "2023-03-03T00:12:44+00:00" + }, + { + "name": "shish/microcrud", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/shish/microcrud.git", + "reference": "c7398edf6b1ed0ee508769a73d656deca8f6a4be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/shish/microcrud/zipball/c7398edf6b1ed0ee508769a73d656deca8f6a4be", + "reference": "c7398edf6b1ed0ee508769a73d656deca8f6a4be", "shasum": "" }, "require": { "ext-pdo": "*", - "php": "^7.3 | ^8.0", + "php": "^8.0", "shish/ffsphp": "^1.0", "shish/microhtml": "^2.0.2" }, "require-dev": { + "friendsofphp/php-cs-fixer": "^3.12", + "phpstan/phpstan": "^1.9", "phpunit/phpunit": "^9.0" }, "type": "library", @@ -426,28 +661,30 @@ ], "support": { "issues": "https://github.com/shish/microcrud/issues", - "source": "https://github.com/shish/microcrud/tree/v2.0.4" + "source": "https://github.com/shish/microcrud/tree/v2.1.0" }, - "time": "2020-10-25T10:39:48+00:00" + "time": "2023-02-04T13:09:53+00:00" }, { "name": "shish/microhtml", - "version": "v2.0.3", + "version": "v2.1.0", "source": { "type": "git", "url": "https://github.com/shish/microhtml.git", - "reference": "e84506f7be7f8f2d315b188df5a96253a714acc1" + "reference": "afef3aac229b514ed5b4afbfb2d970d1419313c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/shish/microhtml/zipball/e84506f7be7f8f2d315b188df5a96253a714acc1", - "reference": "e84506f7be7f8f2d315b188df5a96253a714acc1", + "url": "https://api.github.com/repos/shish/microhtml/zipball/afef3aac229b514ed5b4afbfb2d970d1419313c8", + "reference": "afef3aac229b514ed5b4afbfb2d970d1419313c8", "shasum": "" }, "require": { - "php": "^7.3 | ^8.0" + "php": "^8.0" }, "require-dev": { + "friendsofphp/php-cs-fixer": "^3.12", + "phpstan/phpstan": "^1.9", "phpunit/phpunit": "^9.0" }, "type": "library", @@ -476,9 +713,79 @@ ], "support": { "issues": "https://github.com/shish/microhtml/issues", - "source": "https://github.com/shish/microhtml/tree/v2.0.3" + "source": "https://github.com/shish/microhtml/tree/v2.1.0" }, - "time": "2020-10-24T14:48:32+00:00" + "time": "2023-02-04T13:02:26+00:00" + }, + { + "name": "webonyx/graphql-php", + "version": "v15.2.1", + "source": { + "type": "git", + "url": "https://github.com/webonyx/graphql-php.git", + "reference": "6b02da9313065889eb783d623567476500a572ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webonyx/graphql-php/zipball/6b02da9313065889eb783d623567476500a572ef", + "reference": "6b02da9313065889eb783d623567476500a572ef", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": "^7.4 || ^8" + }, + "require-dev": { + "amphp/amp": "^2.6", + "dms/phpunit-arraysubset-asserts": "^0.4", + "ergebnis/composer-normalize": "^2.28", + "mll-lab/php-cs-fixer-config": "^5.0", + "nyholm/psr7": "^1.5", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "1.10.3", + "phpstan/phpstan-phpunit": "1.3.8", + "phpstan/phpstan-strict-rules": "1.5.0", + "phpunit/phpunit": "^9.5", + "psr/http-message": "^1", + "react/http": "^1.6", + "react/promise": "^2.9", + "symfony/polyfill-php81": "^1.23", + "symfony/var-exporter": "^5 || ^6", + "thecodingmachine/safe": "^1.3 || ^2" + }, + "suggest": { + "psr/http-message": "To use standard GraphQL server", + "react/promise": "To leverage async resolving on React PHP platform" + }, + "type": "library", + "autoload": { + "psr-4": { + "GraphQL\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP port of GraphQL reference implementation", + "homepage": "https://github.com/webonyx/graphql-php", + "keywords": [ + "api", + "graphql" + ], + "support": { + "issues": "https://github.com/webonyx/graphql-php/issues", + "source": "https://github.com/webonyx/graphql-php/tree/v15.2.1" + }, + "funding": [ + { + "url": "https://opencollective.com/webonyx-graphql-php", + "type": "open_collective" + } + ], + "time": "2023-02-28T13:00:18+00:00" } ], "packages-dev": [ @@ -488,27 +795,27 @@ "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "1bbc34bff31a65639963abbda90ce220e783cb2b" + "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/1bbc34bff31a65639963abbda90ce220e783cb2b", - "reference": "1bbc34bff31a65639963abbda90ce220e783cb2b", + "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", + "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1", + "phpstan/phpstan": "^1.3", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^4.2 || ^5" + "symfony/phpunit-bridge": "^5" }, "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.x-dev" + "dev-main": "3.x-dev" } }, "autoload": { @@ -536,7 +843,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/main" + "source": "https://github.com/composer/pcre/tree/3.1.0" }, "funding": [ { @@ -552,7 +859,7 @@ "type": "tidelift" } ], - "time": "2021-12-06T20:05:46+00:00" + "time": "2022-11-17T09:50:14+00:00" }, { "name": "composer/semver", @@ -560,19 +867,19 @@ "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "83e511e247de329283478496f7a1e114c9517506" + "reference": "fa1ec24f0ab1efe642671ec15c51a3ab879f59bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/83e511e247de329283478496f7a1e114c9517506", - "reference": "83e511e247de329283478496f7a1e114c9517506", + "url": "https://api.github.com/repos/composer/semver/zipball/fa1ec24f0ab1efe642671ec15c51a3ab879f59bf", + "reference": "fa1ec24f0ab1efe642671ec15c51a3ab879f59bf", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.54", + "phpstan/phpstan": "^1.4", "symfony/phpunit-bridge": "^4.2 || ^5" }, "default-branch": true, @@ -616,9 +923,9 @@ "versioning" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.6" + "source": "https://github.com/composer/semver/tree/main" }, "funding": [ { @@ -634,31 +941,31 @@ "type": "tidelift" } ], - "time": "2021-10-25T11:34:17+00:00" + "time": "2023-01-13T15:47:53+00:00" }, { "name": "composer/xdebug-handler", - "version": "2.0.3", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "6555461e76962fd0379c444c46fd558a0fcfb65e" + "reference": "ced299686f41dce890debac69273b47ffe98a40c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6555461e76962fd0379c444c46fd558a0fcfb65e", - "reference": "6555461e76962fd0379c444c46fd558a0fcfb65e", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", + "reference": "ced299686f41dce890debac69273b47ffe98a40c", "shasum": "" }, "require": { - "composer/pcre": "^1", - "php": "^5.3.2 || ^7.0 || ^8.0", + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", "psr/log": "^1 || ^2 || ^3" }, "require-dev": { "phpstan/phpstan": "^1.0", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" + "symfony/phpunit-bridge": "^6.0" }, "type": "library", "autoload": { @@ -684,7 +991,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/2.0.3" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" }, "funding": [ { @@ -700,36 +1007,40 @@ "type": "tidelift" } ], - "time": "2021-12-08T13:07:32+00:00" + "time": "2022-02-25T21:32:43+00:00" }, { "name": "doctrine/annotations", - "version": "1.14.x-dev", + "version": "2.0.x-dev", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "2da982ad3c26da81b91db8d7b54abf3a5922e73c" + "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/2da982ad3c26da81b91db8d7b54abf3a5922e73c", - "reference": "2da982ad3c26da81b91db8d7b54abf3a5922e73c", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f", + "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f", "shasum": "" }, "require": { - "doctrine/lexer": "1.*", + "doctrine/lexer": "^2 || ^3", "ext-tokenizer": "*", - "php": "^7.1 || ^8.0", + "php": "^7.2 || ^8.0", "psr/cache": "^1 || ^2 || ^3" }, "require-dev": { - "doctrine/cache": "^1.11 || ^2.0", - "doctrine/coding-standard": "^6.0 || ^8.1", - "phpstan/phpstan": "^0.12.20", - "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", - "symfony/cache": "^4.4 || ^5.2", + "doctrine/cache": "^2.0", + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.8.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "symfony/cache": "^5.4 || ^6", "vimeo/psalm": "^4.10" }, + "suggest": { + "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -771,9 +1082,52 @@ ], "support": { "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.14.x" + "source": "https://github.com/doctrine/annotations/tree/2.0.1" }, - "time": "2021-10-15T21:17:00+00:00" + "time": "2023-02-02T22:02:53+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "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.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + }, + "time": "2022-05-02T15:47:09+00:00" }, { "name": "doctrine/instantiator", @@ -781,26 +1135,28 @@ "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "6410c4b8352cb64218641457cef64997e6b784fb" + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/6410c4b8352cb64218641457cef64997e6b784fb", - "reference": "6410c4b8352cb64218641457cef64997e6b784fb", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^8.0", + "doctrine/coding-standard": "^9 || ^11", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.30 || ^5.4" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -826,7 +1182,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.x" + "source": "https://github.com/doctrine/instantiator/tree/1.5.0" }, "funding": [ { @@ -842,34 +1198,38 @@ "type": "tidelift" } ], - "time": "2020-11-10T19:05:51+00:00" + "time": "2022-12-30T00:15:36+00:00" }, { "name": "doctrine/lexer", - "version": "1.3.x-dev", + "version": "2.1.x-dev", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "59bfb3b9be04237be4cd1afea9bbb58794c25ce8" + "reference": "e74756f7517d72c238b9163fcd1ed54eb1f92bd0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/59bfb3b9be04237be4cd1afea9bbb58794c25ce8", - "reference": "59bfb3b9be04237be4cd1afea9bbb58794c25ce8", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/e74756f7517d72c238b9163fcd1ed54eb1f92bd0", + "reference": "e74756f7517d72c238b9163fcd1ed54eb1f92bd0", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "doctrine/deprecations": "^1.0", + "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^8.0", - "phpstan/phpstan": "^0.12", - "phpunit/phpunit": "^8.2 || ^9.4" + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^4.11 || ^5.0" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + "Doctrine\\Common\\Lexer\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -901,7 +1261,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.3.x" + "source": "https://github.com/doctrine/lexer/tree/2.1.x" }, "funding": [ { @@ -917,56 +1277,57 @@ "type": "tidelift" } ], - "time": "2021-01-20T07:15:06+00:00" + "time": "2022-12-29T09:22:42+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.4.0", + "version": "v3.14.4", "source": { "type": "git", - "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad" + "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", + "reference": "1b3d9dba63d93b8a202c31e824748218781eae6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", - "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/1b3d9dba63d93b8a202c31e824748218781eae6b", + "reference": "1b3d9dba63d93b8a202c31e824748218781eae6b", "shasum": "" }, "require": { - "composer/semver": "^3.2", - "composer/xdebug-handler": "^2.0", - "doctrine/annotations": "^1.12", + "composer/semver": "^3.3", + "composer/xdebug-handler": "^3.0.3", + "doctrine/annotations": "^2", + "doctrine/lexer": "^2 || ^3", "ext-json": "*", "ext-tokenizer": "*", - "php": "^7.2.5 || ^8.0", - "php-cs-fixer/diff": "^2.0", - "symfony/console": "^4.4.20 || ^5.1.3 || ^6.0", - "symfony/event-dispatcher": "^4.4.20 || ^5.0 || ^6.0", - "symfony/filesystem": "^4.4.20 || ^5.0 || ^6.0", - "symfony/finder": "^4.4.20 || ^5.0 || ^6.0", - "symfony/options-resolver": "^4.4.20 || ^5.0 || ^6.0", - "symfony/polyfill-mbstring": "^1.23", - "symfony/polyfill-php80": "^1.23", - "symfony/polyfill-php81": "^1.23", - "symfony/process": "^4.4.20 || ^5.0 || ^6.0", - "symfony/stopwatch": "^4.4.20 || ^5.0 || ^6.0" + "php": "^7.4 || ^8.0", + "sebastian/diff": "^4.0 || ^5.0", + "symfony/console": "^5.4 || ^6.0", + "symfony/event-dispatcher": "^5.4 || ^6.0", + "symfony/filesystem": "^5.4 || ^6.0", + "symfony/finder": "^5.4 || ^6.0", + "symfony/options-resolver": "^5.4 || ^6.0", + "symfony/polyfill-mbstring": "^1.27", + "symfony/polyfill-php80": "^1.27", + "symfony/polyfill-php81": "^1.27", + "symfony/process": "^5.4 || ^6.0", + "symfony/stopwatch": "^5.4 || ^6.0" }, "require-dev": { "justinrainbow/json-schema": "^5.2", - "keradus/cli-executor": "^1.5", - "mikey179/vfsstream": "^1.6.8", - "php-coveralls/php-coveralls": "^2.5.2", + "keradus/cli-executor": "^2.0", + "mikey179/vfsstream": "^1.6.11", + "php-coveralls/php-coveralls": "^2.5.3", "php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", - "phpspec/prophecy": "^1.15", - "phpspec/prophecy-phpunit": "^1.1 || ^2.0", - "phpunit/phpunit": "^8.5.21 || ^9.5", - "phpunitgoodpractices/polyfill": "^1.5", - "phpunitgoodpractices/traits": "^1.9.1", - "symfony/phpunit-bridge": "^5.2.4 || ^6.0", - "symfony/yaml": "^4.4.20 || ^5.0 || ^6.0" + "phpspec/prophecy": "^1.16", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "phpunitgoodpractices/polyfill": "^1.6", + "phpunitgoodpractices/traits": "^1.9.2", + "symfony/phpunit-bridge": "^6.2.3", + "symfony/yaml": "^5.4 || ^6.0" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -997,8 +1358,8 @@ ], "description": "A tool to automatically fix PHP code style", "support": { - "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", - "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.4.0" + "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.14.4" }, "funding": [ { @@ -1006,7 +1367,503 @@ "type": "github" } ], - "time": "2021-12-11T16:25:08+00:00" + "time": "2023-02-09T21:49:13+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "8459341c16f96b9610dcdfe22bd3060d60c0da04" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/8459341c16f96b9610dcdfe22bd3060d60c0da04", + "reference": "8459341c16f96b9610dcdfe22bd3060d60c0da04", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5", + "guzzlehttp/psr7": "^1.9 || ^2.4", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "ext-curl": "*", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "default-branch": true, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "7.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/master" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-08-29T11:03:19+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "b94b2807d85443f9719887892882d0329d1e2598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", + "reference": "b94b2807d85443f9719887892882d0329d1e2598", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2022-08-28T14:55:35+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "58d0734481de3fbc62f3d13da4d991e051521282" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/58d0734481de3fbc62f3d13da4d991e051521282", + "reference": "58d0734481de3fbc62f3d13da4d991e051521282", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "default-branch": true, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/master" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2023-02-15T13:59:53+00:00" + }, + { + "name": "jms/metadata", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/metadata.git", + "reference": "7ca240dcac0c655eb15933ee55736ccd2ea0d7a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/7ca240dcac0c655eb15933ee55736ccd2ea0d7a6", + "reference": "7ca240dcac0c655eb15933ee55736ccd2ea0d7a6", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "require-dev": { + "doctrine/cache": "^1.0", + "doctrine/coding-standard": "^8.0", + "mikey179/vfsstream": "^1.6.7", + "phpunit/phpunit": "^8.5|^9.0", + "psr/container": "^1.0|^2.0", + "symfony/cache": "^3.1|^4.0|^5.0", + "symfony/dependency-injection": "^3.1|^4.0|^5.0" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Metadata\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "Class/method/property metadata management in PHP", + "keywords": [ + "annotations", + "metadata", + "xml", + "yaml" + ], + "support": { + "issues": "https://github.com/schmittjoh/metadata/issues", + "source": "https://github.com/schmittjoh/metadata/tree/2.8.0" + }, + "time": "2023-02-15T13:44:18+00:00" + }, + { + "name": "jms/serializer", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/serializer.git", + "reference": "ac0b16ee5317d1aacc41deb91c6c325eae97c176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/ac0b16ee5317d1aacc41deb91c6c325eae97c176", + "reference": "ac0b16ee5317d1aacc41deb91c6c325eae97c176", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.13 || ^2.0", + "doctrine/instantiator": "^1.0.3", + "doctrine/lexer": "^1.1 || ^2", + "jms/metadata": "^2.6", + "php": "^7.2||^8.0", + "phpstan/phpdoc-parser": "^0.4 || ^0.5 || ^1.0" + }, + "require-dev": { + "doctrine/coding-standard": "^8.1", + "doctrine/orm": "~2.1", + "doctrine/persistence": "^1.3.3|^2.0|^3.0", + "doctrine/phpcr-odm": "^1.3|^2.0", + "ext-pdo_sqlite": "*", + "jackalope/jackalope-doctrine-dbal": "^1.1.5", + "ocramius/proxy-manager": "^1.0|^2.0", + "phpbench/phpbench": "^1.0", + "phpstan/phpstan": "^1.0.2", + "phpunit/phpunit": "^8.5.21||^9.0", + "psr/container": "^1.0|^2.0", + "symfony/dependency-injection": "^3.0|^4.0|^5.0|^6.0", + "symfony/expression-language": "^3.2|^4.0|^5.0|^6.0", + "symfony/filesystem": "^3.0|^4.0|^5.0|^6.0", + "symfony/form": "^3.0|^4.0|^5.0|^6.0", + "symfony/translation": "^3.0|^4.0|^5.0|^6.0", + "symfony/uid": "^5.1|^6.0", + "symfony/validator": "^3.1.9|^4.0|^5.0|^6.0", + "symfony/yaml": "^3.3|^4.0|^5.0|^6.0", + "twig/twig": "~1.34|~2.4|^3.0" + }, + "suggest": { + "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", + "symfony/cache": "Required if you like to use cache functionality.", + "symfony/uid": "Required if you'd like to serialize UID objects.", + "symfony/yaml": "Required if you'd like to use the YAML metadata format." + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "JMS\\Serializer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "Library for (de-)serializing data of any complexity; supports XML, and JSON.", + "homepage": "http://jmsyst.com/libs/serializer", + "keywords": [ + "deserialization", + "jaxb", + "json", + "serialization", + "xml" + ], + "support": { + "issues": "https://github.com/schmittjoh/serializer/issues", + "source": "https://github.com/schmittjoh/serializer/tree/3.23.0" + }, + "funding": [ + { + "url": "https://github.com/goetas", + "type": "github" + } + ], + "time": "2023-02-17T17:40:48+00:00" }, { "name": "myclabs/deep-copy", @@ -1014,34 +1871,35 @@ "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, - "replace": { - "myclabs/deep-copy": "self.version" + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" }, "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "default-branch": true, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, "files": [ "src/DeepCopy/deep_copy.php" - ] + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1057,7 +1915,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" }, "funding": [ { @@ -1065,20 +1923,20 @@ "type": "tidelift" } ], - "time": "2020-11-13T09:40:50+00:00" + "time": "2022-03-03T13:19:32+00:00" }, { "name": "nikic/php-parser", - "version": "v4.13.2", + "version": "4.x-dev", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", "shasum": "" }, "require": { @@ -1089,6 +1947,7 @@ "ircmaxell/php-yacc": "^0.0.7", "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, + "default-branch": true, "bin": [ "bin/php-parse" ], @@ -1119,9 +1978,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" }, - "time": "2021-11-30T19:35:32+00:00" + "time": "2023-01-16T22:05:37+00:00" }, { "name": "phar-io/manifest", @@ -1129,16 +1988,17 @@ "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "36d8a21e851a9512db2b086dc5ac2c61308f0138" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/36d8a21e851a9512db2b086dc5ac2c61308f0138", + "reference": "36d8a21e851a9512db2b086dc5ac2c61308f0138", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -1180,22 +2040,28 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/master" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2022-02-21T19:55:33+00:00" }, { "name": "phar-io/version", - "version": "3.1.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "bae7c545bef187884426f042434e561ab1ddb182" + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", - "reference": "bae7c545bef187884426f042434e561ab1ddb182", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", "shasum": "" }, "require": { @@ -1231,291 +2097,190 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.1.0" + "source": "https://github.com/phar-io/version/tree/3.2.1" }, - "time": "2021-02-23T14:00:09+00:00" + "time": "2022-02-21T01:04:05+00:00" }, { - "name": "php-cs-fixer/diff", - "version": "v2.0.2", + "name": "phpoption/phpoption", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/PHP-CS-Fixer/diff.git", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3" + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/29dc0d507e838c4580d018bd8b5cb412474f7ec3", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e", + "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0 || ^8.0" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", - "symfony/process": "^3.3" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" + }, + "default-branch": true, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2023-02-25T19:38:58+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.16.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e27e92d939e2e3636f0a1f0afaba59692c0bf571", + "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" }, "type": "library", "autoload": { - "classmap": [ - "src/" + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.16.1" + }, + "time": "2023-02-07T18:11:17+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.10.x-dev", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "aed9319bda4e1bf862e2576baf28949877891853" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/aed9319bda4e1bf862e2576baf28949877891853", + "reference": "aed9319bda4e1bf862e2576baf28949877891853", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "default-branch": true, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "sebastian/diff v3 backport support for PHP 5.6+", - "homepage": "https://github.com/PHP-CS-Fixer", - "keywords": [ - "diff" - ], - "support": { - "issues": "https://github.com/PHP-CS-Fixer/diff/issues", - "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" - }, - "time": "2020-10-14T08:32:19+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "a0eeab580cbdf4414fef6978732510a36ed0a9d6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/a0eeab580cbdf4414fef6978732510a36ed0a9d6", - "reference": "a0eeab580cbdf4414fef6978732510a36ed0a9d6", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", + "description": "PHPStan - PHP Static Analysis Tool", "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", + "dev", "static analysis" ], "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master" + "issues": "https://github.com/phpstan/phpstan/issues", + "source": "https://github.com/phpstan/phpstan/tree/1.10.x" }, - "time": "2021-06-25T13:47:51+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" - }, - "default-branch": true, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "funding": [ { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" + "url": "https://github.com/ondrejmirtes", + "type": "github" }, { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" - }, - "time": "2021-10-19T17:43:47+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.x-dev", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "f8ec4ab631de5a97769e66b13418c3b8b24e81f4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/f8ec4ab631de5a97769e66b13418c3b8b24e81f4", - "reference": "f8ec4ab631de5a97769e66b13418c3b8b24e81f4", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "*", - "psalm/phar": "^4.8" - }, - "default-branch": true, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.x" - }, - "time": "2021-11-24T08:29:39+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", - "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.2", - "phpdocumentor/reflection-docblock": "^5.2", - "sebastian/comparator": "^3.0 || ^4.0", - "sebastian/recursion-context": "^3.0 || ^4.0" - }, - "require-dev": { - "phpspec/phpspec": "^6.0 || ^7.0", - "phpunit/phpunit": "^8.0 || ^9.0" - }, - "default-branch": true, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" + "url": "https://github.com/phpstan", + "type": "github" }, { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" } ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "support": { - "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" - }, - "time": "2021-12-08T12:19:24+00:00" + "time": "2023-03-02T09:48:34+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1523,19 +2288,19 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "747f93928bcac855054f2781c209ec80d469fe14" + "reference": "700aa825126460ce5be79ae5e1cf2e2c5b71588b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/747f93928bcac855054f2781c209ec80d469fe14", - "reference": "747f93928bcac855054f2781c209ec80d469fe14", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/700aa825126460ce5be79ae5e1cf2e2c5b71588b", + "reference": "700aa825126460ce5be79ae5e1cf2e2c5b71588b", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.13.0", + "nikic/php-parser": "^4.15", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -1592,7 +2357,7 @@ "type": "github" } ], - "time": "2021-12-13T15:03:35+00:00" + "time": "2023-02-27T12:51:14+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1600,12 +2365,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + "reference": "38b24367e1b340aa78b96d7cab042942d917bb84" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/38b24367e1b340aa78b96d7cab042942d917bb84", + "reference": "38b24367e1b340aa78b96d7cab042942d917bb84", "shasum": "" }, "require": { @@ -1652,7 +2417,7 @@ "type": "github" } ], - "time": "2021-12-02T12:48:52+00:00" + "time": "2022-02-11T16:23:04+00:00" }, { "name": "phpunit/php-invoker", @@ -1837,20 +2602,20 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.x-dev", + "version": "9.6.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "09f082e2c7564dc3a889e73015c65b836e2303a0" + "reference": "d6454d6dd71024848893a1e2d1f1dd78683351db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/09f082e2c7564dc3a889e73015c65b836e2303a0", - "reference": "09f082e2c7564dc3a889e73015c65b836e2303a0", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d6454d6dd71024848893a1e2d1f1dd78683351db", + "reference": "d6454d6dd71024848893a1e2d1f1dd78683351db", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1", + "doctrine/instantiator": "^1.3.1 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", @@ -1861,28 +2626,23 @@ "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", - "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.7", + "phpunit/php-code-coverage": "^9.2.13", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", "phpunit/php-timer": "^5.0.2", "sebastian/cli-parser": "^1.0.1", "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.5", + "sebastian/comparator": "^4.0.8", "sebastian/diff": "^4.0.3", "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.3", + "sebastian/exporter": "^4.0.5", "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3.4", + "sebastian/type": "^3.2", "sebastian/version": "^3.0.2" }, - "require-dev": { - "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0.1" - }, "suggest": { "ext-soap": "*", "ext-xdebug": "*" @@ -1893,15 +2653,15 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "9.6-dev" } }, "autoload": { - "classmap": [ - "src/" - ], "files": [ "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1924,7 +2684,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6" }, "funding": [ { @@ -1934,31 +2694,39 @@ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" } ], - "time": "2021-12-13T14:59:17+00:00" + "time": "2023-02-28T06:43:37+00:00" }, { "name": "psr/cache", - "version": "1.0.1", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/php-fig/cache.git", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + "reference": "0a7c67d0d1c8167b342eb74339d6f961663826ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "url": "https://api.github.com/repos/php-fig/cache/zipball/0a7c67d0d1c8167b342eb74339d6f961663826ce", + "reference": "0a7c67d0d1c8167b342eb74339d6f961663826ce", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, + "suggest": { + "fig/cache-util": "Provides some useful PSR-6 utilities" + }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -1973,7 +2741,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for caching libraries", @@ -1985,26 +2753,32 @@ "support": { "source": "https://github.com/php-fig/cache/tree/master" }, - "time": "2016-08-06T20:24:11+00:00" + "time": "2021-02-24T03:25:37+00:00" }, { "name": "psr/container", - "version": "1.x-dev", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + "reference": "90db7b9ac2a2c5b849fcb69dde58f3ae182c68f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "url": "https://api.github.com/repos/php-fig/container/zipball/90db7b9ac2a2c5b849fcb69dde58f3ae182c68f5", + "reference": "90db7b9ac2a2c5b849fcb69dde58f3ae182c68f5", "shasum": "" }, "require": { "php": ">=7.4.0" }, + "default-branch": true, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -2031,9 +2805,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" + "source": "https://github.com/php-fig/container/tree/master" }, - "time": "2021-11-05T16:50:12+00:00" + "time": "2022-07-19T17:36:59+00:00" }, { "name": "psr/event-dispatcher", @@ -2041,12 +2815,12 @@ "source": { "type": "git", "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "aa4f89e91c423b516ff226c50dc83f824011c253" + "reference": "e275e2d67d53964a3f13e056886ecd769edee021" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/aa4f89e91c423b516ff226c50dc83f824011c253", - "reference": "aa4f89e91c423b516ff226c50dc83f824011c253", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/e275e2d67d53964a3f13e056886ecd769edee021", + "reference": "e275e2d67d53964a3f13e056886ecd769edee021", "shasum": "" }, "require": { @@ -2086,34 +2860,198 @@ "support": { "source": "https://github.com/php-fig/event-dispatcher/tree/master" }, - "time": "2021-02-08T21:15:39+00:00" + "time": "2022-06-29T17:22:39+00:00" }, { - "name": "psr/log", - "version": "1.1.4", + "name": "psr/http-client", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + "url": "https://github.com/php-fig/http-client.git", + "reference": "22b2ef5687f43679481615605d7a15c557ce85b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/22b2ef5687f43679481615605d7a15c557ce85b1", + "reference": "22b2ef5687f43679481615605d7a15c557ce85b1", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, + "time": "2020-09-19T09:12:31+00:00" + }, + { + "name": "psr/http-factory", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "5a4f141ac2e5bc35e615134f127e1833158d2944" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/5a4f141ac2e5bc35e615134f127e1833158d2944", + "reference": "5a4f141ac2e5bc35e615134f127e1833158d2944", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2022-07-14T07:21:53+00:00" + }, + { + "name": "psr/http-message", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "efd67d1dc14a7ef4fc4e518e7dee91c271d524e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/efd67d1dc14a7ef4fc4e518e7dee91c271d524e4", + "reference": "efd67d1dc14a7ef4fc4e518e7dee91c271d524e4", "shasum": "" }, "require": { "php": ">=5.3.0" }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2019-08-29T13:16:46+00:00" + }, + { + "name": "psr/log", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2134,9 +3072,99 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" + "source": "https://github.com/php-fig/log/tree/3.0.0" }, - "time": "2021-05-03T11:20:27+00:00" + "time": "2021-07-14T16:46:02+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "scrutinizer/ocular", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/scrutinizer-ci/ocular.git", + "reference": "dda3540f7458b2645cee2a02b24291914769c41c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/scrutinizer-ci/ocular/zipball/dda3540f7458b2645cee2a02b24291914769c41c", + "reference": "dda3540f7458b2645cee2a02b24291914769c41c", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "~6.3|^7.0", + "jms/serializer": "^1.0.0|^3.0", + "phpoption/phpoption": "~1.0", + "symfony/console": "^2.1.0|~3.0|~4.0|~5.0|^6.0", + "symfony/process": "~2.3|~3.0|~4.0|~5.0|^6.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", + "phpunit/phpunit": "^9.0.0", + "symfony/filesystem": "~2.0|~3.0|~4.0|~5.0|^6.0" + }, + "default-branch": true, + "bin": [ + "bin/ocular" + ], + "type": "library", + "autoload": { + "psr-4": { + "Scrutinizer\\Ocular\\": "src/Scrutinizer/Ocular" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "support": { + "issues": "https://github.com/scrutinizer-ci/ocular/issues", + "source": "https://github.com/scrutinizer-ci/ocular/tree/1.9" + }, + "time": "2022-02-22T09:49:51+00:00" }, { "name": "sebastian/cli-parser", @@ -2307,16 +3335,16 @@ }, { "name": "sebastian/comparator", - "version": "4.0.6", + "version": "4.0.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382" + "reference": "b247957a1c8dc81a671770f74b479c0a78a818f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/b247957a1c8dc81a671770f74b479c0a78a818f1", + "reference": "b247957a1c8dc81a671770f74b479c0a78a818f1", "shasum": "" }, "require": { @@ -2369,7 +3397,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0" }, "funding": [ { @@ -2377,7 +3405,7 @@ "type": "github" } ], - "time": "2020-10-26T15:49:45+00:00" + "time": "2022-09-14T12:46:14+00:00" }, { "name": "sebastian/complexity", @@ -2504,16 +3532,16 @@ }, { "name": "sebastian/environment", - "version": "5.1.3", + "version": "5.1.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac" + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { @@ -2555,7 +3583,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + "source": "https://github.com/sebastianbergmann/environment/tree/5.1" }, "funding": [ { @@ -2563,7 +3591,7 @@ "type": "github" } ], - "time": "2020-09-28T05:52:38+00:00" + "time": "2023-02-03T06:03:51+00:00" }, { "name": "sebastian/exporter", @@ -2571,12 +3599,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", "shasum": "" }, "require": { @@ -2640,20 +3668,20 @@ "type": "github" } ], - "time": "2021-11-11T14:18:36+00:00" + "time": "2022-09-14T06:03:37+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.3", + "version": "5.0.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49" + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49", - "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", "shasum": "" }, "require": { @@ -2696,7 +3724,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" }, "funding": [ { @@ -2704,7 +3732,7 @@ "type": "github" } ], - "time": "2021-06-11T13:31:12+00:00" + "time": "2022-02-14T08:28:10+00:00" }, { "name": "sebastian/lines-of-code", @@ -2877,16 +3905,16 @@ }, { "name": "sebastian/recursion-context", - "version": "4.0.4", + "version": "4.0.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", "shasum": "" }, "require": { @@ -2925,10 +3953,10 @@ } ], "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" }, "funding": [ { @@ -2936,20 +3964,20 @@ "type": "github" } ], - "time": "2020-10-26T13:17:30+00:00" + "time": "2023-02-03T06:07:39+00:00" }, { "name": "sebastian/resource-operations", - "version": "dev-master", + "version": "dev-main", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "e1157eac767e4dc4ae40dd9aab7fb4de6e56bd32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/e1157eac767e4dc4ae40dd9aab7fb4de6e56bd32", + "reference": "e1157eac767e4dc4ae40dd9aab7fb4de6e56bd32", "shasum": "" }, "require": { @@ -2962,7 +3990,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -2983,8 +4011,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/main" }, "funding": [ { @@ -2992,32 +4019,32 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2023-02-08T06:53:39+00:00" }, { "name": "sebastian/type", - "version": "2.3.x-dev", + "version": "3.2.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "f24cbc541026c3bb7d27c647f0f9ea337135b22a" + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f24cbc541026c3bb7d27c647f0f9ea337135b22a", - "reference": "f24cbc541026c3bb7d27c647f0f9ea337135b22a", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", "shasum": "" }, "require": { "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -3040,7 +4067,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3" + "source": "https://github.com/sebastianbergmann/type/tree/3.2" }, "funding": [ { @@ -3048,7 +4075,7 @@ "type": "github" } ], - "time": "2021-06-18T06:28:45+00:00" + "time": "2023-02-03T06:13:03+00:00" }, { "name": "sebastian/version", @@ -3105,46 +4132,43 @@ }, { "name": "symfony/console", - "version": "5.4.x-dev", + "version": "6.3.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "9130e1a0fc93cb0faadca4ee917171bd2ca9e5f4" + "reference": "1090bd292e4de35682f80e94d196c62aab4b3ad7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/9130e1a0fc93cb0faadca4ee917171bd2ca9e5f4", - "reference": "9130e1a0fc93cb0faadca4ee917171bd2ca9e5f4", + "url": "https://api.github.com/repos/symfony/console/zipball/1090bd292e4de35682f80e94d196c62aab4b3ad7", + "reference": "1090bd292e4de35682f80e94d196c62aab4b3ad7", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/string": "^5.1|^6.0" + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0" }, "conflict": { - "psr/log": ">=3", - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" }, "provide": { - "psr/log-implementation": "1.0|2.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { - "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/lock": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0" + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/lock": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/var-dumper": "^5.4|^6.0" }, "suggest": { "psr/log": "For using the console logger", @@ -3152,7 +4176,6 @@ "symfony/lock": "", "symfony/process": "" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -3185,7 +4208,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.1" + "source": "https://github.com/symfony/console/tree/6.3" }, "funding": [ { @@ -3201,29 +4224,30 @@ "type": "tidelift" } ], - "time": "2021-12-09T11:22:43+00:00" + "time": "2023-02-25T17:00:13+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "2.5.x-dev", + "version": "dev-main", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" + "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", - "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", + "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.1" }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.3-dev" }, "thanks": { "name": "symfony/contracts", @@ -3252,7 +4276,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/main" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1" }, "funding": [ { @@ -3268,50 +4292,48 @@ "type": "tidelift" } ], - "time": "2021-07-12T14:48:14+00:00" + "time": "2023-03-01T10:25:55+00:00" }, { "name": "symfony/event-dispatcher", - "version": "5.4.x-dev", + "version": "6.3.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "27d39ae126352b9fa3be5e196ccf4617897be3eb" + "reference": "c58ec8623b8cbb3739fbaab5bf972df3f68ef312" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/27d39ae126352b9fa3be5e196ccf4617897be3eb", - "reference": "27d39ae126352b9fa3be5e196ccf4617897be3eb", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c58ec8623b8cbb3739fbaab5bf972df3f68ef312", + "reference": "c58ec8623b8cbb3739fbaab5bf972df3f68ef312", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/event-dispatcher-contracts": "^2|^3", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<4.4" + "symfony/dependency-injection": "<5.4", + "symfony/service-contracts": "<2.5" }, "provide": { "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0" + "symfony/event-dispatcher-implementation": "2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^4.4|^5.0|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/stopwatch": "^4.4|^5.0|^6.0" + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/error-handler": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^5.4|^6.0" }, "suggest": { "symfony/dependency-injection": "", "symfony/http-kernel": "" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -3338,7 +4360,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.0" + "source": "https://github.com/symfony/event-dispatcher/tree/6.3" }, "funding": [ { @@ -3354,33 +4376,34 @@ "type": "tidelift" } ], - "time": "2021-11-23T10:19:22+00:00" + "time": "2023-02-16T09:01:12+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "2.5.x-dev", + "version": "dev-main", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "66bea3b09be61613cd3b4043a65a8ec48cfa6d2a" + "reference": "0ad3b6f1e4e2da5690fefe075cd53a238646d8dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/66bea3b09be61613cd3b4043a65a8ec48cfa6d2a", - "reference": "66bea3b09be61613cd3b4043a65a8ec48cfa6d2a", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ad3b6f1e4e2da5690fefe075cd53a238646d8dd", + "reference": "0ad3b6f1e4e2da5690fefe075cd53a238646d8dd", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "psr/event-dispatcher": "^1" }, "suggest": { "symfony/event-dispatcher-implementation": "" }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.3-dev" }, "thanks": { "name": "symfony/contracts", @@ -3417,7 +4440,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/2.5" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.2.1" }, "funding": [ { @@ -3433,29 +4456,27 @@ "type": "tidelift" } ], - "time": "2021-07-12T14:48:14+00:00" + "time": "2023-03-01T10:32:47+00:00" }, { "name": "symfony/filesystem", - "version": "5.4.x-dev", + "version": "6.3.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "731f917dc31edcffec2c6a777f3698c33bea8f01" + "reference": "bf3226d895bb4cd6635ef42649ec4a5818e3bf01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/731f917dc31edcffec2c6a777f3698c33bea8f01", - "reference": "731f917dc31edcffec2c6a777f3698c33bea8f01", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/bf3226d895bb4cd6635ef42649ec4a5818e3bf01", + "reference": "bf3226d895bb4cd6635ef42649ec4a5818e3bf01", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", - "symfony/polyfill-php80": "^1.16" + "symfony/polyfill-mbstring": "~1.8" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -3482,7 +4503,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.0" + "source": "https://github.com/symfony/filesystem/tree/6.3" }, "funding": [ { @@ -3498,28 +4519,28 @@ "type": "tidelift" } ], - "time": "2021-10-28T13:39:27+00:00" + "time": "2023-02-14T09:04:20+00:00" }, { "name": "symfony/finder", - "version": "5.4.x-dev", + "version": "6.3.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "d2f29dac98e96a98be467627bd49c2efb1bc2590" + "reference": "f5891f0383dc22a615ebd5848e87328d1efad0be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/d2f29dac98e96a98be467627bd49c2efb1bc2590", - "reference": "d2f29dac98e96a98be467627bd49c2efb1bc2590", + "url": "https://api.github.com/repos/symfony/finder/zipball/f5891f0383dc22a615ebd5848e87328d1efad0be", + "reference": "f5891f0383dc22a615ebd5848e87328d1efad0be", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1" + }, + "require-dev": { + "symfony/filesystem": "^6.0" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -3546,7 +4567,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.0" + "source": "https://github.com/symfony/finder/tree/6.3" }, "funding": [ { @@ -3562,29 +4583,26 @@ "type": "tidelift" } ], - "time": "2021-11-28T15:25:38+00:00" + "time": "2023-02-14T09:04:20+00:00" }, { "name": "symfony/options-resolver", - "version": "5.4.x-dev", + "version": "6.3.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "b0fb78576487af19c500aaddb269fd36701d4847" + "reference": "2fdfd4259397b1300da21c04ba52a673763b73c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b0fb78576487af19c500aaddb269fd36701d4847", - "reference": "b0fb78576487af19c500aaddb269fd36701d4847", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/2fdfd4259397b1300da21c04ba52a673763b73c9", + "reference": "2fdfd4259397b1300da21c04ba52a673763b73c9", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php73": "~1.0", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -3616,7 +4634,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.4.0" + "source": "https://github.com/symfony/options-resolver/tree/6.3" }, "funding": [ { @@ -3632,7 +4650,7 @@ "type": "tidelift" } ], - "time": "2021-11-23T10:19:22+00:00" + "time": "2023-02-14T09:04:20+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3640,12 +4658,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { @@ -3661,7 +4679,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3669,12 +4687,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3715,7 +4733,7 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -3723,12 +4741,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + "reference": "875e90aeea2777b6f135677f618529449334a612" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", + "reference": "875e90aeea2777b6f135677f618529449334a612", "shasum": "" }, "require": { @@ -3741,7 +4759,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3749,12 +4767,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3797,7 +4815,7 @@ "type": "tidelift" } ], - "time": "2021-11-23T21:10:46+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-intl-normalizer", @@ -3805,12 +4823,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "shasum": "" }, "require": { @@ -3823,7 +4841,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3831,12 +4849,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -3866,7 +4884,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/main" }, "funding": [ { @@ -3882,7 +4900,7 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -3890,12 +4908,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + "reference": "f9c7affe77a00ae32ca127ca6833d034e6d33f25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f9c7affe77a00ae32ca127ca6833d034e6d33f25", + "reference": "f9c7affe77a00ae32ca127ca6833d034e6d33f25", "shasum": "" }, "require": { @@ -3911,7 +4929,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3919,12 +4937,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3966,87 +4984,7 @@ "type": "tidelift" } ], - "time": "2021-11-30T18:21:41+00:00" - }, - { - "name": "symfony/polyfill-php73", - "version": "dev-main", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "default-branch": true, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/main" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-06-05T21:20:04+00:00" + "time": "2023-01-30T17:25:47+00:00" }, { "name": "symfony/polyfill-php80", @@ -4054,12 +4992,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9" + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9", - "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "shasum": "" }, "require": { @@ -4069,7 +5007,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4077,12 +5015,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -4130,7 +5068,7 @@ "type": "tidelift" } ], - "time": "2021-09-13T13:58:33+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-php81", @@ -4138,12 +5076,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f" + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", - "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", "shasum": "" }, "require": { @@ -4153,7 +5091,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4161,12 +5099,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -4210,27 +5148,25 @@ "type": "tidelift" } ], - "time": "2021-09-13T13:58:11+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/process", - "version": "5.4.x-dev", + "version": "6.3.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "bf0e245dd8f115502d11df04cdb91c49abbc83ec" + "reference": "e65ce5c9ccb249616aab1dbec53fc938c9017a4c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/bf0e245dd8f115502d11df04cdb91c49abbc83ec", - "reference": "bf0e245dd8f115502d11df04cdb91c49abbc83ec", + "url": "https://api.github.com/repos/symfony/process/zipball/e65ce5c9ccb249616aab1dbec53fc938c9017a4c", + "reference": "e65ce5c9ccb249616aab1dbec53fc938c9017a4c", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -4257,7 +5193,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/5.4" + "source": "https://github.com/symfony/process/tree/6.3" }, "funding": [ { @@ -4273,26 +5209,25 @@ "type": "tidelift" } ], - "time": "2021-12-11T16:33:38+00:00" + "time": "2023-02-24T10:44:40+00:00" }, { "name": "symfony/service-contracts", - "version": "2.5.x-dev", + "version": "dev-main", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "034c73d5dd4c05c71a27f05b3c43c0f2fcc8985a" + "reference": "a8c9cedf55f314f3a186041d19537303766df09a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/034c73d5dd4c05c71a27f05b3c43c0f2fcc8985a", - "reference": "034c73d5dd4c05c71a27f05b3c43c0f2fcc8985a", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a8c9cedf55f314f3a186041d19537303766df09a", + "reference": "a8c9cedf55f314f3a186041d19537303766df09a", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1|^3" + "php": ">=8.1", + "psr/container": "^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -4300,10 +5235,11 @@ "suggest": { "symfony/service-implementation": "" }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.3-dev" }, "thanks": { "name": "symfony/contracts", @@ -4313,7 +5249,10 @@ "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" - } + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4340,7 +5279,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/2.5" + "source": "https://github.com/symfony/service-contracts/tree/v3.2.1" }, "funding": [ { @@ -4356,27 +5295,26 @@ "type": "tidelift" } ], - "time": "2021-11-23T10:19:22+00:00" + "time": "2023-03-01T10:32:47+00:00" }, { "name": "symfony/stopwatch", - "version": "5.4.x-dev", + "version": "6.3.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "208ef96122bfed82a8f3a61458a07113a08bdcfe" + "reference": "f7fa451783b748e7b5942b9afe889b8df062e935" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/208ef96122bfed82a8f3a61458a07113a08bdcfe", - "reference": "208ef96122bfed82a8f3a61458a07113a08bdcfe", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/f7fa451783b748e7b5942b9afe889b8df062e935", + "reference": "f7fa451783b748e7b5942b9afe889b8df062e935", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/service-contracts": "^1|^2|^3" + "php": ">=8.1", + "symfony/service-contracts": "^2.5|^3" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -4403,7 +5341,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.4.0" + "source": "https://github.com/symfony/stopwatch/tree/6.3" }, "funding": [ { @@ -4419,48 +5357,47 @@ "type": "tidelift" } ], - "time": "2021-11-23T10:19:22+00:00" + "time": "2023-02-14T09:04:20+00:00" }, { "name": "symfony/string", - "version": "5.4.x-dev", + "version": "6.3.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "1a03b5bab07779e5f23f8b60ba76ccb7662ffcf6" + "reference": "599f0f073afa9866d1d3b16c1ffafa74a69fb3ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/1a03b5bab07779e5f23f8b60ba76ccb7662ffcf6", - "reference": "1a03b5bab07779e5f23f8b60ba76ccb7662ffcf6", + "url": "https://api.github.com/repos/symfony/string/zipball/599f0f073afa9866d1d3b16c1ffafa74a69fb3ce", + "reference": "599f0f073afa9866d1d3b16c1ffafa74a69fb3ce", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": ">=3.0" + "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0|^6.0" + "symfony/error-handler": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/intl": "^6.2", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^5.4|^6.0" }, - "default-branch": true, "type": "library", "autoload": { - "psr-4": { - "Symfony\\Component\\String\\": "" - }, "files": [ "Resources/functions.php" ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, "exclude-from-classmap": [ "/Tests/" ] @@ -4490,7 +5427,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/5.4" + "source": "https://github.com/symfony/string/tree/6.3" }, "funding": [ { @@ -4506,7 +5443,7 @@ "type": "tidelift" } ], - "time": "2021-12-11T13:33:37+00:00" + "time": "2023-02-24T10:44:40+00:00" }, { "name": "theseer/tokenizer", @@ -4557,81 +5494,27 @@ } ], "time": "2021-07-28T10:34:58+00:00" - }, - { - "name": "webmozart/assert", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "b419d648592b0b8911cbbe10d450fe314f4fd262" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/b419d648592b0b8911cbbe10d450fe314f4fd262", - "reference": "b419d648592b0b8911cbbe10d450fe314f4fd262", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "default-branch": true, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/master" - }, - "time": "2021-06-19T13:45:26+00:00" } ], "aliases": [], "minimum-stability": "dev", - "stability-flags": [], + "stability-flags": { + "shish/gqla": 20, + "naroga/redis-cache": 20, + "scrutinizer/ocular": 20, + "phpstan/phpstan": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.4 | ^8.0", + "php": "^8.1", "ext-pdo": "*", "ext-json": "*", "ext-fileinfo": "*" }, "platform-dev": [], "platform-overrides": { - "php": "7.4.0" + "php": "8.1.0" }, - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } diff --git a/core/basepage.php b/core/basepage.php index 11a99a88..410ae35b 100644 --- a/core/basepage.php +++ b/core/basepage.php @@ -1,15 +1,18 @@ mode = $mode; } @@ -227,7 +230,7 @@ class BasePage public function send_headers(): void { if (!headers_sent()) { - header("HTTP/1.0 {$this->code} Shimmie"); + header("HTTP/1.1 {$this->code} Shimmie"); header("Content-type: " . $this->mime); header("X-Powered-By: Shimmie-" . VERSION); @@ -255,7 +258,7 @@ class BasePage case PageMode::MANUAL: break; case PageMode::PAGE: - usort($this->blocks, "blockcmp"); + usort($this->blocks, "Shimmie2\blockcmp"); $this->add_auto_html_headers(); $this->render(); break; @@ -270,6 +273,7 @@ class BasePage if (!is_null($this->filename)) { header('Content-Disposition: ' . $this->disposition . '; filename=' . $this->filename); } + assert($this->file, "file should not be null with PageMode::FILE"); // https://gist.github.com/codler/3906826 $size = filesize($this->file); // File size @@ -468,8 +472,8 @@ class BasePage } $sub_links = $sub_links??[]; - usort($nav_links, "sort_nav_links"); - usort($sub_links, "sort_nav_links"); + usort($nav_links, "Shimmie2\sort_nav_links"); + usort($sub_links, "Shimmie2\sort_nav_links"); return [$nav_links, $sub_links]; } diff --git a/core/basethemelet.php b/core/basethemelet.php index 13e8f245..2338d34f 100644 --- a/core/basethemelet.php +++ b/core/basethemelet.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + /** * Class BaseThemelet * @@ -64,7 +66,7 @@ class BaseThemelet } $custom_classes = ""; - if (class_exists("Relationships")) { + if (class_exists("Shimmie2\Relationships")) { if (property_exists($image, 'parent_id') && $image->parent_id !== null) { $custom_classes .= "shm-thumb-has_parent "; } @@ -136,8 +138,8 @@ class BaseThemelet $next_html = $at_end ? "Next" : $this->gen_page_link($base_url, $query, $next, "Next"); $last_html = $at_end ? "Last" : $this->gen_page_link($base_url, $query, $total_pages, "Last"); - $start = $current_page-5 > 1 ? $current_page-5 : 1; - $end = $start+10 < $total_pages ? $start+10 : $total_pages; + $start = max($current_page - 5, 1); + $end = min($start + 10, $total_pages); $pages = []; foreach (range($start, $end) as $i) { diff --git a/core/block.php b/core/block.php index 40e0c726..8cf31329 100644 --- a/core/block.php +++ b/core/block.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + /** * Class Block * @@ -43,10 +45,10 @@ class Block */ public bool $is_content = true; - public function __construct(string $header=null, string $body=null, string $section="main", int $position=50, string $id=null) + public function __construct(string $header=null, string|\MicroHTML\HTMLElement $body=null, string $section="main", int $position=50, string $id=null) { $this->header = $header; - $this->body = $body; + $this->body = (string)$body; $this->section = $section; $this->position = $position; diff --git a/core/cacheengine.php b/core/cacheengine.php index 37dadbea..18c379cc 100644 --- a/core/cacheengine.php +++ b/core/cacheengine.php @@ -1,200 +1,129 @@ memcache = new Memcached(); - #$this->memcache->setOption(Memcached::OPT_COMPRESSION, False); - #$this->memcache->setOption(Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_PHP); - #$this->memcache->setOption(Memcached::OPT_PREFIX_KEY, phpversion()); - $this->memcache->addServer($hp[0], (int)$hp[1]); + $this->engine = $engine; + $this->tracer = $tracer; } - public function get(string $key) + public function get($key, $default=null) { - $key = urlencode($key); - - $val = $this->memcache->get($key); - $res = $this->memcache->getResultCode(); - - if ($res == Memcached::RES_SUCCESS) { - return $val; - } elseif ($res == Memcached::RES_NOTFOUND) { - return false; - } else { - error_log("Memcached error during get($key): $res"); - return false; + if ($key === "__etc_cache_hits") { + return $this->hits; } - } - - public function set(string $key, $val, int $time=0): void - { - $key = urlencode($key); - - $this->memcache->set($key, $val, $time); - $res = $this->memcache->getResultCode(); - if ($res != Memcached::RES_SUCCESS) { - error_log("Memcached error during set($key): $res"); + if ($key === "__etc_cache_misses") { + return $this->misses; } - } - public function delete(string $key): void - { - $key = urlencode($key); - - $this->memcache->delete($key); - $res = $this->memcache->getResultCode(); - if ($res != Memcached::RES_SUCCESS && $res != Memcached::RES_NOTFOUND) { - error_log("Memcached error during delete($key): $res"); - } - } -} - -class APCCache implements CacheEngine -{ - public function __construct(string $args) - { - // $args is not used, but is passed in when APC cache is created. - } - - public function get(string $key) - { - return apc_fetch($key); - } - - public function set(string $key, $val, int $time=0): void - { - apc_store($key, $val, $time); - } - - public function delete(string $key): void - { - apc_delete($key); - } -} - -class RedisCache implements CacheEngine -{ - private Redis $redis; - - public function __construct(string $args) - { - $this->redis = new Redis(); - $hp = explode(":", $args); - $this->redis->pconnect($hp[0], (int)$hp[1]); - $this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); - $this->redis->setOption(Redis::OPT_PREFIX, 'shm:'); - } - - public function get(string $key) - { - return $this->redis->get($key); - } - - public function set(string $key, $val, int $time=0): void - { - if ($time > 0) { - $this->redis->setEx($key, $time, $val); - } else { - $this->redis->set($key, $val); - } - } - - public function delete(string $key): void - { - $this->redis->del($key); - } -} - -class Cache -{ - public $engine; - public int $hits=0; - public int $misses=0; - public int $time=0; - - public function __construct(?string $dsn) - { - $matches = []; - $c = null; - if ($dsn && preg_match("#(.*)://(.*)#", $dsn, $matches) && !isset($_GET['DISABLE_CACHE'])) { - if ($matches[1] == "memcached") { - $c = new MemcachedCache($matches[2]); - } elseif ($matches[1] == "apc") { - $c = new APCCache($matches[2]); - } elseif ($matches[1] == "redis") { - $c = new RedisCache($matches[2]); - } - } else { - $c = new NoCache(); - } - $this->engine = $c; - } - - public function get(string $key) - { - global $_tracer; - $_tracer->begin("Cache Query", ["key"=>$key]); - $val = $this->engine->get($key); - if ($val !== false) { + $sentinel = "__etc_sentinel"; + $this->tracer->begin("Cache Get", ["key"=>$key]); + $val = $this->engine->get($key, $sentinel); + if ($val != $sentinel) { $res = "hit"; $this->hits++; } else { $res = "miss"; + $val = $default; $this->misses++; } - $_tracer->end(null, ["result"=>$res]); + $this->tracer->end(null, ["result"=>$res]); return $val; } - public function set(string $key, $val, int $time=0) + public function set($key, $value, $ttl = null) { - global $_tracer; - $_tracer->begin("Cache Set", ["key"=>$key, "time"=>$time]); - $this->engine->set($key, $val, $time); - $_tracer->end(); + $this->tracer->begin("Cache Set", ["key"=>$key, "ttl"=>$ttl]); + $val = $this->engine->set($key, $value, $ttl); + $this->tracer->end(); + return $val; } - public function delete(string $key) + public function delete($key) { - global $_tracer; - $_tracer->begin("Cache Delete", ["key"=>$key]); - $this->engine->delete($key); - $_tracer->end(); + $this->tracer->begin("Cache Delete", ["key"=>$key]); + $val = $this->engine->delete($key); + $this->tracer->end(); + return $val; } - public function get_hits(): int + public function clear() { - return $this->hits; + $this->tracer->begin("Cache Clear"); + $val = $this->engine->clear(); + $this->tracer->end(); + return $val; } - public function get_misses(): int + + public function getMultiple($keys, $default = null) { - return $this->misses; + $this->tracer->begin("Cache Get Multiple", ["keys" => $keys]); + $val = $this->engine->getMultiple($keys, $default); + $this->tracer->end(); + return $val; + } + + public function setMultiple($values, $ttl = null) + { + $this->tracer->begin("Cache Set Multiple", ["keys" => array_keys($values)]); + $val = $this->engine->setMultiple($values, $ttl); + $this->tracer->end(); + return $val; + } + + public function deleteMultiple($keys) + { + $this->tracer->begin("Cache Delete Multiple", ["keys" => $keys]); + $val = $this->engine->deleteMultiple($keys); + $this->tracer->end(); + return $val; + } + + public function has($key) + { + $this->tracer->begin("Cache Has", ["key"=>$key]); + $val = $this->engine->has($key); + $this->tracer->end(null, ["exists"=>$val]); + return $val; } } + +function loadCache(?string $dsn): CacheInterface +{ + $matches = []; + $c = null; + if ($dsn && preg_match("#(.*)://(.*)#", $dsn, $matches) && !isset($_GET['DISABLE_CACHE'])) { + if ($matches[1] == "memcached" || $matches[1] == "memcache") { + $hp = explode(":", $matches[2]); + $memcache = new \Memcached(); + $memcache->addServer($hp[0], (int)$hp[1]); + $c = new \Sabre\Cache\Memcached($memcache); + } elseif ($matches[1] == "apc") { + $c = new \Sabre\Cache\Apcu(); + } elseif ($matches[1] == "redis") { + $hp = explode(":", $matches[2]); + $redis = new \Predis\Client([ + 'scheme' => 'tcp', + 'host' => $hp[0], + 'port' => (int)$hp[1] + ], ['prefix' => 'shm:']); + $c = new \Naroga\RedisCache\Redis($redis); + } + } else { + $c = new \Sabre\Cache\Memory(); + } + global $_tracer; + return new EventTracingCache($c, $_tracer); +} diff --git a/core/captcha.php b/core/captcha.php index ec79c2cb..22c36f97 100644 --- a/core/captcha.php +++ b/core/captcha.php @@ -1,6 +1,9 @@ "; - } else { + } /*else { session_start(); - $captcha = Securimage::getCaptchaHtml(['securimage_path' => './vendor/dapphp/securimage/']); - } + $captcha = \Securimage::getCaptchaHtml(['securimage_path' => './vendor/dapphp/securimage/']); + }*/ } return $captcha; } @@ -48,14 +51,14 @@ function captcha_check(): bool log_info("core", "Captcha failed (ReCaptcha): " . implode("", $resp->getErrorCodes())); return false; } - } else { + } /*else { session_start(); - $securimg = new Securimage(); + $securimg = new \Securimage(); if ($securimg->check($_POST['captcha_code']) === false) { log_info("core", "Captcha failed (Securimage)"); return false; } - } + }*/ } return true; diff --git a/core/command_builder.php b/core/command_builder.php index bd1f828b..34b4532e 100644 --- a/core/command_builder.php +++ b/core/command_builder.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + // Provides mechanisms for cleanly executing command-line applications // Was created to try to centralize a solution for whatever caused this: // quotes are only needed if the path to convert contains a space; some other times, quotes break things, see github bug #27 @@ -14,7 +16,7 @@ class CommandBuilder public function __construct(String $executable) { if (empty($executable)) { - throw new InvalidArgumentException("executable cannot be empty"); + throw new \InvalidArgumentException("executable cannot be empty"); } $this->executable = $executable; diff --git a/core/config.php b/core/config.php index 708d94be..3372bf17 100644 --- a/core/config.php +++ b/core/config.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + /** * Interface Config * @@ -262,6 +264,7 @@ class DatabaseConfig extends BaseConfig private string $table_name; private ?string $sub_column; private ?string $sub_value; + private string $cache_name; public function __construct( Database $database, @@ -275,14 +278,10 @@ class DatabaseConfig extends BaseConfig $this->table_name = $table_name; $this->sub_value = $sub_value; $this->sub_column = $sub_column; + $this->cache_name = empty($sub_value) ? "config" : "config_{$sub_value}"; - $cache_name = "config"; - if (!empty($sub_value)) { - $cache_name .= "_".$sub_value; - } - - $cached = $cache->get($cache_name); - if ($cached) { + $cached = $cache->get($this->cache_name); + if (!is_null($cached)) { $this->values = $cached; } else { $this->values = []; @@ -298,7 +297,7 @@ class DatabaseConfig extends BaseConfig foreach ($this->database->get_all($query, $args) as $row) { $this->values[$row["name"]] = $row["value"]; } - $cache->set($cache_name, $this->values); + $cache->set($this->cache_name, $this->values); } } @@ -333,7 +332,7 @@ class DatabaseConfig extends BaseConfig } // rather than deleting and having some other request(s) do a thundering // herd of race-conditioned updates, just save the updated version once here - $cache->set("config", $this->values); - $this->database->notify("config"); + $cache->set($this->cache_name, $this->values); + $this->database->notify($this->cache_name); } } diff --git a/core/database.php b/core/database.php index e83b08e7..78f8cf80 100644 --- a/core/database.php +++ b/core/database.php @@ -1,13 +1,17 @@ db = new PDO($this->dsn); $this->connect_engine(); - $this->engine->init($this->db); + $this->get_engine()->init($this->db); $this->begin_transaction(); } @@ -54,11 +59,11 @@ class Database throw new SCoreException("Can't figure out database engine"); } - if ($db_proto === DatabaseDriver::MYSQL) { + if ($db_proto === DatabaseDriverID::MYSQL->value) { $this->engine = new MySQL(); - } elseif ($db_proto === DatabaseDriver::PGSQL) { + } elseif ($db_proto === DatabaseDriverID::PGSQL->value) { $this->engine = new PostgreSQL(); - } elseif ($db_proto === DatabaseDriver::SQLITE) { + } elseif ($db_proto === DatabaseDriverID::SQLITE->value) { $this->engine = new SQLite(); } else { die_nicely( @@ -98,47 +103,53 @@ class Database } } - public function scoreql_to_sql(string $input): string + private function get_engine(): DBEngine { if (is_null($this->engine)) { $this->connect_engine(); } - return $this->engine->scoreql_to_sql($input); + return $this->engine; } - public function get_driver_name(): string + public function scoreql_to_sql(string $input): string { - if (is_null($this->engine)) { - $this->connect_engine(); - } - return $this->engine->name; + return $this->get_engine()->scoreql_to_sql($input); + } + + public function get_driver_id(): DatabaseDriverID + { + return $this->get_engine()->id; } public function get_version(): string { - return $this->engine->get_version($this->db); + return $this->get_engine()->get_version($this->db); } private function count_time(string $method, float $start, string $query, ?array $args): void { global $_tracer, $tracer_enabled; - $dur = microtime(true) - $start; + $dur = ftime() - $start; + // trim whitespace + $query = preg_replace('/[\n\t ]/m', ' ', $query); + $query = preg_replace('/ +/m', ' ', $query); + $query = trim($query); if ($tracer_enabled) { - $query = trim(preg_replace('/^[\t ]+/m', '', $query)); // trim leading whitespace $_tracer->complete($start * 1000000, $dur * 1000000, "DB Query", ["query"=>$query, "args"=>$args, "method"=>$method]); } + $this->queries[] = $query; $this->query_count++; $this->dbtime += $dur; } public function set_timeout(?int $time): void { - $this->engine->set_timeout($this->db, $time); + $this->get_engine()->set_timeout($this->db, $time); } public function notify(string $channel, ?string $data=null): void { - $this->engine->notify($this->db, $channel, $data); + $this->get_engine()->notify($this->db, $channel, $data); } public function execute(string $query, array $args = []): PDOStatement @@ -147,12 +158,17 @@ class Database if (is_null($this->db)) { $this->connect_db(); } - return $this->db->execute( + $ret = $this->db->execute( "-- " . str_replace("%2F", "/", urlencode($_GET['q'] ?? '')). "\n" . $query, $args ); - } catch (PDOException $pdoe) { + if ($ret === false) { + throw new SCoreException("Query failed", $query); + } + /** @noinspection PhpIncompatibleReturnTypeInspection */ + return $ret; + } catch (\PDOException $pdoe) { throw new SCoreException($pdoe->getMessage(), $query); } } @@ -162,7 +178,7 @@ class Database */ public function get_all(string $query, array $args = []): array { - $_start = microtime(true); + $_start = ftime(); $data = $this->execute($query, $args)->fetchAll(); $this->count_time("get_all", $_start, $query, $args); return $data; @@ -173,7 +189,7 @@ class Database */ public function get_all_iterable(string $query, array $args = []): PDOStatement { - $_start = microtime(true); + $_start = ftime(); $data = $this->execute($query, $args); $this->count_time("get_all_iterable", $_start, $query, $args); return $data; @@ -184,7 +200,7 @@ class Database */ public function get_row(string $query, array $args = []): ?array { - $_start = microtime(true); + $_start = ftime(); $row = $this->execute($query, $args)->fetch(); $this->count_time("get_row", $_start, $query, $args); return $row ? $row : null; @@ -195,7 +211,7 @@ class Database */ public function get_col(string $query, array $args = []): array { - $_start = microtime(true); + $_start = ftime(); $res = $this->execute($query, $args)->fetchAll(PDO::FETCH_COLUMN); $this->count_time("get_col", $_start, $query, $args); return $res; @@ -204,9 +220,9 @@ class Database /** * Execute an SQL query and return the first column of each row as a single iterable object. */ - public function get_col_iterable(string $query, array $args = []): Generator + public function get_col_iterable(string $query, array $args = []): \Generator { - $_start = microtime(true); + $_start = ftime(); $stmt = $this->execute($query, $args); $this->count_time("get_col_iterable", $_start, $query, $args); foreach ($stmt as $row) { @@ -219,7 +235,7 @@ class Database */ public function get_pairs(string $query, array $args = []): array { - $_start = microtime(true); + $_start = ftime(); $res = $this->execute($query, $args)->fetchAll(PDO::FETCH_KEY_PAIR); $this->count_time("get_pairs", $_start, $query, $args); return $res; @@ -229,9 +245,9 @@ class Database /** * Execute an SQL query and return the the first column => the second column as an iterable object. */ - public function get_pairs_iterable(string $query, array $args = []): Generator + public function get_pairs_iterable(string $query, array $args = []): \Generator { - $_start = microtime(true); + $_start = ftime(); $stmt = $this->execute($query, $args); $this->count_time("get_pairs_iterable", $_start, $query, $args); foreach ($stmt as $row) { @@ -244,7 +260,7 @@ class Database */ public function get_one(string $query, array $args = []) { - $_start = microtime(true); + $_start = ftime(); $row = $this->execute($query, $args)->fetch(); $this->count_time("get_one", $_start, $query, $args); return $row ? $row[0] : null; @@ -255,7 +271,7 @@ class Database */ public function exists(string $query, array $args = []): bool { - $_start = microtime(true); + $_start = ftime(); $row = $this->execute($query, $args)->fetch(); $this->count_time("exists", $_start, $query, $args); if ($row==null) { @@ -269,7 +285,7 @@ class Database */ public function get_last_insert_id(string $seq): int { - if ($this->engine->name == DatabaseDriver::PGSQL) { + if ($this->get_engine()->id == DatabaseDriverID::PGSQL) { $id = $this->db->lastInsertId($seq); } else { $id = $this->db->lastInsertId(); @@ -287,7 +303,7 @@ class Database $this->connect_engine(); } $data = trim($data, ", \t\n\r\0\x0B"); // mysql doesn't like trailing commas - $this->execute($this->engine->create_table_sql($name, $data)); + $this->execute($this->get_engine()->create_table_sql($name, $data)); } /** @@ -301,32 +317,35 @@ class Database $this->connect_db(); } - if ($this->engine->name === DatabaseDriver::MYSQL) { + if ($this->get_engine()->id === DatabaseDriverID::MYSQL) { return count( $this->get_all("SHOW TABLES") ); - } elseif ($this->engine->name === DatabaseDriver::PGSQL) { + } elseif ($this->get_engine()->id === DatabaseDriverID::PGSQL) { return count( $this->get_all("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'") ); - } elseif ($this->engine->name === DatabaseDriver::SQLITE) { + } elseif ($this->get_engine()->id === DatabaseDriverID::SQLITE) { return count( $this->get_all("SELECT name FROM sqlite_master WHERE type = 'table'") ); } else { - throw new SCoreException("Can't count tables for database type {$this->engine->name}"); + throw new SCoreException("Can't count tables for database type {$this->get_engine()->id}"); } } public function raw_db(): PDO { + if (is_null($this->db)) { + $this->connect_db(); + } return $this->db; } public function standardise_boolean(string $table, string $column, bool $include_postgres=false): void { - $d = $this->get_driver_name(); - if ($d == DatabaseDriver::MYSQL) { + $d = $this->get_driver_id(); + if ($d == DatabaseDriverID::MYSQL) { # In mysql, ENUM('Y', 'N') is secretly INTEGER where Y=1 and N=2. # BOOLEAN is secretly TINYINT where true=1 and false=0. # So we can cast directly from ENUM to BOOLEAN which gives us a @@ -335,16 +354,16 @@ class Database $this->execute("ALTER TABLE $table MODIFY COLUMN $column BOOLEAN;"); $this->execute("UPDATE $table SET $column=0 WHERE $column=2;"); } - if ($d == DatabaseDriver::SQLITE) { + if ($d == DatabaseDriverID::SQLITE) { # SQLite doesn't care about column types at all, everything is # text, so we can in-place replace a char with a bool $this->execute("UPDATE $table SET $column = ($column IN ('Y', 1))"); } - if ($d == DatabaseDriver::PGSQL && $include_postgres) { - $this->execute("ALTER TABLE $table ADD COLUMN ${column}_b BOOLEAN DEFAULT FALSE NOT NULL"); - $this->execute("UPDATE $table SET ${column}_b = ($column = 'Y')"); + if ($d == DatabaseDriverID::PGSQL && $include_postgres) { + $this->execute("ALTER TABLE $table ADD COLUMN {$column}_b BOOLEAN DEFAULT FALSE NOT NULL"); + $this->execute("UPDATE $table SET {$column}_b = ($column = 'Y')"); $this->execute("ALTER TABLE $table DROP COLUMN $column"); - $this->execute("ALTER TABLE $table RENAME COLUMN ${column}_b TO $column"); + $this->execute("ALTER TABLE $table RENAME COLUMN {$column}_b TO $column"); } } } diff --git a/core/dbengine.php b/core/dbengine.php index 22ea3cc0..bf32cd47 100644 --- a/core/dbengine.php +++ b/core/dbengine.php @@ -1,6 +1,11 @@ exec("PRAGMA foreign_keys = ON;"); - $db->sqliteCreateFunction('UNIX_TIMESTAMP', '_unix_timestamp', 1); - $db->sqliteCreateFunction('now', '_now', 0); - $db->sqliteCreateFunction('floor', '_floor', 1); - $db->sqliteCreateFunction('log', '_log'); - $db->sqliteCreateFunction('isnull', '_isnull', 1); - $db->sqliteCreateFunction('md5', '_md5', 1); - $db->sqliteCreateFunction('concat', '_concat', 2); - $db->sqliteCreateFunction('lower', '_lower', 1); - $db->sqliteCreateFunction('rand', '_rand', 0); - $db->sqliteCreateFunction('ln', '_ln', 1); + $db->sqliteCreateFunction('UNIX_TIMESTAMP', 'Shimmie2\_unix_timestamp', 1); + $db->sqliteCreateFunction('now', 'Shimmie2\_now', 0); + $db->sqliteCreateFunction('floor', 'Shimmie2\_floor', 1); + $db->sqliteCreateFunction('log', 'Shimmie2\_log'); + $db->sqliteCreateFunction('isnull', 'Shimmie2\_isnull', 1); + $db->sqliteCreateFunction('md5', 'Shimmie2\_md5', 1); + $db->sqliteCreateFunction('concat', 'Shimmie2\_concat', 2); + $db->sqliteCreateFunction('lower', 'Shimmie2\_lower', 1); + $db->sqliteCreateFunction('rand', 'Shimmie2\_rand', 0); + $db->sqliteCreateFunction('ln', 'Shimmie2\_ln', 1); } public function scoreql_to_sql(string $data): string diff --git a/core/event.php b/core/event.php index 355ac504..db6798ab 100644 --- a/core/event.php +++ b/core/event.php @@ -1,6 +1,9 @@ theme = $this->get_theme_object($class); $this->info = ExtensionInfo::get_for_extension_class($class); - if ($this->info===null) { - throw new ScoreException("Info class not found for extension $class"); - } $this->key = $this->info->key; } @@ -37,8 +37,9 @@ abstract class Extension */ private function get_theme_object(string $base): ?Themelet { - $custom = 'Custom'.$base.'Theme'; - $normal = $base.'Theme'; + $base = str_replace("Shimmie2\\", "", $base); + $custom = "Shimmie2\Custom{$base}Theme"; + $normal = "Shimmie2\\{$base}Theme"; if (class_exists($custom)) { return new $custom(); @@ -61,9 +62,11 @@ abstract class Extension public static function determine_enabled_extensions(): void { self::$enabled_extensions = []; + $extras = defined("EXTRA_EXTS") ? explode(",", EXTRA_EXTS) : []; + foreach (array_merge( ExtensionInfo::get_core_extensions(), - explode(",", EXTRA_EXTS) + $extras ) as $key) { $ext = ExtensionInfo::get_by_key($key); if ($ext===null || !$ext->is_supported()) { @@ -107,6 +110,13 @@ abstract class Extension } } +enum ExtensionVisibility +{ + case DEFAULT; + case ADMIN; + case HIDDEN; +} + abstract class ExtensionInfo { // Every credit you get costs us RAM. It stops now. @@ -119,11 +129,6 @@ abstract class ExtensionInfo public const LICENSE_MIT = "MIT"; public const LICENSE_WTFPL = "WTFPL"; - public const VISIBLE_DEFAULT = "default"; - public const VISIBLE_ADMIN = "admin"; - public const VISIBLE_HIDDEN = "hidden"; - private const VALID_VISIBILITY = [self::VISIBLE_DEFAULT, self::VISIBLE_ADMIN, self::VISIBLE_HIDDEN]; - public string $key; public bool $core = false; @@ -135,12 +140,12 @@ abstract class ExtensionInfo public array $authors = []; public array $dependencies = []; public array $conflicts = []; - public string $visibility = self::VISIBLE_DEFAULT; + public ExtensionVisibility $visibility = ExtensionVisibility::DEFAULT; public ?string $link = null; public ?string $version = null; public ?string $documentation = null; - /** @var string[] which DBs this ext supports (blank for 'all') */ + /** @var DatabaseDriverID[] which DBs this ext supports (blank for 'all') */ public array $db_support = []; private ?bool $supported = null; private ?string $support_info = null; @@ -169,7 +174,6 @@ abstract class ExtensionInfo { assert(!empty($this->key), "key field is required"); assert(!empty($this->name), "name field is required for extension $this->key"); - assert(empty($this->visibility) || in_array($this->visibility, self::VALID_VISIBILITY), "Invalid visibility for extension $this->key"); assert(is_array($this->db_support), "db_support has to be an array for extension $this->key"); assert(is_array($this->authors), "authors has to be an array for extension $this->key"); assert(is_array($this->dependencies), "dependencies has to be an array for extension $this->key"); @@ -184,7 +188,7 @@ abstract class ExtensionInfo { global $database; $this->support_info = ""; - if (!empty($this->db_support) && !in_array($database->get_driver_name(), $this->db_support)) { + if (!empty($this->db_support) && !in_array($database->get_driver_id(), $this->db_support)) { $this->support_info .= "Database not supported. "; } if (!empty($this->conflicts)) { @@ -223,23 +227,24 @@ abstract class ExtensionInfo } } - public static function get_for_extension_class(string $base): ?ExtensionInfo + public static function get_for_extension_class(string $base): ExtensionInfo { - $normal = $base.'Info'; + $normal = "{$base}Info"; if (array_key_exists($normal, self::$all_info_by_class)) { return self::$all_info_by_class[$normal]; } else { - return null; + $infos = print_r(array_keys(self::$all_info_by_class), true); + throw new SCoreException("$normal not found in {$infos}"); } } public static function load_all_extension_info() { - foreach (get_subclasses_of("ExtensionInfo") as $class) { + foreach (get_subclasses_of("Shimmie2\ExtensionInfo") as $class) { $extension_info = new $class(); if (array_key_exists($extension_info->key, self::$all_info_by_key)) { - throw new ScoreException("Extension Info $class with key $extension_info->key has already been loaded"); + throw new SCoreException("Extension Info $class with key $extension_info->key has already been loaded"); } self::$all_info_by_key[$extension_info->key] = $extension_info; @@ -308,43 +313,20 @@ abstract class DataHandlerExtension extends Extension if (is_null($existing)) { throw new UploadException("Post to replace does not exist!"); } - if ($existing->hash === $event->metadata['hash']) { + if ($existing->hash === $event->hash) { throw new UploadException("The uploaded post is the same as the one to replace."); } // even more hax.. $event->metadata['tags'] = $existing->get_tag_list(); - $image = $this->create_image_from_data(warehouse_path(Image::IMAGE_DIR, $event->metadata['hash']), $event->metadata); - if (is_null($image)) { - throw new UploadException("Data handler failed to create post object from data"); - } - if (empty($image->get_mime())) { - throw new UploadException("Unable to determine MIME for ". $event->tmpname); - } - try { - send_event(new MediaCheckPropertiesEvent($image)); - } catch (MediaException $e) { - throw new UploadException("Unable to scan media properties: ".$e->getMessage()); - } + $image = $this->create_image_from_data(warehouse_path(Image::IMAGE_DIR, $event->hash), $event->metadata); send_event(new ImageReplaceEvent($event->replace_id, $image)); $_id = $event->replace_id; assert(!is_null($_id)); $event->image_id = $_id; } else { $image = $this->create_image_from_data(warehouse_path(Image::IMAGE_DIR, $event->hash), $event->metadata); - if (is_null($image)) { - throw new UploadException("Data handler failed to create post object from data"); - } - if (empty($image->get_mime())) { - throw new UploadException("Unable to determine MIME for ". $event->tmpname); - } - try { - send_event(new MediaCheckPropertiesEvent($image)); - } catch (MediaException $e) { - throw new UploadException("Unable to scan media properties: ".$e->getMessage()); - } - $iae = send_event(new ImageAdditionEvent($image)); $event->image_id = $iae->image->id; $event->merged = $iae->merged; @@ -358,7 +340,7 @@ abstract class DataHandlerExtension extends Extension // Locked Stuff. if (!empty($event->metadata['locked'])) { $locked = $event->metadata['locked']; - send_event(new LockSetEvent($image, !empty($locked))); + send_event(new LockSetEvent($image, $locked)); } } } elseif ($supported_mime && !$check_contents) { @@ -390,14 +372,14 @@ abstract class DataHandlerExtension extends Extension { global $page; if ($this->supported_mime($event->image->get_mime())) { - /** @noinspection PhpPossiblePolymorphicInvocationInspection */ + // @phpstan-ignore-next-line $this->theme->display_image($page, $event->image); } } public function onMediaCheckProperties(MediaCheckPropertiesEvent $event) { - if ($this->supported_mime($event->mime)) { + if ($this->supported_mime($event->image->get_mime())) { $this->media_check_properties($event); } } @@ -406,19 +388,23 @@ abstract class DataHandlerExtension extends Extension { $image = new Image(); - $image->filesize = $metadata['size']; - $image->hash = $metadata['hash']; + assert(is_readable($filename)); + $image->filesize = filesize($filename); + $image->hash = md5_file($filename); $image->filename = (($pos = strpos($metadata['filename'], '?')) !== false) ? substr($metadata['filename'], 0, $pos) : $metadata['filename']; - - if (array_key_exists("extension", $metadata)) { - $image->set_mime(MimeType::get_for_file($filename, $metadata["extension"])); - } else { - $image->set_mime(MimeType::get_for_file($filename)); - } - + $image->set_mime(MimeType::get_for_file($filename, get_file_ext($metadata["filename"]) ?? null)); $image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']); $image->source = $metadata['source']; + if (empty($image->get_mime())) { + throw new UploadException("Unable to determine MIME for $filename"); + } + try { + send_event(new MediaCheckPropertiesEvent($image)); + } catch (MediaException $e) { + throw new UploadException("Unable to scan media properties $filename / $image->filename / $image->hash: ".$e->getMessage()); + } + return $image; } @@ -434,13 +420,13 @@ abstract class DataHandlerExtension extends Extension public static function get_all_supported_mimes(): array { $arr = []; - foreach (get_subclasses_of("DataHandlerExtension") as $handler) { + foreach (get_subclasses_of("Shimmie2\DataHandlerExtension") as $handler) { $handler = (new $handler()); $arr = array_merge($arr, $handler->SUPPORTED_MIME); } // Not sure how to handle this otherwise, don't want to set up a whole other event for this one class - if (class_exists("TranscodeImage")) { + if (class_exists("Shimmie2\TranscodeImage")) { $arr = array_merge($arr, TranscodeImage::get_enabled_mimes()); } diff --git a/core/imageboard/event.php b/core/imageboard/event.php index 70dc0afe..1580f848 100644 --- a/core/imageboard/event.php +++ b/core/imageboard/event.php @@ -2,13 +2,14 @@ declare(strict_types=1); +namespace Shimmie2; + /** * An image is being added to the database. */ class ImageAdditionEvent extends Event { public User $user; - public Image $image; public bool $merged = false; /** @@ -16,10 +17,10 @@ class ImageAdditionEvent extends Event * information. Also calls TagSetEvent to set the tags for * this new image. */ - public function __construct(Image $image) - { + public function __construct( + public Image $image, + ) { parent::__construct(); - $this->image = $image; } } @@ -32,20 +33,17 @@ class ImageAdditionException extends SCoreException */ class ImageDeletionEvent extends Event { - public Image $image; - public bool $force = false; - /** * Deletes an image. * * Used by things like tags and comments handlers to * clean out related rows in their tables. */ - public function __construct(Image $image, bool $force = false) - { + public function __construct( + public Image $image, + public bool $force = false, + ) { parent::__construct(); - $this->image = $image; - $this->force = $force; } } @@ -54,9 +52,6 @@ class ImageDeletionEvent extends Event */ class ImageReplaceEvent extends Event { - public int $id; - public Image $image; - /** * Replaces an image. * @@ -64,11 +59,11 @@ class ImageReplaceEvent extends Event * file, leaving the tags and such unchanged. Also removes * the old image file and thumbnail from the disk. */ - public function __construct(int $id, Image $image) - { + public function __construct( + public int $id, + public Image $image + ) { parent::__construct(); - $this->id = $id; - $this->image = $image; } } @@ -81,20 +76,17 @@ class ImageReplaceException extends SCoreException */ class ThumbnailGenerationEvent extends Event { - public string $hash; - public string $mime; - public bool $force; public bool $generated; /** * Request a thumbnail be made for an image object */ - public function __construct(string $hash, string $mime, bool $force=false) - { + public function __construct( + public string $hash, + public string $mime, + public bool $force=false + ) { parent::__construct(); - $this->hash = $hash; - $this->mime = $mime; - $this->force = $force; $this->generated = false; } } diff --git a/core/imageboard/image.php b/core/imageboard/image.php index f2fb0961..f40590a6 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -1,6 +1,13 @@ id; + } + #[Field(name: "id")] + public function graphql_guid(): string + { + return "post:{$this->id}"; + } + + #[Query(name: "post")] + public static function by_id(int $post_id): ?Image { global $database; - $row = $database->get_row("SELECT * FROM images WHERE images.id=:id", ["id"=>$id]); + if ($post_id > 2**32) { + // for some reason bots query huge numbers and pollute the DB error logs... + return null; + } + $row = $database->get_row("SELECT * FROM images WHERE images.id=:id", ["id"=>$post_id]); return ($row ? new Image($row) : null); } @@ -132,12 +166,13 @@ class Image /** * Search for an array of images * - * #param string[] $tags - * #return Image[] + * @param String[] $tags + * @return Image[] */ - public static function find_images(int $start, ?int $limit = null, array $tags=[]): array + #[Query(name: "posts", type: "[Post!]!", args: ["tags" => "[string!]"])] + public static function find_images(?int $offset = 0, ?int $limit = null, array $tags=[]): array { - $result = self::find_images_internal($start, $limit, $tags); + $result = self::find_images_internal($offset, $limit, $tags); $images = []; foreach ($result as $row) { @@ -149,7 +184,7 @@ class Image /** * Search for an array of images, returning a iterable object of Image */ - public static function find_images_iterable(int $start = 0, ?int $limit = null, array $tags=[]): Generator + public static function find_images_iterable(int $start = 0, ?int $limit = null, array $tags=[]): \Generator { $result = self::find_images_internal($start, $limit, $tags); foreach ($result as $row) { @@ -165,7 +200,7 @@ class Image { global $cache, $database; $total = $cache->get("image-count"); - if (!$total) { + if (is_null($total)) { $total = (int)$database->get_one("SELECT COUNT(*) FROM images"); $cache->set("image-count", $total, 600); } @@ -184,7 +219,7 @@ class Image /** * Count the number of image results for a given search * - * #param string[] $tags + * @param String[] $tags */ public static function count_images(array $tags=[]): int { @@ -207,7 +242,7 @@ class Image // implode(tags) can be too long for memcache... $cache_key = "image-count:" . md5(Tag::implode($tags)); $total = $cache->get($cache_key); - if (!$total) { + if (is_null($total)) { if (Extension::is_enabled(RatingsInfo::KEY)) { $tags[] = "rating:*"; } @@ -229,7 +264,7 @@ class Image /** * Count the number of pages for a given search * - * #param string[] $tags + * @param String[] $tags */ public static function count_pages(array $tags=[]): int { @@ -248,7 +283,6 @@ class Image * Turn a bunch of strings into a bunch of TagCondition * and ImgCondition objects */ - /** @var $stpe SearchTermParseEvent */ $stpe = send_event(new SearchTermParseEvent($stpen++, null, $terms)); if ($stpe->order) { $order = $stpe->order; @@ -268,7 +302,6 @@ class Image continue; } - /** @var $stpe SearchTermParseEvent */ $stpe = send_event(new SearchTermParseEvent($stpen++, $term, $terms)); if ($stpe->order) { $order = $stpe->order; @@ -296,7 +329,7 @@ class Image * Rather than simply $this_id + 1, one must take into account * deleted images and search queries * - * #param string[] $tags + * @param String[] $tags */ public function get_next(array $tags=[], bool $next=true): ?Image { @@ -332,7 +365,7 @@ class Image /** * The reverse of get_next * - * #param string[] $tags + * @param String[] $tags */ public function get_prev(array $tags=[]): ?Image { @@ -342,6 +375,7 @@ class Image /** * Find the User who owns this Image */ + #[Field(name: "owner")] public function get_owner(): User { return User::by_id($this->owner_id); @@ -369,7 +403,7 @@ class Image $cut_name = substr($this->filename, 0, 255); if (is_null($this->posted) || $this->posted == "") { - $this->posted = date('c', time()); + $this->posted = date('Y-m-d H:i:s', time()); } if (is_null($this->id)) { @@ -440,8 +474,9 @@ class Image /** * Get this image's tags as an array. * - * #return string[] + * @return String[] */ + #[Field(name: "tags", type: "[string!]!")] public function get_tag_array(): array { global $database; @@ -469,6 +504,7 @@ class Image /** * Get the URL for the full size image */ + #[Field(name: "image_link")] public function get_image_link(): string { return $this->get_link(ImageConfig::ILINK, '_images/$hash/$id%20-%20$tags.$ext', 'image/$id.$ext'); @@ -477,16 +513,16 @@ class Image /** * Get the nicely formatted version of the file name */ + #[Field(name: "nice_name")] public function get_nice_image_name(): string { - $plte = new ParseLinkTemplateEvent('$id - $tags.$ext', $this); - send_event($plte); - return $plte->text; + return send_event(new ParseLinkTemplateEvent('$id - $tags.$ext', $this))->text; } /** * Get the URL for the thumbnail */ + #[Field(name: "thumb_link")] public function get_thumb_link(): string { global $config; @@ -521,24 +557,22 @@ class Image * Get the tooltip for this image, formatted according to the * configured template. */ + #[Field(name: "tooltip")] public function get_tooltip(): string { global $config; - $plte = new ParseLinkTemplateEvent($config->get_string(ImageConfig::TIP), $this); - send_event($plte); - return $plte->text; + return send_event(new ParseLinkTemplateEvent($config->get_string(ImageConfig::TIP), $this))->text; } /** * Get the info for this image, formatted according to the * configured template. */ + #[Field(name: "info")] public function get_info(): string { global $config; - $plte = new ParseLinkTemplateEvent($config->get_string(ImageConfig::INFO), $this); - send_event($plte); - return $plte->text; + return send_event(new ParseLinkTemplateEvent($config->get_string(ImageConfig::INFO), $this))->text; } @@ -561,6 +595,7 @@ class Image /** * Get the original filename. */ + #[Field(name: "filename")] public function get_filename(): string { return $this->filename; @@ -569,6 +604,7 @@ class Image /** * Get the image's extension. */ + #[Field(name: "ext")] public function get_ext(): string { return $this->ext; @@ -577,6 +613,7 @@ class Image /** * Get the image's mime type. */ + #[Field(name: "mime")] public function get_mime(): ?string { if ($this->mime===MimeType::WEBP&&$this->lossless) { @@ -650,7 +687,7 @@ class Image public function delete_tags_from_image(): void { global $database; - if ($database->get_driver_name() == DatabaseDriver::MYSQL) { + if ($database->get_driver_id() == DatabaseDriverID::MYSQL) { //mysql < 5.6 has terrible subquery optimization, using EXISTS / JOIN fixes this $database->execute( " @@ -743,7 +780,7 @@ class Image VALUES(:iid, :tid) ", ["iid"=>$this->id, "tid"=>$id]); - array_push($written_tags, $id); + $written_tags[] = $id; } $database->execute( " @@ -796,14 +833,14 @@ class Image { global $database; $sq = "SELECT id FROM tags WHERE LOWER(tag) LIKE LOWER(:tag)"; - if ($database->get_driver_name() === DatabaseDriver::SQLITE) { + if ($database->get_driver_id() === DatabaseDriverID::SQLITE) { $sq .= "ESCAPE '\\'"; } return $database->get_col($sq, ["tag" => Tag::sqlify($tag)]); } /** - * #param string[] $terms + * @param String[] $terms */ private static function build_search_querylet( array $terms, diff --git a/core/imageboard/misc.php b/core/imageboard/misc.php index 0b871a78..e9944606 100644 --- a/core/imageboard/misc.php +++ b/core/imageboard/misc.php @@ -1,6 +1,9 @@ pathinfo($filename, PATHINFO_BASENAME), + 'tags' => Tag::explode($tags), + 'source' => $source, + ])); +} - $pathinfo = pathinfo($filename); - $metadata = []; - $metadata['filename'] = $pathinfo['basename']; - if (array_key_exists('extension', $pathinfo)) { - $metadata['extension'] = $pathinfo['extension']; - } - - $metadata['tags'] = Tag::explode($tags); - $metadata['source'] = null; - - $due = new DataUploadEvent($tmpname, $metadata); - send_event($due); - - return $due->image_id; +function get_file_ext(string $filename): ?string +{ + return pathinfo($filename)['extension'] ?? null; } /** diff --git a/core/imageboard/search.php b/core/imageboard/search.php index 10df2ec0..11ac9b03 100644 --- a/core/imageboard/search.php +++ b/core/imageboard/search.php @@ -1,15 +1,15 @@ sql = $sql; - $this->variables = $variables; + public function __construct( + public string $sql, + public array $variables=[], + ) { } public function append(Querylet $querylet): void @@ -31,24 +31,18 @@ class Querylet class TagCondition { - public string $tag; - public bool $positive; - - public function __construct(string $tag, bool $positive) - { - $this->tag = $tag; - $this->positive = $positive; + public function __construct( + public string $tag, + public bool $positive, + ) { } } class ImgCondition { - public Querylet $qlet; - public bool $positive; - - public function __construct(Querylet $qlet, bool $positive) - { - $this->qlet = $qlet; - $this->positive = $positive; + public function __construct( + public Querylet $qlet, + public bool $positive, + ) { } } diff --git a/core/imageboard/tag.php b/core/imageboard/tag.php index 3e79e26c..c5997586 100644 --- a/core/imageboard/tag.php +++ b/core/imageboard/tag.php @@ -1,6 +1,85 @@ tag = $tag; + $this->uses = $uses; + } + + /** + * @return TagUsage[] + */ + #[Query(name: "tags", type: '[TagUsage!]!')] + public static function tags(string $search, int $limit=10): array + { + global $cache, $database; + + if (!$search) { + return []; + } + + $search = strtolower($search); + if ( + $search == '' || + $search[0] == '_' || + $search[0] == '%' || + strlen($search) > 32 + ) { + return []; + } + + $cache_key = "tagusage-$search"; + $limitSQL = ""; + $search = str_replace('_', '\_', $search); + $search = str_replace('%', '\%', $search); + $SQLarr = ["search"=>"$search%"]; #, "cat_search"=>"%:$search%"]; + if ($limit !== 0) { + $limitSQL = "LIMIT :limit"; + $SQLarr['limit'] = $limit; + $cache_key .= "-" . $limit; + } + + $res = $cache->get($cache_key); + if (is_null($res)) { + $res = $database->get_pairs( + " + SELECT tag, count + FROM tags + WHERE LOWER(tag) LIKE LOWER(:search) + -- OR LOWER(tag) LIKE LOWER(:cat_search) + AND count > 0 + ORDER BY count DESC + $limitSQL + ", + $SQLarr + ); + $cache->set($cache_key, $res, 600); + } + + $counts = []; + foreach ($res as $k => $v) { + $counts[] = new TagUsage($k, $v); + } + return $counts; + } +} + /** * Class Tag * @@ -90,7 +169,7 @@ class Tag public static function sanitize(string $tag): string { $tag = preg_replace("/\s/", "", $tag); # whitespace - $tag = preg_replace('/\x20[\x0e\x0f]/', '', $tag); # unicode RTL + $tag = preg_replace('/\x20[\x0e\x0f]/', '', $tag); # unicode RTL $tag = preg_replace("/\.+/", ".", $tag); # strings of dots? $tag = preg_replace("/^(\.+[\/\\\\])+/", "", $tag); # trailing slashes? $tag = trim($tag, ", \t\n\r\0\x0B"); @@ -100,7 +179,7 @@ class Tag } // hard-code one bad case... if (mb_strlen($tag, 'UTF-8') > 255) { - throw new ScoreException("The tag below is longer than 255 characters, please use a shorter tag.\n$tag\n"); + throw new SCoreException("The tag below is longer than 255 characters, please use a shorter tag.\n$tag\n"); } return $tag; } @@ -113,15 +192,10 @@ class Tag $tags1 = array_map("strtolower", $tags1); $tags2 = array_map("strtolower", $tags2); - natcasesort($tags1); - natcasesort($tags2); + sort($tags1); + sort($tags2); - for ($i = 0; $i < count($tags1); $i++) { - if ($tags1[$i]!==$tags2[$i]) { - return false; - } - } - return true; + return $tags1 == $tags2; } public static function get_diff_tags(array $source, array $remove): array @@ -144,7 +218,7 @@ class Tag foreach ($tags as $tag) { try { $tag = Tag::sanitize($tag); - } catch (Exception $e) { + } catch (\Exception $e) { $page->flash($e->getMessage()); continue; } @@ -159,7 +233,7 @@ class Tag public static function sqlify(string $term): string { global $database; - if ($database->get_driver_name() === DatabaseDriver::SQLITE) { + if ($database->get_driver_id() === DatabaseDriverID::SQLITE) { $term = str_replace('\\', '\\\\', $term); } $term = str_replace('_', '\_', $term); diff --git a/core/install.php b/core/install.php index 106aa537..b18c14f8 100644 --- a/core/install.php +++ b/core/install.php @@ -1,4 +1,9 @@ value) { /** @noinspection PhpUnhandledExceptionInspection */ $id = bin2hex(random_bytes(5)); $dsn = "sqlite:data/shimmie.{$id}.sqlite"; @@ -97,11 +102,11 @@ function ask_questions() "; } - $drivers = PDO::getAvailableDrivers(); + $drivers = \PDO::getAvailableDrivers(); if ( - !in_array(DatabaseDriver::MYSQL, $drivers) && - !in_array(DatabaseDriver::PGSQL, $drivers) && - !in_array(DatabaseDriver::SQLITE, $drivers) + !in_array(DatabaseDriverID::MYSQL->value, $drivers) && + !in_array(DatabaseDriverID::PGSQL->value, $drivers) && + !in_array(DatabaseDriverID::SQLITE->value, $drivers) ) { $errors[] = " No database connection library could be found; shimmie needs @@ -109,9 +114,9 @@ function ask_questions() "; } - $db_m = in_array(DatabaseDriver::MYSQL, $drivers) ? '' : ""; - $db_p = in_array(DatabaseDriver::PGSQL, $drivers) ? '' : ""; - $db_s = in_array(DatabaseDriver::SQLITE, $drivers) ? '' : ""; + $db_m = in_array(DatabaseDriverID::MYSQL->value, $drivers) ? '' : ""; + $db_p = in_array(DatabaseDriverID::PGSQL->value, $drivers) ? '' : ""; + $db_s = in_array(DatabaseDriverID::SQLITE->value, $drivers) ? '' : ""; $warn_msg = $warnings ? "

Warnings

".implode("\n

", $warnings) : ""; $err_msg = $errors ? "

Errors

".implode("\n

", $errors) : ""; @@ -287,7 +292,7 @@ function create_tables(Database $db) if ($db->is_transaction_open()) { $db->commit(); } - } catch (PDOException $e) { + } catch (\PDOException $e) { throw new InstallerException( "PDO Error:", "

An error occurred while trying to create the database tables necessary for Shimmie.

diff --git a/core/logging.php b/core/logging.php index 50db58db..7b5c3694 100644 --- a/core/logging.php +++ b/core/logging.php @@ -1,6 +1,9 @@ isAbstract() && is_subclass_of($class, $parent)) { $result[] = $class; } @@ -333,38 +336,17 @@ function get_base_href(): string function unparse_url(array $parsed_url): string { $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : ''; - $host = isset($parsed_url['host']) ? $parsed_url['host'] : ''; + $host = $parsed_url['host'] ?? ''; $port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : ''; - $user = isset($parsed_url['user']) ? $parsed_url['user'] : ''; + $user = $parsed_url['user'] ?? ''; $pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : ''; $pass = ($user || $pass) ? "$pass@" : ''; - $path = isset($parsed_url['path']) ? $parsed_url['path'] : ''; + $path = $parsed_url['path'] ?? ''; $query = !empty($parsed_url['query']) ? '?' . $parsed_url['query'] : ''; $fragment = !empty($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : ''; return "$scheme$user$pass$host$port$path$query$fragment"; } -# finally in the core library starting from php8 -if (!function_exists('str_starts_with')) { - function str_starts_with(string $haystack, string $needle): bool - { - return strncmp($haystack, $needle, strlen($needle)) === 0; - } -} - -if (!function_exists('str_ends_with')) { - function str_ends_with(string $haystack, string $needle): bool - { - return $needle === '' || $needle === substr($haystack, - strlen($needle)); - } -} - -if (!function_exists('str_contains')) { - function str_contains(string $haystack, string $needle): bool - { - return '' === $needle || false !== strpos($haystack, $needle); - } -} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Input / Output Sanitising * @@ -517,19 +499,24 @@ function truncate(string $string, int $limit, string $break=" ", string $pad=".. function parse_shorthand_int(string $limit): int { if (preg_match('/^([\d\.]+)([tgmk])?b?$/i', (string)$limit, $m)) { - $value = $m[1]; + $value = (float)$m[1]; if (isset($m[2])) { switch (strtolower($m[2])) { /** @noinspection PhpMissingBreakStatementInspection */ - case 't': $value *= 1024; // fall through - /** @noinspection PhpMissingBreakStatementInspection */ - // no break - case 'g': $value *= 1024; // fall through - /** @noinspection PhpMissingBreakStatementInspection */ - // no break - case 'm': $value *= 1024; // fall through - // no break - case 'k': $value *= 1024; break; + case 't': + $value *= 1024; // fall through + /** @noinspection PhpMissingBreakStatementInspection */ + // no break + case 'g': + $value *= 1024; // fall through + /** @noinspection PhpMissingBreakStatementInspection */ + // no break + case 'm': + $value *= 1024; // fall through + // no break + case 'k': + $value *= 1024; + break; default: $value = -1; } } @@ -787,7 +774,7 @@ function join_path(string ...$paths): string /** * Perform callback on each item returned by an iterator. */ -function iterator_map(callable $callback, iterator $iter): Generator +function iterator_map(callable $callback, \iterator $iter): \Generator { foreach ($iter as $i) { yield call_user_func($callback, $i); @@ -797,7 +784,7 @@ function iterator_map(callable $callback, iterator $iter): Generator /** * Perform callback on each item returned by an iterator and combine the result into an array. */ -function iterator_map_to_array(callable $callback, iterator $iter): array +function iterator_map_to_array(callable $callback, \iterator $iter): array { return iterator_to_array(iterator_map($callback, $iter)); } @@ -806,7 +793,7 @@ function stringer($s): string { if (is_array($s)) { if (isset($s[0])) { - return "[" . implode(", ", array_map("stringer", $s)) . "]"; + return "[" . implode(", ", array_map("Shimmie2\stringer", $s)) . "]"; } else { $pairs = []; foreach ($s as $k=>$v) { @@ -815,8 +802,20 @@ function stringer($s): string return "[" . implode(", ", $pairs) . "]"; } } + if (is_null($s)) { + return "null"; + } if (is_string($s)) { return "\"$s\""; // FIXME: handle escaping quotes } - return (string)$s; + if (is_numeric($s)) { + return "$s"; + } + if (is_bool($s)) { + return $s ? "true" : "false"; + } + if (method_exists($s, "__toString")) { + return $s->__toString(); + } + return ""; } diff --git a/core/sanitize_php.php b/core/sanitize_php.php index db0f8654..a47cc394 100644 --- a/core/sanitize_php.php +++ b/core/sanitize_php.php @@ -1,6 +1,9 @@ =") === false) { die_nicely("Not Supported", " Shimmie does not support versions of PHP lower than $min_php @@ -45,7 +48,7 @@ set_error_handler(function ($errNo, $errStr) { // Should we turn ALL notices into errors? PHP allows a lot of // terrible things to happen by default... if (str_starts_with($errStr, 'Use of undefined constant ')) { - throw new Exception("PHP Error#$errNo: $errStr"); + throw new \Exception("PHP Error#$errNo: $errStr"); } else { return false; } diff --git a/core/send_event.php b/core/send_event.php index 4e461d1a..9eacf5cc 100644 --- a/core/send_event.php +++ b/core/send_event.php @@ -1,6 +1,9 @@ $listeners) { $p .= "\t'$event' => array(\n"; foreach ($listeners as $id => $listener) { - $p .= "\t\t$id => \$".get_class($listener).",\n"; + $p .= "\t\t$id => \$"._namespaced_class_name(get_class($listener)).",\n"; } $p .= "\t),\n"; } @@ -87,16 +96,21 @@ $_shm_event_count = 0; /** * Send an event to all registered Extensions. + * + * @template T of Event + * @param T $event + * @return T */ function send_event(Event $event): Event { global $tracer_enabled; global $_shm_event_listeners, $_shm_event_count, $_tracer; - if (!isset($_shm_event_listeners[get_class($event)])) { + $event_name = _namespaced_class_name(get_class($event)); + if (!isset($_shm_event_listeners[$event_name])) { return $event; } - $method_name = "on".str_replace("Event", "", get_class($event)); + $method_name = "on".str_replace("Event", "", $event_name); // send_event() is performance sensitive, and with the number // of times tracer gets called the time starts to add up @@ -104,7 +118,7 @@ function send_event(Event $event): Event $_tracer->begin(get_class($event)); } // SHIT: https://bugs.php.net/bug.php?id=35106 - $my_event_listeners = $_shm_event_listeners[get_class($event)]; + $my_event_listeners = $_shm_event_listeners[$event_name]; ksort($my_event_listeners); foreach ($my_event_listeners as $listener) { diff --git a/core/sys_config.php b/core/sys_config.php index 90f11169..2f5cb0c2 100644 --- a/core/sys_config.php +++ b/core/sys_config.php @@ -1,6 +1,9 @@ assertEquals("foo^q", Tag::caret("foo?")); $this->assertEquals("a^^b^sc^bd^qe^af", Tag::caret("a^b/c\\d?e&f")); } + + public function test_compare() + { + $this->assertFalse(Tag::compare(["foo"], ["bar"])); + $this->assertFalse(Tag::compare(["foo"], ["foo", "bar"])); + $this->assertTrue(Tag::compare([], [])); + $this->assertTrue(Tag::compare(["foo"], ["FoO"])); + $this->assertTrue(Tag::compare(["foo", "bar"], ["bar", "FoO"])); + } } diff --git a/core/tests/urls.test.php b/core/tests/urls.test.php index bdb6208d..fb34d4ab 100644 --- a/core/tests/urls.test.php +++ b/core/tests/urls.test.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + use PHPUnit\Framework\TestCase; require_once "core/urls.php"; diff --git a/core/tests/util.test.php b/core/tests/util.test.php index aea73971..30fffbf7 100644 --- a/core/tests/util.test.php +++ b/core/tests/util.test.php @@ -2,12 +2,49 @@ declare(strict_types=1); +namespace Shimmie2; + use PHPUnit\Framework\TestCase; require_once "core/util.php"; class UtilTest extends TestCase { + public function test_get_theme() + { + $this->assertEquals("default", get_theme()); + } + + public function test_get_memory_limit() + { + get_memory_limit(); + $this->assertTrue(true); + } + + public function test_check_gd_version() + { + check_gd_version(); + $this->assertTrue(true); + } + + public function test_check_im_version() + { + check_im_version(); + $this->assertTrue(true); + } + + public function test_human_filesize() + { + $this->assertEquals("123.00B", human_filesize(123)); + $this->assertEquals("123B", human_filesize(123, 0)); + $this->assertEquals("120.56KB", human_filesize(123456)); + } + + public function test_generate_key() + { + $this->assertEquals(20, strlen(generate_key())); + } + public function test_warehouse_path() { $hash = "7ac19c10d6859415"; @@ -85,4 +122,44 @@ class UtilTest extends TestCase load_balance_url("https://{foo=10,bar=5,baz=5}.mycdn.com/$hash.$ext", $hash, 1) ); } + + public function test_path_to_tags() + { + $this->assertEquals( + "", + path_to_tags("nope.jpg") + ); + $this->assertEquals( + "", + path_to_tags("\\") + ); + $this->assertEquals( + "", + path_to_tags("/") + ); + $this->assertEquals( + "", + path_to_tags("C:\\") + ); + $this->assertEquals( + "test tag", + path_to_tags("123 - test tag.jpg") + ); + $this->assertEquals( + "foo bar", + path_to_tags("/foo/bar/baz.jpg") + ); + $this->assertEquals( + "cake pie foo bar", + path_to_tags("/foo/bar/123 - cake pie.jpg") + ); + $this->assertEquals( + "bacon lemon", + path_to_tags("\\bacon\\lemon\\baz.jpg") + ); + $this->assertEquals( + "category:tag", + path_to_tags("/category:/tag/baz.jpg") + ); + } } diff --git a/core/urls.php b/core/urls.php index 80467e85..9ef20b41 100644 --- a/core/urls.php +++ b/core/urls.php @@ -2,6 +2,10 @@ declare(strict_types=1); +namespace Shimmie2; + +use PhpParser\Node\Expr\Cast\Double; + class Link { public ?string $page; diff --git a/core/user.php b/core/user.php index 6337b96c..0d553017 100644 --- a/core/user.php +++ b/core/user.php @@ -2,6 +2,12 @@ declare(strict_types=1); +namespace Shimmie2; + +use GQLA\Type; +use GQLA\Field; +use GQLA\Query; + function _new_user(array $row): User { return new User($row); @@ -15,13 +21,17 @@ function _new_user(array $row): User * * The currently logged in user will always be accessible via the global variable $user. */ +#[Type(name: "User")] class User { public int $id; + #[Field] public string $name; public ?string $email; + #[Field] public string $join_date; public ?string $passhash; + #[Field] public UserClass $class; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * @@ -56,12 +66,31 @@ class User } } + #[Query] + public static function me(): User + { + global $user; + return $user; + } + + #[Field(name: "user_id")] + public function graphql_oid(): int + { + return $this->id; + } + #[Field(name: "id")] + public function graphql_guid(): string + { + return "user:{$this->id}"; + } + + public static function by_session(string $name, string $session): ?User { global $cache, $config, $database; $row = $cache->get("user-session:$name-$session"); - if (!$row) { - if ($database->get_driver_name() === DatabaseDriver::MYSQL) { + if (is_null($row)) { + if ($database->get_driver_id() === DatabaseDriverID::MYSQL) { $query = "SELECT * FROM users WHERE name = :name AND md5(concat(pass, :ip)) = :sess"; } else { $query = "SELECT * FROM users WHERE name = :name AND md5(pass || :ip) = :sess"; @@ -77,7 +106,7 @@ class User global $cache, $database; if ($id === 1) { $cached = $cache->get('user-id:'.$id); - if ($cached) { + if (!is_null($cached)) { return new User($cached); } } @@ -88,6 +117,7 @@ class User return is_null($row) ? null : new User($row); } + #[Query(name: "user")] public static function by_name(string $name): ?User { global $database; @@ -163,7 +193,7 @@ class User { global $database; if (User::by_name($name)) { - throw new ScoreException("Desired username is already in use"); + throw new SCoreException("Desired username is already in use"); } $old_name = $this->name; $this->name = $name; @@ -196,6 +226,16 @@ class User * a local file, a remote file, a gravatar, a something else, etc. */ public function get_avatar_html(): string + { + $url = $this->get_avatar_url(); + if (!empty($url)) { + return "avatar"; + } + return ""; + } + + #[Field(name: "avatar_url")] + public function get_avatar_url(): ?string { // FIXME: configurable global $config; @@ -206,10 +246,10 @@ class User $d = urlencode($config->get_string("avatar_gravatar_default")); $r = $config->get_string("avatar_gravatar_rating"); $cb = date("Y-m-d"); - return "avatar"; + return "https://www.gravatar.com/avatar/$hash.jpg?s=$s&d=$d&r=$r&cacheBreak=$cb"; } } - return ""; + return null; } /** diff --git a/core/userclass.php b/core/userclass.php index a68ebb1b..5e66256c 100644 --- a/core/userclass.php +++ b/core/userclass.php @@ -1,6 +1,13 @@ getConstants() as $k => $v) { + if ($this->can($v)) { + $perms[] = $v; + } + } + return $perms; + } + /** * Determine if this class of user can perform an action or has ability. * @@ -58,7 +80,7 @@ class UserClass } $_all_false = []; -foreach ((new ReflectionClass('Permissions'))->getConstants() as $k => $v) { +foreach ((new \ReflectionClass('\Shimmie2\Permissions'))->getConstants() as $k => $v) { $_all_false[$v] = false; } new UserClass("base", null, $_all_false); @@ -86,6 +108,7 @@ new UserClass("user", "base", [ Permissions::CREATE_IMAGE_REPORT => true, Permissions::EDIT_IMAGE_RATING => true, Permissions::EDIT_FAVOURITES => true, + Permissions::CREATE_VOTE => true, Permissions::SEND_PM => true, Permissions::READ_PM => true, Permissions::SET_PRIVATE_IMAGE => true, @@ -161,6 +184,7 @@ new UserClass("admin", "base", [ Permissions::EDIT_FEATURE => true, Permissions::BULK_EDIT_VOTE => true, Permissions::EDIT_OTHER_VOTE => true, + Permissions::CREATE_VOTE => true, Permissions::VIEW_SYSINTO => true, Permissions::HELLBANNED => false, diff --git a/core/util.php b/core/util.php index ab60089b..84796074 100644 --- a/core/util.php +++ b/core/util.php @@ -1,7 +1,11 @@ formatted; + $event = send_event(new TextFormattingEvent($string)); + return $event->formatted; } /** @@ -258,7 +262,7 @@ function load_balance_url(string $tmpl, string $hash, int $n=0): string if (isset($flexihashes[$opts])) { $flexihash = $flexihashes[$opts]; } else { - $flexihash = new Flexihash\Flexihash(); + $flexihash = new \Flexihash\Flexihash(); foreach (explode(",", $opts) as $opt) { $parts = explode("=", $opt); $parts_count = count($parts); @@ -354,10 +358,13 @@ function path_to_tags(string $path): string $tags = explode(" ", $matches[1]); } - $path = dirname($path); + $path = str_replace("\\", "/", $path); $path = str_replace(";", ":", $path); $path = str_replace("__", " ", $path); - + $path = dirname($path); + if ($path == "\\" || $path == "/" || $path == ".") { + $path = ""; + } $category = ""; foreach (explode("/", $path) as $dir) { @@ -390,18 +397,6 @@ function path_to_tags(string $path): string return implode(" ", $tags); } - -function join_url(string $base, string ...$paths): string -{ - $output = $base; - foreach ($paths as $path) { - $output = rtrim($output, "/"); - $path = ltrim($path, "/"); - $output .= "/".$path; - } - return $output; -} - function get_dir_contents(string $dir): array { assert(!empty($dir)); @@ -486,18 +481,18 @@ function scan_dir(string $path): array $bytestotal = 0; $nbfiles = 0; - $ite = new RecursiveDirectoryIterator( + $ite = new \RecursiveDirectoryIterator( $path, - FilesystemIterator::KEY_AS_PATHNAME | - FilesystemIterator::CURRENT_AS_FILEINFO | - FilesystemIterator::SKIP_DOTS + \FilesystemIterator::KEY_AS_PATHNAME | + \FilesystemIterator::CURRENT_AS_FILEINFO | + \FilesystemIterator::SKIP_DOTS ); - foreach (new RecursiveIteratorIterator($ite) as $filename => $cur) { + foreach (new \RecursiveIteratorIterator($ite) as $filename => $cur) { try { $filesize = $cur->getSize(); $bytestotal += $filesize; $nbfiles++; - } catch (RuntimeException $e) { + } catch (\RuntimeException $e) { // This usually just means that the file got eaten by the import continue; } @@ -509,14 +504,20 @@ function scan_dir(string $path): array } +/** + * because microtime() returns string|float, and we only ever want float + */ +function ftime(): float +{ + return (float)microtime(true); +} + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Debugging functions * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -// SHIT by default this returns the time as a string. And it's not even a -// string representation of a number, it's two numbers separated by a space. -// What the fuck were the PHP developers smoking. -$_shm_load_start = microtime(true); +$_shm_load_start = ftime(); /** * Collects some debug information (execution time, memory usage, queries, etc) @@ -524,28 +525,39 @@ $_shm_load_start = microtime(true); */ function get_debug_info(): string { - global $cache, $config, $_shm_event_count, $database, $_shm_load_start; + $d = get_debug_info_arr(); - $i_mem = sprintf("%5.2f", ((memory_get_peak_usage(true)+512)/1024)/1024); + $debug = "
Took {$d['time']} seconds (db:{$d['dbtime']}) and {$d['mem_mb']}MB of RAM"; + $debug .= "; Used {$d['files']} files and {$d['query_count']} queries"; + $debug .= "; Sent {$d['event_count']} events"; + $debug .= "; {$d['cache_hits']} cache hits and {$d['cache_misses']} misses"; + $debug .= "; Shimmie version {$d['version']}"; + + return $debug; +} + +function get_debug_info_arr(): array +{ + global $cache, $config, $_shm_event_count, $database, $_shm_load_start; if ($config->get_string("commit_hash", "unknown") == "unknown") { $commit = ""; } else { $commit = " (".$config->get_string("commit_hash").")"; } - $time = sprintf("%.2f", microtime(true) - $_shm_load_start); - $dbtime = sprintf("%.2f", $database->dbtime); - $i_files = count(get_included_files()); - $hits = $cache->get_hits(); - $miss = $cache->get_misses(); - $debug = "
Took $time seconds (db:$dbtime) and {$i_mem}MB of RAM"; - $debug .= "; Used $i_files files and {$database->query_count} queries"; - $debug .= "; Sent $_shm_event_count events"; - $debug .= "; $hits cache hits and $miss misses"; - $debug .= "; Shimmie version ". VERSION . $commit; - - return $debug; + return [ + "time" => round(ftime() - $_shm_load_start, 2), + "dbtime" => round($database->dbtime, 2), + "mem_mb" => round(((memory_get_peak_usage(true)+512)/1024)/1024, 2), + "files" => count(get_included_files()), + "query_count" => $database->query_count, + // "query_log" => $database->queries, + "event_count" => $_shm_event_count, + "cache_hits" => $cache->get("__etc_cache_hits"), + "cache_misses" => $cache->get("__etc_cache_misses"), + "version" => VERSION . $commit, + ]; } @@ -553,10 +565,6 @@ function get_debug_info(): string * Request initialisation stuff * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/** @privatesection - * @noinspection PhpIncludeInspection - */ - function require_all(array $files): void { foreach ($files as $filename) { @@ -575,7 +583,9 @@ function _load_core_files() function _load_theme_files() { - require_all(_get_themelet_files(get_theme())); + $theme = get_theme(); + $files = _get_themelet_files($theme); + require_all($files); } function _set_up_shimmie_environment(): void @@ -617,13 +627,13 @@ function _get_themelet_files(string $_theme): array /** * Used to display fatal errors to the web user. */ -function _fatal_error(Exception $e): void +function _fatal_error(\Exception $e): void { $version = VERSION; $message = $e->getMessage(); $phpver = phpversion(); - $query = is_subclass_of($e, "SCoreException") ? $e->query : null; - $code = is_subclass_of($e, "SCoreException") ? $e->http_code : 500; + $query = is_subclass_of($e, "Shimmie2\SCoreException") ? $e->query : null; + $code = is_subclass_of($e, "Shimmie2\SCoreException") ? $e->http_code : 500; //$hash = exec("git rev-parse HEAD"); //$h_hash = $hash ? "

Hash: $hash" : ""; @@ -635,7 +645,7 @@ function _fatal_error(Exception $e): void foreach ($t as $n => $f) { $c = $f['class'] ?? ''; $t = $f['type'] ?? ''; - $a = implode(", ", array_map("stringer", $f['args'])); + $a = implode(", ", array_map("Shimmie2\stringer", $f['args'])); print("$n: {$f['file']}({$f['line']}): {$c}{$t}{$f['function']}({$a})\n"); } @@ -674,12 +684,18 @@ function _get_user(): User { global $config, $page; $my_user = null; - if ($page->get_cookie("user") && $page->get_cookie("session")) { - $tmp_user = User::by_session($page->get_cookie("user"), $page->get_cookie("session")); - if (!is_null($tmp_user)) { - $my_user = $tmp_user; + if (isset($_SERVER['HTTP_AUTHORIZATION'])) { + $parts = explode(" ", $_SERVER['HTTP_AUTHORIZATION'], 2); + if (count($parts) == 2 && $parts[0] == "Bearer") { + $parts = explode(":", $parts[1], 2); + if (count($parts) == 2) { + $my_user = User::by_session($parts[0], $parts[1]); + } } } + if ($page->get_cookie("user") && $page->get_cookie("session")) { + $my_user = User::by_session($page->get_cookie("user"), $page->get_cookie("session")); + } if (is_null($my_user)) { $my_user = User::by_id($config->get_int("anon_id", 0)); } diff --git a/ext/admin/info.php b/ext/admin/info.php index 54751718..806d37d9 100644 --- a/ext/admin/info.php +++ b/ext/admin/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class AdminPageInfo extends ExtensionInfo { public const KEY = "admin"; @@ -13,5 +15,5 @@ class AdminPageInfo extends ExtensionInfo public string $license = self::LICENSE_GPLV2; public string $description = "Provides a base for various small admin functions"; public bool $core = true; - public string $visibility = self::VISIBLE_HIDDEN; + public ExtensionVisibility $visibility = ExtensionVisibility::HIDDEN; } diff --git a/ext/admin/main.php b/ext/admin/main.php index ad3bc67c..b06d0f7c 100644 --- a/ext/admin/main.php +++ b/ext/admin/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + /** * Sent when the admin page is ready to be added to */ @@ -115,7 +117,7 @@ class AdminPage extends Extension $key = $event->args[1]; switch ($cmd) { case "get": - var_dump($cache->get($key)); + var_export($cache->get($key)); break; case "set": $cache->set($key, $event->args[2], 60); diff --git a/ext/admin/test.php b/ext/admin/test.php index ae0583a3..a4cbfcae 100644 --- a/ext/admin/test.php +++ b/ext/admin/test.php @@ -1,6 +1,9 @@ 0) { $tmp = $_FILES['alias_file']['tmp_name']; $contents = file_get_contents($tmp); - $this->add_alias_csv($database, $contents); + $this->add_alias_csv($contents); log_info("alias_editor", "Imported aliases from file", "Imported aliases"); # FIXME: how many? $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("alias/list")); @@ -177,7 +179,7 @@ class AliasEditor extends Extension return $csv; } - private function add_alias_csv(Database $database, string $csv): int + private function add_alias_csv(string $csv): int { $csv = str_replace("\r", "\n", $csv); $i = 0; diff --git a/ext/alias_editor/test.php b/ext/alias_editor/test.php index d194fc31..78437026 100644 --- a/ext/alias_editor/test.php +++ b/ext/alias_editor/test.php @@ -1,6 +1,9 @@ get_arg(0)) { //*************ARTIST SECTION************** case "list": - { - $this->get_listing($page, $event); - $this->theme->sidebar_options("neutral"); - break; - } + { + $this->get_listing($event); + $this->theme->sidebar_options("neutral"); + break; + } case "new": - { - if (!$user->is_anonymous()) { - $this->theme->new_artist_composer(); - } else { - $this->theme->display_error(401, "Error", "You must be registered and logged in to create a new artist."); - } - break; - } - case "new_artist": - { - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/new")); - break; - } - case "create": - { - if (!$user->is_anonymous()) { - $newArtistID = $this->add_artist(); - if ($newArtistID == -1) { - $this->theme->display_error(400, "Error", "Error when entering artist data."); + { + if (!$user->is_anonymous()) { + $this->theme->new_artist_composer(); } else { - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/view/".$newArtistID)); + $this->theme->display_error(401, "Error", "You must be registered and logged in to create a new artist."); } - } else { - $this->theme->display_error(401, "Error", "You must be registered and logged in to create a new artist."); + break; + } + case "new_artist": + { + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/new")); + break; + } + case "create": + { + if (!$user->is_anonymous()) { + $newArtistID = $this->add_artist(); + if ($newArtistID == -1) { + $this->theme->display_error(400, "Error", "Error when entering artist data."); + } else { + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/view/".$newArtistID)); + } + } else { + $this->theme->display_error(401, "Error", "You must be registered and logged in to create a new artist."); + } + break; } - break; - } case "view": - { - $artistID = int_escape($event->get_arg(1)); - $artist = $this->get_artist($artistID); - $aliases = $this->get_alias($artist['id']); - $members = $this->get_members($artist['id']); - $urls = $this->get_urls($artist['id']); + { + $artistID = int_escape($event->get_arg(1)); + $artist = $this->get_artist($artistID); + $aliases = $this->get_alias($artist['id']); + $members = $this->get_members($artist['id']); + $urls = $this->get_urls($artist['id']); - $userIsLogged = !$user->is_anonymous(); - $userIsAdmin = $user->can(Permissions::ARTISTS_ADMIN); + $userIsLogged = !$user->is_anonymous(); + $userIsAdmin = $user->can(Permissions::ARTISTS_ADMIN); - $images = Image::find_images(0, 4, Tag::explode($artist['name'])); + $images = Image::find_images(0, 4, Tag::explode($artist['name'])); - $this->theme->show_artist($artist, $aliases, $members, $urls, $images, $userIsLogged, $userIsAdmin); - /* - if ($userIsLogged) { - $this->theme->show_new_alias_composer($artistID); - $this->theme->show_new_member_composer($artistID); - $this->theme->show_new_url_composer($artistID); + $this->theme->show_artist($artist, $aliases, $members, $urls, $images, $userIsLogged, $userIsAdmin); + /* + if ($userIsLogged) { + $this->theme->show_new_alias_composer($artistID); + $this->theme->show_new_member_composer($artistID); + $this->theme->show_new_url_composer($artistID); + } + */ + + $this->theme->sidebar_options("editor", $artistID, $userIsAdmin); + + break; } - */ - - $this->theme->sidebar_options("editor", $artistID, $userIsAdmin); - - break; - } case "edit": - { - $artistID = int_escape($event->get_arg(1)); - $artist = $this->get_artist($artistID); - $aliases = $this->get_alias($artistID); - $members = $this->get_members($artistID); - $urls = $this->get_urls($artistID); + { + $artistID = int_escape($event->get_arg(1)); + $artist = $this->get_artist($artistID); + $aliases = $this->get_alias($artistID); + $members = $this->get_members($artistID); + $urls = $this->get_urls($artistID); - if (!$user->is_anonymous()) { - $this->theme->show_artist_editor($artist, $aliases, $members, $urls); + if (!$user->is_anonymous()) { + $this->theme->show_artist_editor($artist, $aliases, $members, $urls); - $userIsAdmin = $user->can(Permissions::ARTISTS_ADMIN); - $this->theme->sidebar_options("editor", $artistID, $userIsAdmin); - } else { - $this->theme->display_error(401, "Error", "You must be registered and logged in to edit an artist."); + $userIsAdmin = $user->can(Permissions::ARTISTS_ADMIN); + $this->theme->sidebar_options("editor", $artistID, $userIsAdmin); + } else { + $this->theme->display_error(401, "Error", "You must be registered and logged in to edit an artist."); + } + break; } - break; - } case "edit_artist": - { - $artistID = $_POST['artist_id']; - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/edit/".$artistID)); - break; - } + { + $artistID = $_POST['artist_id']; + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/edit/".$artistID)); + break; + } case "edited": - { - $artistID = int_escape($_POST['id']); - $this->update_artist(); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/view/".$artistID)); - break; - } + { + $artistID = int_escape($_POST['id']); + $this->update_artist(); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/view/".$artistID)); + break; + } case "nuke_artist": - { - $artistID = $_POST['artist_id']; - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/nuke/".$artistID)); - break; - } + { + $artistID = $_POST['artist_id']; + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/nuke/".$artistID)); + break; + } case "nuke": - { - $artistID = int_escape($event->get_arg(1)); - $this->delete_artist($artistID); // this will delete the artist, its alias, its urls and its members - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/list")); - break; - } + { + $artistID = int_escape($event->get_arg(1)); + $this->delete_artist($artistID); // this will delete the artist, its alias, its urls and its members + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/list")); + break; + } case "add_alias": - { - $artistID = $_POST['artist_id']; - $this->theme->show_new_alias_composer($artistID); - break; - } + { + $artistID = $_POST['artist_id']; + $this->theme->show_new_alias_composer($artistID); + break; + } case "add_member": - { - $artistID = $_POST['artist_id']; - $this->theme->show_new_member_composer($artistID); - break; - } + { + $artistID = $_POST['artist_id']; + $this->theme->show_new_member_composer($artistID); + break; + } case "add_url": - { - $artistID = $_POST['artist_id']; - $this->theme->show_new_url_composer($artistID); - break; - } - //***********ALIAS SECTION *********************** + { + $artistID = $_POST['artist_id']; + $this->theme->show_new_url_composer($artistID); + break; + } + //***********ALIAS SECTION *********************** case "alias": - { - switch ($event->get_arg(1)) { - case "add": - { - $artistID = $_POST['artistID']; - $this->add_alias(); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/view/".$artistID)); - break; - } - case "delete": - { - $aliasID = int_escape($event->get_arg(2)); - $artistID = $this->get_artistID_by_aliasID($aliasID); - $this->delete_alias($aliasID); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/view/".$artistID)); - break; - } - case "edit": - { - $aliasID = int_escape($event->get_arg(2)); - $alias = $this->get_alias_by_id($aliasID); - $this->theme->show_alias_editor($alias); - break; - } - case "edited": - { - $this->update_alias(); - $aliasID = int_escape($_POST['aliasID']); - $artistID = $this->get_artistID_by_aliasID($aliasID); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/view/".$artistID)); - break; + { + switch ($event->get_arg(1)) { + case "add": + { + $artistID = $_POST['artistID']; + $this->add_alias(); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/view/".$artistID)); + break; + } + case "delete": + { + $aliasID = int_escape($event->get_arg(2)); + $artistID = $this->get_artistID_by_aliasID($aliasID); + $this->delete_alias($aliasID); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/view/".$artistID)); + break; + } + case "edit": + { + $aliasID = int_escape($event->get_arg(2)); + $alias = $this->get_alias_by_id($aliasID); + $this->theme->show_alias_editor($alias); + break; + } + case "edited": + { + $this->update_alias(); + $aliasID = int_escape($_POST['aliasID']); + $artistID = $this->get_artistID_by_aliasID($aliasID); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/view/".$artistID)); + break; + } } + break; // case: alias } - break; // case: alias - } - //**************** URLS SECTION ********************** + //**************** URLS SECTION ********************** case "url": - { - switch ($event->get_arg(1)) { - case "add": - { - $artistID = $_POST['artistID']; - $this->add_urls(); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/view/".$artistID)); - break; - } - case "delete": - { - $urlID = int_escape($event->get_arg(2)); - $artistID = $this->get_artistID_by_urlID($urlID); - $this->delete_url($urlID); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/view/".$artistID)); - break; - } - case "edit": - { - $urlID = int_escape($event->get_arg(2)); - $url = $this->get_url_by_id($urlID); - $this->theme->show_url_editor($url); - break; - } - case "edited": - { - $this->update_url(); - $urlID = int_escape($_POST['urlID']); - $artistID = $this->get_artistID_by_urlID($urlID); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/view/".$artistID)); - break; + { + switch ($event->get_arg(1)) { + case "add": + { + $artistID = $_POST['artistID']; + $this->add_urls(); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/view/".$artistID)); + break; + } + case "delete": + { + $urlID = int_escape($event->get_arg(2)); + $artistID = $this->get_artistID_by_urlID($urlID); + $this->delete_url($urlID); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/view/".$artistID)); + break; + } + case "edit": + { + $urlID = int_escape($event->get_arg(2)); + $url = $this->get_url_by_id($urlID); + $this->theme->show_url_editor($url); + break; + } + case "edited": + { + $this->update_url(); + $urlID = int_escape($_POST['urlID']); + $artistID = $this->get_artistID_by_urlID($urlID); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/view/".$artistID)); + break; + } } + break; // case: urls } - break; // case: urls - } - //******************* MEMBERS SECTION ********************* + //******************* MEMBERS SECTION ********************* case "member": - { - switch ($event->get_arg(1)) { - case "add": - { - $artistID = $_POST['artistID']; - $this->add_members(); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/view/".$artistID)); - break; - } - case "delete": - { - $memberID = int_escape($event->get_arg(2)); - $artistID = $this->get_artistID_by_memberID($memberID); - $this->delete_member($memberID); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/view/".$artistID)); - break; - } - case "edit": - { - $memberID = int_escape($event->get_arg(2)); - $member = $this->get_member_by_id($memberID); - $this->theme->show_member_editor($member); - break; - } - case "edited": - { - $this->update_member(); - $memberID = int_escape($_POST['memberID']); - $artistID = $this->get_artistID_by_memberID($memberID); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("artist/view/".$artistID)); - break; + { + switch ($event->get_arg(1)) { + case "add": + { + $artistID = $_POST['artistID']; + $this->add_members(); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/view/".$artistID)); + break; + } + case "delete": + { + $memberID = int_escape($event->get_arg(2)); + $artistID = $this->get_artistID_by_memberID($memberID); + $this->delete_member($memberID); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/view/".$artistID)); + break; + } + case "edit": + { + $memberID = int_escape($event->get_arg(2)); + $member = $this->get_member_by_id($memberID); + $this->theme->show_member_editor($member); + break; + } + case "edited": + { + $this->update_member(); + $memberID = int_escape($_POST['memberID']); + $artistID = $this->get_artistID_by_memberID($memberID); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("artist/view/".$artistID)); + break; + } } + break; //case: members } - break; //case: members - } } } } @@ -845,7 +847,7 @@ class Artists extends Extension /* * HERE WE GET THE LIST OF ALL ARTIST WITH PAGINATION */ - private function get_listing(Page $page, PageRequestEvent $event) + private function get_listing(PageRequestEvent $event) { global $config, $database; @@ -1048,7 +1050,8 @@ class Artists extends Extension ORDER BY alias ASC ", ['artist_id'=>$artistID]); - for ($i = 0 ; $i < count($result) ; $i++) { + $rc = count($result); + for ($i = 0 ; $i < $rc ; $i++) { $result[$i]["alias_name"] = stripslashes($result[$i]["alias_name"]); } return $result; diff --git a/ext/artists/test.php b/ext/artists/test.php index fdebbce5..47f312bd 100644 --- a/ext/artists/test.php +++ b/ext/artists/test.php @@ -1,6 +1,9 @@ "; if (count($aliases) > 1) { - for ($i = 1; $i < count($aliases); $i++) { + $ac = count($aliases); + for ($i = 1; $i < $ac; $i++) { $aliasViewLink = str_replace("_", " ", $aliases[$i]['alias_name']); // no link anymore $aliasEditLink = "Edit"; $aliasDeleteLink = "Delete"; @@ -479,7 +483,8 @@ class ArtistsTheme extends Themelet $html .= ""; if (count($members) > 1) { - for ($i = 1; $i < count($members); $i++) { + $mc = count($members); + for ($i = 1; $i < $mc; $i++) { $memberViewLink = str_replace("_", " ", $members[$i]['name']); // no link anymore $memberEditLink = "Edit"; $memberDeleteLink = "Delete"; @@ -524,7 +529,8 @@ class ArtistsTheme extends Themelet $html .= ""; if (count($urls) > 1) { - for ($i = 1; $i < count($urls); $i++) { + $uc = count($urls); + for ($i = 1; $i < $uc; $i++) { $urlViewLink = "" . str_replace("_", " ", $urls[$i]['url']) . ""; $urlEditLink = "Edit"; $urlDeleteLink = "Delete"; diff --git a/ext/auto_tagger/config.php b/ext/auto_tagger/config.php index 3dd8e478..6fd5ed8e 100644 --- a/ext/auto_tagger/config.php +++ b/ext/auto_tagger/config.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + abstract class AutoTaggerConfig { public const VERSION = "ext_auto_tagger_ver"; diff --git a/ext/auto_tagger/info.php b/ext/auto_tagger/info.php index a466d470..ad1a7969 100644 --- a/ext/auto_tagger/info.php +++ b/ext/auto_tagger/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class AutoTaggerInfo extends ExtensionInfo { public const KEY = "auto_tagger"; diff --git a/ext/auto_tagger/main.php b/ext/auto_tagger/main.php index 3ffd75ea..370cdac5 100644 --- a/ext/auto_tagger/main.php +++ b/ext/auto_tagger/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + require_once 'config.php'; use MicroCRUD\ActionColumn; @@ -110,7 +112,7 @@ class AutoTagger extends Extension if (count($_FILES) > 0) { $tmp = $_FILES['auto_tag_file']['tmp_name']; $contents = file_get_contents($tmp); - $count = $this->add_auto_tag_csv($database, $contents); + $count = $this->add_auto_tag_csv($contents); log_info(AutoTaggerInfo::KEY, "Imported $count auto-tag definitions from file from file", "Imported $count auto-tag definitions"); $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("auto_tag/list")); @@ -142,7 +144,7 @@ class AutoTagger extends Extension additional_tags VARCHAR(2000) NOT NULL "); - if ($database->get_driver_name() == DatabaseDriver::PGSQL) { + if ($database->get_driver_id() == DatabaseDriverID::PGSQL) { $database->execute('CREATE INDEX auto_tag_lower_tag_idx ON auto_tag ((lower(tag)))'); } $this->set_version(AutoTaggerConfig::VERSION, 1); @@ -189,7 +191,7 @@ class AutoTagger extends Extension return $csv; } - private function add_auto_tag_csv(Database $database, string $csv): int + private function add_auto_tag_csv(string $csv): int { $csv = str_replace("\r", "\n", $csv); $i = 0; @@ -210,23 +212,23 @@ class AutoTagger extends Extension private function add_auto_tag(string $tag, string $additional_tags) { global $database; - $existing_tags = $database->get_one("SELECT additional_tags FROM auto_tag WHERE LOWER(tag)=LOWER(:tag)", ["tag"=>$tag]); - if (!is_null($existing_tags)) { - // Auto Tags already exist, so we will append new tags to the existing one - $tag = Tag::sanitize($tag); + $existing_tags = $database->get_one("SELECT additional_tags FROM auto_tag WHERE LOWER(tag)=LOWER(:tag)", ["tag"=>$tag]); + if (!is_null($existing_tags)) { + // Auto Tags already exist, so we will append new tags to the existing one + $tag = Tag::sanitize($tag); $additional_tags = Tag::explode($additional_tags); - $existing_tags = Tag::explode($existing_tags); - foreach ($additional_tags as $t) { - if (!in_array(strtolower($t), $existing_tags)) { - array_push($existing_tags, strtolower($t)); - } - } - - $database->execute( + $existing_tags = Tag::explode($existing_tags); + foreach ($additional_tags as $t) { + if (!in_array(strtolower($t), $existing_tags)) { + $existing_tags[] = strtolower($t); + } + } + + $database->execute( "UPDATE auto_tag set additional_tags=:existing_tags where tag=:tag", ["tag"=>$tag, "existing_tags"=>Tag::implode($existing_tags)] ); - log_info( + log_info( AutoTaggerInfo::KEY, "Updated auto-tag for {$tag} -> {".implode(" ", $additional_tags)."}" ); @@ -244,39 +246,8 @@ class AutoTagger extends Extension "Added auto-tag for {$tag} -> {".implode(" ", $additional_tags)."}" ); } - // Now we apply it to existing items - $this->apply_new_auto_tag($tag); - } - - private function update_auto_tag(string $tag, string $additional_tags): bool - { - global $database; - $result = $database->get_row("SELECT * FROM auto_tag WHERE LOWER(tag)=LOWER(:tag)", ["tag"=>$tag]); - - if ($result===null) { - throw new AutoTaggerException("Auto-tag not set for $tag, can't update"); - } else { - $additional_tags = Tag::explode($additional_tags); - $current_additional_tags = Tag::explode($result["additional_tags"]); - - if (!Tag::compare($additional_tags, $current_additional_tags)) { - $database->execute( - "UPDATE auto_tag SET additional_tags = :additional_tags WHERE LOWER(tag)=LOWER(:tag)", - ["tag"=>$tag, "additional_tags"=>Tag::implode($additional_tags)] - ); - - log_info( - AutoTaggerInfo::KEY, - "Updated auto-tag for {$tag} -> {".implode(" ", $additional_tags)."}", - "Updated Auto-Tag" - ); - - // Now we apply it to existing items - $this->apply_new_auto_tag($tag); - return true; - } - } - return false; + // Now we apply it to existing items + $this->apply_new_auto_tag($tag); } private function apply_new_auto_tag(string $tag) @@ -288,14 +259,11 @@ class AutoTagger extends Extension foreach ($image_ids as $image_id) { $image_id = (int) $image_id; $image = Image::by_id($image_id); - $event = new TagSetEvent($image, $image->get_tag_array()); - send_event($event); + send_event(new TagSetEvent($image, $image->get_tag_array())); } } } - - private function remove_auto_tag(String $tag) { global $database; diff --git a/ext/auto_tagger/test.php b/ext/auto_tagger/test.php index 419d72c9..e8ed6293 100644 --- a/ext/auto_tagger/test.php +++ b/ext/auto_tagger/test.php @@ -1,6 +1,9 @@ get($cache_key); - if (!$res) { + if (is_null($res)) { $res = $database->get_pairs( " SELECT tag, count diff --git a/ext/autocomplete/test.php b/ext/autocomplete/test.php index ec9d1ba4..8378e584 100644 --- a/ext/autocomplete/test.php +++ b/ext/autocomplete/test.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class AutoCompleteTest extends ShimmiePHPUnitTestCase { public function testAuth() diff --git a/ext/autocomplete/theme.php b/ext/autocomplete/theme.php index d5fcbe8b..d2d17047 100644 --- a/ext/autocomplete/theme.php +++ b/ext/autocomplete/theme.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class AutoCompleteTheme extends Themelet { public function build_autocomplete(Page $page) diff --git a/ext/ban_words/info.php b/ext/ban_words/info.php index b1f84dcb..247ab304 100644 --- a/ext/ban_words/info.php +++ b/ext/ban_words/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BanWordsInfo extends ExtensionInfo { public const KEY = "ban_words"; diff --git a/ext/ban_words/main.php b/ext/ban_words/main.php index 39febc87..4e57b7b4 100644 --- a/ext/ban_words/main.php +++ b/ext/ban_words/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BanWords extends Extension { public function onInitExt(InitExtEvent $event) diff --git a/ext/ban_words/test.php b/ext/ban_words/test.php index 69ec598b..a70f6a06 100644 --- a/ext/ban_words/test.php +++ b/ext/ban_words/test.php @@ -1,6 +1,9 @@ get_auth_html(); - $html = SHM_SIMPLE_FORM( - $post_url, + make_link("biography"), TEXTAREA(["style"=>"width: 100%", "rows"=>"6", "name"=>"biography"], $bio), SHM_SUBMIT("Save") ); - $page->add_block(new Block("About Me", (string)$html, "main", 30)); + $page->add_block(new Block("About Me", $html, "main", 30)); } } diff --git a/ext/blocks/info.php b/ext/blocks/info.php index e42066b3..7dca5bd3 100644 --- a/ext/blocks/info.php +++ b/ext/blocks/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BlocksInfo extends ExtensionInfo { public const KEY = "blocks"; diff --git a/ext/blocks/main.php b/ext/blocks/main.php index f278dec0..ccf71069 100644 --- a/ext/blocks/main.php +++ b/ext/blocks/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class Blocks extends Extension { /** @var BlocksTheme */ @@ -47,7 +49,7 @@ class Blocks extends Extension global $cache, $database, $page, $user; $blocks = $cache->get("blocks"); - if ($blocks === false) { + if (is_null($blocks)) { $blocks = $database->get_all("SELECT * FROM blocks"); $cache->set("blocks", $blocks, 600); } diff --git a/ext/blocks/test.php b/ext/blocks/test.php index b30ae863..15677c4f 100644 --- a/ext/blocks/test.php +++ b/ext/blocks/test.php @@ -1,6 +1,9 @@ theme->display_permission_denied(); } else { $id = int_escape($_POST['id']); - if (!isset($id)) { - die("No ID!"); - } $database->execute("DELETE FROM blotter WHERE id=:id", ["id"=>$id]); log_info("blotter", "Removed Entry #$id"); $page->set_mode(PageMode::REDIRECT); diff --git a/ext/blotter/test.php b/ext/blotter/test.php index 1824a295..4bd3cfdb 100644 --- a/ext/blotter/test.php +++ b/ext/blotter/test.php @@ -1,6 +1,9 @@ action = $action; @@ -173,7 +175,7 @@ class BulkActions extends Extension if (empty($data)) { throw new BulkActionException("No ids specified in bulk_selected_ids"); } - if (is_array($data) && !empty($data)) { + if (is_array($data)) { $items = $this->yield_items($data); } } elseif (isset($_POST['bulk_query']) && $_POST['bulk_query'] != "") { @@ -201,7 +203,7 @@ class BulkActions extends Extension } } - private function yield_items(array $data): Generator + private function yield_items(array $data): \Generator { foreach ($data as $id) { if (is_numeric($id)) { @@ -213,7 +215,7 @@ class BulkActions extends Extension } } - private function yield_search_results(string $query): Generator + private function yield_search_results(string $query): \Generator { $tags = Tag::explode($query); return Image::find_images_iterable(0, null, $tags); @@ -231,7 +233,7 @@ class BulkActions extends Extension $size = 0; foreach ($posts as $post) { try { - if (class_exists("ImageBan") && isset($_POST['bulk_ban_reason'])) { + if (class_exists("Shimmie2\ImageBan") && isset($_POST['bulk_ban_reason'])) { $reason = $_POST['bulk_ban_reason']; if ($reason) { send_event(new AddImageHashBanEvent($post->hash, $reason)); @@ -240,7 +242,7 @@ class BulkActions extends Extension send_event(new ImageDeletionEvent($post)); $total++; $size += $post->filesize; - } catch (Exception $e) { + } catch (\Exception $e) { $page->flash("Error while removing {$post->id}: " . $e->getMessage()); } } @@ -295,7 +297,7 @@ class BulkActions extends Extension try { send_event(new SourceSetEvent($image, $source)); $total++; - } catch (Exception $e) { + } catch (\Exception $e) { $page->flash("Error while setting source for {$image->id}: " . $e->getMessage()); } } diff --git a/ext/bulk_actions/theme.php b/ext/bulk_actions/theme.php index e41a9764..777a7606 100644 --- a/ext/bulk_actions/theme.php +++ b/ext/bulk_actions/theme.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BulkActionsTheme extends Themelet { public function display_selector(Page $page, array $actions, string $query) @@ -49,7 +51,7 @@ class BulkActionsTheme extends Themelet public function render_ban_reason_input(): string { - if (class_exists("ImageBan")) { + if (class_exists("Shimmie2\ImageBan")) { return ""; } else { return ""; @@ -64,6 +66,6 @@ class BulkActionsTheme extends Themelet public function render_source_input(): string { - return ""; + return ""; } } diff --git a/ext/bulk_add/info.php b/ext/bulk_add/info.php index dc5cfada..149c1b8e 100644 --- a/ext/bulk_add/info.php +++ b/ext/bulk_add/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BulkAddInfo extends ExtensionInfo { public const KEY = "bulk_add"; diff --git a/ext/bulk_add/main.php b/ext/bulk_add/main.php index 953b36d7..9aed87dd 100644 --- a/ext/bulk_add/main.php +++ b/ext/bulk_add/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BulkAddEvent extends Event { public string $dir; diff --git a/ext/bulk_add/test.php b/ext/bulk_add/test.php index d99eb9b0..78c6e74c 100644 --- a/ext/bulk_add/test.php +++ b/ext/bulk_add/test.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BulkAddTest extends ShimmiePHPUnitTestCase { public function testInvalidDir() diff --git a/ext/bulk_add/theme.php b/ext/bulk_add/theme.php index cc7135da..6a74b3ef 100644 --- a/ext/bulk_add/theme.php +++ b/ext/bulk_add/theme.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BulkAddTheme extends Themelet { private array $messages = []; diff --git a/ext/bulk_add_csv/info.php b/ext/bulk_add_csv/info.php index 4d13d45a..46d13192 100644 --- a/ext/bulk_add_csv/info.php +++ b/ext/bulk_add_csv/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BulkAddCSVInfo extends ExtensionInfo { public const KEY = "bulk_add_csv"; diff --git a/ext/bulk_add_csv/main.php b/ext/bulk_add_csv/main.php index 9ae858e9..6dfcb488 100644 --- a/ext/bulk_add_csv/main.php +++ b/ext/bulk_add_csv/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BulkAddCSV extends Extension { /** @var BulkAddCSVTheme */ @@ -48,21 +50,11 @@ class BulkAddCSV extends Extension */ private function add_image(string $tmpname, string $filename, string $tags, string $source, string $rating, string $thumbfile) { - assert(file_exists($tmpname)); - - $pathinfo = pathinfo($filename); - $metadata = []; - $metadata['filename'] = $pathinfo['basename']; - if (array_key_exists('extension', $pathinfo)) { - $metadata['extension'] = $pathinfo['extension']; - } - $metadata['tags'] = Tag::explode($tags); - $metadata['source'] = $source; - $event = send_event(new DataUploadEvent($tmpname, $metadata)); + $event = add_image($tmpname, $filename, $tags, $source); if ($event->image_id == -1) { throw new UploadException("File type not recognised"); } else { - if (class_exists("RatingSetEvent") && in_array($rating, ["s", "q", "e"])) { + if (class_exists("Shimmie2\RatingSetEvent") && in_array($rating, ["s", "q", "e"])) { send_event(new RatingSetEvent(Image::by_id($event->image_id), $rating)); } if (file_exists($thumbfile)) { @@ -103,14 +95,13 @@ class BulkAddCSV extends Extension $source = $csvdata[2]; $rating = $csvdata[3]; $thumbfile = $csvdata[4]; - $pathinfo = pathinfo($fullpath); - $shortpath = $pathinfo["basename"]; + $shortpath = pathinfo($fullpath, PATHINFO_BASENAME); $list .= "
".html_escape("$shortpath (".str_replace(" ", ", ", $tags).")... "); if (file_exists($csvdata[0]) && is_file($csvdata[0])) { try { - $this->add_image($fullpath, $pathinfo["basename"], $tags, $source, $rating, $thumbfile); + $this->add_image($fullpath, $shortpath, $tags, $source, $rating, $thumbfile); $list .= "ok\n"; - } catch (Exception $ex) { + } catch (\Exception $ex) { $list .= "failed:
". $ex->getMessage(); } } else { diff --git a/ext/bulk_add_csv/theme.php b/ext/bulk_add_csv/theme.php index 0af200e2..2128e5ae 100644 --- a/ext/bulk_add_csv/theme.php +++ b/ext/bulk_add_csv/theme.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BulkAddCSVTheme extends Themelet { private array $messages = []; diff --git a/ext/bulk_download/info.php b/ext/bulk_download/info.php index 02745855..d5260459 100644 --- a/ext/bulk_download/info.php +++ b/ext/bulk_download/info.php @@ -2,6 +2,7 @@ declare(strict_types=1); +namespace Shimmie2; class BulkDownloadInfo extends ExtensionInfo { diff --git a/ext/bulk_download/main.php b/ext/bulk_download/main.php index 34eddfa6..64e38025 100644 --- a/ext/bulk_download/main.php +++ b/ext/bulk_download/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BulkDownloadConfig { public const SIZE_LIMIT = "bulk_download_size_limit"; @@ -47,11 +49,11 @@ class BulkDownload extends Extension ($event->action == BulkDownload::DOWNLOAD_ACTION_NAME)) { $download_filename = $user->name . '-' . date('YmdHis') . '.zip'; $zip_filename = tempnam(sys_get_temp_dir(), "shimmie_bulk_download"); - $zip = new ZipArchive(); + $zip = new \ZipArchive(); $size_total = 0; $max_size = $config->get_int(BulkDownloadConfig::SIZE_LIMIT); - if ($zip->open($zip_filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE) === true) { + if ($zip->open($zip_filename, \ZIPARCHIVE::CREATE | \ZIPARCHIVE::OVERWRITE) === true) { foreach ($event->items as $image) { $img_loc = warehouse_path(Image::IMAGE_DIR, $image->hash, false); $size_total += filesize($img_loc); diff --git a/ext/bulk_import_export/events.php b/ext/bulk_import_export/events.php index 7a4d2c7a..89b4b00c 100644 --- a/ext/bulk_import_export/events.php +++ b/ext/bulk_import_export/events.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class BulkExportEvent extends Event { public Image $image; diff --git a/ext/bulk_import_export/info.php b/ext/bulk_import_export/info.php index 78ebaf1d..6ad951b0 100644 --- a/ext/bulk_import_export/info.php +++ b/ext/bulk_import_export/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + include_once "events.php"; class BulkImportExportInfo extends ExtensionInfo diff --git a/ext/bulk_import_export/main.php b/ext/bulk_import_export/main.php index 65d433a9..5f635784 100644 --- a/ext/bulk_import_export/main.php +++ b/ext/bulk_import_export/main.php @@ -2,6 +2,7 @@ declare(strict_types=1); +namespace Shimmie2; class BulkImportExport extends DataHandlerExtension { @@ -16,7 +17,7 @@ class BulkImportExport extends DataHandlerExtension if ($this->supported_mime($event->mime) && $user->can(Permissions::BULK_IMPORT)) { - $zip = new ZipArchive(); + $zip = new \ZipArchive(); if ($zip->open($event->tmpname) === true) { $json_data = $this->get_export_data($zip); @@ -51,7 +52,7 @@ class BulkImportExport extends DataHandlerExtension file_put_contents($tmpfile, $stream); - $id = add_image($tmpfile, $item->filename, Tag::implode($item->tags)); + $id = add_image($tmpfile, $item->filename, Tag::implode($item->tags))->image_id; if ($id==-1) { throw new SCoreException("Unable to import file $item->hash"); @@ -70,11 +71,11 @@ class BulkImportExport extends DataHandlerExtension $database->commit(); $total++; - } catch (Exception $ex) { + } catch (\Exception $ex) { $failed++; try { $database->rollBack(); - } catch (Exception $ex2) { + } catch (\Exception $ex2) { log_error(BulkImportExportInfo::KEY, "Could not roll back transaction: " . $ex2->getMessage(), "Could not import " . $item->hash . ": " . $ex->getMessage()); } log_error(BulkImportExportInfo::KEY, "Could not import " . $item->hash . ": " . $ex->getMessage(), "Could not import " . $item->hash . ": " . $ex->getMessage()); @@ -117,23 +118,22 @@ class BulkImportExport extends DataHandlerExtension ($event->action == self::EXPORT_ACTION_NAME)) { $download_filename = $user->name . '-' . date('YmdHis') . '.zip'; $zip_filename = tempnam(sys_get_temp_dir(), "shimmie_bulk_export"); - $zip = new ZipArchive(); + $zip = new \ZipArchive(); $json_data = []; - if ($zip->open($zip_filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE) === true) { + if ($zip->open($zip_filename, \ZIPARCHIVE::CREATE | \ZIPARCHIVE::OVERWRITE) === true) { foreach ($event->items as $image) { $img_loc = warehouse_path(Image::IMAGE_DIR, $image->hash, false); - $export_event = new BulkExportEvent($image); - send_event($export_event); + $export_event = send_event(new BulkExportEvent($image)); $data = $export_event->fields; $data["hash"] = $image->hash; $data["tags"] = $image->get_tag_array(); $data["filename"] = $image->filename; $data["source"] = $image->source; - array_push($json_data, $data); + $json_data[] = $data; $zip->addFile($img_loc, $image->hash); } @@ -166,17 +166,17 @@ class BulkImportExport extends DataHandlerExtension return false; } - private function get_export_data(ZipArchive $zip): ?array + private function get_export_data(\ZipArchive $zip): ?array { $info = $zip->getStream(self::EXPORT_INFO_FILE_NAME); if ($info !== false) { try { $json_string = stream_get_contents($info); $json_data = json_decode($json_string); + return $json_data; } finally { fclose($info); } - return $json_data; } else { return null; } diff --git a/ext/comment/info.php b/ext/comment/info.php index d3fd5951..840aae94 100644 --- a/ext/comment/info.php +++ b/ext/comment/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class CommentListInfo extends ExtensionInfo { public const KEY = "comment"; diff --git a/ext/comment/main.php b/ext/comment/main.php index e48c0bab..b6da4eed 100644 --- a/ext/comment/main.php +++ b/ext/comment/main.php @@ -2,6 +2,13 @@ declare(strict_types=1); +namespace Shimmie2; + +use GQLA\Type; +use GQLA\Field; +use GQLA\Query; +use GQLA\Mutation; + require_once "vendor/ifixit/php-akismet/akismet.class.php"; class CommentPostingEvent extends Event @@ -39,6 +46,7 @@ class CommentPostingException extends SCoreException { } +#[Type(name: "Comment")] class Comment { public ?User $owner; @@ -46,10 +54,13 @@ class Comment public string $owner_name; public ?string $owner_email; public string $owner_class; + #[Field] public string $comment; + #[Field] public int $comment_id; public int $image_id; public string $poster_ip; + #[Field] public string $posted; public function __construct($row) @@ -76,6 +87,7 @@ class Comment ", ["owner_id"=>$user->id]); } + #[Field(name: "owner")] public function get_owner(): User { if (empty($this->owner)) { @@ -83,6 +95,20 @@ class Comment } return $this->owner; } + + #[Field(extends: "Post", name: "comments", type: "[Comment!]!")] + public static function get_comments(Image $post): array + { + return CommentList::get_comments($post->id); + } + + #[Mutation(name: "create_comment")] + public static function create_comment(int $post_id, string $comment): bool + { + global $user; + send_event(new CommentPostingEvent($post_id, $user, $comment)); + return true; + } } class CommentList extends Extension @@ -171,11 +197,21 @@ class CommentList extends Extension { if ($event->page_matches("comment")) { switch ($event->get_arg(0)) { - case "add": $this->onPageRequest_add(); break; - case "delete": $this->onPageRequest_delete($event); break; - case "bulk_delete": $this->onPageRequest_bulk_delete(); break; - case "list": $this->onPageRequest_list($event); break; - case "beta-search": $this->onPageRequest_beta_search($event); break; + case "add": + $this->onPageRequest_add(); + break; + case "delete": + $this->onPageRequest_delete($event); + break; + case "bulk_delete": + $this->onPageRequest_bulk_delete(); + break; + case "list": + $this->onPageRequest_list($event); + break; + case "beta-search": + $this->onPageRequest_beta_search($event); + break; } } } @@ -186,8 +222,7 @@ class CommentList extends Extension if (isset($_POST['image_id']) && isset($_POST['comment'])) { try { $i_iid = int_escape($_POST['image_id']); - $cpe = new CommentPostingEvent(int_escape($_POST['image_id']), $user, $_POST['comment']); - send_event($cpe); + send_event(new CommentPostingEvent(int_escape($_POST['image_id']), $user, $_POST['comment'])); $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/$i_iid", null, "comment_on_$i_iid")); } catch (CommentPostingException $ex) { @@ -244,7 +279,7 @@ class CommentList extends Extension $where = SPEED_HAX ? "WHERE posted > now() - interval '24 hours'" : ""; $total_pages = $cache->get("comment_pages"); - if (empty($total_pages)) { + if (is_null($total_pages)) { $total_pages = (int)ceil($database->get_one(" SELECT COUNT(c1) FROM (SELECT COUNT(image_id) AS c1 FROM comments $where GROUP BY image_id) AS s1 @@ -316,7 +351,7 @@ class CommentList extends Extension $cc = $config->get_int("comment_count"); if ($cc > 0) { $recent = $cache->get("recent_comments"); - if (empty($recent)) { + if (is_null($recent)) { $recent = $this->get_recent_comments($cc); $cache->set("recent_comments", $recent, 60); } @@ -415,7 +450,7 @@ class CommentList extends Extension /** * #return Comment[] */ - private function get_generic_comments(string $query, array $args): array + private static function get_generic_comments(string $query, array $args): array { global $database; $rows = $database->get_all($query, $args); @@ -429,9 +464,9 @@ class CommentList extends Extension /** * #return Comment[] */ - private function get_recent_comments(int $count): array + private static function get_recent_comments(int $count): array { - return $this->get_generic_comments(" + return CommentList::get_generic_comments(" SELECT users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class, comments.comment as comment, comments.id as comment_id, @@ -447,9 +482,9 @@ class CommentList extends Extension /** * #return Comment[] */ - private function get_user_comments(int $user_id, int $count, int $offset=0): array + private static function get_user_comments(int $user_id, int $count, int $offset=0): array { - return $this->get_generic_comments(" + return CommentList::get_generic_comments(" SELECT users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class, comments.comment as comment, comments.id as comment_id, @@ -464,11 +499,12 @@ class CommentList extends Extension } /** + * public just for Image::get_comments() * #return Comment[] */ - private function get_comments(int $image_id): array + public static function get_comments(int $image_id): array { - return $this->get_generic_comments(" + return CommentList::get_generic_comments(" SELECT users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class, comments.comment as comment, comments.id as comment_id, @@ -486,14 +522,14 @@ class CommentList extends Extension global $config, $database; // sqlite fails at intervals - if ($database->get_driver_name() === DatabaseDriver::SQLITE) { + if ($database->get_driver_id() === DatabaseDriverID::SQLITE) { return false; } $window = $config->get_int('comment_window'); $max = $config->get_int('comment_limit'); - if ($database->get_driver_name() == DatabaseDriver::MYSQL) { + if ($database->get_driver_id() == DatabaseDriverID::MYSQL) { $window_sql = "interval $window minute"; } else { $window_sql = "interval '$window minute'"; @@ -540,15 +576,18 @@ class CommentList extends Extension 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'none', ]; - $akismet = new Akismet( + // @phpstan-ignore-next-line + $akismet = new \Akismet( $_SERVER['SERVER_NAME'], $config->get_string('comment_wordpress_key'), $comment ); + // @phpstan-ignore-next-line if ($akismet->errorsExist()) { return false; } else { + // @phpstan-ignore-next-line return $akismet->isSpam(); } } diff --git a/ext/comment/test.php b/ext/comment/test.php index 0c60f0c0..4bafa098 100644 --- a/ext/comment/test.php +++ b/ext/comment/test.php @@ -1,6 +1,9 @@ comment); - send_event($tfe); + $tfe = send_event(new TextFormattingEvent($comment->comment)); $i_uid = $comment->owner_id; $h_name = html_escape($comment->owner_name); diff --git a/ext/cron_uploader/config.php b/ext/cron_uploader/config.php index f6b37e88..1c827049 100644 --- a/ext/cron_uploader/config.php +++ b/ext/cron_uploader/config.php @@ -2,6 +2,7 @@ declare(strict_types=1); +namespace Shimmie2; abstract class CronUploaderConfig { diff --git a/ext/cron_uploader/info.php b/ext/cron_uploader/info.php index 63379559..45d1635f 100644 --- a/ext/cron_uploader/info.php +++ b/ext/cron_uploader/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + /* * Name: Cron Uploader * Authors: YaoiFox , Matthew Barbour diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php index f52bb4c9..8da3c467 100644 --- a/ext/cron_uploader/main.php +++ b/ext/cron_uploader/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + require_once "config.php"; class CronUploader extends Extension @@ -207,7 +209,7 @@ class CronUploader extends Extension { global $user_config; - $user_api_key = $user_config->get_string(UserConfig::API_KEY); + $user_api_key = $user_config->get_string(UserConfig::API_KEY, "API_KEY"); return make_http(make_link("/cron_upload/run", "api_key=".urlencode($user_api_key))); } @@ -328,7 +330,7 @@ class CronUploader extends Extension $this->set_headers(); if (!$config->get_bool(UserConfig::ENABLE_API_KEYS)) { - throw new SCoreException("User API keys are note enabled. Please enable them for the cron upload functionality to work."); + throw new SCoreException("User API keys are not enabled. Please enable them for the cron upload functionality to work."); } if ($user->is_anonymous()) { @@ -351,7 +353,7 @@ class CronUploader extends Extension //set_time_limit(0); $output_subdir = date('Ymd-His', time()); - $image_queue = $this->generate_image_queue($user_config->get_string(CronUploaderConfig::DIR)); + $image_queue = $this->generate_image_queue(); // Randomize Images //shuffle($this->image_queue); @@ -362,7 +364,7 @@ class CronUploader extends Extension // Upload the file(s) foreach ($image_queue as $img) { - $execution_time = microtime(true) - $_shm_load_start; + $execution_time = ftime() - $_shm_load_start; if ($execution_time>$max_time) { break; } else { @@ -382,12 +384,13 @@ class CronUploader extends Extension } else { $added++; } - } catch (Exception $e) { + } catch (\Exception $e) { try { if ($database->is_transaction_open()) { $database->rollback(); } - } catch (Exception $e) { + } catch (\Exception $e) { + // rollback failed, let's just log things and die } $failed++; @@ -463,30 +466,11 @@ class CronUploader extends Extension */ private function add_image(string $tmpname, string $filename, string $tags): DataUploadEvent { - assert(file_exists($tmpname)); - - $tagArray = Tag::explode($tags); - if (count($tagArray) == 0) { - $tagArray[] = "tagme"; - } - - $pathinfo = pathinfo($filename); - $metadata = []; - $metadata ['filename'] = $pathinfo ['basename']; - if (array_key_exists('extension', $pathinfo)) { - $metadata ['extension'] = $pathinfo ['extension']; - } - $metadata ['tags'] = $tagArray; - $metadata ['source'] = null; - $event = new DataUploadEvent($tmpname, $metadata); - send_event($event); + $event = add_image($tmpname, $filename, $tags, null); // Generate info message if ($event->image_id == -1) { - if (array_key_exists("mime", $event->metadata)) { - throw new UploadException("File type not recognised (".$event->metadata["mime"]."). Filename: {$filename}"); - } - throw new UploadException("File type not recognised. Filename: {$filename}"); + throw new UploadException("File type not recognised (".$event->mime."). Filename: {$filename}"); } elseif ($event->merged === true) { $infomsg = "Post merged. ID: {$event->image_id} - Filename: {$filename}"; } else { @@ -499,18 +483,6 @@ class CronUploader extends Extension private const PARTIAL_DOWNLOAD_EXTENSIONS = ['crdownload','part']; private const SKIPPABLE_FILES = ['.ds_store','thumbs.db']; - private const SKIPPABLE_DIRECTORIES = ['__macosx']; - - private function is_skippable_dir(string $path): bool - { - $info = pathinfo($path); - - if (array_key_exists("basename", $info) && in_array(strtolower($info['basename']), self::SKIPPABLE_DIRECTORIES)) { - return true; - } - - return false; - } private function is_skippable_file(string $path): bool { @@ -527,7 +499,7 @@ class CronUploader extends Extension return false; } - private function generate_image_queue(string $root_dir, ?int $limit = null): Generator + private function generate_image_queue(): \Generator { $base = $this->get_queue_dir(); @@ -536,17 +508,15 @@ class CronUploader extends Extension return; } - $ite = new RecursiveDirectoryIterator($base, FilesystemIterator::SKIP_DOTS); - foreach (new RecursiveIteratorIterator($ite) as $fullpath => $cur) { + $ite = new \RecursiveDirectoryIterator($base, \FilesystemIterator::SKIP_DOTS); + foreach (new \RecursiveIteratorIterator($ite) as $fullpath => $cur) { if (!is_link($fullpath) && !is_dir($fullpath) && !$this->is_skippable_file($fullpath)) { - $pathinfo = pathinfo($fullpath); - $relativePath = substr($fullpath, strlen($base)); $tags = path_to_tags($relativePath); yield [ 0 => $fullpath, - 1 => $pathinfo ["basename"], + 1 => pathinfo($fullpath, PATHINFO_BASENAME), 2 => $tags ]; } diff --git a/ext/cron_uploader/theme.php b/ext/cron_uploader/theme.php index 43d218ee..64b43c7c 100644 --- a/ext/cron_uploader/theme.php +++ b/ext/cron_uploader/theme.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + use function MicroHTML\LABEL; use function MicroHTML\TABLE; use function MicroHTML\TBODY; @@ -123,7 +125,7 @@ class CronUploaderTheme extends Themelet } } - public function get_user_options(string $dir, bool $stop_on_error, int $log_level, bool $all_logs): string + public function get_user_options(): string { $form = SHM_SIMPLE_FORM( "user_admin/cron_uploader", diff --git a/ext/custom_html_headers/info.php b/ext/custom_html_headers/info.php index 1db8441d..0c75d190 100644 --- a/ext/custom_html_headers/info.php +++ b/ext/custom_html_headers/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class CustomHtmlHeadersInfo extends ExtensionInfo { public const KEY = "custom_html_headers"; diff --git a/ext/custom_html_headers/main.php b/ext/custom_html_headers/main.php index d48a43e2..0cabae53 100644 --- a/ext/custom_html_headers/main.php +++ b/ext/custom_html_headers/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class CustomHtmlHeaders extends Extension { # Adds setup block for custom content diff --git a/ext/danbooru_api/info.php b/ext/danbooru_api/info.php index c8a8b8ce..10113a91 100644 --- a/ext/danbooru_api/info.php +++ b/ext/danbooru_api/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class DanbooruApiInfo extends ExtensionInfo { public const KEY = "danbooru_api"; diff --git a/ext/danbooru_api/main.php b/ext/danbooru_api/main.php index ee8cc36f..6b46ef20 100644 --- a/ext/danbooru_api/main.php +++ b/ext/danbooru_api/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + use MicroHTML\HTMLElement; function TAGS(...$args): HTMLElement @@ -334,22 +336,13 @@ class DanbooruApi extends Extension return; } - // Fire off an event which should process the new file and add it to the db - $fileinfo = pathinfo($filename); - $metadata = []; - $metadata['filename'] = $fileinfo['basename']; - if (array_key_exists('extension', $fileinfo)) { - $metadata['extension'] = $fileinfo['extension']; - } - $metadata['tags'] = $posttags; - $metadata['source'] = $source; //log_debug("danbooru_api","========== NEW($filename) ========="); //log_debug("danbooru_api", "upload($filename): fileinfo(".var_export($fileinfo,TRUE)."), metadata(".var_export($metadata,TRUE).")..."); try { - $nevent = new DataUploadEvent($file, $metadata); + // Fire off an event which should process the new file and add it to the db + $nevent = add_image($file, $filename, $posttags, $source); //log_debug("danbooru_api", "send_event(".var_export($nevent,TRUE).")"); - send_event($nevent); // If it went ok, grab the id for the newly uploaded image and pass it in the header $newimg = Image::by_hash($hash); // FIXME: Unsupported file doesn't throw an error? $newid = make_link("post/view/" . $newimg->id); diff --git a/ext/danbooru_api/test.php b/ext/danbooru_api/test.php index aa36c167..5a9da84a 100644 --- a/ext/danbooru_api/test.php +++ b/ext/danbooru_api/test.php @@ -1,6 +1,9 @@ get_string("downtime_message"); $this->theme->display_message($msg); if (!defined("UNITTEST")) { // hax D: - header("HTTP/1.0 {$page->code} Downtime"); + header("HTTP/1.1 {$page->code} Downtime"); print($page->data); exit; } diff --git a/ext/downtime/test.php b/ext/downtime/test.php index 6399f8be..d27638b9 100644 --- a/ext/downtime/test.php +++ b/ext/downtime/test.php @@ -1,6 +1,9 @@ "; $n = 1; foreach ($list as $item) { - $pathinfo = pathinfo($item); - $name = $pathinfo["filename"]; + $name = pathinfo($item, PATHINFO_FILENAME); $html .= "$name :$name:"; if ($n++ % 3 == 0) { $html .= ""; diff --git a/ext/eokm/info.php b/ext/eokm/info.php index 254cdd94..673415b6 100644 --- a/ext/eokm/info.php +++ b/ext/eokm/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class EokmInfo extends ExtensionInfo { public const KEY = "eokm"; diff --git a/ext/eokm/main.php b/ext/eokm/main.php index 767679a1..83b98f32 100644 --- a/ext/eokm/main.php +++ b/ext/eokm/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class Eokm extends Extension { public function get_priority(): int diff --git a/ext/eokm/test.php b/ext/eokm/test.php index 96fee799..b71e45e1 100644 --- a/ext/eokm/test.php +++ b/ext/eokm/test.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class EokmTest extends ShimmiePHPUnitTestCase { public function testPass() diff --git a/ext/et/info.php b/ext/et/info.php index b2fcdef7..e641eee8 100644 --- a/ext/et/info.php +++ b/ext/et/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class ETInfo extends ExtensionInfo { public const KEY = "et"; diff --git a/ext/et/main.php b/ext/et/main.php index a20e4f60..00d74a4e 100644 --- a/ext/et/main.php +++ b/ext/et/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class ET extends Extension { /** @var ETTheme */ @@ -71,7 +73,7 @@ class ET extends Extension 'shimmie' => VERSION, 'schema' => $config->get_int("db_version"), 'php' => phpversion(), - 'db' => $database->get_driver_name() . " " . $database->get_version(), + 'db' => $database->get_driver_id()->value . " " . $database->get_version(), 'os' => php_uname(), 'server' => $_SERVER["SERVER_SOFTWARE"] ?? 'unknown', ], @@ -111,7 +113,8 @@ class ET extends Extension 'branch' => $commitBranch, 'origin' => $commitOrigin, ]; - } catch (Exception $e) { + } catch (\Exception $e) { + // If we can't get git data, just skip it } } diff --git a/ext/et/test.php b/ext/et/test.php index e2cdeeb0..8e94f525 100644 --- a/ext/et/test.php +++ b/ext/et/test.php @@ -1,6 +1,9 @@ add_block(new Block("Information:", $this->build_data_form($yaml))); } - protected function build_data_form($yaml): string + protected function build_data_form($yaml): \MicroHTML\HTMLElement { - return (string)FORM( + return FORM( ["action"=>"https://shimmie.shishnet.org/register.php", "method"=>"POST"], INPUT(["type"=>"hidden", "name"=>"registration_api", "value"=>"2"]), P( diff --git a/ext/et_server/info.php b/ext/et_server/info.php index a19945b4..d5ad2aac 100644 --- a/ext/et_server/info.php +++ b/ext/et_server/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class ETServerInfo extends ExtensionInfo { public const KEY = "et_server"; @@ -13,5 +15,5 @@ class ETServerInfo extends ExtensionInfo public string $license = self::LICENSE_GPLV2; public string $description = "Keep track of shimmie registrations"; public ?string $documentation = "For internal use"; - public string $visibility = self::VISIBLE_HIDDEN; + public ExtensionVisibility $visibility = ExtensionVisibility::HIDDEN; } diff --git a/ext/et_server/main.php b/ext/et_server/main.php index 485e612c..2c3f2762 100644 --- a/ext/et_server/main.php +++ b/ext/et_server/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + use function MicroHTML\{PRE}; class ETServer extends Extension @@ -26,7 +28,7 @@ class ETServer extends Extension foreach ($database->get_all("SELECT responded, data FROM registration ORDER BY responded DESC") as $row) { $page->add_block(new Block( $row["responded"], - (string)PRE(["style"=>"text-align: left; overflow: scroll;"], $row["data"]), + PRE(["style"=>"text-align: left; overflow: scroll;"], $row["data"]), "main", $n++ )); diff --git a/ext/ext_manager/info.php b/ext/ext_manager/info.php index 22242b86..78ffba3a 100644 --- a/ext/ext_manager/info.php +++ b/ext/ext_manager/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class ExtManagerInfo extends ExtensionInfo { public const KEY = "ext_manager"; @@ -11,7 +13,7 @@ class ExtManagerInfo extends ExtensionInfo public string $url = self::SHIMMIE_URL; public array $authors = self::SHISH_AUTHOR; public string $license = self::LICENSE_GPLV2; - public string $visibility = self::VISIBLE_ADMIN; + public ExtensionVisibility $visibility = ExtensionVisibility::ADMIN; public string $description = "A thing for point & click extension management"; public ?string $documentation = "Allows the admin to view a list of all extensions and enable or disable them; also allows users to view the list of activated extensions and read their documentation"; public bool $core = true; diff --git a/ext/ext_manager/main.php b/ext/ext_manager/main.php index 33958352..2fa7d5db 100644 --- a/ext/ext_manager/main.php +++ b/ext/ext_manager/main.php @@ -2,6 +2,7 @@ declare(strict_types=1); +namespace Shimmie2; function __extman_extcmp(ExtensionInfo $a, ExtensionInfo $b): int { @@ -115,9 +116,9 @@ class ExtManager extends Extension { $extensions = ExtensionInfo::get_all(); if (!$all) { - $extensions = array_filter($extensions, "__extman_extactive"); + $extensions = array_filter($extensions, "Shimmie2\__extman_extactive"); } - usort($extensions, "__extman_extcmp"); + usort($extensions, "Shimmie2\__extman_extcmp"); return $extensions; } diff --git a/ext/ext_manager/test.php b/ext/ext_manager/test.php index 4ac9d0fb..acb56b77 100644 --- a/ext/ext_manager/test.php +++ b/ext/ext_manager/test.php @@ -1,6 +1,9 @@ visibility === ExtensionInfo::VISIBLE_ADMIN) - || $extension->visibility === ExtensionInfo::VISIBLE_HIDDEN) { + if ((!$editable && $extension->visibility === ExtensionVisibility::ADMIN) + || $extension->visibility === ExtensionVisibility::HIDDEN) { continue; } @@ -87,7 +89,7 @@ class ExtManagerTheme extends Themelet $page->set_title("Extensions"); $page->set_heading("Extensions"); $page->add_block(new NavBlock()); - $page->add_block(new Block("Extension Manager", (string)$form)); + $page->add_block(new Block("Extension Manager", $form)); } public function display_doc(Page $page, ExtensionInfo $info) @@ -119,6 +121,6 @@ class ExtManagerTheme extends Themelet $page->set_title("Documentation for " . html_escape($info->name)); $page->set_heading(html_escape($info->name)); $page->add_block(new NavBlock()); - $page->add_block(new Block("Documentation", (string)$html)); + $page->add_block(new Block("Documentation", $html)); } } diff --git a/ext/favorites/info.php b/ext/favorites/info.php index b33c7fb0..d0db6ae5 100644 --- a/ext/favorites/info.php +++ b/ext/favorites/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class FavoritesInfo extends ExtensionInfo { public const KEY = "favorites"; diff --git a/ext/favorites/main.php b/ext/favorites/main.php index 778e7be3..8a6e72f9 100644 --- a/ext/favorites/main.php +++ b/ext/favorites/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class FavoriteSetEvent extends Event { public int $image_id; @@ -143,7 +145,7 @@ class Favorites extends Extension public function onHelpPageBuilding(HelpPageBuildingEvent $event) { if ($event->key===HelpPages::SEARCH) { - $event->add_block(new Block("Favorites", (string)$this->theme->get_help_html())); + $event->add_block(new Block("Favorites", $this->theme->get_help_html())); } } diff --git a/ext/favorites/test.php b/ext/favorites/test.php index 8b38926c..ed1247bc 100644 --- a/ext/favorites/test.php +++ b/ext/favorites/test.php @@ -1,6 +1,9 @@ get_int("featured_id"); if ($fid > 0) { $image = $cache->get("featured_image_object:$fid"); - if ($image === false) { + if (is_null($image)) { $image = Image::by_id($fid); if ($image) { // make sure the object is fully populated before saving $image->get_tag_array(); @@ -69,6 +71,15 @@ class Featured extends Extension } } + public function onImageDeletion(ImageDeletionEvent $event) + { + global $config; + if ($event->image->id == $config->get_int("featured_id")) { + $config->set_int("featured_id", 0); + $config->save(); + } + } + public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { global $user; diff --git a/ext/featured/test.php b/ext/featured/test.php index ee27be17..ef0c4119 100644 --- a/ext/featured/test.php +++ b/ext/featured/test.php @@ -1,6 +1,9 @@ width, $image->height); - return (string)DIV( + return DIV( ["style"=>"text-align: center;"], A( ["href"=>make_link("post/view/{$image->id}", $query)], diff --git a/ext/forum/info.php b/ext/forum/info.php index 9e2d4e34..09021550 100644 --- a/ext/forum/info.php +++ b/ext/forum/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class ForumInfo extends ExtensionInfo { public const KEY = "forum"; diff --git a/ext/forum/main.php b/ext/forum/main.php index 79c1026b..443af4ac 100644 --- a/ext/forum/main.php +++ b/ext/forum/main.php @@ -1,6 +1,9 @@ execute("UPDATE forum_threads SET uptodate=now() WHERE id=:id", ['id'=>$threadID]); } - private function retrieve_posts(int $threadID, int $pageNumber): array - { - global $database, $config; - $postsPerPage = $config->get_int('forumPostsPerPage', 15); - - return $database->get_all( - "SELECT p.id, p.date, p.message, u.name as user_name, u.email AS user_email, u.class AS user_class ". - "FROM forum_posts AS p ". - "INNER JOIN users AS u ". - "ON p.user_id = u.id ". - "WHERE thread_id = :thread_id ". - "ORDER BY p.date ASC ". - "LIMIT :limit OFFSET :offset ", - ["thread_id"=>$threadID, "offset"=>($pageNumber - 1) * $postsPerPage, "limit"=>$postsPerPage] - ); - } - private function delete_thread(int $threadID): void { global $database; diff --git a/ext/forum/theme.php b/ext/forum/theme.php index f3c316b2..9e7bab4e 100644 --- a/ext/forum/theme.php +++ b/ext/forum/theme.php @@ -1,6 +1,9 @@ formatted; - + $message = send_event(new TextFormattingEvent($message))->formatted; $message = str_replace('\n\r', '
', $message); $message = str_replace('\r\n', '
', $message); $message = str_replace('\n', '
', $message); diff --git a/ext/four_oh_four/info.php b/ext/four_oh_four/info.php index 943fe5ef..e40a5ffe 100644 --- a/ext/four_oh_four/info.php +++ b/ext/four_oh_four/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class FourOhFourInfo extends ExtensionInfo { public const KEY = "four_oh_four"; @@ -11,7 +13,7 @@ class FourOhFourInfo extends ExtensionInfo public string $url = self::SHIMMIE_URL; public array $authors = self::SHISH_AUTHOR; public string $license = self::LICENSE_GPLV2; - public string $visibility = self::VISIBLE_HIDDEN; + public ExtensionVisibility $visibility = ExtensionVisibility::HIDDEN; public string $description = "If no other extension puts anything onto the page, show 404"; public bool $core = true; } diff --git a/ext/four_oh_four/main.php b/ext/four_oh_four/main.php index 241a2967..836c8f24 100644 --- a/ext/four_oh_four/main.php +++ b/ext/four_oh_four/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class FourOhFour extends Extension { public function onPageRequest(PageRequestEvent $event) diff --git a/ext/four_oh_four/test.php b/ext/four_oh_four/test.php index a6f2a1a1..5c71a839 100644 --- a/ext/four_oh_four/test.php +++ b/ext/four_oh_four/test.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class FourOhFourTest extends ShimmiePHPUnitTestCase { public function test404Handler() diff --git a/ext/google_analytics/info.php b/ext/google_analytics/info.php index e0c4401a..af4f5c9d 100644 --- a/ext/google_analytics/info.php +++ b/ext/google_analytics/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class GoogleAnalyticsInfo extends ExtensionInfo { public const KEY = "google_analytics"; diff --git a/ext/google_analytics/main.php b/ext/google_analytics/main.php index 410ff0b4..a9759374 100644 --- a/ext/google_analytics/main.php +++ b/ext/google_analytics/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class GoogleAnalytics extends Extension { # Add analytics to config diff --git a/ext/graphql/info.php b/ext/graphql/info.php new file mode 100644 index 00000000..c6bfce05 --- /dev/null +++ b/ext/graphql/info.php @@ -0,0 +1,17 @@ +tags; + $_POST['tag_edit__source'] = $metadata->source; + $image = Image::by_id($post_id); + if (!$image->is_locked() || $user->can(Permissions::EDIT_IMAGE_LOCK)) { + send_event(new ImageInfoSetEvent($image)); + } + return Image::by_id($post_id); + } +} + +class GraphQL extends Extension +{ + public static function get_schema(): Schema + { + global $_tracer; + $_tracer->begin("Create Schema"); + $schema = new \GQLA\Schema(); + $_tracer->end(null); + return $schema; + } + + private function cors(): void + { + global $config; + $pat = $config->get_string("graphql_cors_pattern"); + + if ($pat && isset($_SERVER['HTTP_ORIGIN'])) { + if (preg_match("#$pat#", $_SERVER['HTTP_ORIGIN'])) { + header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}"); + header('Access-Control-Allow-Credentials: true'); + header('Access-Control-Max-Age: 86400'); + } + } + + if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { + if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) { + header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); + } + if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) { + header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}"); + } + exit(0); + } + } + + public function onInitExt(InitExtEvent $event) + { + global $config; + $config->set_default_string('graphql_cors_pattern', ""); + $config->set_default_bool('graphql_debug', false); + } + + public function onPageRequest(PageRequestEvent $event) + { + global $config, $page; + if ($event->page_matches("graphql")) { + $this->cors(); + $t1 = ftime(); + $server = new StandardServer([ + 'schema' => $this->get_schema(), + ]); + $t2 = ftime(); + $resp = $server->executeRequest(); + if ($config->get_bool("graphql_debug")) { + $debug = DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::RETHROW_INTERNAL_EXCEPTIONS; + $body = $resp->toArray($debug); + } else { + $body = $resp->toArray(); + } + $t3 = ftime(); + $body['stats'] = get_debug_info_arr(); + $body['stats']['graphql_schema_time'] = round($t2 - $t1, 2); + $body['stats']['graphql_execute_time'] = round($t3 - $t2, 2); + // sleep(1); + $page->set_mode(PageMode::DATA); + $page->set_mime("application/json"); + $page->set_data(\json_encode($body, JSON_UNESCAPED_UNICODE)); + } + if ($event->page_matches("graphql_upload")) { + $this->cors(); + $page->set_mode(PageMode::DATA); + $page->set_mime("application/json"); + $page->set_data(\json_encode(self::handle_uploads())); + } + } + + private static function handle_uploads(): array + { + global $user; + + if (!$user->can(Permissions::CREATE_IMAGE)) { + return ["error" => "User cannot create posts"]; + } + + $common_tags = $_POST['common_tags']; + $common_source = $_POST['common_source']; + + $results = []; + for ($n=0; $n<100; $n++) { + if (empty($_POST["url$n"]) && empty($_FILES["data$n"])) { + break; + } + if (isset($_FILES["data$n"]) && ($_FILES["data$n"]["size"] == 0 || $_FILES["data$n"]["error"] == UPLOAD_ERR_NO_FILE)) { + break; + } + try { + $results[] = self::handle_upload($n, $common_tags, $common_source); + } catch(\Exception $e) { + $results[] = ["error" => $e->getMessage()]; + } + } + return ["results" => $results]; + } + + private static function handle_upload(int $n, string $common_tags, string $common_source): array + { + if (!empty($_POST["url$n"])) { + return ["error" => "URLs not handled yet"]; + $tmpname = "..."; + $filename = "..."; + } else { + $ec = $_FILES["data$n"]["error"]; + switch($ec) { + case UPLOAD_ERR_OK: + $tmpname = $_FILES["data$n"]["tmp_name"]; + $filename = $_FILES["data$n"]["name"]; + break; + case UPLOAD_ERR_INI_SIZE: + return ["error" => "File larger than PHP can handle"]; + default: + return ["error" => "Mystery error: $ec"]; + } + } + + $tags = trim($common_tags . " " . $_POST["tags$n"]); + $source = $common_source; + if (!empty($_POST["source$n"])) { + $source = $_POST["source$n"]; + } + $event = send_event(new DataUploadEvent($tmpname, [ + 'filename' => $filename, + 'tags' => Tag::explode($tags), + 'source' => $source, + ])); + + return ["image_id" => $event->image_id]; + } + + public function onCommand(CommandEvent $event) + { + if ($event->cmd == "help") { + print "\tgraphql \n"; + print "\t\teg 'graphql \"{ post(id: 18) { id, hash } }\"'\n\n"; + print "\tgraphql-schema\n"; + print "\t\tdump the schema\n\n"; + } + if ($event->cmd == "graphql") { + $t1 = ftime(); + $schema = $this->get_schema(); + $t2 = ftime(); + $debug = DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::RETHROW_INTERNAL_EXCEPTIONS; + $body = GQL::executeQuery($schema, $event->args[0])->toArray($debug); + $t3 = ftime(); + $body['stats'] = get_debug_info_arr(); + $body['stats']['graphql_schema_time'] = round($t2 - $t1, 2); + $body['stats']['graphql_execute_time'] = round($t3 - $t2, 2); + echo \json_encode($body, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT); + } + if ($event->cmd == "graphql-schema") { + $schema = $this->get_schema(); + echo(SchemaPrinter::doPrint($schema)); + } + } +} diff --git a/ext/graphql/test.php b/ext/graphql/test.php new file mode 100644 index 00000000..db30ca7f --- /dev/null +++ b/ext/graphql/test.php @@ -0,0 +1,15 @@ +assertValid(); + $this->assertTrue(true); + } +} diff --git a/ext/handle_archive/info.php b/ext/handle_archive/info.php index 35ca10a3..b5c315da 100644 --- a/ext/handle_archive/info.php +++ b/ext/handle_archive/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class ArchiveFileHandlerInfo extends ExtensionInfo { public const KEY = "handle_archive"; diff --git a/ext/handle_archive/main.php b/ext/handle_archive/main.php index 0117f8f4..a975643b 100644 --- a/ext/handle_archive/main.php +++ b/ext/handle_archive/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class ArchiveFileHandler extends DataHandlerExtension { protected array $SUPPORTED_MIME = [MimeType::ZIP]; diff --git a/ext/handle_cbz/info.php b/ext/handle_cbz/info.php index a8b07a36..2ffb4fb8 100644 --- a/ext/handle_cbz/info.php +++ b/ext/handle_cbz/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class CBZFileHandlerInfo extends ExtensionInfo { public const KEY = "handle_cbz"; diff --git a/ext/handle_cbz/main.php b/ext/handle_cbz/main.php index c1508bba..1ff44636 100644 --- a/ext/handle_cbz/main.php +++ b/ext/handle_cbz/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class CBZFileHandler extends DataHandlerExtension { protected array $SUPPORTED_MIME = [MimeType::COMIC_ZIP]; @@ -13,7 +15,7 @@ class CBZFileHandler extends DataHandlerExtension $event->image->audio = false; $event->image->image = false; - $tmp = $this->get_representative_image($event->file_name); + $tmp = $this->get_representative_image($event->image->get_image_filename()); $info = getimagesize($tmp); if ($info) { $event->image->width = $info[0]; @@ -47,7 +49,7 @@ class CBZFileHandler extends DataHandlerExtension { $out = "data/comic-cover-FIXME.jpg"; // TODO: random - $za = new ZipArchive(); + $za = new \ZipArchive(); $za->open($archive); $names = []; for ($i=0; $i<$za->numFiles;$i++) { diff --git a/ext/handle_cbz/theme.php b/ext/handle_cbz/theme.php index 65115329..ce574a8f 100644 --- a/ext/handle_cbz/theme.php +++ b/ext/handle_cbz/theme.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class CBZFileHandlerTheme extends Themelet { public function display_image(Page $page, Image $image) diff --git a/ext/handle_flash/info.php b/ext/handle_flash/info.php index a33c4b98..24f36c39 100644 --- a/ext/handle_flash/info.php +++ b/ext/handle_flash/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class FlashFileHandlerInfo extends ExtensionInfo { public const KEY = "handle_flash"; diff --git a/ext/handle_flash/main.php b/ext/handle_flash/main.php index 9a8ea390..8670ef65 100644 --- a/ext/handle_flash/main.php +++ b/ext/handle_flash/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class FlashFileHandler extends DataHandlerExtension { protected array $SUPPORTED_MIME = [MimeType::FLASH]; @@ -12,7 +14,7 @@ class FlashFileHandler extends DataHandlerExtension $event->image->video = true; $event->image->image = false; - $info = getimagesize($event->file_name); + $info = getimagesize($event->image->get_image_filename()); if ($info) { $event->image->width = $info[0]; $event->image->height = $info[1]; diff --git a/ext/handle_flash/theme.php b/ext/handle_flash/theme.php index 369420f9..9e2c799f 100644 --- a/ext/handle_flash/theme.php +++ b/ext/handle_flash/theme.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class FlashFileHandlerTheme extends Themelet { public function display_image(Page $page, Image $image) diff --git a/ext/handle_ico/info.php b/ext/handle_ico/info.php index 6c6c4a54..874c0895 100644 --- a/ext/handle_ico/info.php +++ b/ext/handle_ico/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class IcoFileHandlerInfo extends ExtensionInfo { public const KEY = "handle_ico"; diff --git a/ext/handle_ico/main.php b/ext/handle_ico/main.php index 38f2b874..2b03096d 100644 --- a/ext/handle_ico/main.php +++ b/ext/handle_ico/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class IcoFileHandler extends DataHandlerExtension { protected array $SUPPORTED_MIME = [MimeType::ICO, MimeType::ANI, MimeType::WIN_BITMAP, MimeType::ICO_OSX]; @@ -11,20 +13,19 @@ class IcoFileHandler extends DataHandlerExtension $event->image->lossless = true; $event->image->video = false; $event->image->audio = false; - $event->image->image = ($event->mime!= MimeType::ANI); + $event->image->image = ($event->image->get_mime() != MimeType::ANI); - $fp = fopen($event->file_name, "r"); + $fp = fopen($event->image->get_image_filename(), "r"); try { unpack("Snull/Stype/Scount", fread($fp, 6)); $subheader = unpack("Cwidth/Cheight/Ccolours/Cnull/Splanes/Sbpp/Lsize/loffset", fread($fp, 16)); + $width = $subheader['width']; + $height = $subheader['height']; + $event->image->width = $width == 0 ? 256 : $width; + $event->image->height = $height == 0 ? 256 : $height; } finally { fclose($fp); } - - $width = $subheader['width']; - $height = $subheader['height']; - $event->image->width = $width == 0 ? 256 : $width; - $event->image->height = $height == 0 ? 256 : $height; } protected function create_thumb(string $hash, string $mime): bool diff --git a/ext/handle_ico/test.php b/ext/handle_ico/test.php index f576a14c..9e108112 100644 --- a/ext/handle_ico/test.php +++ b/ext/handle_ico/test.php @@ -1,6 +1,9 @@ image->lossless = Media::is_lossless($event->file_name, $event->mime); + $filename = $event->image->get_image_filename(); + $mime = $event->image->get_mime(); + + $event->image->lossless = Media::is_lossless($filename, $mime); $event->image->audio = false; - switch ($event->mime) { + switch ($mime) { case MimeType::GIF: - $event->image->video = MimeType::is_animated_gif($event->file_name); + $event->image->video = MimeType::is_animated_gif($filename); break; case MimeType::WEBP: - $event->image->video = MimeType::is_animated_webp($event->file_name); + $event->image->video = MimeType::is_animated_webp($filename); break; default: $event->image->video = false; @@ -23,7 +28,7 @@ class PixelFileHandler extends DataHandlerExtension } $event->image->image = !$event->image->video; - $info = getimagesize($event->file_name); + $info = getimagesize($event->image->get_image_filename()); if ($info) { $event->image->width = $info[0]; $event->image->height = $info[1]; @@ -51,7 +56,7 @@ class PixelFileHandler extends DataHandlerExtension log_warning("handle_pixel", "Insufficient memory while creating thumbnail: ".$e->getMessage()); imagestring($thumb, 5, 10, 24, "Image Too Large :(", $black); return true; - } catch (Exception $e) { + } catch (\Exception $e) { log_error("handle_pixel", "Error while creating thumbnail: ".$e->getMessage()); return false; } diff --git a/ext/handle_pixel/test.php b/ext/handle_pixel/test.php index 0e8f8f6c..0b12a459 100644 --- a/ext/handle_pixel/test.php +++ b/ext/handle_pixel/test.php @@ -1,6 +1,9 @@ image->audio = false; $event->image->image = true; - $msp = new MiniSVGParser($event->file_name); + $msp = new MiniSVGParser($event->image->get_image_filename()); $event->image->width = $msp->width; $event->image->height = $msp->height; } @@ -47,6 +50,7 @@ class SVGFileHandler extends DataHandlerExtension $sanitizer->removeRemoteReferences(true); $dirtySVG = file_get_contents($event->tmpname); $cleanSVG = $sanitizer->sanitize($dirtySVG); + $event->hash = md5($cleanSVG); file_put_contents(warehouse_path(Image::IMAGE_DIR, $event->hash), $cleanSVG); } @@ -93,7 +97,7 @@ class MiniSVGParser xml_parser_free($xml_parser); } - public function startElement($parser, $name, $attrs) + public function startElement($parser, $name, $attrs): void { if ($name == "SVG" && $this->xml_depth == 0) { $this->width = int_escape($attrs["WIDTH"]); @@ -102,7 +106,7 @@ class MiniSVGParser $this->xml_depth++; } - public function endElement($parser, $name) + public function endElement($parser, $name): void { $this->xml_depth--; } diff --git a/ext/handle_svg/test.php b/ext/handle_svg/test.php index 74155544..60652ffe 100644 --- a/ext/handle_svg/test.php +++ b/ext/handle_svg/test.php @@ -1,6 +1,9 @@ log_in_as_user(); $image_id = $this->post_image("tests/alert.svg", "something"); diff --git a/ext/handle_svg/theme.php b/ext/handle_svg/theme.php index 0fc57974..37557581 100644 --- a/ext/handle_svg/theme.php +++ b/ext/handle_svg/theme.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class SVGFileHandlerTheme extends Themelet { public function display_image(Page $page, Image $image) diff --git a/ext/handle_video/info.php b/ext/handle_video/info.php index ec035c36..d200f785 100644 --- a/ext/handle_video/info.php +++ b/ext/handle_video/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class VideoFileHandlerInfo extends ExtensionInfo { public const KEY = "handle_video"; diff --git a/ext/handle_video/main.php b/ext/handle_video/main.php index 188c4c88..2ae4f627 100644 --- a/ext/handle_video/main.php +++ b/ext/handle_video/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + abstract class VideoFileHandlerConfig { public const PLAYBACK_AUTOPLAY = "video_playback_autoplay"; @@ -62,7 +64,7 @@ class VideoFileHandler extends DataHandlerExtension $event->image->video = true; $event->image->image = false; try { - $data = Media::get_ffprobe_data($event->file_name); + $data = Media::get_ffprobe_data($event->image->get_image_filename()); if (is_array($data)) { if (array_key_exists("streams", $data)) { diff --git a/ext/handle_video/theme.php b/ext/handle_video/theme.php index 8866b997..87453343 100644 --- a/ext/handle_video/theme.php +++ b/ext/handle_video/theme.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class VideoFileHandlerTheme extends Themelet { public function display_image(Page $page, Image $image) diff --git a/ext/hellban/info.php b/ext/hellban/info.php index fcb484a7..12a3caaa 100644 --- a/ext/hellban/info.php +++ b/ext/hellban/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + /* * Name: [Beta] Hellban */ diff --git a/ext/hellban/main.php b/ext/hellban/main.php index 194a9cdb..abcfc9af 100644 --- a/ext/hellban/main.php +++ b/ext/hellban/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class HellBan extends Extension { public function onPageRequest(PageRequestEvent $event) diff --git a/ext/help_pages/info.php b/ext/help_pages/info.php index 01b3ddb2..e01c44ae 100644 --- a/ext/help_pages/info.php +++ b/ext/help_pages/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class HelpPagesInfo extends ExtensionInfo { public const KEY = "help_pages"; @@ -11,6 +13,6 @@ class HelpPagesInfo extends ExtensionInfo public array $authors = ["Matthew Barbour"=>"matthew@darkholme.net"]; public string $license = self::LICENSE_WTFPL; public string $description = "Provides documentation screens"; - public string $visibility = self::VISIBLE_HIDDEN; + public ExtensionVisibility $visibility = ExtensionVisibility::HIDDEN; public bool $core = true; } diff --git a/ext/help_pages/main.php b/ext/help_pages/main.php index 4d6312e2..2a208c46 100644 --- a/ext/help_pages/main.php +++ b/ext/help_pages/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class HelpPageListBuildingEvent extends Event { public array $pages = []; @@ -42,9 +44,7 @@ class HelpPages extends Extension private function get_pages(): array { if ($this->pages==null) { - $e = new HelpPageListBuildingEvent(); - send_event($e); - $this->pages = $e->pages; + $this->pages = send_event(new HelpPageListBuildingEvent())->pages; } return $this->pages; } @@ -72,8 +72,7 @@ class HelpPages extends Extension $this->theme->display_help_page($title); - $hpbe = new HelpPageBuildingEvent($name); - send_event($hpbe); + $hpbe = send_event(new HelpPageBuildingEvent($name)); asort($hpbe->blocks); foreach ($hpbe->blocks as $key=>$value) { diff --git a/ext/help_pages/test.php b/ext/help_pages/test.php index eeab5076..80a5de59 100644 --- a/ext/help_pages/test.php +++ b/ext/help_pages/test.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class HelpPagesTest extends ShimmiePHPUnitTestCase { public function test_list() diff --git a/ext/help_pages/theme.php b/ext/help_pages/theme.php index 11d37af6..6e946e9e 100644 --- a/ext/help_pages/theme.php +++ b/ext/help_pages/theme.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class HelpPagesTheme extends Themelet { public function display_list_page(array $pages) diff --git a/ext/holiday/info.php b/ext/holiday/info.php index e32dad0d..a1963a04 100644 --- a/ext/holiday/info.php +++ b/ext/holiday/info.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class HolidayInfo extends ExtensionInfo { public const KEY = "holiday"; diff --git a/ext/holiday/main.php b/ext/holiday/main.php index d429a6be..8dd450c2 100644 --- a/ext/holiday/main.php +++ b/ext/holiday/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class Holiday extends Extension { /** @var HolidayTheme */ diff --git a/ext/holiday/theme.php b/ext/holiday/theme.php index 060287b7..762e0b99 100644 --- a/ext/holiday/theme.php +++ b/ext/holiday/theme.php @@ -1,6 +1,9 @@ "bzchan@animemahou.com"]; public string $license = self::LICENSE_GPLV2; - public string $visibility = self::VISIBLE_ADMIN; + public ExtensionVisibility $visibility = ExtensionVisibility::ADMIN; public string $description = "Displays a front page with logo, search box and post count"; public ?string $documentation = "Once enabled, the page will show up at the URL \"home\", so if you want diff --git a/ext/home/main.php b/ext/home/main.php index 8c00c499..4a4fe5d4 100644 --- a/ext/home/main.php +++ b/ext/home/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + class Home extends Extension { /** @var HomeTheme */ @@ -64,10 +66,10 @@ class Home extends Extension $main_links = $config->get_string('home_links'); } else { $main_links = '[url=site://post/list]Posts[/url][url=site://comment/list]Comments[/url][url=site://tags]Tags[/url]'; - if (class_exists("Pools")) { + if (class_exists("Shimmie2\Pools")) { $main_links .= '[url=site://pool/list]Pools[/url]'; } - if (class_exists("Wiki")) { + if (class_exists("Shimmie2\Wiki")) { $main_links .= '[url=site://wiki]Wiki[/url]'; } $main_links .= '[url=site://ext_doc]Documentation[/url]'; diff --git a/ext/home/test.php b/ext/home/test.php index bb5621c3..3dece097 100644 --- a/ext/home/test.php +++ b/ext/home/test.php @@ -1,6 +1,9 @@ self::SHISH_EMAIL, "jgen"=>"jgen.tech@gmail.com"]; public string $license = self::LICENSE_GPLV2; public string $description = "Handle the image database"; - public string $visibility = self::VISIBLE_HIDDEN; + public ExtensionVisibility $visibility = ExtensionVisibility::HIDDEN; public bool $core = true; } diff --git a/ext/image/main.php b/ext/image/main.php index aff6e6c8..8709ddf7 100644 --- a/ext/image/main.php +++ b/ext/image/main.php @@ -2,6 +2,8 @@ declare(strict_types=1); +namespace Shimmie2; + require_once "config.php"; /** @@ -181,9 +183,8 @@ class ImageIO extends Extension $tags_to_set = $image->get_tag_array(); $image->tag_array = []; send_event(new TagSetEvent($image, $tags_to_set)); - - if ($image->source !== null) { - log_info("core-image", "Source for >>{$image->id} set to: {$image->source}"); + if ($image->source) { + send_event(new SourceSetEvent($image, $image->source)); } } catch (ImageAdditionException $e) { throw new UploadException($e->error); diff --git a/ext/image/test.php b/ext/image/test.php index be021f4f..881d56a3 100644 --- a/ext/image/test.php +++ b/ext/image/test.php @@ -1,6 +1,9 @@ post_image("tests/pbx_screenshot.jpg", "test"); $_POST['image_id'] = "$image_id"; send_event(new PageRequestEvent("image/replace")); - $this->assertEquals("redirect", $page->mode); + $this->assertEquals(PageMode::REDIRECT, $page->mode); } } diff --git a/ext/image/theme.php b/ext/image/theme.php index b64b6495..3a016fc7 100644 --- a/ext/image/theme.php +++ b/ext/image/theme.php @@ -1,6 +1,9 @@ post_image("tests/pbx_screenshot.jpg", "pbx"); - $this->assertTrue(false); + $this->fail(); } catch (UploadException $e) { $this->assertTrue(true); } @@ -46,7 +49,7 @@ class ImageBanTest extends ShimmiePHPUnitTestCase $this->assertEquals(200, $page->code); } - public function onNotSuccessfulTest(Throwable $t): void + public function onNotSuccessfulTest(\Throwable $t): void { send_event(new RemoveImageHashBanEvent($this->hash)); parent::onNotSuccessfulTest($t); // TODO: Change the autogenerated stub diff --git a/ext/image_hash_ban/theme.php b/ext/image_hash_ban/theme.php index 426e841c..723d197a 100644 --- a/ext/image_hash_ban/theme.php +++ b/ext/image_hash_ban/theme.php @@ -1,6 +1,9 @@ -

  • by tag, eg - -
  • -
  • size (=, <, >, <=, >=) width x height, eg - -
  • -
  • width (=, <, >, <=, >=) width, eg - -
  • -
  • height (=, <, >, <=, >=) height, eg - -
  • -
  • ratio (=, <, >, <=, >=) width : height, eg - -
  • -
  • filesize (=, <, >, <=, >=) size, eg - -
  • -
  • id (=, <, >, <=, >=) number, eg - -
  • -
  • user=Username & poster=Username, eg - -
  • -
  • user_id=userID & poster_id=userID, eg - -
  • -
  • hash=md5sum & md5=md5sum, eg - -
  • -
  • filename=blah & name=blah, eg - -
  • -
  • posted (=, <, >, <=, >=) date, eg - -
  • -
  • tags (=, <, >, <=, >=) count, eg - -
  • -
  • source=(URL, any, none) eg - -
  • -
  • order=(id, width, height, filesize, filename)_(ASC, DESC), eg - -
  • -
  • order=random_####, eg - -
  • - -

    Search items can be combined to search for posts which match both, -or you can stick \"-\" in front of an item to search for things that don't -match it. -

    Metatags can be followed by \":\" rather than \"=\" if you prefer. -
    I.E: \"posted:2014-01-01\", \"id:>=500\" etc. + public ?string $documentation = " etc.

    Some search methods provided by extensions: