From 6fdc5447f1b2929f305f11bae588d31e4eb48f3c Mon Sep 17 00:00:00 2001 From: Benjamin Renard Date: Sun, 29 Jan 2023 11:51:41 +0100 Subject: [PATCH] Some improvments from recent works on apps based on its "framework" * Code cleaning and fix some small errors using Phpstan * Configure pre-commit to run Phpstan before each commit * Some little improvments and logging, mail, smarty & URL libs * Add Sentry integration * Add Webstat JS code inclusion * Install Smarty dependency using composer Breaking changes: * Rename Event class as HookEvent to avoid conflict with PECL event * URL with refresh GET parameter now automatically trigger redirection without it after page loading to avoid to keep it in URL --- .pre-commit-config.yaml | 9 + composer.json | 14 +- composer.lock | 1833 ++++++++++++++++++++++++++++------ docs/config.md | 8 + docs/install.md | 2 +- includes/cli.php | 11 +- includes/config.inc.php | 45 +- includes/core.php | 23 +- includes/db.php | 129 +-- includes/functions.php | 23 +- includes/hooks.php | 12 +- includes/logging.php | 137 ++- includes/mail.php | 129 ++- includes/sentry.php | 213 ++++ includes/session.php | 4 +- includes/smarty.php | 104 +- includes/translation-cli.php | 8 +- includes/translation.php | 2 + includes/url-helpers.php | 2 + includes/url-public.php | 2 + includes/url.php | 129 ++- phpstan.neon | 31 + public_html/index.php | 2 + templates/empty.tpl | 1 + 24 files changed, 2363 insertions(+), 510 deletions(-) create mode 100644 .pre-commit-config.yaml create mode 100644 includes/sentry.php create mode 100644 phpstan.neon diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4c5e5e3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,9 @@ +# Pre-commit hooks to run tests and ensure code is cleaned. +# See https://pre-commit.com for more information +repos: +- repo: https://github.com/digitalpulp/pre-commit-php.git + rev: 1.4.0 + hooks: + - id: php-stan + files: \.(php)$ + args: ['--configuration=phpstan.neon'] diff --git a/composer.json b/composer.json index 0a6863c..acd05e5 100644 --- a/composer.json +++ b/composer.json @@ -1,13 +1,23 @@ { + "name": "ee/eesyphp", + "description": "Easter-eggs easyphp PHP framework for simple web apps", + "authors": [ + { + "name": "Easter-eggs", + "email": "info@easter-eggs.com" + } + ], "require": { "envms/fluentpdo": "^1.1", "pear/console_table": "^1.3", "brenard/php-unidecode": "dev-master", + "smarty/smarty": "3.1.34", "smarty-gettext/smarty-gettext": "^1.6", "smarty-gettext/tsmarty2c": "^0.2.1", - "sepia/po-parser": "^6.0" + "sepia/po-parser": "^6.0", + "sentry/sdk": "^3.3" }, "require-dev": { - "overtrue/phplint": "^3.0" + "phpstan/phpstan": "^1.9" } } diff --git a/composer.lock b/composer.lock index 067d857..71da389 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "996b970dc0d35f8d9dc7a0dbcbb1c55b", + "content-hash": "d528bc17185d97252de5ee65c0489059", "packages": [ { "name": "brenard/php-unidecode", @@ -35,6 +35,72 @@ "homepage": "https://gitlab.easter-eggs.com/brenard/php-unidecode", "time": "2021-07-27T10:40:43+00:00" }, + { + "name": "clue/stream-filter", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/clue/stream-filter.git", + "reference": "d6169430c7731d8509da7aecd0af756a5747b78e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/stream-filter/zipball/d6169430c7731d8509da7aecd0af756a5747b78e", + "reference": "d6169430c7731d8509da7aecd0af756a5747b78e", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "Clue\\StreamFilter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + } + ], + "description": "A simple and modern approach to stream filtering in PHP", + "homepage": "https://github.com/clue/php-stream-filter", + "keywords": [ + "bucket brigade", + "callback", + "filter", + "php_user_filter", + "stream", + "stream_filter_append", + "stream_filter_register" + ], + "support": { + "issues": "https://github.com/clue/stream-filter/issues", + "source": "https://github.com/clue/stream-filter/tree/v1.6.0" + }, + "funding": [ + { + "url": "https://clue.engineering/support", + "type": "custom" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2022-02-21T13:15:14+00:00" + }, { "name": "envms/fluentpdo", "version": "v1.1.3", @@ -133,6 +199,326 @@ }, "time": "2016-08-24T22:08:24+00:00" }, + { + "name": "guzzlehttp/promises", + "version": "1.5.2", + "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" + }, + "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": "2.4.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "67c26b443f348a51926030c83481b85718457d3d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/67c26b443f348a51926030c83481b85718457d3d", + "reference": "67c26b443f348a51926030c83481b85718457d3d", + "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" + }, + "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/2.4.3" + }, + "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": "2022-10-26T14:07:24+00:00" + }, + { + "name": "http-interop/http-factory-guzzle", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/http-interop/http-factory-guzzle.git", + "reference": "8f06e92b95405216b237521cc64c804dd44c4a81" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/http-interop/http-factory-guzzle/zipball/8f06e92b95405216b237521cc64c804dd44c4a81", + "reference": "8f06e92b95405216b237521cc64c804dd44c4a81", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^1.7||^2.0", + "php": ">=7.3", + "psr/http-factory": "^1.0" + }, + "provide": { + "psr/http-factory-implementation": "^1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^9.5" + }, + "suggest": { + "guzzlehttp/psr7": "Includes an HTTP factory starting in version 2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Http\\Factory\\Guzzle\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "An HTTP Factory using Guzzle PSR7", + "keywords": [ + "factory", + "http", + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/http-interop/http-factory-guzzle/issues", + "source": "https://github.com/http-interop/http-factory-guzzle/tree/1.2.0" + }, + "time": "2021-07-21T13:50:14+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0.0", + "php": "^7.1|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.17", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^0.12.66", + "phpunit/phpunit": "^7.5|^8.5|^9.4", + "vimeo/psalm": "^4.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" + }, + "time": "2021-10-08T21:21:46+00:00" + }, { "name": "pear/console_table", "version": "v1.3.1", @@ -192,6 +578,395 @@ }, "time": "2018-01-25T20:47:17+00:00" }, + { + "name": "php-http/client-common", + "version": "2.6.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/client-common.git", + "reference": "45db684cd4e186dcdc2b9c06b22970fe123796c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/client-common/zipball/45db684cd4e186dcdc2b9c06b22970fe123796c0", + "reference": "45db684cd4e186dcdc2b9c06b22970fe123796c0", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "php-http/httplug": "^2.0", + "php-http/message": "^1.6", + "php-http/message-factory": "^1.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "symfony/options-resolver": "~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0 || ^6.0", + "symfony/polyfill-php80": "^1.17" + }, + "require-dev": { + "doctrine/instantiator": "^1.1", + "guzzlehttp/psr7": "^1.4", + "nyholm/psr7": "^1.2", + "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", + "phpspec/prophecy": "^1.10.2", + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.3" + }, + "suggest": { + "ext-json": "To detect JSON responses with the ContentTypePlugin", + "ext-libxml": "To detect XML responses with the ContentTypePlugin", + "php-http/cache-plugin": "PSR-6 Cache plugin", + "php-http/logger-plugin": "PSR-3 Logger plugin", + "php-http/stopwatch-plugin": "Symfony Stopwatch plugin" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Client\\Common\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Common HTTP Client implementations and tools for HTTPlug", + "homepage": "http://httplug.io", + "keywords": [ + "client", + "common", + "http", + "httplug" + ], + "support": { + "issues": "https://github.com/php-http/client-common/issues", + "source": "https://github.com/php-http/client-common/tree/2.6.0" + }, + "time": "2022-09-29T09:59:43+00:00" + }, + { + "name": "php-http/discovery", + "version": "1.14.3", + "source": { + "type": "git", + "url": "https://github.com/php-http/discovery.git", + "reference": "31d8ee46d0215108df16a8527c7438e96a4d7735" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/discovery/zipball/31d8ee46d0215108df16a8527c7438e96a4d7735", + "reference": "31d8ee46d0215108df16a8527c7438e96a4d7735", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "nyholm/psr7": "<1.0" + }, + "require-dev": { + "graham-campbell/phpspec-skip-example-extension": "^5.0", + "php-http/httplug": "^1.0 || ^2.0", + "php-http/message-factory": "^1.0", + "phpspec/phpspec": "^5.1 || ^6.1" + }, + "suggest": { + "php-http/message": "Allow to use Guzzle, Diactoros or Slim Framework factories" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Discovery\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Finds installed HTTPlug implementations and PSR-7 message factories", + "homepage": "http://php-http.org", + "keywords": [ + "adapter", + "client", + "discovery", + "factory", + "http", + "message", + "psr7" + ], + "support": { + "issues": "https://github.com/php-http/discovery/issues", + "source": "https://github.com/php-http/discovery/tree/1.14.3" + }, + "time": "2022-07-11T14:04:40+00:00" + }, + { + "name": "php-http/httplug", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/httplug.git", + "reference": "f640739f80dfa1152533976e3c112477f69274eb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/httplug/zipball/f640739f80dfa1152533976e3c112477f69274eb", + "reference": "f640739f80dfa1152533976e3c112477f69274eb", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "php-http/promise": "^1.1", + "psr/http-client": "^1.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "friends-of-phpspec/phpspec-code-coverage": "^4.1", + "phpspec/phpspec": "^5.1 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eric GELOEN", + "email": "geloen.eric@gmail.com" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "HTTPlug, the HTTP client abstraction for PHP", + "homepage": "http://httplug.io", + "keywords": [ + "client", + "http" + ], + "support": { + "issues": "https://github.com/php-http/httplug/issues", + "source": "https://github.com/php-http/httplug/tree/2.3.0" + }, + "time": "2022-02-21T09:52:22+00:00" + }, + { + "name": "php-http/message", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/message.git", + "reference": "7886e647a30a966a1a8d1dad1845b71ca8678361" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/message/zipball/7886e647a30a966a1a8d1dad1845b71ca8678361", + "reference": "7886e647a30a966a1a8d1dad1845b71ca8678361", + "shasum": "" + }, + "require": { + "clue/stream-filter": "^1.5", + "php": "^7.1 || ^8.0", + "php-http/message-factory": "^1.0.2", + "psr/http-message": "^1.0" + }, + "provide": { + "php-http/message-factory-implementation": "1.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.6", + "ext-zlib": "*", + "guzzlehttp/psr7": "^1.0", + "laminas/laminas-diactoros": "^2.0", + "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", + "slim/slim": "^3.0" + }, + "suggest": { + "ext-zlib": "Used with compressor/decompressor streams", + "guzzlehttp/psr7": "Used with Guzzle PSR-7 Factories", + "laminas/laminas-diactoros": "Used with Diactoros Factories", + "slim/slim": "Used with Slim Framework PSR-7 implementation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "files": [ + "src/filters.php" + ], + "psr-4": { + "Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "HTTP Message related tools", + "homepage": "http://php-http.org", + "keywords": [ + "http", + "message", + "psr-7" + ], + "support": { + "issues": "https://github.com/php-http/message/issues", + "source": "https://github.com/php-http/message/tree/1.13.0" + }, + "time": "2022-02-11T13:41:14+00:00" + }, + { + "name": "php-http/message-factory", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-http/message-factory.git", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Factory interfaces for PSR-7 HTTP Message", + "homepage": "http://php-http.org", + "keywords": [ + "factory", + "http", + "message", + "stream", + "uri" + ], + "support": { + "issues": "https://github.com/php-http/message-factory/issues", + "source": "https://github.com/php-http/message-factory/tree/master" + }, + "time": "2015-12-19T14:08:53+00:00" + }, + { + "name": "php-http/promise", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/promise.git", + "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/promise/zipball/4c4c1f9b7289a2ec57cde7f1e9762a5789506f88", + "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "friends-of-phpspec/phpspec-code-coverage": "^4.3.2", + "phpspec/phpspec": "^5.1.2 || ^6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joel Wurtz", + "email": "joel.wurtz@gmail.com" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Promise used for asynchronous HTTP requests", + "homepage": "http://httplug.io", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/php-http/promise/issues", + "source": "https://github.com/php-http/promise/tree/1.1.0" + }, + "time": "2020-07-07T09:29:14+00:00" + }, { "name": "psr/container", "version": "1.1.2", @@ -240,6 +1015,421 @@ }, "time": "2021-11-05T16:50:12+00:00" }, + { + "name": "psr/http-client", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "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": "http://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-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "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": "http://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": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "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": "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": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+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": "sentry/sdk", + "version": "3.3.0", + "source": { + "type": "git", + "url": "https://github.com/getsentry/sentry-php-sdk.git", + "reference": "d0678fc7274dbb03046ed05cb24eb92945bedf8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getsentry/sentry-php-sdk/zipball/d0678fc7274dbb03046ed05cb24eb92945bedf8e", + "reference": "d0678fc7274dbb03046ed05cb24eb92945bedf8e", + "shasum": "" + }, + "require": { + "http-interop/http-factory-guzzle": "^1.0", + "sentry/sentry": "^3.9", + "symfony/http-client": "^4.3|^5.0|^6.0" + }, + "type": "metapackage", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sentry", + "email": "accounts@sentry.io" + } + ], + "description": "This is a metapackage shipping sentry/sentry with a recommended HTTP client.", + "homepage": "http://sentry.io", + "keywords": [ + "crash-reporting", + "crash-reports", + "error-handler", + "error-monitoring", + "log", + "logging", + "sentry" + ], + "support": { + "issues": "https://github.com/getsentry/sentry-php-sdk/issues", + "source": "https://github.com/getsentry/sentry-php-sdk/tree/3.3.0" + }, + "funding": [ + { + "url": "https://sentry.io/", + "type": "custom" + }, + { + "url": "https://sentry.io/pricing/", + "type": "custom" + } + ], + "time": "2022-10-11T09:05:00+00:00" + }, + { + "name": "sentry/sentry", + "version": "3.12.1", + "source": { + "type": "git", + "url": "https://github.com/getsentry/sentry-php.git", + "reference": "155bb9b78438999de4529d6f051465be15a58bc5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/155bb9b78438999de4529d6f051465be15a58bc5", + "reference": "155bb9b78438999de4529d6f051465be15a58bc5", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "guzzlehttp/promises": "^1.4", + "guzzlehttp/psr7": "^1.8.4|^2.1.1", + "jean85/pretty-package-versions": "^1.5|^2.0.4", + "php": "^7.2|^8.0", + "php-http/async-client-implementation": "^1.0", + "php-http/client-common": "^1.5|^2.0", + "php-http/discovery": "^1.11", + "php-http/httplug": "^1.1|^2.0", + "php-http/message": "^1.5", + "psr/http-factory": "^1.0", + "psr/http-message-implementation": "^1.0", + "psr/log": "^1.0|^2.0|^3.0", + "symfony/options-resolver": "^3.4.43|^4.4.30|^5.0.11|^6.0", + "symfony/polyfill-php80": "^1.17" + }, + "conflict": { + "php-http/client-common": "1.8.0", + "raven/raven": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.19|3.4.*", + "http-interop/http-factory-guzzle": "^1.0", + "monolog/monolog": "^1.6|^2.0|^3.0", + "nikic/php-parser": "^4.10.3", + "php-http/mock-client": "^1.3", + "phpbench/phpbench": "^1.0", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^8.5.14|^9.4", + "symfony/phpunit-bridge": "^5.2|^6.0", + "vimeo/psalm": "^4.17" + }, + "suggest": { + "monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.12.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Sentry\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sentry", + "email": "accounts@sentry.io" + } + ], + "description": "A PHP SDK for Sentry (http://sentry.io)", + "homepage": "http://sentry.io", + "keywords": [ + "crash-reporting", + "crash-reports", + "error-handler", + "error-monitoring", + "log", + "logging", + "sentry" + ], + "support": { + "issues": "https://github.com/getsentry/sentry-php/issues", + "source": "https://github.com/getsentry/sentry-php/tree/3.12.1" + }, + "funding": [ + { + "url": "https://sentry.io/", + "type": "custom" + }, + { + "url": "https://sentry.io/pricing/", + "type": "custom" + } + ], + "time": "2023-01-12T12:24:27+00:00" + }, { "name": "sepia/po-parser", "version": "6.0.1", @@ -296,34 +1486,31 @@ }, { "name": "smarty-gettext/smarty-gettext", - "version": "1.6.2", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/smarty-gettext/smarty-gettext.git", - "reference": "22e5b91b642cd643f9acdd8d04ab0e05647b98a7" + "reference": "64f0e167f5a021358f9e1e4aaa4b5a1283b71e60" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/smarty-gettext/smarty-gettext/zipball/22e5b91b642cd643f9acdd8d04ab0e05647b98a7", - "reference": "22e5b91b642cd643f9acdd8d04ab0e05647b98a7", + "url": "https://api.github.com/repos/smarty-gettext/smarty-gettext/zipball/64f0e167f5a021358f9e1e4aaa4b5a1283b71e60", + "reference": "64f0e167f5a021358f9e1e4aaa4b5a1283b71e60", "shasum": "" }, "require": { "ext-gettext": "*", "ext-pcre": "*", - "php": "~5.3|~7.0|~8.0" + "php": ">=5.3" }, "require-dev": { "azatoth/php-pgettext": "~1.0", - "phpunit/phpunit": ">=4.8.36", + "phpunit/phpunit": "^4.8.36", "smarty/smarty": "3.1.*" }, "suggest": { "azatoth/php-pgettext": "Support msgctxt for {t} via context parameter" }, - "bin": [ - "tsmarty2c.php" - ], "type": "library", "autoload": { "files": [ @@ -342,16 +1529,16 @@ }, { "name": "Elan Ruusamäe", - "email": "glen@delfi.ee" + "email": "glen@pld-linux.org" } ], "description": "Gettext plugin enabling internationalization in Smarty Package files", "homepage": "https://github.com/smarty-gettext/smarty-gettext", "support": { "issues": "https://github.com/smarty-gettext/smarty-gettext/issues", - "source": "https://github.com/smarty-gettext/smarty-gettext/tree/1.6.2" + "source": "https://github.com/smarty-gettext/smarty-gettext/tree/1.7.0" }, - "time": "2021-02-23T22:00:29+00:00" + "time": "2023-01-15T13:14:50+00:00" }, { "name": "smarty-gettext/tsmarty2c", @@ -470,16 +1657,16 @@ }, { "name": "symfony/console", - "version": "v5.4.7", + "version": "v5.4.19", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "900275254f0a1a2afff1ab0e11abd5587a10e1d6" + "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/900275254f0a1a2afff1ab0e11abd5587a10e1d6", - "reference": "900275254f0a1a2afff1ab0e11abd5587a10e1d6", + "url": "https://api.github.com/repos/symfony/console/zipball/dccb8d251a9017d5994c988b034d3e18aaabf740", + "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740", "shasum": "" }, "require": { @@ -549,7 +1736,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.7" + "source": "https://github.com/symfony/console/tree/v5.4.19" }, "funding": [ { @@ -565,11 +1752,11 @@ "type": "tidelift" } ], - "time": "2022-03-31T17:09:19+00:00" + "time": "2023-01-01T08:32:19+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -616,7 +1803,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" }, "funding": [ { @@ -636,16 +1823,16 @@ }, { "name": "symfony/finder", - "version": "v5.4.3", + "version": "v5.4.19", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d" + "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/231313534dded84c7ecaa79d14bc5da4ccb69b7d", - "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d", + "url": "https://api.github.com/repos/symfony/finder/zipball/6071aebf810ad13fe8200c224f36103abb37cf1f", + "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f", "shasum": "" }, "require": { @@ -679,7 +1866,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.3" + "source": "https://github.com/symfony/finder/tree/v5.4.19" }, "funding": [ { @@ -695,20 +1882,254 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:34:36+00:00" + "time": "2023-01-14T19:14:44+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.25.0", + "name": "symfony/http-client", + "version": "v5.4.19", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "url": "https://github.com/symfony/http-client.git", + "reference": "0c22562d0601e19bd01c4480893f5438e6b12db5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/http-client/zipball/0c22562d0601e19bd01c4480893f5438e6b12db5", + "reference": "0c22562d0601e19bd01c4480893f5438e6b12db5", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/http-client-contracts": "^2.4", + "symfony/polyfill-php73": "^1.11", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.0|^2|^3" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "2.4" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4.13|^5.1.5|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-client/tree/v5.4.19" + }, + "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": "2023-01-12T15:47:53+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "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": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + }, + "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": "2022-04-12T15:48:08+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v5.4.19", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "b03c99236445492f20c61666e8f7e5d388b078e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b03c99236445492f20c61666e8f7e5d388b078e5", + "reference": "b03c99236445492f20c61666e8f7e5d388b078e5", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php73": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v5.4.19" + }, + "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": "2023-01-01T08:32:19+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "shasum": "" }, "require": { @@ -723,7 +2144,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -761,7 +2182,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" }, "funding": [ { @@ -777,20 +2198,20 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.25.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + "reference": "511a08c03c1960e08a883f4cffcacd219b758354" }, "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/511a08c03c1960e08a883f4cffcacd219b758354", + "reference": "511a08c03c1960e08a883f4cffcacd219b758354", "shasum": "" }, "require": { @@ -802,7 +2223,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -842,7 +2263,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" }, "funding": [ { @@ -858,20 +2279,20 @@ "type": "tidelift" } ], - "time": "2021-11-23T21:10:46+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.25.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" }, "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/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", "shasum": "" }, "require": { @@ -883,7 +2304,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -926,7 +2347,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" }, "funding": [ { @@ -942,20 +2363,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.25.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" }, "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/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "shasum": "" }, "require": { @@ -970,7 +2391,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1009,7 +2430,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" }, "funding": [ { @@ -1025,20 +2446,20 @@ "type": "tidelift" } ], - "time": "2021-11-30T18:21:41+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.25.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", "shasum": "" }, "require": { @@ -1047,7 +2468,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1088,7 +2509,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" }, "funding": [ { @@ -1104,20 +2525,20 @@ "type": "tidelift" } ], - "time": "2021-06-05T21:20:04+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.25.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "shasum": "" }, "require": { @@ -1126,7 +2547,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1171,7 +2592,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" }, "funding": [ { @@ -1187,20 +2608,20 @@ "type": "tidelift" } ], - "time": "2022-03-04T08:16:47+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c" + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/24d9dc654b83e91aa59f9d167b131bc3b5bea24c", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", "shasum": "" }, "require": { @@ -1254,7 +2675,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" }, "funding": [ { @@ -1270,20 +2691,20 @@ "type": "tidelift" } ], - "time": "2022-03-13T20:07:29+00:00" + "time": "2022-05-30T19:17:29+00:00" }, { "name": "symfony/string", - "version": "v5.4.3", + "version": "v5.4.19", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10" + "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/92043b7d8383e48104e411bc9434b260dbeb5a10", - "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10", + "url": "https://api.github.com/repos/symfony/string/zipball/0a01071610fd861cc160dfb7e2682ceec66064cb", + "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb", "shasum": "" }, "require": { @@ -1340,7 +2761,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.3" + "source": "https://github.com/symfony/string/tree/v5.4.19" }, "funding": [ { @@ -1356,262 +2777,68 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2023-01-01T08:32:19+00:00" } ], "packages-dev": [ { - "name": "n98/junit-xml", - "version": "1.1.0", + "name": "phpstan/phpstan", + "version": "1.9.14", "source": { "type": "git", - "url": "https://github.com/cmuench/junit-xml.git", - "reference": "0017dd92ac8cb619f02e32f4cffd768cfe327c73" + "url": "https://github.com/phpstan/phpstan.git", + "reference": "e5fcc96289cf737304286a9b505fbed091f02e58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cmuench/junit-xml/zipball/0017dd92ac8cb619f02e32f4cffd768cfe327c73", - "reference": "0017dd92ac8cb619f02e32f4cffd768cfe327c73", - "shasum": "" - }, - "require-dev": { - "phpunit/phpunit": "^9.5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "N98\\JUnitXml\\": "src/N98/JUnitXml" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Münch", - "email": "c.muench@netz98.de" - } - ], - "description": "JUnit XML Document generation library", - "support": { - "issues": "https://github.com/cmuench/junit-xml/issues", - "source": "https://github.com/cmuench/junit-xml/tree/1.1.0" - }, - "time": "2020-12-25T09:08:58+00:00" - }, - { - "name": "overtrue/phplint", - "version": "3.0.6", - "source": { - "type": "git", - "url": "https://github.com/overtrue/phplint.git", - "reference": "b4212c2c65bf50f6c823ab8e7c13c9ead9433241" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/overtrue/phplint/zipball/b4212c2c65bf50f6c823ab8e7c13c9ead9433241", - "reference": "b4212c2c65bf50f6c823ab8e7c13c9ead9433241", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5fcc96289cf737304286a9b505fbed091f02e58", + "reference": "e5fcc96289cf737304286a9b505fbed091f02e58", "shasum": "" }, "require": { - "ext-json": "*", - "n98/junit-xml": "1.1.0", - "php": ">=5.5.9", - "symfony/console": "^3.2|^4.0|^5.0", - "symfony/finder": "^3.0|^4.0|^5.0", - "symfony/process": "^3.3|^4.0|^5.0", - "symfony/yaml": "^3.0|^4.0|^5.0" - }, - "require-dev": { - "brainmaestro/composer-git-hooks": "^2.7", - "friendsofphp/php-cs-fixer": "^2.16", - "jakub-onderka/php-console-highlighter": "^0.3.2 || ^0.4" - }, - "bin": [ - "bin/phplint" - ], - "type": "library", - "extra": { - "hooks": { - "pre-commit": [ - "composer fix-style" - ], - "pre-push": [ - "composer check-style" - ] - } - }, - "autoload": { - "psr-4": { - "Overtrue\\PHPLint\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "overtrue", - "email": "anzhengchao@gmail.com" - } - ], - "description": "`phplint` is a tool that can speed up linting of php files by running several lint processes at once.", - "keywords": [ - "check", - "lint", - "phplint", - "syntax" - ], - "support": { - "issues": "https://github.com/overtrue/phplint/issues", - "source": "https://github.com/overtrue/phplint/tree/3.0.6" - }, - "funding": [ - { - "url": "https://github.com/overtrue", - "type": "github" - } - ], - "time": "2021-11-30T15:45:02+00:00" - }, - { - "name": "symfony/process", - "version": "v5.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "38a44b2517b470a436e1c944bf9b9ba3961137fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/38a44b2517b470a436e1c944bf9b9ba3961137fb", - "reference": "38a44b2517b470a436e1c944bf9b9ba3961137fb", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.16" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Executes commands in sub-processes", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/process/tree/v5.4.7" - }, - "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": "2022-03-18T16:18:52+00:00" - }, - { - "name": "symfony/yaml", - "version": "v5.4.3", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "e80f87d2c9495966768310fc531b487ce64237a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e80f87d2c9495966768310fc531b487ce64237a2", - "reference": "e80f87d2c9495966768310fc531b487ce64237a2", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-ctype": "^1.8" + "php": "^7.2|^8.0" }, "conflict": { - "symfony/console": "<5.3" - }, - "require-dev": { - "symfony/console": "^5.3|^6.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" + "phpstan/phpstan-shim": "*" }, "bin": [ - "Resources/bin/yaml-lint" + "phpstan", + "phpstan.phar" ], "type": "library", "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" + "files": [ + "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" ], - "description": "Loads and dumps YAML files", - "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.3" + "issues": "https://github.com/phpstan/phpstan/issues", + "source": "https://github.com/phpstan/phpstan/tree/1.9.14" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/ondrejmirtes", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", "type": "tidelift" } ], - "time": "2022-01-26T16:32:32+00:00" + "time": "2023-01-19T10:47:09+00:00" } ], "aliases": [], @@ -1623,5 +2850,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.0.0" } diff --git a/docs/config.md b/docs/config.md index a018439..5dd4328 100644 --- a/docs/config.md +++ b/docs/config.md @@ -49,3 +49,11 @@ Some other variables exist to manage the email sending by the application : - `$mail_headers` : an PHP array of default headers add to mail sent by the application - `$mail_sender` : the email address of the sender of all emails sent by the application - `$mail_catch_all` : for debugging purpose, you can using this variable to specify an email address that will received all email sent by the application in place of the original recipient + +## Web stats JS code inclusion + +If you use a Web stats tool that need to include a piece of JS code in all page like [Matomo](https://matomo.org/), you could defined the `$webstats_js_code` variable. + +## Sentry integration + +If you want to enable the [Sentry](https://sentry.io) integration, you have to define the `$sentry_dsn`. This integration permit to report PHP errors (see `$sentry_php_error_types`) and exception as issues and to monitor performance of the application (see `$sentry_traces_sample_rate`). diff --git a/docs/install.md b/docs/install.md index e129f47..36f46d3 100644 --- a/docs/install.md +++ b/docs/install.md @@ -5,7 +5,7 @@ Some Debian packages have to be installed : ```bash -apt install git composer php-cli php-mail php-mail-mine php-net-smtp php-auth-sasl php-json php-mbstring php-intl smarty3 +apt install git composer php-cli php-mail php-mail-mine php-net-smtp php-auth-sasl php-json php-mbstring php-intl # for PostgreSQL DB backend apt install php-pgsql # for MySQL/MariaDB DB backend diff --git a/includes/cli.php b/includes/cli.php index 2968639..8ada725 100644 --- a/includes/cli.php +++ b/includes/cli.php @@ -5,7 +5,7 @@ function add_cli_command($command, $handler, $short_desc, $usage_args=false, $lo $override=false) { global $cli_commands; if (array_key_exists($command, $cli_commands) && !$override) { - logging('ERROR', _("The CLI command '%s' already exists.", $command)); + logging('ERROR', _("The CLI command '%s' already exists."), $command); return False; } @@ -331,10 +331,10 @@ function cli_restore($command_args) { $fd = fopen((count($command_args) >= 1?$command_args[0]:'php://stdin'), 'r'); restore_items($fd); fclose($fd); - logging('INFO', sprint( - "Items restored from '%s'", + logging( + 'INFO', "Items restored from '%s'", (count($command_args) >= 1?$command_args[0]:'STDIN') - )); + ); } add_cli_command( 'restore', @@ -389,7 +389,6 @@ function cli_cron($command_args) { logging('INFO', 'Item #%s (%s) deleted (creation date: %s)', $item['id'], $item['name'], format_time($item['date']) ); - remove_item_attachments($item['id']); } else { logging('ERROR', 'Fail to delete item "%s" (%s, creation date: %s)', @@ -416,3 +415,5 @@ add_cli_command( ___("-m/--max-age Item expiration limit (in days, optional)"), ) ); + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/config.inc.php b/includes/config.inc.php index 96ef4ce..50cffb0 100644 --- a/includes/config.inc.php +++ b/includes/config.inc.php @@ -35,8 +35,39 @@ $log_level = 'INFO'; // Debug Ajax request/response $debug_ajax = false; -// Smarty class path -$smarty_path = 'smarty3/Smarty.class.php'; +// Log PHP errors levels (as specified to set_error_handler()) +// Default: +// - In TRACE or DEBUG: E_ALL & ~E_STRICT +// - Otherwise: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +// $log_php_errors_levels = E_ALL & ~E_STRICT; + +/* + * Sentry configuration + */ + +// Sentry DSN +$sentry_dsn = null; + +// Log PHP errors in Sentry: list of errors types to logs +// Note: must also match with $log_php_errors_levels. +// See: https://www.php.net/manual/fr/errorfunc.constants.php +$sentry_php_error_types = array( + E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, + E_RECOVERABLE_ERROR,E_DEPRECATED, +); + +// Traces sample rate (between 0 and 1) +// Note: this parameter permit to determine how many transactions (=~ access) are traced and +// sent to Sentry, for instance, 0.2 meen that 20% of the transactions will be traced. In dev +// mode, set to 1 if you want all transactions are sent to Sentry. +// Default: 0.2 +$sentry_traces_sample_rate = 0.2; + +/* + * Smarty template configuration + */ + +// Smarty directories $smarty_templates_dir = "$root_dir_path/templates"; $smarty_templates_c_dir = "$tmp_root_dir/templates_c"; @@ -116,7 +147,9 @@ $mail_sender = "noreply@example.org"; // Catch all e-mails sent to a configured e-mail address $mail_catch_all = false; -// Load local configuration file is present -if (is_file("$root_dir_path/includes/config.local.php")) { - require "$root_dir_path/includes/config.local.php"; -} +/** + * Web Stats JS code + */ +$webstats_js_code = ''; + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/core.php b/includes/core.php index 2b8008b..b0c77df 100644 --- a/includes/core.php +++ b/includes/core.php @@ -3,7 +3,8 @@ error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED); // Root directory path -if (__FILE__ != "") { +$script = null; +if (defined('__FILE__') && constant('__FILE__')) { $script = __FILE__; } else { @@ -12,7 +13,8 @@ else { if (basename($script) == 'core.php') break; } -$root_dir_path=realpath(dirname($script).'/../'); +if (!$script) die('Fail to detect root directory path'); +$root_dir_path = realpath(dirname($script).'/../'); // Include App's includes and vendor directories to PHP include paths set_include_path($root_dir_path.'/includes' . PATH_SEPARATOR . get_include_path()); @@ -27,13 +29,19 @@ $api_mode = false; require_once('translation.php'); require_once('config.inc.php'); -// Check $public_root_url end -if (substr($public_root_url, -1)=='/') { - $public_root_url=substr($public_root_url, 0, -1); +// Load local configuration file is present +if (is_file("$root_dir_path/includes/config.local.php")) { + require "$root_dir_path/includes/config.local.php"; } +require_once 'sentry.php'; +$sentry_transaction = new SentryTransaction(); + +$sentry_span = new SentrySpan('core.init', 'Core initialization'); + // Define upload_tmp_dir -ini_set('upload_tmp_dir',$upload_tmp_dir); +if (isset($upload_tmp_dir)) + ini_set('upload_tmp_dir', $upload_tmp_dir); require_once('logging.php'); require_once('functions.php'); @@ -60,3 +68,6 @@ require_once('mail.php'); init_translation(); foreach($status_list as $key => $value) $status_list[$key] = _($value); +$sentry_span->finish(); + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/db.php b/includes/db.php index 5fa3d6a..621e199 100644 --- a/includes/db.php +++ b/includes/db.php @@ -2,8 +2,18 @@ use Unidecode\Unidecode; +if (!isset($db_dsn)) { + logging('FATAL', 'Database DSN not configured'); + exit(1); +} + try { - $pdo = new PDO($db_dsn, $db_user, $db_pwd, $db_options); + $pdo = new PDO( + $db_dsn, + isset($db_user)?$db_user:null, + isset($db_pwd)?$db_pwd:null, + isset($db_options)?$db_options:null + ); $pdo -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $fpdo = new FluentPDO($pdo); @@ -266,18 +276,18 @@ function search_items($params) { $orderby="$order $order_direction"; $limit = ""; + $page = 1; + $nb_by_page = 10; $offset = 0; if (!isset($params['all'])) { - $page=1; - $nb_by_page=10; if (isset($params['page']) && $params['page']>0) { if (isset($params['nb_by_page']) && $params['nb_by_page']>0) { - $nb_by_page=intval($params['nb_by_page']); + $nb_by_page = intval($params['nb_by_page']); } - $page=intval($params['page']); + $page = intval($params['page']); } - $offset=($page-1)*$nb_by_page; - $limit=$nb_by_page; + $offset = ($page-1)*$nb_by_page; + $limit = $nb_by_page; } try { @@ -297,60 +307,57 @@ function search_items($params) { -> offset($offset) -> execute(); - if ($result !== false) { - $rows = $result -> fetchAll(); - $items = array(); - foreach ($rows as $row) { - $items[] = _format_row_info($row, array('date')); - } - if (is_array($items)) { - if (empty($limit)) { - return array( - 'count' => count($items), - 'first' => 1, - 'last' => count($items), - 'nb_pages' => 1, - 'page' => 1, - 'items' => $items - ); - } - else { - $query_count = $fpdo -> from('item') - -> select(null) - -> select('count(*) as count'); - if (!empty($where)) - $query_count -> where($where); - foreach ($patterns_where as $patterns_word) - call_user_func_array( - array($query_count, 'where'), - array_merge( - array('('.implode(' OR ', array_keys($patterns_word)).')'), - array_values($patterns_word) - ) - ); - - $result_count = $query_count -> execute(); - - if ($result_count === false) { - logging('DEBUG', 'search_items() : search for count in DB return false'); - return False; - } - $count = $result_count -> fetch(); - return array( - 'count' => $count['count'], - 'first' => $offset+1, - 'last' => ( - $offset+$nb_by_page<$count['count']? - $offset+$nb_by_page:$count['count']), - 'nb_pages' => ceil($count['count']/$nb_by_page), - 'page' => $page, - 'items' => $items, - ); - } - } - } - else + if ($result === false) { logging('ERROR', 'search_items() : search in DB return false'); + return false; + } + + $rows = $result -> fetchAll(); + $items = array(); + foreach ($rows as $row) { + $items[] = _format_row_info($row, array('date')); + } + if (isset($params['all'])) { + return array( + 'count' => count($items), + 'first' => 1, + 'last' => count($items), + 'nb_pages' => 1, + 'page' => 1, + 'items' => $items + ); + } + $query_count = $fpdo -> from('item') + -> select(null) + -> select('count(*) as count'); + if (!empty($where)) + $query_count -> where($where); + foreach ($patterns_where as $patterns_word) + call_user_func_array( + array($query_count, 'where'), + array_merge( + array('('.implode(' OR ', array_keys($patterns_word)).')'), + array_values($patterns_word) + ) + ); + + $result_count = $query_count -> execute(); + + if ($result_count === false) { + logging('DEBUG', 'search_items() : search for count in DB return false'); + return False; + } + $count = $result_count -> fetch(); + return array( + 'count' => $count['count'], + 'first' => $offset+1, + 'last' => ( + $offset+$nb_by_page<$count['count']? + $offset+$nb_by_page:$count['count']), + 'nb_pages' => ceil($count['count']/$nb_by_page), + 'page' => $page, + 'items' => $items, + ); } catch (Exception $e) { log_exception( @@ -461,3 +468,5 @@ function restore_items($fd=null) { return !$error; } + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/functions.php b/includes/functions.php index 6796eae..1056df1 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -232,6 +232,25 @@ function vardump($data) { return $data; } +/** + * Format a callable object for logging + * @param string|array $callable The callable object + * @return string The callable object string representation + */ +function format_callable($callable) { + if (is_string($callable)) + return $callable."()"; + if (is_array($callable)) + if (is_string($callable[0])) + return $callable[0]."::".$callable[1]."()"; + elseif (is_object($callable[0])) + return get_class($callable[0])."->".$callable[1]."()"; + else + return "Unkown->".$callable[1]."()"; + // @phpstan-ignore-next-line + return vardump($callable); +} + function check_is_empty($val) { switch(gettype($val)) { case "boolean": @@ -322,7 +341,7 @@ function delete_directory($dir, $recursive=true) { * error **/ function run_external_command($command, $data_stdin=null, $escape_command_args=true) { - if (array($command)) + if (is_array($command)) $command = implode(' ', $command); if ($escape_command_args) $command = escapeshellcmd($command); @@ -365,3 +384,5 @@ function run_external_command($command, $data_stdin=null, $escape_command_args=t return array($return_value, $stdout, $stderr); } + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/hooks.php b/includes/hooks.php index 6d202ff..1ac062c 100644 --- a/includes/hooks.php +++ b/includes/hooks.php @@ -25,7 +25,7 @@ function register_hook($event, $callable, $param=NULL) { /** * Run triggered actions on specific event * - * @param $event string Event name + * @param $event string HookEvent name * * @return boolean True if all triggered actions succefully runned, false otherwise */ @@ -35,16 +35,16 @@ function trigger_hook($event_name, $event_data=null) { if (isset($hooks[$event_name]) && is_array($hooks[$event_name])) { if ($event_name == 'all') - $event = new Event($event_data['event_name'], $event_data['event_data']); + $event = new HookEvent($event_data['event_name'], $event_data['event_data']); else - $event = new Event($event_name, $event_data); + $event = new HookEvent($event_name, $event_data); foreach ($hooks[$event_name] as $e) { if (is_callable($e['callable'])) { try { call_user_func_array($e['callable'],array($event, &$e['param'])); } catch(Exception $e) { - logException( + log_exception( $e, "An exception occured running hook ".format_callable($e['callable']). " on event $event_name"); $return = false; @@ -75,7 +75,7 @@ function trigger_hook($event_name, $event_data=null) { return $return; } -class Event implements JsonSerializable { +class HookEvent implements JsonSerializable { private $name; private $data; @@ -101,3 +101,5 @@ class Event implements JsonSerializable { ); } } + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/logging.php b/includes/logging.php index ed732e8..a99c4a4 100644 --- a/includes/logging.php +++ b/includes/logging.php @@ -7,14 +7,23 @@ * * // Log level (DEBUG / INFO / WARNING / ERROR / FATAL) * $log_level='INFO'; + * + * // Log PHP errors levels (as specified to set_error_handler()) + * // $log_php_errors_levels = E_ALL & ~E_STRICT; + + * // Log PHP errors levels (as specified to set_error_handler()) + * // Default: + * // - In TRACE or DEBUG: E_ALL & ~E_STRICT + * // - Otherwise: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED + * // $log_php_errors_levels = E_ALL & ~E_STRICT; */ // Log file descriptor (Do not change !!!) -$_log_file_fd=null; +$_log_file_fd = null; // Log Levels -$_log_levels=array( +$_log_levels = array( 'TRACE' => 0, 'DEBUG' => 1, 'INFO' => 2, @@ -23,13 +32,22 @@ $_log_levels=array( 'FATAL' => 5, ); +// Custom fatal error handler +$_fatal_error_handler = null; + +/** + * Log a message + * @param string $level The message level (key of $_log_levels) + * @param string $message The message to log + * @return true + */ function logging($level, $message) { - global $log_file, $_log_file_fd, $_log_levels, $log_level, $argv, $auth_user; + global $log_file, $_log_file_fd, $_log_levels, $log_level, $argv, + $_fatal_error_handler, $auth_user; if (!array_key_exists($level, $_log_levels)) $level = 'INFO'; $level_id = $_log_levels[$level]; - if (!array_key_exists($log_level, $_log_levels)) $log_level = 'INFO'; $log_level_id = $_log_levels[$log_level]; if ($level_id < $log_level_id) return true; @@ -66,10 +84,12 @@ function logging($level, $message) { $msg = implode(' - ', $msg)."\n"; } - fwrite($_log_file_fd , $msg); + fwrite($_log_file_fd, $msg); if ($level == 'FATAL') - if (function_exists('fatal_error')) + if (!is_null($_fatal_error_handler)) + call_user_func($_fatal_error_handler, $message); + elseif (function_exists('fatal_error')) fatal_error($message); else die("\n$message\n\n"); @@ -79,6 +99,38 @@ function logging($level, $message) { return true; } +// Set default log level (if not defined or invalid) +$default_log_level = 'WARNING'; +if (!isset($log_level)) { + $log_level = $default_log_level; +} +elseif (!array_key_exists($log_level, $_log_levels)) { + $invalid_value = $log_level; + $log_level = $default_log_level; + logging( + $log_level, "Invalid log level value found in configuration (%s). ". + "Set as default (%s).", $invalid_value, $log_level); +} + +/** + * Register a contextual fatal error handler + * @param null|callable $handler The fatal error handler (set as null to reset) + * @return void + */ +function register_fatal_error_handler($handler) { + // @phpstan-ignore-next-line + if ($handler && !is_callable($handler)) + logging('FATAL', 'Fatal handler provided is not callable !'); + global $_fatal_error_handler; + $_fatal_error_handler = ($handler?$handler:null); +} + + +/** + * Change of current log file + * @param string $file The new log file path + * @return bool + */ function change_log_file($file) { global $log_file, $_log_file_fd; if ($file == $log_file) return True; @@ -90,7 +142,17 @@ function change_log_file($file) { return True; } -// Handle exception logging +/* + ******************************************************************************* + * Handle exception logging + ******************************************************************************* + */ + +/** + * Get the current backtrace + * @param int $ignore_last The number of last levels to ignore + * @return string + */ function get_debug_backtrace_context($ignore_last=0) { $traces = debug_backtrace(); @@ -105,6 +167,7 @@ function get_debug_backtrace_context($ignore_last=0) { $trace = array("#$i"); if (isset($traces[$i]['file'])) $trace[] = $traces[$i]['file'].(isset($traces[$i]['line'])?":".$traces[$i]['line']:""); + // @phpstan-ignore-next-line if (isset($traces[$i]['class']) && isset($traces[$i]['function'])) $trace[] = implode(" ", array( $traces[$i]['class'], @@ -118,7 +181,16 @@ function get_debug_backtrace_context($ignore_last=0) { return implode("\n", $msg); } +/** + * Log an exception + * @param Throwable $exception + * @param string|null $prefix The prefix of the log message + * (optional, default: "An exception occured") + * @return void + */ function log_exception($exception, $prefix=null) { + if (function_exists('log_in_sentry')) + log_in_sentry($exception); // If more than 2 arguments passed, format prefix message using sprintf if ($prefix && func_num_args() > 2) { $prefix = call_user_func_array( @@ -135,13 +207,50 @@ function log_exception($exception, $prefix=null) { } set_exception_handler('log_exception'); -// Handle PHP error logging -function log_php_eror($errno, $errstr, $errfile, $errline) { - logging("ERROR", "A PHP error occured : [%d] %s\nFile : %s (line : %d)", - $errno, $errstr, $errfile, $errline); +/* + ******************************************************************************* + * Handle PHP error logging + ******************************************************************************* + */ + +/** + * Convert PHP error number to the corresponding label + * @param int $errno + * @return string + */ +function errno2type($errno) { + $constants = get_defined_constants(); + if (is_array($constants)) + foreach($constants as $label => $value) + if ($value == $errno && preg_match('/^E_(.*)$/', $label, $m)) + return $m[1]; + return 'UNKNOWN ERROR #'.$errno; +} + +/** + * Log a PHP error + * Note: method design to be used as callable by set_error_handler() + * @param int $errno The error number + * @param string $errstr The error message + * @param string $errfile The filename that the error was raised in + * @param int $errline The line number where the error was raised + * @return false Return false to let the normal error handler continues. + */ +function log_php_error($errno, $errstr, $errfile, $errline) { + $msg = sprintf( + "A PHP error occured : [%s] %s\nFile : %s (line : %d)", + errno2type($errno), $errstr, $errfile, $errline + ); + logging("ERROR", $msg); + if (function_exists('log_php_error_in_sentry')) + log_php_error_in_sentry($errno, $msg); return False; } -if ($log_level == 'DEBUG') - set_error_handler('log_php_eror', E_ALL & ~E_STRICT); +if (isset($log_php_errors_levels)) + set_error_handler('log_php_error', $log_php_errors_levels); +elseif (in_array($log_level, array('DEBUG', 'TRACE'))) + set_error_handler('log_php_error', E_ALL & ~E_STRICT); else - set_error_handler('log_php_eror', E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED); + set_error_handler('log_php_error', E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED); + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/mail.php b/includes/mail.php index a180246..fd6c405 100644 --- a/includes/mail.php +++ b/includes/mail.php @@ -1,24 +1,72 @@ $to Email recipient(s) + * @param string $subject Email subject + * @param string $msg Email body + * @param boolean $html Set to true to send an HTML email (default: false) + * @param array|null $attachments Email attachments as an array with + * filepath as key and filename as value + * @param array|null $headers Email headers + * @param string|null $encoding Email encoding (default: utf8) + * @param string|null $eol End of line string (default : \n) + * + * @return boolean true If mail was sent, false otherwise + */ +function send_mail($from, $to, $subject, $msg, $html=false, $attachments=null, $headers=null, + $encoding=null, $eol=null) { + global $mail_send_method, $mail_headers, $mail_send_params, $mail_sender, $mail_catch_all; + $mail_obj = & Mail::factory($mail_send_method, $mail_send_params); - if ($mail_catch_all) { - $msg .= sprintf( - _("\n\n\nMail initialy intended for %s."), - (is_array($to)?implode(',', $to):$to)); - $to = $mail_catch_all; + if (!$headers) $headers = array(); + if(isset($mail_headers) && is_array($mail_headers)) { + $headers = array_merge($headers, $mail_headers); } - if(is_array($mail_headers)) { - $headers = array_merge($headers,$mail_headers); + logging( + 'TRACE', 'Mail catch all: %s', + isset($mail_catch_all) && $mail_catch_all? + vardump($mail_catch_all):'not set' + ); + if (isset($mail_catch_all) && $mail_catch_all) { + logging( + 'DEBUG', 'Mail catch to %s', + is_array($mail_catch_all)?implode(',', $mail_catch_all):$mail_catch_all + ); + $msg .= sprintf( + ( + $html? + _("

Mail initialy intended for %s.

"): + _("\n\n\nMail initialy intended for %s.") + ), + (is_array($to)?implode(',', $to):$to)); + $headers["X-Orig-To"] = $to; + $to = ( + is_array($mail_catch_all)? + implode(',', $mail_catch_all):$mail_catch_all + ); } + + if ($subject) { + $headers["Subject"] = $subject; + } + + if (isset($headers['From'])) { + if (!$from) + $from = $headers['From']; + unset($headers['From']); + } + elseif (!$from) { + $from = $mail_sender; + } + $headers["To"] = $to; $to = array ( @@ -26,33 +74,43 @@ function send_mail($from, $to, $subject, $msg, $headers=array(), $attachments=ar ); foreach(array_keys($headers) as $header) { - if(strtoupper($header) == 'BCC') { - $to['BCC'] = $headers[$header]; - } - elseif(strtoupper($header) == 'CC') { - $to['CC'] = $headers[$header]; + if(in_array(strtoupper($header), array('BCC', 'CC'))) { + if (isset($mail_catch_all) && $mail_catch_all) { + logging('DEBUG', "Mail catched: remove $header header"); + $msg .= sprintf( + ( + $html? + _("

%s: %s

"): + _("\n%s: %s") + ), + strtoupper($header), + (is_array($headers[$header])?implode(',', $headers[$header]):$headers[$header])); + unset($headers[$header]); + continue; + } + $to[strtoupper($header)] = $headers[$header]; } } + if (!$encoding) $encoding = "utf8"; $mime = new Mail_mime( array( - 'eol' => $crlf, - 'text_charset' => 'utf8', - 'head_charset' => 'utf8', + 'eol' => ($eol?$eol:"\n"), + ($html?'html_charset':'text_charset') => $encoding, + 'head_charset' => $encoding, ) ); - if ($from) { - $mime->setFrom($from); - } - elseif ($mail_sender) { - $mime->setFrom($mail_sender); - } - if ($subject) { + if ($from) + $mime->setFrom($from); + + if ($subject) $mime->setSubject($subject); - } - $mime->setTXTBody($msg); + if ($html) + $mime->setHTMLBody($msg); + else + $mime->setTXTBody($msg); if (is_array($attachments) && !empty($attachments)) { $finfo = new finfo(FILEINFO_MIME_TYPE); @@ -64,11 +122,14 @@ function send_mail($from, $to, $subject, $msg, $headers=array(), $attachments=ar $body = $mime->get(); $headers = $mime->headers($headers); - $ret = $mail_obj -> send($to,$headers,$body); + $ret = $mail_obj -> send($to, $headers, $body); - if ($ret instanceof PEAR_Error) { - logging('ERROR',"Error sending email to $to : ".$ret -> getMessage()); - return False; + if (PEAR::isError($ret)) { + $msg = "Error sending email: ".$ret -> getMessage(); + logging('ERROR', $msg); + return false; } return true; } + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/sentry.php b/includes/sentry.php new file mode 100644 index 0000000..b0c3fc6 --- /dev/null +++ b/includes/sentry.php @@ -0,0 +1,213 @@ + $sentry_dsn, + 'traces_sample_rate' => ( + isset($sentry_traces_sample_rate) ? + $sentry_traces_sample_rate : 0.2 + ), + ]); + + \Sentry\configureScope(function (\Sentry\State\Scope $scope): void { + global $auth_user; + $scope->setUser([ + 'id' => isset($auth_user) && $auth_user?$auth_user['uid']:null, + 'email' => isset($auth_user) && $auth_user?$auth_user['mail']:null, + 'segment' => isset($auth_user) && $auth_user?$auth_user['type']:null, + 'ip_address' => $_SERVER['REMOTE_ADDR'], + ]); + }); +} + +/** + * Log an exception or a message in Sentry + * @param string|Exception $msg + * @return void + */ +function log_in_sentry($msg) { + global $sentry_dsn; + if (!isset($sentry_dsn) || !$sentry_dsn) { + logging('TRACE', 'Sentry DSN not configured, do not log this error'); + return; + } + if (is_string($msg)) { + logging('DEBUG', 'Error logged in Sentry'); + \Sentry\captureMessage($msg); + } + elseif ($msg instanceof Exception) { + logging('DEBUG', 'Exception logged in Sentry'); + \Sentry\captureException($msg); + } +} + +/** + * Log a PHP error in Sentry + * @param int $errno The error number + * @param string $msg The error message + * @return void + */ +function log_php_error_in_sentry($errno, $msg) { + global $sentry_php_error_types; + if ( + isset($sentry_php_error_types) + && is_array($sentry_php_error_types) + && in_array($errno, $sentry_php_error_types) + ) + log_in_sentry($msg); +} + +/* + * Performance monitoring + */ + +class SentryTransaction { + + /** + * The Sentry transaction object + * @var \Sentry\Tracing\Transaction + */ + private $transaction; + + /** + * The Sentry transaction context object + * @var \Sentry\Tracing\TransactionContext + */ + private $context; + + /** + * Constructor: start a Sentry transaction + * @param string|null $op The operation name + * @param string|null $name The transaction name + * @return void + */ + public function __construct($op=null, $name=null) { + // Setup context for the full transaction + $this->context = new \Sentry\Tracing\TransactionContext(); + $this->context->setName( + $name?$name: + (php_sapi_name()=='cli'?'CLI execution':'HTTP request') + ); + $this->context->setOp( + $op?$op: + (php_sapi_name()=='cli'?'cli.command':'http.request') + ); + + // Start the transaction + $this->transaction = \Sentry\startTransaction($this->context); + + // Set the current transaction as the current span so we can retrieve it later + \Sentry\SentrySdk::getCurrentHub()->setSpan($this->transaction); + } + + /** + * Destructor: Stop the current Sentry transaction + * @return void + */ + public function __destruct() { + SentrySpan :: finishAll(); + $this->transaction->finish(); + } +} + +/** + * Internal Sentry Span object implementation + * This internal implementation principally permit to keep trace of new span parent + * and list of started spans. + */ +class SentrySpan { + + /** + * Keep trace of started Sentry spans + * @var array + */ + private static $_started_spans = array(); + + /** + * The unique ID of the Sentry span + * Note: internal ID used as key in self::$_started_spans + * @var int|null + */ + private $id = null; + + /** + * The parent of the Sentry span + * @var mixed + */ + private $parent = null; + + /** + * The context of the Sentry span + * @var null|\Sentry\Tracing\SpanContext + */ + private $context = null; + + /** + * The Sentry span object + * @var mixed + */ + private $span = null; + + /** + * Sentry span constructor + * @param string|null $op The operation name + * @param string|null $name The span name + * @return void + */ + public function __construct($op, $name) { + $this -> parent = \Sentry\SentrySdk::getCurrentHub()->getSpan(); + // Check if we have a parent span (this is the case if we started a transaction earlier) + if (is_null($this -> parent)) return; + + while (is_null($this -> id)) { + $this -> id = rand(); + if (isset(self :: $_started_spans[$this -> id])) + $this -> id = null; + } + $this -> context = new \Sentry\Tracing\SpanContext(); + $this -> context->setOp($op); + $this -> context->setDescription($name); + $this -> span = $this->parent->startChild($this -> context); + + // Set the current span to the span we just started + \Sentry\SentrySdk::getCurrentHub()->setSpan($this -> span); + + self :: $_started_spans[$this -> id] = $this; + } + + /** + * Finish the span (if started) + * @return void + */ + public function finish() { + if (!$this -> span) return; + $this -> span -> finish(); + unset(self::$_started_spans[$this -> id]); + \Sentry\SentrySdk::getCurrentHub()->setSpan($this -> parent); + } + + /** + * Finish all started spans + * @see SentryTransaction::__destruct() + * @return void + */ + public static function finishAll() { + foreach (array_reverse(self :: $_started_spans) as $id => $span) + $span -> finish(); + } +} + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/session.php b/includes/session.php index 51a592a..8a1812e 100644 --- a/includes/session.php +++ b/includes/session.php @@ -17,7 +17,7 @@ if (!isset($_SESSION['session_key'])) { } // Handle session timeout -if ($session_timeout) { +if (isset($session_timeout) && $session_timeout) { if (!isset($_SESSION['session_last_access'])) { logging('DEBUG', 'Set initial session last access'); $_SESSION['session_last_access'] = time(); @@ -40,3 +40,5 @@ function check_session_key($value=null) { $value = $_REQUEST['session_key']; return ($value && $_SESSION['session_key'] == $value); } + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/smarty.php b/includes/smarty.php index e076990..fc37919 100644 --- a/includes/smarty.php +++ b/includes/smarty.php @@ -3,7 +3,6 @@ if (php_sapi_name() == "cli") return true; -require_once($smarty_path); $smarty = new Smarty(); /* @@ -62,8 +61,26 @@ else { } // Configure templates/templates_c directories -$smarty->setTemplateDir($smarty_templates_dir); -$smarty->setCompileDir($smarty_templates_c_dir); +if ( + !isset($smarty_templates_dir) + || !is_dir($smarty_templates_dir) +) + logging( + 'FATAL', "Template directory not found (%s)", + isset($smarty_templates_dir)?$smarty_templates_dir:'not set'); +else + $smarty->setTemplateDir($smarty_templates_dir); + +if ( + !isset($smarty_templates_c_dir) + || !is_dir($smarty_templates_c_dir) + || !is_writable($smarty_templates_c_dir) +) + logging( + 'FATAL', "Template cache directory not found or not writable (%s)", + isset($smarty_templates_c_dir)?$smarty_templates_c_dir:'not set'); +else + $smarty->setCompileDir($smarty_templates_c_dir); // Enable Smarty security smarty_enable_security_mode( @@ -77,13 +94,13 @@ smarty_enable_security_mode( ); // Defined some global template variables -$smarty->assign('public_root_url', $public_root_url); -$smarty->assign('main_pagetitle', $main_pagetitle); +$smarty->assign('public_root_url', isset($public_root_url)?$public_root_url:'/'); +$smarty->assign('main_pagetitle', isset($main_pagetitle)?$main_pagetitle:null); $smarty->assign('session_key', $_SESSION['session_key']); // Handle in-page errors & messages if (!isset($_SESSION['errors'])) - $_SESSION['errors']=array(); + $_SESSION['errors'] = array(); function add_error($error) { // If more than one arguments passed, format error message using sprintf if (func_num_args() > 1) { @@ -96,7 +113,7 @@ function add_error($error) { } if (!isset($_SESSION['messages'])) - $_SESSION['messages']=array(); + $_SESSION['messages'] = array(); function add_message($message) { // If more than one arguments passed, format message using sprintf if (func_num_args() > 1) { @@ -113,42 +130,72 @@ if (isset($included_css_files) && is_array($included_css_files)) { $_css = $included_css_files; } else { - $_css=array(); + $_css = array(); } -function add_css_file($files) { +function add_css_file() { global $_css; - if (!is_array($files)) $files=array($files); - foreach ($files as $file) - if (!in_array($file, $_css)) - $_css[]=$file; + foreach (func_get_args() as $files) { + if (!is_array($files)) $files=array($files); + foreach ($files as $file) { + if (!in_array($file, $_css)) + $_css[]=$file; + } + } } -$_js=array(); -function add_js_file($files) { +$_js = array(); +function add_js_file() { global $_js; - if (!is_array($files)) $files=array($files); - foreach ($files as $file) - if (!in_array($file, $_js)) - $_js[]=$file; + foreach (func_get_args() as $files) { + if (!is_array($files)) $files = array($files); + foreach ($files as $file) { + if (!in_array($file, $_js)) + $_js[] = $file; + } + } } function _defineCommonTemplateVariables($template, $pagetitle) { - global $smarty, $_css, $_js, $status_list, $auth_user, $admin; + global $smarty, $_css, $_js, $status_list, $auth_user, $admin, $webstats_js_code; $smarty->assign('pagetitle', $pagetitle); + + // Messages + $smarty -> assign('errors', (isset($_SESSION['errors'])?$_SESSION['errors']:array())); + $smarty -> assign('messages', (isset($_SESSION['messages'])?$_SESSION['messages']:array())); + + // Files inclusions + $smarty -> assign('css', $_css); + $smarty -> assign('js', $_js); + + // Authenticated user info if (isset($auth_user)) $smarty->assign('auth_user', $auth_user); - $smarty->assign('errors', $_SESSION['errors']); - $smarty->assign('messages', $_SESSION['messages']); - $smarty->assign('css', $_css); - $smarty->assign('js', $_js); + + // Webstats JS code + $smarty->assign( + 'webstats_js_code', + isset($webstats_js_code)?$webstats_js_code:null); } function display_template($template, $pagetitle=false) { if (!$template) logging("FATAL", _("No template specified.")); + + // If refresh parameter is present, remove it and redirect + if (isset($_GET['refresh'])) { + unset($_GET['refresh']); + $url = get_current_url(); + if (!empty($_GET)) + $url .= '?'.http_build_query($_GET); + redirect($url); + return; + } + + $sentry_span = new SentrySpan('smarty.display_template', "Display Smarty template"); + global $smarty; // If more than 2 arguments passed, format pagetitle using sprintf - if ($pagetitle & func_num_args() > 2) { + if ($pagetitle && func_num_args() > 2) { $pagetitle = call_user_func_array( 'sprintf', array_merge(array($pagetitle), array_slice(func_get_args(), 2)) @@ -163,8 +210,11 @@ function display_template($template, $pagetitle=false) { catch (Exception $e) { log_exception($e, "Smarty - An exception occured displaying template '$template'"); if ($template != 'fatal_error.tpl') - logging("FATAL", _("An error occurred while viewing this page.")); + logging("FATAL", _("An error occurred while displaying this page.")); } + + $sentry_span->finish(); + } function display_ajax_return($data=null, $pretty=false) { @@ -269,3 +319,5 @@ function smarty_encodeJsonBase64($params, $smarty) { echo base64_encode(json_encode($params['data'])); } smarty_register_function('encodeJsonBase64','smarty_encodeJsonBase64'); + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/translation-cli.php b/includes/translation-cli.php index 52ac5b2..796b09b 100644 --- a/includes/translation-cli.php +++ b/includes/translation-cli.php @@ -154,7 +154,7 @@ add_cli_command( * all PO file in lang/[lang]/LC_MESSAGES. * * @param array $command_args The command arguments - * @return void + * @return bool */ function cli_update_messages($command_args) { global $root_dir_path, $root_lang_dir, $smarty_templates_dir; @@ -234,6 +234,7 @@ function cli_update_messages($command_args) { } logging('FATAL', _("Fail to open root lang directory (%s)."), $root_dir_path); + return false; } add_cli_command( 'update_messages', @@ -248,7 +249,7 @@ add_cli_command( * to corresponding MO files and as JSON catalog (for translation in JS). * * @param array $command_args The command arguments - * @return void + * @return bool */ function cli_compile_messages($command_args) { global $root_dir_path, $root_lang_dir, $smarty_templates_dir; @@ -354,6 +355,7 @@ function cli_compile_messages($command_args) { return !$error; } logging('FATAL', _("Fail to open root lang directory (%s)."), $root_dir_path); + return false; } add_cli_command( 'compile_messages', @@ -368,3 +370,5 @@ add_cli_command( "directories to MO files and as JSON catalogs in public_html/translations." ) ); + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/translation.php b/includes/translation.php index 52ed33b..93043d9 100644 --- a/includes/translation.php +++ b/includes/translation.php @@ -145,3 +145,5 @@ function init_translation() { add_js_file(array("lib/babel.js", "js/translation.js", $js_translation_file)); } } + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/url-helpers.php b/includes/url-helpers.php index ed0307c..0888882 100644 --- a/includes/url-helpers.php +++ b/includes/url-helpers.php @@ -14,3 +14,5 @@ function get_item_from_url($id, $fatal=false) { } return $item; } + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/url-public.php b/includes/url-public.php index f7849a6..6e50dba 100644 --- a/includes/url-public.php +++ b/includes/url-public.php @@ -258,3 +258,5 @@ function handle_delete($request) { redirect('item'); } add_url_handler('|^item/(?P[0-9]+)/delete$|', 'handle_delete'); + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/includes/url.php b/includes/url.php index 4b4a520..0dfe1d0 100644 --- a/includes/url.php +++ b/includes/url.php @@ -26,15 +26,16 @@ $url_patterns =array(); /** * Add an URL pattern * - * @param $pattern string The URL pattern (required) - * @param $handler callable The URL pattern handler (must be callable, required) - * @param $authenticated boolean Permit to define if this URL is accessible only for - * authenticated users (optional, default: true if the special - * force_authentication function is defined, false otherwise) - * @param $override boolean Allow override if a command already exists with the - * same name (optional, default: false) - * @param $api_mode boolean Enable API mode (optional, default: false) - * @param $methods array|null HTTP method (optional, default: array('GET', 'POST')) + * @param string|array $pattern The URL pattern or an array of patterns (required) + * @param callable $handler The URL pattern handler (must be callable, required) + * @param boolean $authenticated Permit to define if this URL is accessible only for + * authenticated users (optional, default: true if the + * special force_authentication function is defined, + * false otherwise) + * @param boolean $override Allow override if a command already exists with the + * same name (optional, default: false) + * @param boolean $api_mode Enable API mode (optional, default: false) + * @param array|string|null $methods HTTP method (optional, default: array('GET', 'POST')) **/ function add_url_handler($pattern, $handler=null, $authenticated=null, $override=true, $api_mode=false, $methods=null) { @@ -67,9 +68,9 @@ function add_url_handler($pattern, $handler=null, $authenticated=null, $override } elseif ($override) { logging( - 'DEBUG', - "URL : override pattern '$pattern' with handler '$handler' ". - "(old handler = '".$url_patterns[$pattern]."')"); + 'DEBUG', "URL : override pattern '%s' with handler '%s' (old handler = '%s')". + $pattern, format_callable($handler), vardump($url_patterns[$pattern]) + ); $url_patterns[$pattern] = array( 'handler' => $handler, 'authenticated' => $authenticated, @@ -133,9 +134,9 @@ function error_page($request=null, $error_code=null) { /** * Error 404 handler * - * @param[in] $request UrlRequest|null The request (optional, default: null) + * @param UrlRequest|null $request The request (optional, default: null) * - * @retval void + * @return void **/ function error_404($request=null) { error_page($request, 404); @@ -174,7 +175,7 @@ function get_request($default_url=null) { logging('DEBUG', "URL : current url = '$current_url'"); logging( - 'DEBUG', + 'TRACE', "URL : check current url with the following URL patterns :\n - ". implode("\n - ", array_keys($url_patterns)) ); @@ -185,7 +186,7 @@ function get_request($default_url=null) { // Reset last redirect if (isset($_SESSION['last_redirect'])) unset($_SESSION['last_redirect']); - logging('DEBUG', "URL : result :\n".varDump($request, 1)); + logging('TRACE', "URL : result :\n".vardump($request)); return $request; } } @@ -212,9 +213,9 @@ function get_request($default_url=null) { /** * Check if the current requested URL match with a specific pattern * - * @param $pattern string The URL pattern - * @param $current_url string|false The current URL (optional) - * @param $methods array|null HTTP method (optional, default: no check) + * @param string $pattern The URL pattern + * @param string|false $current_url The current URL (optional) + * @param array|null $methods HTTP method (optional, default: no check) * * @return array|false The URL info if pattern matched, false otherwise. **/ @@ -229,7 +230,7 @@ function url_match($pattern, $current_url=false, $methods=null) { logging( 'DEBUG', "URL : Match found with pattern '$pattern' :\n\t". - str_replace("\n", "\n\t", print_r($m, 1))); + str_replace("\n", "\n\t", print_r($m, true))); return $m; } return False; @@ -241,10 +242,10 @@ function url_match($pattern, $current_url=false, $methods=null) { * @return string|false The current request URL or false if fail **/ function get_current_url() { - logging('DEBUG', "URL : request URI = '".$_SERVER['REQUEST_URI']."'"); + logging('TRACE', "URL : request URI = '".$_SERVER['REQUEST_URI']."'"); $base = get_rewrite_base(); - logging('DEBUG', "URL : rewrite base = '$base'"); + logging('TRACE', "URL : rewrite base = '$base'"); if ($_SERVER['REQUEST_URI'] == $base) return ''; @@ -289,7 +290,7 @@ function get_rewrite_base() { /** * Trigger redirect to specified URL (or homepage if omited) * - * @param $go string|false The destination URL + * @param string|false $go The destination URL * * @return void **/ @@ -298,6 +299,15 @@ function redirect($go=false) { if ($go===false) $go = ""; + // If more than one argument passed, format URL using sprintf & urlencode parameters + elseif (func_num_args() > 1) + $go = call_user_func_array( + 'sprintf', + array_merge( + array($go), + array_map('urlencode', array_slice(func_get_args(), 1)) + ) + ); if (is_absolute_url($go)) $url = $go; @@ -332,7 +342,7 @@ function redirect($go=false) { * invoke the force_authentication() special function (or trigger a fatal error * if it's not defined). * - * @param $default_url string|null The default URL if current one does not + * @param string|null $default_url The default URL if current one does not * match with any configured pattern. * * @return void @@ -340,10 +350,14 @@ function redirect($go=false) { function handle_request($default_url=null) { global $smarty, $api_mode; + $sentry_span = new SentrySpan('http.handle_request', 'Handle the HTTP request'); + $request = get_request($default_url); if (!is_callable($request -> handler)) { - logging('ERROR', "URL handler function ".$request -> handler."() does not exists !"); + logging( + 'ERROR', "URL handler function %s does not exists !", + format_callable($request -> handler)); logging('FATAL', _("This request cannot be processed.")); } @@ -360,19 +374,20 @@ function handle_request($default_url=null) { logging('FATAL', _("Authentication required but force_authentication function is not defined.")); try { - return call_user_func($request -> handler, $request); + call_user_func($request -> handler, $request); } catch (Exception $e) { log_exception( $e, "An exception occured running URL handler function ".$request -> handler."()"); logging('FATAL', _("This request could not be processed correctly.")); } + $sentry_span->finish(); } /** * Remove trailing slash in specified URL * - * @param $url string The URL + * @param string $url The URL * * @return string The specified URL without trailing slash **/ @@ -390,13 +405,13 @@ function remove_trailing_slash($url) { * Check if session key is present and valid and set AJAX * mode. * - * @param $session_key string The current session key (optional) + * @param string|null $session_key string The current session key (optional) * * @return void **/ function check_ajax_request($session_key=null) { global $ajax, $debug_ajax; - $ajax=true; + $ajax = true; if (check_session_key($session_key)) fatal_error('Invalid request'); @@ -408,7 +423,7 @@ function check_ajax_request($session_key=null) { /** * Get the public absolute URL * - * @param $relative_url string|null Relative URL to convert (Default: current URL) + * @param string|null $relative_url Relative URL to convert (Default: current URL) * * @return string The public absolute URL **/ @@ -430,7 +445,7 @@ function get_absolute_url($relative_url=null) { } if (substr($relative_url, 0, 1) == '/') - $relative_url = substr($url, 1); + $relative_url = substr($relative_url, 1); $url = remove_trailing_slash($public_root_url)."/$relative_url"; logging('DEBUG', "URL :: get_absolute_url($relative_url): result = $url"); return $url; @@ -439,7 +454,7 @@ function get_absolute_url($relative_url=null) { /** * Check if specified URL is absolute * - * @param $url string The URL to check + * @param string $url The URL to check * * @return boolean True if specified URL is absolute, False otherwise **/ @@ -450,12 +465,12 @@ function is_absolute_url($url) { /** * Add parameter in specified URL * - * @param &$url string The reference of the URL - * @param $param string The parameter name - * @param $value string The parameter value - * @param $encode boolean Set if parameter value must be URL encoded (optional, default: true) + * @param string &$url The reference of the URL + * @param string $param The parameter name + * @param string $value The parameter value + * @param boolean $encode Set if parameter value must be URL encoded (optional, default: true) * - * @return string|null The completed URL + * @return string The completed URL */ function add_url_parameter(&$url, $param, $value, $encode=true) { if (strpos($url, '?') === false) @@ -503,7 +518,7 @@ class UrlRequest { /** * Get request info * - * @param $key string The name of the info + * @param string $key The name of the info * * @return mixed The value **/ @@ -527,15 +542,39 @@ class UrlRequest { logging('WARNING', "__get($key): invalid property requested\n".get_debug_backtrace_context()); } + /** + * Set request info + * + * @param string $key The name of the info + * @param mixed $value The value of the info + * + * @return void + **/ + public function __set($key, $value) { + if ($key == 'referer') + $_SERVER['HTTP_REFERER'] = $value; + elseif ($key == 'http_method') + $_SERVER['REQUEST_METHOD'] = $value; + else + $this->url_params[$key] = $value; + } + + + /** * Check is request info is set * - * @param $key string The name of the info + * @param string $key The name of the info * - * @return boolval True is info is set, False otherwise + * @return bool True is info is set, False otherwise **/ public function __isset($key) { - if (in_array($key, array('current_url', 'handler', 'authenticated'))) + if ( + in_array( + $key, array('current_url', 'handler', 'authenticated', + 'api_mode', 'referer', 'http_method') + ) + ) return True; return array_key_exists($key, $this->url_params); } @@ -543,9 +582,9 @@ class UrlRequest { /** * Get request parameter * - * @param $parameter string The name of the parameter - * @param $decode string If true, the parameter value will be urldecoded - * (optional, default: true) + * @param string $parameter The name of the parameter + * @param bool $decode If true, the parameter value will be urldecoded + * (optional, default: true) * * @return mixed The value or false if parameter does not exists **/ @@ -570,3 +609,5 @@ class UrlRequest { } } + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..dc7379c --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,31 @@ +parameters: + level: 5 + paths: + - includes + - public_html + - bin + excludePaths: + - includes/config.local.php + ignoreErrors: + - + message: "#Instantiated class Mail_mime not found\\.#" + path: includes/mail.php + - + message: "#Call to method (setFrom|setSubject|setHTMLBody|setTXTBody|get|headers|addAttachment)\\(\\) on an unknown class Mail_mime\\.#" + path: includes/mail.php + - + message: "#Call to static method factory\\(\\) on an unknown class Mail\\.#" + path: includes/mail.php + - + message: "#Call to static method isError\\(\\) on an unknown class PEAR\\.#" + path: includes/mail.php + - + message: "#Variable \\$root_dir_path might not be defined\\.#" + paths: + - includes/config.inc.php + - "#Access to private property UrlRequest::\\$(handler|api_mode|authenticated)\\.#" + - + message: "#Variable \\$status_list might not be defined\\.#" + paths: + - includes/cli.php + diff --git a/public_html/index.php b/public_html/index.php index 4243b3f..ce2db4e 100644 --- a/public_html/index.php +++ b/public_html/index.php @@ -5,3 +5,5 @@ include 'url-public.php'; $default_url=''; handle_request(); + +# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab diff --git a/templates/empty.tpl b/templates/empty.tpl index 61fd041..f9a1e5a 100644 --- a/templates/empty.tpl +++ b/templates/empty.tpl @@ -97,5 +97,6 @@ {/foreach} +{if $webstats_js_code}{$webstats_js_code}{/if}