diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..fe62752
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,22 @@
+# Git
+.git
+
+# IDEs
+.idea
+*.iml
+.vscode
+.zed
+
+# Composer
+vendor
+
+# PHP code sniffer
+.php_cs.cache
+
+# PHP Unit
+build
+.phpunit.result.cache
+
+# Dev / Testing
+test.php
+coverage/*
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..f69d363
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,15 @@
+* text eol=lf
+entrypoint.sh linguist-detectable=false
+Dockerfile linguist-detectable=false
+
+/.github export-ignore
+/coverage export-ignore
+/tests export-ignore
+/.dockerignore export-ignore
+/.gitattributes export-ignore
+/.gitignore export-ignore
+/.php-cs-fixer.php export-ignore
+/Dockerfile export-ignore
+/docker-compose.yml export-ignore
+/entrypoint.sh export-ignore
+/phpunit.xml export-ignore
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..d48e2ea
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,28 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: "[BUG] "
+labels: "bug"
+assignees: rancoud
+
+---
+## Description
+
+
+## Steps to reproduce this issue
+1.
+2.
+3.
+4.
+
+## Expected behavior
+
+
+## Actual behavior
+
+
+## Screenshots
+
+
+## Additional context
+
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..6227d75
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,23 @@
+---
+name: Feature request
+about: Suggest an idea
+title: "[FEATURE] "
+labels: "enhancement"
+assignees: rancoud
+
+---
+
+## My problem
+
+
+## My suggestion
+
+
+## Alternatives
+
+
+## Additional context
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..1bc6936
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,9 @@
+
+# Description
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index a8ce69f..336f33b 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,91 +1,57 @@
name: test
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
on:
push:
+ branches:
+ - master
pull_request:
+ paths-ignore:
+ - '**.md'
+ types:
+ - opened
+ - synchronize
+ - reopened
jobs:
test:
runs-on: ${{ matrix.os }}
+
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
-
- services:
- mysql:
- image: mysql:5.7
- env:
- MYSQL_ALLOW_EMPTY_PASSWORD: yes
- MYSQL_USER: root
- MYSQL_PASSWORD: ''
- MYSQL_DATABASE: test_database
- ports:
- - 3306:3306
- options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
-
- redis:
- image: redis
- options: >-
- --health-cmd "redis-cli ping"
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
- ports:
- - 6379:6379
+ php-version:
+ - '8.4'
+ - '8.5'
steps:
- - name: Verify MySQL connection from host
- run: |
- sudo apt-get install -y mysql-client
- mysql --host 127.0.0.1 --port 3306 -uroot --password="" -e "SHOW DATABASES"
-
- - uses: actions/checkout@v2
+ - name: Checkout
+ uses: actions/checkout@v6
- - uses: shivammathur/setup-php@v2
- with:
- php-version: '7.4'
- coverage: xdebug
-
- - name: Set files permission
- run: |
- sudo chown -R www-data:www-data /var/lib/php/sessions/
- sudo chmod -R 777 /var/lib/php/sessions/
-
- - name: Validate composer.json and composer.lock
- run: composer validate
-
- - name: Cache Composer packages
- id: composer-cache
- uses: actions/cache@v2
- with:
- path: vendor
- key: ${{ runner.os }}-node-${{ hashFiles('**/composer.lock') }}
- restore-keys: |
- ${{ runner.os }}-node-
+ - name: Pull
+ run: docker compose pull --quiet
- - name: Install dependencies
- if: steps.composer-cache.outputs.cache-hit != 'true'
- run: composer install --prefer-dist --no-progress --no-suggest
+ - name: Build
+ run: docker compose build --build-arg PHPVERSION=${{ matrix.php-version }}
- - name: PHPCS
- if: ${{ runner.os != 'Windows' }}
- run: |
- vendor/bin/php-cs-fixer fix --diff --dry-run
+ - name: Lint
+ if: matrix.php-version == '8.4'
+ run: docker compose run lib composer lint
- - name: PHPUnit
- run: |
- vendor/bin/phpunit --colors --coverage-text --coverage-clover coverage/clover.xml
- env:
- MYSQL_HOST: 127.0.0.1
- MYSQL_PORT: ${{ job.services.mysql.ports[3306] }}
- MYSQL_USER: root
- MYSQL_PASSWORD:
+ - name: Test
+ run: docker compose run lib composer test
- name: Upload coverage
- uses: codecov/codecov-action@v1.0.7
+ uses: codecov/codecov-action@v6
if: success()
with:
token: ${{ secrets.CODECOV_TOKEN }}
- file: ./coverage/clover.xml
\ No newline at end of file
+ files: ./coverage/clover.xml
diff --git a/.gitignore b/.gitignore
index 6bb5f43..45b8f15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,17 +1,20 @@
-# IntelliJ
-.idea
-*.iml
-
-# Composer
-vendor/
-
-# PHP code sniffer
-.php_cs.cache
-
-# PHP Unit
-build/
-.phpunit.result.cache
-
-# Dev / Testing
-test.php
-coverage/
\ No newline at end of file
+# IDEs
+.idea
+*.iml
+.vscode
+.zed
+
+# Composer
+vendor/
+
+# PHP code sniffer
+.php-cs-fixer.cache
+
+# PHP Unit
+build/
+.phpunit.result.cache
+
+# Dev / Testing
+test.php
+coverage/*
+!coverage/.gitkeep
\ No newline at end of file
diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php
new file mode 100644
index 0000000..0b39c42
--- /dev/null
+++ b/.php-cs-fixer.php
@@ -0,0 +1,413 @@
+ true,
+ 'backtick_to_shell_exec' => true,
+ 'ereg_to_preg' => true,
+ 'mb_str_functions' => true,
+ 'modernize_strpos' => ['modernize_stripos' => true],
+ 'no_alias_functions' => ['sets' => ['@all']],
+ 'no_alias_language_construct_call' => true,
+ 'no_mixed_echo_print' => ['use' => 'echo'],
+ 'pow_to_exponentiation' => true,
+ 'random_api_migration' => ['replacements' => ['getrandmax' => 'mt_getrandmax', 'srand' => 'mt_srand', 'mt_rand' => 'random_int', 'rand' => 'random_int']],
+ 'set_type_to_cast' => true
+];
+
+$arrayNotationRules = [
+ 'array_syntax' => ['syntax' => 'short'],
+ 'no_multiline_whitespace_around_double_arrow' => true,
+ 'no_whitespace_before_comma_in_array' => ['after_heredoc' => true],
+ 'normalize_index_brace' => true,
+ 'return_to_yield_from' => true,
+ 'trim_array_spaces' => true,
+ 'whitespace_after_comma_in_array' => ['ensure_single_space' => true],
+ 'yield_from_array_to_yields' => true
+];
+
+$attributeNotationRules = [
+ 'attribute_empty_parentheses' => ['use_parentheses' => false],
+ 'general_attribute_remove' => ['attributes' => []],
+ 'ordered_attributes' => ['order' => [], 'sort_algorithm' => 'alpha']
+];
+
+$basicRules = [
+ 'braces_position' => [
+ 'allow_single_line_anonymous_functions' => true,
+ 'allow_single_line_empty_anonymous_classes' => true,
+ 'anonymous_classes_opening_brace' => 'same_line',
+ 'anonymous_functions_opening_brace' => 'same_line',
+ 'classes_opening_brace' => 'next_line_unless_newline_at_signature_end',
+ 'control_structures_opening_brace' => 'same_line',
+ 'functions_opening_brace' => 'next_line_unless_newline_at_signature_end'
+ ],
+ 'encoding' => true,
+ 'no_multiple_statements_per_line' => true,
+ 'no_trailing_comma_in_singleline' => ['elements' => ['arguments', 'array', 'array_destructuring', 'group_import']],
+ 'non_printable_character' => ['use_escape_sequences_in_strings' => true],
+ 'numeric_literal_separator' => false,
+ 'octal_notation' => true,
+ 'psr_autoloading' => ['dir' => null],
+ 'single_line_empty_body' => true
+];
+
+$casingRules = [
+ 'class_reference_name_casing' => true,
+ 'constant_case' => ['case' => 'lower'],
+ 'integer_literal_case' => true,
+ 'lowercase_keywords' => true,
+ 'lowercase_static_reference' => true,
+ 'magic_constant_casing' => true,
+ 'magic_method_casing' => true,
+ 'native_function_casing' => true,
+ 'native_type_declaration_casing' => true
+];
+
+$castNotationRules = [
+ 'cast_spaces' => ['space' => 'single'],
+ 'lowercase_cast' => true,
+ 'modernize_types_casting' => true,
+ 'no_short_bool_cast' => true,
+ 'no_unset_cast' => true,
+ 'short_scalar_cast' => true
+];
+
+$classNotationRules = [
+ 'class_attributes_separation' => ['elements' => ['const' => 'one', 'method' => 'one', 'property' => 'one', 'trait_import' => 'none', 'case' => 'none']],
+ 'class_definition' => ['inline_constructor_arguments' => true, 'multi_line_extends_each_single_line' => false, 'single_item_single_line' => true, 'single_line' => true, 'space_before_parenthesis' => false],
+ 'final_class' => false,
+ 'final_internal_class' => false,
+ 'final_public_method_for_abstract_class' => false,
+ 'no_blank_lines_after_class_opening' => true,
+ 'no_null_property_initialization' => true,
+ 'no_php4_constructor' => true,
+ 'no_unneeded_final_method' => ['private_methods' => true],
+ 'ordered_class_elements' => ['case_sensitive' => false, 'order' => ['use_trait', 'case', 'constant_public', 'constant_protected', 'constant_private', 'property_public', 'property_protected', 'property_private', 'construct', 'destruct', 'magic', 'phpunit'], 'sort_algorithm' => 'none'],
+ 'ordered_interfaces' => ['case_sensitive' => false, 'direction' => 'ascend', 'order' => 'alpha'],
+ 'ordered_traits' => ['case_sensitive' => false],
+ 'ordered_types' => ['case_sensitive' => false, 'null_adjustment' => 'always_last', 'sort_algorithm' => 'alpha'],
+ 'phpdoc_readonly_class_comment_to_keyword' => true,
+ 'protected_to_private' => false,
+ 'self_accessor' => true,
+ 'self_static_accessor' => true,
+ 'single_class_element_per_statement' => ['elements' => ['const', 'property']],
+ 'single_trait_insert_per_statement' => true,
+ 'visibility_required' => ['elements' => ['const', 'method', 'property']]
+];
+
+$classUsageRules = [
+ 'date_time_immutable' => true
+];
+
+$commentRules = [
+ 'comment_to_phpdoc' => ['ignored_tags' => ['codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd']],
+ 'header_comment' => false,
+ 'multiline_comment_opening_closing' => true,
+ 'no_empty_comment' => true,
+ 'no_trailing_whitespace_in_comment' => true,
+ 'single_line_comment_spacing' => true,
+ 'single_line_comment_style' => ['comment_types' => ['hash']]
+];
+
+$constantNotationRules = [
+ 'native_constant_invocation' => ['exclude' => ['null', 'false', 'true'], 'fix_built_in' => true, 'include' => [], 'scope' => 'all', 'strict' => false],
+];
+
+$controlStructureRules = [
+ 'control_structure_braces' => true,
+ 'control_structure_continuation_position' => ['position' => 'same_line'],
+ 'elseif' => true,
+ 'empty_loop_body' => ['style' => 'braces'],
+ 'empty_loop_condition' => ['style' => 'while'],
+ 'include' => true,
+ 'no_alternative_syntax' => ['fix_non_monolithic_code' => true],
+ 'no_break_comment' => ['comment_text' => 'no break'],
+ 'no_superfluous_elseif' => true,
+ 'no_unneeded_braces' => ['namespaces' => true],
+ 'no_unneeded_control_parentheses' => ['statements' => ['break', 'clone', 'continue', 'echo_print', 'others', 'return', 'switch_case', 'yield', 'yield_from']],
+ 'no_useless_else' => true,
+ 'simplified_if_return' => true,
+ 'switch_case_semicolon_to_colon' => true,
+ 'switch_case_space' => true,
+ 'switch_continue_to_break' => true,
+ 'trailing_comma_in_multiline' => false,
+ 'yoda_style' => false
+];
+
+$doctrineAnnotationRules = [
+ 'doctrine_annotation_array_assignment' => false,
+ 'doctrine_annotation_braces' => false,
+ 'doctrine_annotation_indentation' => false,
+ 'doctrine_annotation_spaces' => false
+];
+
+$functionNotationRules = [
+ 'combine_nested_dirname' => true,
+ 'date_time_create_from_format_call' => true,
+ 'fopen_flag_order' => true,
+ 'fopen_flags' => ['b_mode' => false],
+ 'function_declaration' => ['closure_fn_spacing' => 'one', 'closure_function_spacing' => 'one', 'trailing_comma_single_line' => false],
+ 'implode_call' => true,
+ 'lambda_not_used_import' => true,
+ 'method_argument_space' => ['after_heredoc' => false, 'attribute_placement' => 'ignore', 'keep_multiple_spaces_after_comma' => false, 'on_multiline' => 'ignore'],
+ 'native_function_invocation' => ['exclude' => [], 'include' => ['@all', '@compiler_optimized', '@internal'], 'scope' => 'all', 'strict' => false],
+ 'no_spaces_after_function_name' => true,
+ 'no_unreachable_default_argument_value' => true,
+ 'no_useless_sprintf' => true,
+ 'nullable_type_declaration_for_default_null_value' => true,
+ 'phpdoc_to_param_type' => false,
+ 'phpdoc_to_property_type' => false,
+ 'phpdoc_to_return_type' => false,
+ 'regular_callable_call' => true,
+ 'return_type_declaration' => ['space_before' => 'none'],
+ 'single_line_throw' => false,
+ 'static_lambda' => true,
+ 'use_arrow_functions' => false,
+ 'void_return' => true
+];
+
+$importRules = [
+ 'fully_qualified_strict_types' => ['import_symbols' => false, 'leading_backslash_in_global_namespace' => false, 'phpdoc_tags' => ['param', 'phpstan-param', 'phpstan-property', 'phpstan-property-read', 'phpstan-property-write', 'phpstan-return', 'phpstan-var', 'property', 'property-read', 'property-write', 'psalm-param', 'psalm-property', 'psalm-property-read', 'psalm-property-write', 'psalm-return', 'psalm-var', 'return', 'see', 'throws', 'var']],
+ 'global_namespace_import' => ['import_classes' => false, 'import_constants' => false, 'import_functions' => false],
+ 'group_import' => false,
+ 'no_leading_import_slash' => true,
+ 'no_unneeded_import_alias' => true,
+ 'no_unused_imports' => true,
+ 'ordered_imports' => ['case_sensitive' => false, 'imports_order' => ['class', 'function', 'const'], 'sort_algorithm' => 'alpha'],
+ 'single_import_per_statement' => ['group_to_single_imports' => true],
+ 'single_line_after_imports' => true
+];
+
+$languageConstructRules = [
+ 'class_keyword' => true,
+ 'combine_consecutive_issets' => true,
+ 'combine_consecutive_unsets' => true,
+ 'declare_equal_normalize' => ['space' => 'none'],
+ 'declare_parentheses' => true,
+ 'dir_constant' => true,
+ 'error_suppression' => ['mute_deprecation_error' => true, 'noise_remaining_usages' => false, 'noise_remaining_usages_exclude' => []],
+ 'explicit_indirect_variable' => true,
+ 'function_to_constant' => ['functions' => ['get_called_class', 'get_class', 'get_class_this', 'php_sapi_name', 'phpversion', 'pi']],
+ 'get_class_to_class_keyword' => true,
+ 'is_null' => true,
+ 'no_unset_on_property' => true,
+ 'nullable_type_declaration' => ['syntax' => 'question_mark'],
+ 'single_space_around_construct' => ['constructs_contain_a_single_space' => ['yield_from'], 'constructs_followed_by_a_single_space' => ['abstract', 'as', 'attribute', 'break', 'case', 'catch', 'class', 'clone', 'comment', 'const', 'const_import', 'continue', 'do', 'echo', 'else', 'elseif', 'enum', 'extends', 'final', 'finally', 'for', 'foreach', 'function', 'function_import', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'match', 'named_argument', 'namespace', 'new', 'open_tag_with_echo', 'php_doc', 'php_open', 'print', 'private', 'protected', 'public', 'readonly', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'type_colon', 'use', 'use_lambda', 'use_trait', 'var', 'while', 'yield', 'yield_from'], 'constructs_preceded_by_a_single_space' => ['as', 'else', 'elseif', 'use_lambda']]
+];
+
+$listNotationRules = [
+ 'list_syntax' => ['syntax' => 'short']
+];
+
+$namespaceNotationRules = [
+ 'blank_line_after_namespace' => true,
+ 'blank_lines_before_namespace' => ['min_line_breaks' => 2, 'max_line_breaks' => 2],
+ 'clean_namespace' => true,
+ 'no_leading_namespace_whitespace' => true
+];
+
+$namingRules = [
+ 'no_homoglyph_names' => true
+];
+
+$operatorRules = [
+ 'assign_null_coalescing_to_coalesce_equal' => true,
+ 'binary_operator_spaces' => ['default' => 'single_space', 'operators' => ['=>' => 'align']],
+ 'concat_space' => ['spacing' => 'one'],
+ 'increment_style' => ['style' => 'pre'],
+ 'logical_operators' => true,
+ 'long_to_shorthand_operator' => true,
+ 'new_with_parentheses' => ['anonymous_class' => true, 'named_class' => true],
+ 'no_space_around_double_colon' => true,
+ 'no_useless_concat_operator' => ['juggle_simple_strings' => false],
+ 'no_useless_nullsafe_operator' => true,
+ 'not_operator_with_space' => false,
+ 'not_operator_with_successor_space' => false,
+ 'object_operator_without_whitespace' => true,
+ 'operator_linebreak' => ['only_booleans' => true, 'position' => 'beginning'],
+ 'standardize_increment' => true,
+ 'standardize_not_equals' => true,
+ 'ternary_operator_spaces' => true,
+ 'ternary_to_elvis_operator' => true,
+ 'ternary_to_null_coalescing' => true,
+ 'unary_operator_spaces' => ['only_dec_inc' => false]
+];
+
+$phpTagRules = [
+ 'blank_line_after_opening_tag' => true,
+ 'echo_tag_syntax' => ['format' => 'long', 'long_function' => 'echo', 'shorten_simple_statements_only' => true],
+ 'full_opening_tag' => true,
+ 'linebreak_after_opening_tag' => true,
+ 'no_closing_tag' => true
+];
+
+$phpUnitRules = [
+ 'php_unit_assert_new_names' => true,
+ 'php_unit_attributes' => ['keep_annotations' => false],
+ 'php_unit_construct' => ['assertions' => ['assertEquals', 'assertNotEquals', 'assertNotSame', 'assertSame']],
+ 'php_unit_data_provider_method_order' => ['placement' => 'before'],
+ 'php_unit_data_provider_name' => ['prefix' => 'provide', 'suffix' => 'DataCases'],
+ 'php_unit_data_provider_return_type' => true,
+ 'php_unit_data_provider_static' => ['force' => true],
+ 'php_unit_dedicate_assert' => ['target' => 'newest'],
+ 'php_unit_dedicate_assert_internal_type' => ['target' => 'newest'],
+ 'php_unit_expectation' => ['target' => 'newest'],
+ 'php_unit_fqcn_annotation' => true,
+ 'php_unit_internal_class' => ['types' => ['abstract', 'final', 'normal']],
+ 'php_unit_method_casing' => ['case' => 'camel_case'],
+ 'php_unit_mock' => ['target' => 'newest'],
+ 'php_unit_mock_short_will_return' => true,
+ 'php_unit_namespaced' => ['target' => 'newest'],
+ 'php_unit_no_expectation_annotation' => ['target' => 'newest', 'use_class_const' => true],
+ 'php_unit_set_up_tear_down_visibility' => true,
+ 'php_unit_size_class' => false,
+ 'php_unit_strict' => ['assertions' => ['assertAttributeEquals', 'assertAttributeNotEquals', 'assertEquals', 'assertNotEquals']],
+ 'php_unit_test_annotation' => ['style' => 'prefix'],
+ 'php_unit_test_case_static_method_calls' => ['call_type' => 'static', 'methods' => []],
+ 'php_unit_test_class_requires_covers' => false
+];
+
+$phpDocRules = [
+ 'align_multiline_comment' => ['comment_type' => 'phpdocs_only'],
+ 'general_phpdoc_annotation_remove' => ['annotations' => [], 'case_sensitive' => false],
+ 'general_phpdoc_tag_rename' => ['case_sensitive' => false, 'fix_annotation' => true, 'fix_inline' => true, 'replacements' => ['inheritDocs' => 'inheritDoc']],
+ 'no_blank_lines_after_phpdoc' => true,
+ 'no_empty_phpdoc' => true,
+ 'no_superfluous_phpdoc_tags' => ['allow_hidden_params' => false, 'allow_mixed' => false, 'allow_unused_params' => false, 'remove_inheritdoc' => true],
+ 'phpdoc_add_missing_param_annotation' => ['only_untyped' => true],
+ 'phpdoc_align' => ['align' => 'vertical', 'spacing' => ['_default' => 1], 'tags' => ['method', 'param', 'property', 'property-read', 'property-write', 'return', 'throws', 'type', 'var']],
+ 'phpdoc_annotation_without_dot' => true,
+ 'phpdoc_array_type' => false,
+ 'phpdoc_indent' => true,
+ 'phpdoc_inline_tag_normalizer' => ['tags' => ['example', 'id', 'internal', 'inheritdoc', 'inheritdocs', 'link', 'source', 'toc', 'tutorial']],
+ 'phpdoc_line_span' => ['const' => 'single', 'method' => 'single', 'property' => 'single'],
+ 'phpdoc_list_type' => false,
+ 'phpdoc_no_access' => true,
+ 'phpdoc_no_alias_tag' => ['replacements' => ['property-read' => 'property', 'property-write' => 'property', 'type' => 'var', 'link' => 'see']],
+ 'phpdoc_no_empty_return' => true,
+ 'phpdoc_no_package' => true,
+ 'phpdoc_no_useless_inheritdoc' => true,
+ 'phpdoc_order_by_value' => ['annotations' => ['author', 'covers', 'coversNothing', 'dataProvider', 'depends', 'group', 'internal', 'method', 'mixin', 'property', 'property-read', 'property-write', 'requires', 'throws', 'uses']],
+ 'phpdoc_order' => ['order' => ['param', 'throws', 'return']],
+ 'phpdoc_param_order' => true,
+ 'phpdoc_return_self_reference' => ['replacements' => ['this' => '$this', '@this' => '$this', '$self' => 'self', '@self' => 'self', '$static' => 'static', '@static' => 'static']],
+ 'phpdoc_scalar' => ['types' => ['boolean', 'callback', 'double', 'integer', 'real', 'str']],
+ 'phpdoc_separation' => ['groups' => [['author', 'copyright', 'license'], ['category', 'package', 'subpackage'], ['property', 'property-read', 'property-write'], ['deprecated', 'link', 'see', 'since']], 'skip_unlisted_annotations' => true],
+ 'phpdoc_single_line_var_spacing' => true,
+ 'phpdoc_summary' => true,
+ 'phpdoc_tag_casing' => ['tags' => ['inheritDoc']],
+ 'phpdoc_tag_type' => ['tags' => ['inheritDoc' => 'inline']],
+ 'phpdoc_to_comment' => ['allow_before_return_statement' => false, 'ignored_tags' => []],
+ 'phpdoc_trim_consecutive_blank_line_separation' => true,
+ 'phpdoc_trim' => true,
+ 'phpdoc_types' => ['groups' => ['alias', 'meta', 'simple']],
+ 'phpdoc_types_order' => ['case_sensitive' => false, 'null_adjustment' => 'always_last', 'sort_algorithm' => 'alpha'],
+ 'phpdoc_var_annotation_correct_order' => true,
+ 'phpdoc_var_without_name' => true
+];
+
+$returnNotationRules = [
+ 'no_useless_return' => true,
+ 'return_assignment' => true,
+ 'simplified_null_return' => true
+];
+
+$semicolonRules = [
+ 'multiline_whitespace_before_semicolons' => ['strategy' => 'no_multi_line'],
+ 'no_empty_statement' => true,
+ 'no_singleline_whitespace_before_semicolons' => true,
+ 'semicolon_after_instruction' => true,
+ 'space_after_semicolon' => ['remove_in_empty_for_expressions' => true]
+];
+
+$strictRules = [
+ 'declare_strict_types' => true,
+ 'strict_comparison' => true,
+ 'strict_param' => true
+];
+
+$stringNotationRules = [
+ 'explicit_string_variable' => true,
+ 'heredoc_closing_marker' => ['closing_marker' => 'EOD', 'explicit_heredoc_style' => false, 'reserved_closing_markers' => ['CSS', 'DIFF', 'HTML', 'JS', 'JSON', 'MD', 'PHP', 'PYTHON', 'RST', 'TS', 'SQL', 'XML', 'YAML']],
+ 'heredoc_to_nowdoc' => true,
+ 'multiline_string_to_heredoc' => true,
+ 'no_binary_string' => true,
+ 'no_trailing_whitespace_in_string' => true,
+ 'simple_to_complex_string_variable' => true,
+ 'single_quote' => ['strings_containing_single_quote_chars' => false],
+ 'string_implicit_backslashes' => false,
+ 'string_length_to_empty' => true,
+ 'string_line_ending' => true
+];
+
+$whitespaceRules = [
+ 'array_indentation' => true,
+ 'blank_line_before_statement' => ['statements' => ['break', 'continue', 'declare', 'phpdoc', 'return', 'throw', 'try', 'yield', 'yield_from']],
+ 'blank_line_between_import_groups' => true,
+ 'compact_nullable_type_declaration' => true,
+ 'heredoc_indentation' => ['indentation' => 'same_as_start'],
+ 'indentation_type' => true,
+ 'line_ending' => true,
+ 'method_chaining_indentation' => true,
+ 'no_extra_blank_lines' => ['tokens' => ['attribute', 'break', 'case', 'continue', 'curly_brace_block', 'default', 'extra', 'parenthesis_brace_block', 'return', 'square_brace_block', 'switch', 'throw', 'use']],
+ 'no_spaces_around_offset' => ['positions' => ['inside', 'outside']],
+ 'no_trailing_whitespace' => true,
+ 'no_whitespace_in_blank_line' => true,
+ 'single_blank_line_at_eof' => true,
+ 'spaces_inside_parentheses' => ['space' => 'none'],
+ 'statement_indentation' => ['stick_comment_to_next_continuous_control_statement' => false],
+ 'type_declaration_spaces' => ['elements' => ['constant', 'function', 'property']],
+ 'types_spaces' => ['space' => 'none', 'space_multiple_catch' => 'none']
+];
+
+$rules = \array_merge(
+ $aliasRules,
+ $arrayNotationRules,
+ $attributeNotationRules,
+ $basicRules,
+ $casingRules,
+ $castNotationRules,
+ $classNotationRules,
+ $classUsageRules,
+ $commentRules,
+ $constantNotationRules,
+ $controlStructureRules,
+ $doctrineAnnotationRules,
+ $functionNotationRules,
+ $importRules,
+ $languageConstructRules,
+ $listNotationRules,
+ $namespaceNotationRules,
+ $namingRules,
+ $operatorRules,
+ $phpTagRules,
+ $phpUnitRules,
+ $phpDocRules,
+ $returnNotationRules,
+ $semicolonRules,
+ $strictRules,
+ $stringNotationRules,
+ $whitespaceRules
+);
+
+$finder = Finder::create()
+ ->in([
+ __DIR__ . '/src',
+ __DIR__ . '/tests'
+ ])
+ ->name('*.php')
+ ->ignoreDotFiles(true)
+ ->ignoreVCS(true);
+
+$config = new Config();
+
+return $config->setFinder($finder)
+ ->setRules($rules)
+ ->setRiskyAllowed(true)
+ ->setUsingCache(true)
+ ->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect());
diff --git a/.php_cs b/.php_cs
deleted file mode 100644
index f25e5bb..0000000
--- a/.php_cs
+++ /dev/null
@@ -1,37 +0,0 @@
-in(__DIR__ . '/src')
-;
-return PhpCsFixer\Config::create()
- ->setRiskyAllowed(true)
- ->setRules([
- '@Symfony' => true,
- 'binary_operator_spaces' => array(
- 'align_equals' => false,
- 'align_double_arrow' => true,
- ),
- '@Symfony:risky' => true,
- 'array_syntax' => ['syntax' => 'short'],
- 'declare_strict_types' => true,
- 'linebreak_after_opening_tag' => true,
- 'mb_str_functions' => true,
- 'native_function_invocation' => true,
- 'no_php4_constructor' => true,
- 'no_unreachable_default_argument_value' => true,
- 'no_useless_else' => true,
- 'no_useless_return' => true,
- 'ordered_imports' => true,
- 'php_unit_strict' => true,
- 'phpdoc_order' => true,
- 'semicolon_after_instruction' => true,
- 'single_import_per_statement' => false,
- 'strict_comparison' => true,
- 'strict_param' => true,
- 'concat_space' => ['spacing' => 'one'],
- 'trailing_comma_in_multiline_array' => false,
- 'yoda_style' => null,
- 'single_line_throw' => false,
- 'no_superfluous_phpdoc_tags' => false
- ])
- ->setFinder($finder)
- ->setCacheFile(__DIR__.'/.php_cs.cache');
\ No newline at end of file
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..00b4e3f
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,128 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+ overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+contact@rancoud.com.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..69c87e6
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,26 @@
+## Contributing
+
+Hi there! I'm thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
+
+Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
+
+## Submitting a pull request
+
+1. [Fork](https://github.com/rancoud/Session/fork) and clone the repository
+2. Create a new branch: `git checkout -b my-branch-name`
+3. Make your change
+4. Push to your fork and [submit a pull request](https://github.com/rancoud/Session/compare)
+5. Pat your self on the back and wait for your pull request to be reviewed and merged.
+
+Here are a few things you can do that will increase the likelihood of your pull request being accepted:
+
+* Make sure the `README.md` and any other relevant **documentation are kept up-to-date**.
+* I try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.
+* Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**.
+* Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
+
+## Resources
+
+* [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
+* [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
+* [GitHub Help](https://help.github.com)
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..0df38dd
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,29 @@
+ARG PHPVERSION="8.4"
+FROM php:$PHPVERSION-cli-alpine
+
+RUN apk --update --no-cache add \
+ mysql-client \
+ && rm -rf /tmp/* /var/cache/apk/*
+
+RUN docker-php-ext-install \
+ pdo_mysql
+
+RUN apk add --no-cache \
+ $PHPIZE_DEPS \
+ linux-headers \
+ && pecl install xdebug-3.5.1 \
+ && docker-php-ext-enable xdebug \
+ && rm -rf /tmp/* /var/cache/apk/*
+
+RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer
+
+WORKDIR /app
+
+COPY composer.json .
+COPY composer.lock .
+RUN composer validate
+RUN composer install --no-interaction --no-progress
+
+COPY . .
+
+ENTRYPOINT ["./entrypoint.sh"]
diff --git a/LICENSE b/LICENSE
index 24ac99b..09407b4 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,21 @@
-MIT License
-
-Copyright (c) 2017 Rancoud
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+MIT License
+
+Copyright (c) 2017 Rancoud
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
index c8c1b87..b12839b 100644
--- a/README.md
+++ b/README.md
@@ -1,201 +1,247 @@
-# Session Package
-
-
-[](https://packagist.org/packages/rancoud/session)
-[](https://packagist.org/packages/rancoud/session)
-[](https://github.com/rancoud/session/blob/master/composer.json)
-[](https://github.com/rancoud/session/actions?workflow=test)
-[](https://codecov.io/gh/rancoud/session)
-[](https://packagist.org/packages/rancoud/session)
-
-Session.
-
-## Installation
-```php
-composer require rancoud/session
-```
-
-## Informations
-By default session is in read only (option read_and_close = 1).
-You can specify it using `Session::setReadWrite()` or `Session::setReadOnly()`
-
-Session::start() is not needed, but:
-* Session will automatically start in read only when using `get, has, hasKeyAndValue, getAll`
-* Session will automatically start in write mode when using `set, remove, getAndRemove, keepFlash, gc, regenerate`
-
-## How to use it?
-Set and get value from $_SESSION
-```php
-Session::set('key', 'value');
-$value = Session::get('key');
-```
-Use custom options
-```php
-// first way
-Session::setOption('name', 'custom_session_name');
-
-// second way
-Session::start(['cookie_lifetime' => 1440]);
-
-Session::set('key', 'value');
-$value = Session::get('key');
-```
-With encryption on default php session
-```php
-Session::useDefaultEncryptionDriver('keyForEncryption');
-Session::set('key', 'value');
-$value = Session::get('key');
-```
-With File driver
-```php
-Session::useFileDriver();
-Session::set('key', 'value');
-$value = Session::get('key');
-```
-With Database driver (you have to install rancoud/database)
-```php
-$conf = new \Rancoud\Database\Configurator([
- 'engine' => 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
-]);
-$db = new \Rancoud\Database\Database($conf);
-
-// for using a current connection
-Session::useCurrentDatabaseDriver($db);
-
-// for creating a new connection
-//Session::useNewDatabaseDriver($conf);
-
-Session::set('key', 'value');
-$value = Session::get('key');
-```
-With Redis driver (you have to install predis/predis)
-```php
-$params = [
- 'scheme' => 'tcp',
- 'host' => '127.0.0.1',
- 'port' => 6379,
-];
-$redis = new Predis\Client($params);
-
-// for using a current connection
-Session::useCurrentRedisDriver($redis);
-
-// for creating a new connection
-//Session::useNewRedisDriver($params);
-
-Session::set('key', 'value');
-$value = Session::get('key');
-```
-With your own driver implementing SessionHandlerInterface
-```php
-$driver = new MyCustomDriver();
-Session::useCustomDriver($driver);
-Session::set('key', 'value');
-$value = Session::get('key');
-```
-
-## Session
-### Static General Commands
-* start([options: array = []]): void
-* regenerate(): bool
-* destroy(): bool
-* commit(): void
-* rollback(): bool
-* unsaved(): bool
-* hasStarted(): bool
-* getId(): string
-* setId(id: string): string
-* gc(): void
-* setReadOnly(): void
-* setReadWrite(): void
-
-### Static Variables $_SESSION access
-* set(key: string, value: mixed): void
-* get(key: string): mixed
-* getAll(): array
-* getAndRemove(key: string): mixed
-* has(key: string): bool
-* hasKeyAndValue(key: string, value: mixed): bool
-* remove(key: string): void
-
-### Static Variables flash access
-Flash data are store in a separate variable.
-They will dissapear at the end of the script execution.
-You can use keepFlash for saving it in $_SESSION.
-When flash data is restore, it will be delete in $_SESSION.
-
-* setFlash(key: string, value: mixed): void
-* getFlash(key: string): mixed
-* getAllFlash(): array
-* hasFlash(key: string): bool
-* hasFlashKeyAndValue(key: string, value: mixed): bool
-* keepFlash([keys: array = []]): void
-* restoreFlashData(): void
-
-### Static Options
-* setOption(key: string, value): void
-* setOptions(options: array): void
-* getOption(key: string): mixed
-
-### Static Driver
-* getDriver(): \SessionHandlerInterface
-
-#### Static PHP Session Default Driver
-* useDefaultDriver(): void
-* useDefaultEncryptionDriver(key: string, [method: string|null = null]): void
-
-#### Static File Driver
-* useFileDriver(): void
-* useFileEncryptionDriver(key: string, [method: string|null = null]): void
-* setPrefixForFile(prefix: string): void
-
-#### Static Database Driver
-* useNewDatabaseDriver(configuration: \Rancoud\Database\Configurator|array): void
-* useCurrentDatabaseDriver(databaseInstance: \Rancoud\Database\Database): void
-* useNewDatabaseEncryptionDriver(configuration: \Rancoud\Database\Configurator|array, key: string, [method: string = null]): void
-* useCurrentDatabaseEncryptionDriver(databaseInstance: \Rancoud\Database\Database, key: string, [method: string = null]): void
-* setUserIdForDatabase(userId: int): void
-
-#### Static Redis Driver
-* useNewRedisDriver(configuration: array|string): void
-* useCurrentRedisDriver(redisInstance: \Predis\Client): void
-* useNewRedisEncryptionDriver(configuration: array|string, key: string, [method: string = null]): void
-* useCurrentRedisEncryptionDriver(redisInstance: \Predis\Client, key: string, [method: string = null]): void
-
-#### Static Custom Driver
-* useCustomDriver(customDriver: \SessionHandlerInterface): void
-
-## Driver Informations
-### Default
-Use SessionHandler
-### File
-Extends SessionHandler
-### Database
-You need to install
-```php
-composer require rancoud/database
-```
-```sql
-CREATE TABLE IF NOT EXISTS `sessions` (
- `id` varchar(128) NOT NULL,
- `id_user` int(10) unsigned DEFAULT NULL,
- `last_access` datetime NOT NULL,
- `content` text NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-```
-### Redis
-You need to install
-```php
-composer require predis/predis
-```
-
-## How to Dev
-`composer ci` for php-cs-fixer and phpunit and coverage
-`composer lint` for php-cs-fixer
-`composer test` for phpunit and coverage
\ No newline at end of file
+# Session Package
+
+
+[](https://packagist.org/packages/rancoud/session)
+[](https://packagist.org/packages/rancoud/session)
+[](https://github.com/rancoud/session/blob/master/composer.json)
+[](https://github.com/rancoud/session/actions/workflows/test.yml)
+[](https://codecov.io/gh/rancoud/session)
+
+Session.
+
+## Installation
+```php
+composer require rancoud/session
+```
+
+## Informations
+By default session is in read only (option read_and_close = 1).
+You can specify it using `Session::setReadWrite()` or `Session::setReadOnly()`
+
+Session::start() is not needed, but:
+* Session will automatically start in read only when using `get, has, hasKeyAndValue, getAll`
+* Session will automatically start in write mode when using `set, remove, getAndRemove, keepFlash, gc, regenerate`
+
+## How to use it?
+Set and get value from $_SESSION
+```php
+Session::set('key', 'value');
+$value = Session::get('key');
+```
+Use custom options
+```php
+// first way
+Session::setOption('name', 'custom_session_name');
+
+// second way
+Session::start(['cookie_lifetime' => 1440]);
+
+Session::set('key', 'value');
+$value = Session::get('key');
+```
+With encryption on default php session
+```php
+Session::useDefaultEncryptionDriver('keyForEncryption');
+Session::set('key', 'value');
+$value = Session::get('key');
+```
+With File driver
+```php
+Session::useFileDriver();
+Session::set('key', 'value');
+$value = Session::get('key');
+```
+With Database driver (you have to install rancoud/database)
+```php
+$conf = new \Rancoud\Database\Configurator([
+ 'engine' => 'mysql',
+ 'host' => '127.0.0.1',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+]);
+$db = new \Rancoud\Database\Database($conf);
+
+// for using a current connection
+Session::useCurrentDatabaseDriver($db);
+
+// for creating a new connection
+//Session::useNewDatabaseDriver($conf);
+
+Session::set('key', 'value');
+$value = Session::get('key');
+```
+With Redis driver (you have to install predis/predis)
+```php
+$params = [
+ 'scheme' => 'tcp',
+ 'host' => '127.0.0.1',
+ 'port' => 6379,
+];
+$redis = new Predis\Client($params);
+
+// for using a current connection
+Session::useCurrentRedisDriver($redis);
+
+// for creating a new connection
+//Session::useNewRedisDriver($params);
+
+Session::set('key', 'value');
+$value = Session::get('key');
+```
+With your own driver implementing `SessionHandlerInterface` and/or `SessionUpdateTimestampHandlerInterface`
+```php
+$driver = new MyCustomDriver();
+Session::useCustomDriver($driver);
+Session::set('key', 'value');
+$value = Session::get('key');
+```
+
+## Session
+### Static General Commands
+* start([options: array = []]): void
+* regenerate(): bool
+* destroy(): bool
+* commit(): void
+* rollback(): bool
+* unsaved(): bool
+* hasStarted(): bool
+* getId(): string
+* setId(id: string): string
+* gc(): void
+* setReadOnly(): void
+* setReadWrite(): void
+* isReadOnly(): bool
+
+### Static Variables $_SESSION access
+* set(key: string, value: mixed): void
+* get(key: string): mixed
+* getAll(): array
+* getAndRemove(key: string): mixed
+* has(key: string): bool
+* hasKeyAndValue(key: string, value: mixed): bool
+* remove(key: string): void
+
+### Static Variables flash access
+Flash data are store in a separate variable.
+They will dissapear at the end of the script execution or after `commit()` `unsaved()`.
+You can use keepFlash for saving it in $_SESSION.
+When flash data is restore, it will be delete in $_SESSION.
+
+* setFlash(key: string, value: mixed): void
+* getFlash(key: string): mixed
+* getAllFlash(): array
+* hasFlash(key: string): bool
+* hasFlashKeyAndValue(key: string, value: mixed): bool
+* keepFlash([keys: array = []]): void
+
+### Static Options
+* setOption(key: string, value): void
+* setOptions(options: array): void
+* getOption(key: string): mixed
+
+### Static Driver
+* getDriver(): \SessionHandlerInterface
+
+#### Static PHP Session Default Driver
+* useDefaultDriver(): void
+* useDefaultEncryptionDriver(key: string, [method: string|null = null]): void
+* setLengthSessionID(length: int): void
+* getLengthSessionID(): int
+
+#### Static File Driver
+* useFileDriver(): void
+* useFileEncryptionDriver(key: string, [method: string|null = null]): void
+* setPrefixForFile(prefix: string): void
+* setLengthSessionID(length: int): void
+* getLengthSessionID(): int
+
+#### Static Database Driver
+* useNewDatabaseDriver(configuration: \Rancoud\Database\Configurator|array): void
+* useCurrentDatabaseDriver(databaseInstance: \Rancoud\Database\Database): void
+* useNewDatabaseEncryptionDriver(configuration: \Rancoud\Database\Configurator|array, key: string, [method: string = null]): void
+* useCurrentDatabaseEncryptionDriver(databaseInstance: \Rancoud\Database\Database, key: string, [method: string = null]): void
+* setUserIdForDatabase(userId: int): void
+* setLengthSessionID(length: int): void
+* getLengthSessionID(): int
+* deleteUserSessionsInDatabase(int $userID): void
+* deleteAnonymousSessionsInDatabase(): int
+
+#### Static Redis Driver
+* useNewRedisDriver(configuration: array|string): void
+* useCurrentRedisDriver(redisInstance: \Predis\Client): void
+* useNewRedisEncryptionDriver(configuration: array|string, key: string, [method: string = null]): void
+* useCurrentRedisEncryptionDriver(redisInstance: \Predis\Client, key: string, [method: string = null]): void
+* setLengthSessionID(length: int): void
+* getLengthSessionID(): int
+
+#### Static Custom Driver
+* useCustomDriver(customDriver: \SessionHandlerInterface): void
+
+## Session options
+List of session options you can change:
+* save_path
+* name
+* save_handler
+* auto_start
+* gc_probability
+* gc_divisor
+* gc_maxlifetime
+* serialize_handler
+* cookie_lifetime
+* cookie_path
+* cookie_domain
+* cookie_secure
+* cookie_httponly
+* cookie_samesite
+* use_strict_mode
+* use_cookies
+* use_only_cookies
+* referer_check
+* cache_limiter
+* cache_expire
+* use_trans_sid
+* trans_sid_tags
+* trans_sid_hosts
+* sid_length
+* sid_bits_per_character
+* upload_progress.enabled
+* upload_progress.cleanup
+* upload_progress.prefix
+* upload_progress.name
+* upload_progress.freq
+* upload_progress.min_freq
+* lazy_write
+* read_and_close
+
+## Driver Informations
+### Default
+Use SessionHandler
+
+### File
+Extends SessionHandler
+
+### Database
+You need to install
+```php
+composer require rancoud/database
+```
+
+```sql
+CREATE TABLE IF NOT EXISTS `sessions` (
+ `id` varchar(128) NOT NULL,
+ `id_user` int(10) unsigned DEFAULT NULL,
+ `last_access` datetime NOT NULL,
+ `content` text NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+```
+
+### Redis
+You need to install
+```php
+composer require predis/predis
+```
+
+## How to Dev
+`docker compose build && docker compose run lib composer ci` for launching tests
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..9b044b8
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,13 @@
+# Security Policy
+
+## Reporting a Vulnerability
+
+The project maintainers take security seriously. If you discover a security
+issue, please bring it to their attention right away!
+
+**Please _DO NOT_ file a public issue**, instead send your report privately to
+contact@rancoud.com .
+
+Security reports are greatly appreciated.
+
+We currently do not offer a paid security bounty program.
diff --git a/composer.json b/composer.json
index c6de6c1..89dd7c3 100644
--- a/composer.json
+++ b/composer.json
@@ -15,16 +15,22 @@
"Rancoud\\Session\\": "src"
}
},
+ "autoload-dev": {
+ "psr-4": {
+ "tests\\": "tests"
+ }
+ },
"require": {
- "php": ">=7.4.0",
- "ext-openssl": ">=7.4.0"
+ "php": ">=8.4.0",
+ "ext-openssl": "*",
+ "ext-session": "*",
+ "ext-mbstring": "*"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^2.16",
- "phpunit/phpunit": "^9.1",
- "predis/predis": "^1.1",
- "rancoud/database": "^4.0",
- "squizlabs/php_codesniffer": "^3.5"
+ "friendsofphp/php-cs-fixer": "3.95.1",
+ "phpunit/phpunit": "12.5.22",
+ "predis/predis": "3.4.2",
+ "rancoud/database": "7.0.3"
},
"scripts": {
"ci": [
@@ -32,11 +38,10 @@
"@test"
],
"lint": [
- "phpcbf",
- "php-cs-fixer fix"
+ "php-cs-fixer fix -vvv"
],
"test": [
- "phpunit --colors --coverage-html ./coverage"
+ "phpunit --colors --display-all-issues --coverage-html ./coverage --coverage-clover coverage/clover.xml"
]
}
}
diff --git a/composer.lock b/composer.lock
index e7353ec..ce63cef 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,33 +4,177 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "7204fb14ec0ef8f966236c6d2b3aa6e0",
+ "content-hash": "b39a2acc6b6ece9034e7f23c8bb51819",
"packages": [],
"packages-dev": [
+ {
+ "name": "clue/ndjson-react",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-ndjson.git",
+ "reference": "392dc165fce93b5bb5c637b67e59619223c931b0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0",
+ "reference": "392dc165fce93b5bb5c637b67e59619223c931b0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\NDJson\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-ndjson",
+ "keywords": [
+ "NDJSON",
+ "json",
+ "jsonlines",
+ "newline",
+ "reactphp",
+ "streaming"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-ndjson/issues",
+ "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-12-23T10:58:28+00:00"
+ },
+ {
+ "name": "composer/pcre",
+ "version": "3.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/pcre.git",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4 || ^8.0"
+ },
+ "conflict": {
+ "phpstan/phpstan": "<1.11.10"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.12 || ^2",
+ "phpstan/phpstan-strict-rules": "^1 || ^2",
+ "phpunit/phpunit": "^8 || ^9"
+ },
+ "type": "library",
+ "extra": {
+ "phpstan": {
+ "includes": [
+ "extension.neon"
+ ]
+ },
+ "branch-alias": {
+ "dev-main": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Pcre\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
+ "keywords": [
+ "PCRE",
+ "preg",
+ "regex",
+ "regular expression"
+ ],
+ "support": {
+ "issues": "https://github.com/composer/pcre/issues",
+ "source": "https://github.com/composer/pcre/tree/3.3.2"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-11-12T16:29:46+00:00"
+ },
{
"name": "composer/semver",
- "version": "1.5.1",
+ "version": "3.4.4",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
- "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de"
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
- "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
+ "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
"shasum": ""
},
"require": {
- "php": "^5.3.2 || ^7.0"
+ "php": "^5.3.2 || ^7.0 || ^8.0"
},
"require-dev": {
- "phpunit/phpunit": "^4.5 || ^5.0.5"
+ "phpstan/phpstan": "^1.11",
+ "symfony/phpunit-bridge": "^3 || ^7"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.x-dev"
+ "dev-main": "3.x-dev"
}
},
"autoload": {
@@ -66,28 +210,46 @@
"validation",
"versioning"
],
- "time": "2020-01-13T12:06:48+00:00"
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/semver/issues",
+ "source": "https://github.com/composer/semver/tree/3.4.4"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ }
+ ],
+ "time": "2025-08-20T19:15:30+00:00"
},
{
"name": "composer/xdebug-handler",
- "version": "1.4.2",
+ "version": "3.0.5",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
- "reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51"
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51",
- "reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51",
+ "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
"shasum": ""
},
"require": {
- "php": "^5.3.2 || ^7.0 || ^8.0",
- "psr/log": "^1.0"
+ "composer/pcre": "^1 || ^2 || ^3",
+ "php": "^7.2.5 || ^8.0",
+ "psr/log": "^1 || ^2 || ^3"
},
"require-dev": {
- "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
+ "phpstan/phpstan": "^1.0",
+ "phpstan/phpstan-strict-rules": "^1.1",
+ "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
},
"type": "library",
"autoload": {
@@ -110,6 +272,11 @@
"Xdebug",
"performance"
],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/xdebug-handler/issues",
+ "source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
+ },
"funding": [
{
"url": "https://packagist.com",
@@ -124,40 +291,55 @@
"type": "tidelift"
}
],
- "time": "2020-06-04T11:16:35+00:00"
+ "time": "2024-05-06T16:37:16+00:00"
},
{
- "name": "doctrine/annotations",
- "version": "1.10.3",
+ "name": "ergebnis/agent-detector",
+ "version": "1.2.0",
"source": {
"type": "git",
- "url": "https://github.com/doctrine/annotations.git",
- "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d"
+ "url": "https://github.com/ergebnis/agent-detector.git",
+ "reference": "e211f17928c8b95a51e06040792d57f5462fb271"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/annotations/zipball/5db60a4969eba0e0c197a19c077780aadbc43c5d",
- "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d",
+ "url": "https://api.github.com/repos/ergebnis/agent-detector/zipball/e211f17928c8b95a51e06040792d57f5462fb271",
+ "reference": "e211f17928c8b95a51e06040792d57f5462fb271",
"shasum": ""
},
"require": {
- "doctrine/lexer": "1.*",
- "ext-tokenizer": "*",
- "php": "^7.1 || ^8.0"
+ "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0 || ~8.6.0"
},
"require-dev": {
- "doctrine/cache": "1.*",
- "phpunit/phpunit": "^7.5"
+ "ergebnis/composer-normalize": "^2.51.0",
+ "ergebnis/license": "^2.7.0",
+ "ergebnis/php-cs-fixer-config": "^6.60.2",
+ "ergebnis/phpstan-rules": "^2.13.1",
+ "ergebnis/phpunit-slow-test-detector": "^2.24.0",
+ "ergebnis/rector-rules": "^1.18.1",
+ "fakerphp/faker": "^1.24.1",
+ "infection/infection": "^0.26.6",
+ "phpstan/extension-installer": "^1.4.3",
+ "phpstan/phpstan": "^2.1.54",
+ "phpstan/phpstan-deprecation-rules": "^2.0.4",
+ "phpstan/phpstan-phpunit": "^2.0.16",
+ "phpstan/phpstan-strict-rules": "^2.0.10",
+ "phpunit/phpunit": "^9.6.34",
+ "rector/rector": "^2.4.2"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.9.x-dev"
+ "dev-main": "1.2-dev"
+ },
+ "composer-normalize": {
+ "indent-size": 2,
+ "indent-style": "space"
}
},
"autoload": {
"psr-4": {
- "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
+ "Ergebnis\\AgentDetector\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -166,70 +348,44 @@
],
"authors": [
{
- "name": "Guilherme Blanco",
- "email": "guilhermeblanco@gmail.com"
- },
- {
- "name": "Roman Borschel",
- "email": "roman@code-factory.org"
- },
- {
- "name": "Benjamin Eberlei",
- "email": "kontakt@beberlei.de"
- },
- {
- "name": "Jonathan Wage",
- "email": "jonwage@gmail.com"
- },
- {
- "name": "Johannes Schmitt",
- "email": "schmittjoh@gmail.com"
+ "name": "Andreas Möller",
+ "email": "am@localheinz.com",
+ "homepage": "https://localheinz.com"
}
],
- "description": "Docblock Annotations Parser",
- "homepage": "http://www.doctrine-project.org",
- "keywords": [
- "annotations",
- "docblock",
- "parser"
- ],
- "time": "2020-05-25T17:24:27+00:00"
+ "description": "Provides a detector for detecting the presence of an agent.",
+ "homepage": "https://github.com/ergebnis/agent-detector",
+ "support": {
+ "issues": "https://github.com/ergebnis/agent-detector/issues",
+ "security": "https://github.com/ergebnis/agent-detector/blob/main/.github/SECURITY.md",
+ "source": "https://github.com/ergebnis/agent-detector"
+ },
+ "time": "2026-05-07T08:19:07+00:00"
},
{
- "name": "doctrine/instantiator",
- "version": "1.3.1",
+ "name": "evenement/evenement",
+ "version": "v3.0.2",
"source": {
"type": "git",
- "url": "https://github.com/doctrine/instantiator.git",
- "reference": "f350df0268e904597e3bd9c4685c53e0e333feea"
+ "url": "https://github.com/igorw/evenement.git",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea",
- "reference": "f350df0268e904597e3bd9c4685c53e0e333feea",
+ "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc",
"shasum": ""
},
"require": {
- "php": "^7.1 || ^8.0"
+ "php": ">=7.0"
},
"require-dev": {
- "doctrine/coding-standard": "^6.0",
- "ext-pdo": "*",
- "ext-phar": "*",
- "phpbench/phpbench": "^0.13",
- "phpstan/phpstan-phpunit": "^0.11",
- "phpstan/phpstan-shim": "^0.11",
- "phpunit/phpunit": "^7.0"
+ "phpunit/phpunit": "^9 || ^6"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.2.x-dev"
- }
- },
"autoload": {
"psr-4": {
- "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+ "Evenement\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -238,64 +394,53 @@
],
"authors": [
{
- "name": "Marco Pivetta",
- "email": "ocramius@gmail.com",
- "homepage": "http://ocramius.github.com/"
+ "name": "Igor Wiedler",
+ "email": "igor@wiedler.ch"
}
],
- "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
- "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
+ "description": "Événement is a very simple event dispatching library for PHP",
"keywords": [
- "constructor",
- "instantiate"
- ],
- "funding": [
- {
- "url": "https://www.doctrine-project.org/sponsorship.html",
- "type": "custom"
- },
- {
- "url": "https://www.patreon.com/phpdoctrine",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
- "type": "tidelift"
- }
+ "event-dispatcher",
+ "event-emitter"
],
- "time": "2020-05-29T17:27:14+00:00"
+ "support": {
+ "issues": "https://github.com/igorw/evenement/issues",
+ "source": "https://github.com/igorw/evenement/tree/v3.0.2"
+ },
+ "time": "2023-08-08T05:53:35+00:00"
},
{
- "name": "doctrine/lexer",
- "version": "1.2.1",
+ "name": "fidry/cpu-core-counter",
+ "version": "1.3.0",
"source": {
"type": "git",
- "url": "https://github.com/doctrine/lexer.git",
- "reference": "e864bbf5904cb8f5bb334f99209b48018522f042"
+ "url": "https://github.com/theofidry/cpu-core-counter.git",
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042",
- "reference": "e864bbf5904cb8f5bb334f99209b48018522f042",
+ "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678",
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
- "doctrine/coding-standard": "^6.0",
- "phpstan/phpstan": "^0.11.8",
- "phpunit/phpunit": "^8.2"
+ "fidry/makefile": "^0.2.0",
+ "fidry/php-cs-fixer-config": "^1.1.2",
+ "phpstan/extension-installer": "^1.2.0",
+ "phpstan/phpstan": "^2.0",
+ "phpstan/phpstan-deprecation-rules": "^2.0.0",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpstan/phpstan-strict-rules": "^2.0",
+ "phpunit/phpunit": "^8.5.31 || ^9.5.26",
+ "webmozarts/strict-phpunit": "^7.5"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.2.x-dev"
- }
- },
"autoload": {
"psr-4": {
- "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer"
+ "Fidry\\CpuCoreCounter\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -304,95 +449,86 @@
],
"authors": [
{
- "name": "Guilherme Blanco",
- "email": "guilhermeblanco@gmail.com"
- },
- {
- "name": "Roman Borschel",
- "email": "roman@code-factory.org"
- },
- {
- "name": "Johannes Schmitt",
- "email": "schmittjoh@gmail.com"
+ "name": "Théo FIDRY",
+ "email": "theo.fidry@gmail.com"
}
],
- "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
- "homepage": "https://www.doctrine-project.org/projects/lexer.html",
+ "description": "Tiny utility to get the number of CPU cores.",
"keywords": [
- "annotations",
- "docblock",
- "lexer",
- "parser",
- "php"
+ "CPU",
+ "core"
],
+ "support": {
+ "issues": "https://github.com/theofidry/cpu-core-counter/issues",
+ "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0"
+ },
"funding": [
{
- "url": "https://www.doctrine-project.org/sponsorship.html",
- "type": "custom"
- },
- {
- "url": "https://www.patreon.com/phpdoctrine",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
- "type": "tidelift"
+ "url": "https://github.com/theofidry",
+ "type": "github"
}
],
- "time": "2020-05-25T17:44:05+00:00"
+ "time": "2025-08-14T07:29:31+00:00"
},
{
"name": "friendsofphp/php-cs-fixer",
- "version": "v2.16.4",
+ "version": "v3.95.1",
"source": {
"type": "git",
- "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
- "reference": "1023c3458137ab052f6ff1e09621a721bfdeca13"
+ "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
+ "reference": "a9727678fbd12997f1d9de8f4a37824ed9df1065"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/1023c3458137ab052f6ff1e09621a721bfdeca13",
- "reference": "1023c3458137ab052f6ff1e09621a721bfdeca13",
+ "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/a9727678fbd12997f1d9de8f4a37824ed9df1065",
+ "reference": "a9727678fbd12997f1d9de8f4a37824ed9df1065",
"shasum": ""
},
"require": {
- "composer/semver": "^1.4",
- "composer/xdebug-handler": "^1.2",
- "doctrine/annotations": "^1.2",
+ "clue/ndjson-react": "^1.3",
+ "composer/semver": "^3.4",
+ "composer/xdebug-handler": "^3.0.5",
+ "ergebnis/agent-detector": "^1.1.1",
+ "ext-filter": "*",
+ "ext-hash": "*",
"ext-json": "*",
"ext-tokenizer": "*",
- "php": "^5.6 || ^7.0",
- "php-cs-fixer/diff": "^1.3",
- "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0",
- "symfony/event-dispatcher": "^3.0 || ^4.0 || ^5.0",
- "symfony/filesystem": "^3.0 || ^4.0 || ^5.0",
- "symfony/finder": "^3.0 || ^4.0 || ^5.0",
- "symfony/options-resolver": "^3.0 || ^4.0 || ^5.0",
- "symfony/polyfill-php70": "^1.0",
- "symfony/polyfill-php72": "^1.4",
- "symfony/process": "^3.0 || ^4.0 || ^5.0",
- "symfony/stopwatch": "^3.0 || ^4.0 || ^5.0"
+ "fidry/cpu-core-counter": "^1.3",
+ "php": "^7.4 || ^8.0",
+ "react/child-process": "^0.6.6",
+ "react/event-loop": "^1.5",
+ "react/socket": "^1.16",
+ "react/stream": "^1.4",
+ "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0",
+ "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/polyfill-mbstring": "^1.33",
+ "symfony/polyfill-php80": "^1.33",
+ "symfony/polyfill-php81": "^1.33",
+ "symfony/polyfill-php84": "^1.33",
+ "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2 || ^8.0",
+ "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0"
},
"require-dev": {
- "johnkary/phpunit-speedtrap": "^1.1 || ^2.0 || ^3.0",
- "justinrainbow/json-schema": "^5.0",
- "keradus/cli-executor": "^1.2",
- "mikey179/vfsstream": "^1.6",
- "php-coveralls/php-coveralls": "^2.1",
- "php-cs-fixer/accessible-object": "^1.0",
- "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.1",
- "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.1",
- "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.1",
- "phpunitgoodpractices/traits": "^1.8",
- "symfony/phpunit-bridge": "^5.1",
- "symfony/yaml": "^3.0 || ^4.0 || ^5.0"
+ "facile-it/paraunit": "^1.3.1 || ^2.8.0",
+ "infection/infection": "^0.32.6",
+ "justinrainbow/json-schema": "^6.8.0",
+ "keradus/cli-executor": "^2.3",
+ "mikey179/vfsstream": "^1.6.12",
+ "php-coveralls/php-coveralls": "^2.9.1",
+ "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.8",
+ "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.8",
+ "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.55",
+ "symfony/polyfill-php85": "^1.33",
+ "symfony/var-dumper": "^5.4.48 || ^6.4.32 || ^7.4.4 || ^8.0.8",
+ "symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0.8"
},
"suggest": {
"ext-dom": "For handling output formats in XML",
- "ext-mbstring": "For handling non-UTF8 characters.",
- "php-cs-fixer/phpunit-constraint-isidenticalstring": "For IsIdenticalString constraint.",
- "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "For XmlMatchesXsd constraint.",
- "symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible."
+ "ext-mbstring": "For handling non-UTF8 characters."
},
"bin": [
"php-cs-fixer"
@@ -402,17 +538,8 @@
"psr-4": {
"PhpCsFixer\\": "src/"
},
- "classmap": [
- "tests/Test/AbstractFixerTestCase.php",
- "tests/Test/AbstractIntegrationCaseFactory.php",
- "tests/Test/AbstractIntegrationTestCase.php",
- "tests/Test/Assert/AssertTokensTrait.php",
- "tests/Test/IntegrationCase.php",
- "tests/Test/IntegrationCaseFactory.php",
- "tests/Test/IntegrationCaseFactoryInterface.php",
- "tests/Test/InternalIntegrationCaseFactory.php",
- "tests/Test/IsIdenticalConstraint.php",
- "tests/TestCase.php"
+ "exclude-from-classmap": [
+ "src/**/Internal/"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -430,47 +557,59 @@
}
],
"description": "A tool to automatically fix PHP code style",
+ "keywords": [
+ "Static code analysis",
+ "fixer",
+ "standards",
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
+ "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.95.1"
+ },
"funding": [
{
"url": "https://github.com/keradus",
"type": "github"
}
],
- "time": "2020-06-27T23:57:46+00:00"
+ "time": "2026-04-12T17:00:09+00:00"
},
{
"name": "myclabs/deep-copy",
- "version": "1.10.1",
+ "version": "1.13.4",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5"
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
- "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
- "replace": {
- "myclabs/deep-copy": "self.version"
+ "conflict": {
+ "doctrine/collections": "<1.6.8",
+ "doctrine/common": "<2.13.3 || >=3 <3.2.2"
},
"require-dev": {
- "doctrine/collections": "^1.0",
- "doctrine/common": "^2.6",
- "phpunit/phpunit": "^7.1"
+ "doctrine/collections": "^1.6.8",
+ "doctrine/common": "^2.13.3 || ^3.2.2",
+ "phpspec/prophecy": "^1.10",
+ "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
},
"type": "library",
"autoload": {
- "psr-4": {
- "DeepCopy\\": "src/DeepCopy/"
- },
"files": [
"src/DeepCopy/deep_copy.php"
- ]
+ ],
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -484,83 +623,102 @@
"object",
"object graph"
],
+ "support": {
+ "issues": "https://github.com/myclabs/DeepCopy/issues",
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
+ },
"funding": [
{
"url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
"type": "tidelift"
}
],
- "time": "2020-06-29T13:22:24+00:00"
+ "time": "2025-08-01T08:46:24+00:00"
},
{
- "name": "paragonie/random_compat",
- "version": "v9.99.99",
+ "name": "nikic/php-parser",
+ "version": "v5.7.0",
"source": {
"type": "git",
- "url": "https://github.com/paragonie/random_compat.git",
- "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95"
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
- "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
"shasum": ""
},
"require": {
- "php": "^7"
+ "ext-ctype": "*",
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "php": ">=7.4"
},
"require-dev": {
- "phpunit/phpunit": "4.*|5.*",
- "vimeo/psalm": "^1"
- },
- "suggest": {
- "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ "ircmaxell/php-yacc": "^0.0.7",
+ "phpunit/phpunit": "^9.0"
},
+ "bin": [
+ "bin/php-parse"
+ ],
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
"authors": [
{
- "name": "Paragon Initiative Enterprises",
- "email": "security@paragonie.com",
- "homepage": "https://paragonie.com"
+ "name": "Nikita Popov"
}
],
- "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+ "description": "A PHP parser written in PHP",
"keywords": [
- "csprng",
- "polyfill",
- "pseudorandom",
- "random"
+ "parser",
+ "php"
],
- "time": "2018-07-02T15:55:56+00:00"
+ "support": {
+ "issues": "https://github.com/nikic/PHP-Parser/issues",
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
+ },
+ "time": "2025-12-06T11:56:16+00:00"
},
{
"name": "phar-io/manifest",
- "version": "1.0.3",
+ "version": "2.0.4",
"source": {
"type": "git",
"url": "https://github.com/phar-io/manifest.git",
- "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
+ "reference": "54750ef60c58e43759730615a392c31c80e23176"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
- "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
+ "reference": "54750ef60c58e43759730615a392c31c80e23176",
"shasum": ""
},
"require": {
"ext-dom": "*",
+ "ext-libxml": "*",
"ext-phar": "*",
- "phar-io/version": "^2.0",
- "php": "^5.6 || ^7.0"
+ "ext-xmlwriter": "*",
+ "phar-io/version": "^3.0.1",
+ "php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "2.0.x-dev"
}
},
"autoload": {
@@ -590,24 +748,34 @@
}
],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
- "time": "2018-07-08T19:23:20+00:00"
+ "support": {
+ "issues": "https://github.com/phar-io/manifest/issues",
+ "source": "https://github.com/phar-io/manifest/tree/2.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-03T12:33:53+00:00"
},
{
"name": "phar-io/version",
- "version": "2.0.1",
+ "version": "3.2.1",
"source": {
"type": "git",
"url": "https://github.com/phar-io/version.git",
- "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
- "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
"shasum": ""
},
"require": {
- "php": "^5.6 || ^7.0"
+ "php": "^7.2 || ^8.0"
},
"type": "library",
"autoload": {
@@ -637,30 +805,52 @@
}
],
"description": "Library for handling version information and constraints",
- "time": "2018-07-08T19:19:57+00:00"
+ "support": {
+ "issues": "https://github.com/phar-io/version/issues",
+ "source": "https://github.com/phar-io/version/tree/3.2.1"
+ },
+ "time": "2022-02-21T01:04:05+00:00"
},
{
- "name": "php-cs-fixer/diff",
- "version": "v1.3.0",
+ "name": "phpunit/php-code-coverage",
+ "version": "12.5.7",
"source": {
"type": "git",
- "url": "https://github.com/PHP-CS-Fixer/diff.git",
- "reference": "78bb099e9c16361126c86ce82ec4405ebab8e756"
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "186dab580576598076de6818596d12b61801880e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/78bb099e9c16361126c86ce82ec4405ebab8e756",
- "reference": "78bb099e9c16361126c86ce82ec4405ebab8e756",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/186dab580576598076de6818596d12b61801880e",
+ "reference": "186dab580576598076de6818596d12b61801880e",
"shasum": ""
},
"require": {
- "php": "^5.6 || ^7.0"
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-xmlwriter": "*",
+ "nikic/php-parser": "^5.7.0",
+ "php": ">=8.3",
+ "phpunit/php-text-template": "^5.0",
+ "sebastian/complexity": "^5.0",
+ "sebastian/environment": "^8.1.2",
+ "sebastian/lines-of-code": "^4.0.1",
+ "sebastian/version": "^6.0",
+ "theseer/tokenizer": "^2.0.1"
},
"require-dev": {
- "phpunit/phpunit": "^5.7.23 || ^6.4.3",
- "symfony/process": "^3.3"
+ "phpunit/phpunit": "^12.5.28"
+ },
+ "suggest": {
+ "ext-pcov": "PHP extension that provides line coverage",
+ "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
},
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "12.5.x-dev"
+ }
+ },
"autoload": {
"classmap": [
"src/"
@@ -672,274 +862,355 @@
],
"authors": [
{
- "name": "Kore Nordmann",
- "email": "mail@kore-nordmann.de"
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+ "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.7"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
},
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
},
{
- "name": "SpacePossum"
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage",
+ "type": "tidelift"
}
],
- "description": "sebastian/diff v2 backport support for PHP5.6",
- "homepage": "https://github.com/PHP-CS-Fixer",
- "keywords": [
- "diff"
- ],
- "time": "2018-02-15T16:58:55+00:00"
+ "time": "2026-06-01T13:24:19+00:00"
},
{
- "name": "phpdocumentor/reflection-common",
- "version": "2.2.0",
+ "name": "phpunit/php-file-iterator",
+ "version": "6.0.1",
"source": {
"type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
- "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
- "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5",
+ "reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5",
"shasum": ""
},
"require": {
- "php": "^7.2 || ^8.0"
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-2.x": "2.x-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src/"
- }
+ "classmap": [
+ "src/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
"authors": [
{
- "name": "Jaap van Otterdijk",
- "email": "opensource@ijaap.nl"
- }
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
],
- "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
- "homepage": "http://www.phpdoc.org",
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
"keywords": [
- "FQSEN",
- "phpDocumentor",
- "phpdoc",
- "reflection",
- "static analysis"
+ "filesystem",
+ "iterator"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+ "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator",
+ "type": "tidelift"
+ }
],
- "time": "2020-06-27T09:03:43+00:00"
+ "time": "2026-02-02T14:04:18+00:00"
},
{
- "name": "phpdocumentor/reflection-docblock",
- "version": "5.1.0",
+ "name": "phpunit/php-invoker",
+ "version": "6.0.0",
"source": {
"type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e"
+ "url": "https://github.com/sebastianbergmann/php-invoker.git",
+ "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e",
- "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406",
+ "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406",
"shasum": ""
},
"require": {
- "ext-filter": "^7.1",
- "php": "^7.2",
- "phpdocumentor/reflection-common": "^2.0",
- "phpdocumentor/type-resolver": "^1.0",
- "webmozart/assert": "^1"
+ "php": ">=8.3"
},
"require-dev": {
- "doctrine/instantiator": "^1",
- "mockery/mockery": "^1"
+ "ext-pcntl": "*",
+ "phpunit/phpunit": "^12.0"
+ },
+ "suggest": {
+ "ext-pcntl": "*"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.x-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src"
- }
+ "classmap": [
+ "src/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
"authors": [
{
- "name": "Mike van Riel",
- "email": "me@mikevanriel.com"
- },
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Invoke callables with a timeout",
+ "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+ "keywords": [
+ "process"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+ "security": "https://github.com/sebastianbergmann/php-invoker/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0"
+ },
+ "funding": [
{
- "name": "Jaap van Otterdijk",
- "email": "account@ijaap.nl"
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
}
],
- "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
- "time": "2020-02-22T12:28:44+00:00"
+ "time": "2025-02-07T04:58:58+00:00"
},
{
- "name": "phpdocumentor/type-resolver",
- "version": "1.3.0",
+ "name": "phpunit/php-text-template",
+ "version": "5.0.0",
"source": {
"type": "git",
- "url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "e878a14a65245fbe78f8080eba03b47c3b705651"
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e878a14a65245fbe78f8080eba03b47c3b705651",
- "reference": "e878a14a65245fbe78f8080eba03b47c3b705651",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53",
+ "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53",
"shasum": ""
},
"require": {
- "php": "^7.2 || ^8.0",
- "phpdocumentor/reflection-common": "^2.0"
+ "php": ">=8.3"
},
"require-dev": {
- "ext-tokenizer": "*"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-main": "5.0-dev"
}
},
"autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src"
- }
+ "classmap": [
+ "src/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
"authors": [
{
- "name": "Mike van Riel",
- "email": "me@mikevanriel.com"
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+ "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
}
],
- "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
- "time": "2020-06-27T10:12:23+00:00"
+ "time": "2025-02-07T04:59:16+00:00"
},
{
- "name": "phpspec/prophecy",
- "version": "v1.10.3",
+ "name": "phpunit/php-timer",
+ "version": "8.0.0",
"source": {
"type": "git",
- "url": "https://github.com/phpspec/prophecy.git",
- "reference": "451c3cd1418cf640de218914901e51b064abb093"
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093",
- "reference": "451c3cd1418cf640de218914901e51b064abb093",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc",
+ "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc",
"shasum": ""
},
"require": {
- "doctrine/instantiator": "^1.0.2",
- "php": "^5.3|^7.0",
- "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
- "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0",
- "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0"
+ "php": ">=8.3"
},
"require-dev": {
- "phpspec/phpspec": "^2.5 || ^3.2",
- "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.10.x-dev"
+ "dev-main": "8.0-dev"
}
},
"autoload": {
- "psr-4": {
- "Prophecy\\": "src/Prophecy"
- }
+ "classmap": [
+ "src/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
"authors": [
{
- "name": "Konstantin Kudryashov",
- "email": "ever.zet@gmail.com",
- "homepage": "http://everzet.com"
- },
- {
- "name": "Marcello Duarte",
- "email": "marcello.duarte@gmail.com"
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
}
],
- "description": "Highly opinionated mocking framework for PHP 5.3+",
- "homepage": "https://github.com/phpspec/prophecy",
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
"keywords": [
- "Double",
- "Dummy",
- "fake",
- "mock",
- "spy",
- "stub"
+ "timer"
],
- "time": "2020-03-05T15:02:03+00:00"
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+ "security": "https://github.com/sebastianbergmann/php-timer/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:59:38+00:00"
},
{
- "name": "phpunit/php-code-coverage",
- "version": "8.0.2",
+ "name": "phpunit/phpunit",
+ "version": "12.5.22",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc"
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "e07667405f0f43317a1799d3907c43a123bc5587"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc",
- "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e07667405f0f43317a1799d3907c43a123bc5587",
+ "reference": "e07667405f0f43317a1799d3907c43a123bc5587",
"shasum": ""
},
"require": {
"ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
"ext-xmlwriter": "*",
- "php": "^7.3",
- "phpunit/php-file-iterator": "^3.0",
- "phpunit/php-text-template": "^2.0",
- "phpunit/php-token-stream": "^4.0",
- "sebastian/code-unit-reverse-lookup": "^2.0",
- "sebastian/environment": "^5.0",
- "sebastian/version": "^3.0",
- "theseer/tokenizer": "^1.1.3"
- },
- "require-dev": {
- "phpunit/phpunit": "^9.0"
- },
- "suggest": {
- "ext-pcov": "*",
- "ext-xdebug": "*"
+ "myclabs/deep-copy": "^1.13.4",
+ "phar-io/manifest": "^2.0.4",
+ "phar-io/version": "^3.2.1",
+ "php": ">=8.3",
+ "phpunit/php-code-coverage": "^12.5.6",
+ "phpunit/php-file-iterator": "^6.0.1",
+ "phpunit/php-invoker": "^6.0.0",
+ "phpunit/php-text-template": "^5.0.0",
+ "phpunit/php-timer": "^8.0.0",
+ "sebastian/cli-parser": "^4.2.0",
+ "sebastian/comparator": "^7.1.6",
+ "sebastian/diff": "^7.0.0",
+ "sebastian/environment": "^8.1.0",
+ "sebastian/exporter": "^7.0.2",
+ "sebastian/global-state": "^8.0.2",
+ "sebastian/object-enumerator": "^7.0.0",
+ "sebastian/recursion-context": "^7.0.1",
+ "sebastian/type": "^6.0.3",
+ "sebastian/version": "^6.0.0",
+ "staabm/side-effects-detector": "^1.0.5"
},
+ "bin": [
+ "phpunit"
+ ],
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "8.0-dev"
+ "dev-main": "12.5-dev"
}
},
"autoload": {
+ "files": [
+ "src/Framework/Assert/Functions.php"
+ ],
"classmap": [
"src/"
]
@@ -955,427 +1226,521 @@
"role": "lead"
}
],
- "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
- "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
"keywords": [
- "coverage",
+ "phpunit",
"testing",
"xunit"
],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+ "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.22"
+ },
"funding": [
{
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
+ "url": "https://phpunit.de/sponsoring.html",
+ "type": "other"
}
],
- "time": "2020-05-23T08:02:54+00:00"
+ "time": "2026-04-17T12:51:04+00:00"
},
{
- "name": "phpunit/php-file-iterator",
- "version": "3.0.3",
+ "name": "predis/predis",
+ "version": "v3.4.2",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "8e282e5f5e2db5fb2271b3962ad69875c34a6f41"
+ "url": "https://github.com/predis/predis.git",
+ "reference": "2033429520d8997a7815a2485f56abe6d2d0e075"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/8e282e5f5e2db5fb2271b3962ad69875c34a6f41",
- "reference": "8e282e5f5e2db5fb2271b3962ad69875c34a6f41",
+ "url": "https://api.github.com/repos/predis/predis/zipball/2033429520d8997a7815a2485f56abe6d2d0e075",
+ "reference": "2033429520d8997a7815a2485f56abe6d2d0e075",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
+ "php": "^7.2 || ^8.0",
+ "psr/http-message": "^1.0|^2.0"
},
"require-dev": {
- "phpunit/phpunit": "^9.0"
+ "friendsofphp/php-cs-fixer": "^3.3",
+ "phpstan/phpstan": "^1.9",
+ "phpunit/phpcov": "^6.0 || ^8.0",
+ "phpunit/phpunit": "^8.0 || ~9.4.4"
},
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.0-dev"
- }
+ "suggest": {
+ "ext-relay": "Faster connection with in-memory caching (>=0.6.2)"
},
+ "type": "library",
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-4": {
+ "Predis\\": "src/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
"authors": [
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
+ "name": "Till Krüss",
+ "homepage": "https://till.im",
+ "role": "Maintainer"
}
],
- "description": "FilterIterator implementation that filters files based on a list of suffixes.",
- "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "description": "A flexible and feature-complete Redis/Valkey client for PHP.",
+ "homepage": "http://github.com/predis/predis",
"keywords": [
- "filesystem",
- "iterator"
+ "nosql",
+ "predis",
+ "redis"
],
+ "support": {
+ "issues": "https://github.com/predis/predis/issues",
+ "source": "https://github.com/predis/predis/tree/v3.4.2"
+ },
"funding": [
{
- "url": "https://github.com/sebastianbergmann",
+ "url": "https://github.com/sponsors/tillkruss",
"type": "github"
}
],
- "time": "2020-06-26T11:50:37+00:00"
+ "time": "2026-03-09T20:33:04+00:00"
},
{
- "name": "phpunit/php-invoker",
- "version": "3.0.2",
+ "name": "psr/container",
+ "version": "2.0.2",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-invoker.git",
- "reference": "f6eedfed1085dd1f4c599629459a0277d25f9a66"
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f6eedfed1085dd1f4c599629459a0277d25f9a66",
- "reference": "f6eedfed1085dd1f4c599629459a0277d25f9a66",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
- },
- "require-dev": {
- "ext-pcntl": "*",
- "phpunit/phpunit": "^9.0"
- },
- "suggest": {
- "ext-pcntl": "*"
+ "php": ">=7.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "2.0.x-dev"
}
},
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
"authors": [
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
}
],
- "description": "Invoke callables with a timeout",
- "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
"keywords": [
- "process"
- ],
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
],
- "time": "2020-06-26T11:53:53+00:00"
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
},
{
- "name": "phpunit/php-text-template",
- "version": "2.0.2",
+ "name": "psr/event-dispatcher",
+ "version": "1.0.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-text-template.git",
- "reference": "6ff9c8ea4d3212b88fcf74e25e516e2c51c99324"
+ "url": "https://github.com/php-fig/event-dispatcher.git",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/6ff9c8ea4d3212b88fcf74e25e516e2c51c99324",
- "reference": "6ff9c8ea4d3212b88fcf74e25e516e2c51c99324",
+ "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^9.0"
+ "php": ">=7.2.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-master": "1.0.x-dev"
}
},
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-4": {
+ "Psr\\EventDispatcher\\": "src/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
"authors": [
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
}
],
- "description": "Simple template engine.",
- "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "description": "Standard interfaces for event handling.",
"keywords": [
- "template"
+ "events",
+ "psr",
+ "psr-14"
],
- "funding": [
+ "support": {
+ "issues": "https://github.com/php-fig/event-dispatcher/issues",
+ "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
+ },
+ "time": "2019-01-08T18:20:26+00:00"
+ },
+ {
+ "name": "psr/http-message",
+ "version": "2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message.git",
+ "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
+ "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
{
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
}
],
- "time": "2020-06-26T11:55:37+00:00"
+ "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/2.0"
+ },
+ "time": "2023-04-04T09:54:51+00:00"
},
{
- "name": "phpunit/php-timer",
- "version": "5.0.1",
+ "name": "psr/log",
+ "version": "3.0.2",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "cc49734779cbb302bf51a44297dab8c4bbf941e7"
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/cc49734779cbb302bf51a44297dab8c4bbf941e7",
- "reference": "cc49734779cbb302bf51a44297dab8c4bbf941e7",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^9.2"
+ "php": ">=8.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-master": "3.x-dev"
}
},
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-4": {
+ "Psr\\Log\\": "src"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
"authors": [
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
}
],
- "description": "Utility class for timing",
- "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
"keywords": [
- "timer"
+ "log",
+ "psr",
+ "psr-3"
],
- "funding": [
+ "support": {
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
+ },
+ "time": "2024-09-11T13:17:53+00:00"
+ },
+ {
+ "name": "rancoud/database",
+ "version": "7.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/rancoud/Database.git",
+ "reference": "b16bf7b65400d0afc4dc06041bc667a9a1b72fd5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/rancoud/Database/zipball/b16bf7b65400d0afc4dc06041bc667a9a1b72fd5",
+ "reference": "b16bf7b65400d0afc4dc06041bc667a9a1b72fd5",
+ "shasum": ""
+ },
+ "require": {
+ "ext-pdo": "*",
+ "php": ">=8.4.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "3.95.1",
+ "phpunit/phpunit": "12.5.22"
+ },
+ "suggest": {
+ "ext-pdo_mysql": "Needed to connect MySQL",
+ "ext-pdo_pgsql": "Needed to connect PostgreSQL",
+ "ext-pdo_sqlite": "Needed to connect SQLite"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Rancoud\\Database\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
{
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
+ "name": "Sebastien Rancoud",
+ "email": "contact@rancoud.com"
}
],
- "time": "2020-06-26T11:58:13+00:00"
+ "description": "Database package",
+ "support": {
+ "issues": "https://github.com/rancoud/Database/issues",
+ "source": "https://github.com/rancoud/Database/tree/7.0.3"
+ },
+ "time": "2026-06-01T21:56:55+00:00"
},
{
- "name": "phpunit/php-token-stream",
- "version": "4.0.3",
+ "name": "react/cache",
+ "version": "v1.2.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "5672711b6b07b14d5ab694e700c62eeb82fcf374"
+ "url": "https://github.com/reactphp/cache.git",
+ "reference": "d47c472b64aa5608225f47965a484b75c7817d5b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/5672711b6b07b14d5ab694e700c62eeb82fcf374",
- "reference": "5672711b6b07b14d5ab694e700c62eeb82fcf374",
+ "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b",
+ "reference": "d47c472b64aa5608225f47965a484b75c7817d5b",
"shasum": ""
},
"require": {
- "ext-tokenizer": "*",
- "php": "^7.3 || ^8.0"
+ "php": ">=5.3.0",
+ "react/promise": "^3.0 || ^2.0 || ^1.1"
},
"require-dev": {
- "phpunit/phpunit": "^9.0"
+ "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "4.0-dev"
- }
- },
"autoload": {
- "classmap": [
- "src/"
- ]
+ "psr-4": {
+ "React\\Cache\\": "src/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
"authors": [
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
}
],
- "description": "Wrapper around PHP's tokenizer extension.",
- "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
+ "description": "Async, Promise-based cache interface for ReactPHP",
"keywords": [
- "tokenizer"
+ "cache",
+ "caching",
+ "promise",
+ "reactphp"
],
+ "support": {
+ "issues": "https://github.com/reactphp/cache/issues",
+ "source": "https://github.com/reactphp/cache/tree/v1.2.0"
+ },
"funding": [
{
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
}
],
- "time": "2020-06-27T06:36:25+00:00"
+ "time": "2022-11-30T15:59:55+00:00"
},
{
- "name": "phpunit/phpunit",
- "version": "9.2.5",
+ "name": "react/child-process",
+ "version": "v0.6.7",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "ad7cc5ec3ab2597b329880e30442d9054526023b"
+ "url": "https://github.com/reactphp/child-process.git",
+ "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ad7cc5ec3ab2597b329880e30442d9054526023b",
- "reference": "ad7cc5ec3ab2597b329880e30442d9054526023b",
+ "url": "https://api.github.com/repos/reactphp/child-process/zipball/970f0e71945556422ee4570ccbabaedc3cf04ad3",
+ "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3",
"shasum": ""
},
"require": {
- "doctrine/instantiator": "^1.2.0",
- "ext-dom": "*",
- "ext-json": "*",
- "ext-libxml": "*",
- "ext-mbstring": "*",
- "ext-xml": "*",
- "ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.9.1",
- "phar-io/manifest": "^1.0.3",
- "phar-io/version": "^2.0.1",
- "php": "^7.3",
- "phpspec/prophecy": "^1.8.1",
- "phpunit/php-code-coverage": "^8.0.1",
- "phpunit/php-file-iterator": "^3.0",
- "phpunit/php-invoker": "^3.0",
- "phpunit/php-text-template": "^2.0",
- "phpunit/php-timer": "^5.0",
- "sebastian/code-unit": "^1.0.2",
- "sebastian/comparator": "^4.0",
- "sebastian/diff": "^4.0",
- "sebastian/environment": "^5.0.1",
- "sebastian/exporter": "^4.0",
- "sebastian/global-state": "^4.0",
- "sebastian/object-enumerator": "^4.0",
- "sebastian/resource-operations": "^3.0",
- "sebastian/type": "^2.1",
- "sebastian/version": "^3.0"
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/event-loop": "^1.2",
+ "react/stream": "^1.4"
},
"require-dev": {
- "ext-pdo": "*",
- "phpspec/prophecy-phpunit": "^2.0"
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/socket": "^1.16",
+ "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0"
},
- "suggest": {
- "ext-soap": "*",
- "ext-xdebug": "*"
- },
- "bin": [
- "phpunit"
- ],
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "9.2-dev"
- }
- },
"autoload": {
- "classmap": [
- "src/"
- ],
- "files": [
- "src/Framework/Assert/Functions.php"
- ]
+ "psr-4": {
+ "React\\ChildProcess\\": "src/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
"authors": [
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
}
],
- "description": "The PHP Unit Testing framework.",
- "homepage": "https://phpunit.de/",
+ "description": "Event-driven library for executing child processes with ReactPHP.",
"keywords": [
- "phpunit",
- "testing",
- "xunit"
+ "event-driven",
+ "process",
+ "reactphp"
],
+ "support": {
+ "issues": "https://github.com/reactphp/child-process/issues",
+ "source": "https://github.com/reactphp/child-process/tree/v0.6.7"
+ },
"funding": [
{
- "url": "https://phpunit.de/donate.html",
- "type": "custom"
- },
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
}
],
- "time": "2020-06-22T07:10:55+00:00"
+ "time": "2025-12-23T15:25:20+00:00"
},
{
- "name": "predis/predis",
- "version": "v1.1.1",
+ "name": "react/dns",
+ "version": "v1.14.0",
"source": {
"type": "git",
- "url": "https://github.com/nrk/predis.git",
- "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1"
+ "url": "https://github.com/reactphp/dns.git",
+ "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nrk/predis/zipball/f0210e38881631afeafb56ab43405a92cafd9fd1",
- "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1",
+ "url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3",
+ "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3",
"shasum": ""
},
"require": {
- "php": ">=5.3.9"
+ "php": ">=5.3.0",
+ "react/cache": "^1.0 || ^0.6 || ^0.5",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.2 || ^2.7 || ^1.2.1"
},
"require-dev": {
- "phpunit/phpunit": "~4.8"
- },
- "suggest": {
- "ext-curl": "Allows access to Webdis when paired with phpiredis",
- "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol"
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/async": "^4.3 || ^3 || ^2",
+ "react/promise-timer": "^1.11"
},
"type": "library",
"autoload": {
"psr-4": {
- "Predis\\": "src/"
+ "React\\Dns\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1384,46 +1749,72 @@
],
"authors": [
{
- "name": "Daniele Alessandri",
- "email": "suppakilla@gmail.com",
- "homepage": "http://clorophilla.net"
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
}
],
- "description": "Flexible and feature-complete Redis client for PHP and HHVM",
- "homepage": "http://github.com/nrk/predis",
+ "description": "Async DNS resolver for ReactPHP",
"keywords": [
- "nosql",
- "predis",
- "redis"
+ "async",
+ "dns",
+ "dns-resolver",
+ "reactphp"
],
- "time": "2016-06-16T16:22:20+00:00"
+ "support": {
+ "issues": "https://github.com/reactphp/dns/issues",
+ "source": "https://github.com/reactphp/dns/tree/v1.14.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-11-18T19:34:28+00:00"
},
{
- "name": "psr/container",
- "version": "1.0.0",
+ "name": "react/event-loop",
+ "version": "v1.6.0",
"source": {
"type": "git",
- "url": "https://github.com/php-fig/container.git",
- "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
+ "url": "https://github.com/reactphp/event-loop.git",
+ "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
- "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+ "url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a",
+ "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
},
+ "suggest": {
+ "ext-pcntl": "For signal handling support when using the StreamSelectLoop"
+ },
+ "type": "library",
"autoload": {
"psr-4": {
- "Psr\\Container\\": "src/"
+ "React\\EventLoop\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1432,47 +1823,71 @@
],
"authors": [
{
- "name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
}
],
- "description": "Common Container Interface (PHP FIG PSR-11)",
- "homepage": "https://github.com/php-fig/container",
+ "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
"keywords": [
- "PSR-11",
- "container",
- "container-interface",
- "container-interop",
- "psr"
+ "asynchronous",
+ "event-loop"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/event-loop/issues",
+ "source": "https://github.com/reactphp/event-loop/tree/v1.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
],
- "time": "2017-02-14T16:28:37+00:00"
+ "time": "2025-11-17T20:46:25+00:00"
},
{
- "name": "psr/event-dispatcher",
- "version": "1.0.0",
+ "name": "react/promise",
+ "version": "v3.3.0",
"source": {
"type": "git",
- "url": "https://github.com/php-fig/event-dispatcher.git",
- "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
+ "url": "https://github.com/reactphp/promise.git",
+ "reference": "23444f53a813a3296c1368bb104793ce8d88f04a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
- "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a",
+ "reference": "23444f53a813a3296c1368bb104793ce8d88f04a",
"shasum": ""
},
"require": {
- "php": ">=7.2.0"
+ "php": ">=7.1.0"
},
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
+ "require-dev": {
+ "phpstan/phpstan": "1.12.28 || 1.4.10",
+ "phpunit/phpunit": "^9.6 || ^7.5"
},
+ "type": "library",
"autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
"psr-4": {
- "Psr\\EventDispatcher\\": "src/"
+ "React\\Promise\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1481,44 +1896,75 @@
],
"authors": [
{
- "name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
}
],
- "description": "Standard interfaces for event handling.",
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
"keywords": [
- "events",
- "psr",
- "psr-14"
+ "promise",
+ "promises"
],
- "time": "2019-01-08T18:20:26+00:00"
+ "support": {
+ "issues": "https://github.com/reactphp/promise/issues",
+ "source": "https://github.com/reactphp/promise/tree/v3.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-08-19T18:57:03+00:00"
},
{
- "name": "psr/log",
- "version": "1.1.3",
+ "name": "react/socket",
+ "version": "v1.17.0",
"source": {
"type": "git",
- "url": "https://github.com/php-fig/log.git",
- "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
+ "url": "https://github.com/reactphp/socket.git",
+ "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
- "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
+ "url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08",
+ "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08",
"shasum": ""
},
"require": {
- "php": ">=5.3.0"
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/dns": "^1.13",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.2 || ^2.6 || ^1.2.1",
+ "react/stream": "^1.4"
},
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.1.x-dev"
- }
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/async": "^4.3 || ^3.3 || ^2",
+ "react/promise-stream": "^1.4",
+ "react/promise-timer": "^1.11"
},
+ "type": "library",
"autoload": {
"psr-4": {
- "Psr\\Log\\": "Psr/Log/"
+ "React\\Socket\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1527,46 +1973,73 @@
],
"authors": [
{
- "name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
}
],
- "description": "Common interface for logging libraries",
- "homepage": "https://github.com/php-fig/log",
+ "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
"keywords": [
- "log",
- "psr",
- "psr-3"
+ "Connection",
+ "Socket",
+ "async",
+ "reactphp",
+ "stream"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/socket/issues",
+ "source": "https://github.com/reactphp/socket/tree/v1.17.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
],
- "time": "2020-03-23T09:12:05+00:00"
+ "time": "2025-11-19T20:47:34+00:00"
},
{
- "name": "rancoud/database",
- "version": "4.0.1",
+ "name": "react/stream",
+ "version": "v1.4.0",
"source": {
"type": "git",
- "url": "https://github.com/rancoud/Database.git",
- "reference": "1c2aa2e8b7554950f4eed765d23ec240b61d2248"
+ "url": "https://github.com/reactphp/stream.git",
+ "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/rancoud/Database/zipball/1c2aa2e8b7554950f4eed765d23ec240b61d2248",
- "reference": "1c2aa2e8b7554950f4eed765d23ec240b61d2248",
+ "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d",
+ "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d",
"shasum": ""
},
"require": {
- "ext-pdo": ">=7.4.0",
- "php": ">=7.4.0"
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.8",
+ "react/event-loop": "^1.2"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^2.16",
- "phpunit/phpunit": "^9.1",
- "squizlabs/php_codesniffer": "^3.5"
+ "clue/stream-filter": "~1.2",
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
},
"type": "library",
"autoload": {
"psr-4": {
- "Rancoud\\Database\\": "src"
+ "React\\Stream\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1575,37 +2048,73 @@
],
"authors": [
{
- "name": "Sebastien Rancoud",
- "email": "contact@rancoud.com"
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
}
],
- "description": "Database package",
- "time": "2020-07-01T20:03:41+00:00"
+ "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
+ "keywords": [
+ "event-driven",
+ "io",
+ "non-blocking",
+ "pipe",
+ "reactphp",
+ "readable",
+ "stream",
+ "writable"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/stream/issues",
+ "source": "https://github.com/reactphp/stream/tree/v1.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2024-06-11T12:45:25+00:00"
},
{
- "name": "sebastian/code-unit",
- "version": "1.0.5",
+ "name": "sebastian/cli-parser",
+ "version": "4.2.1",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/code-unit.git",
- "reference": "c1e2df332c905079980b119c4db103117e5e5c90"
+ "url": "https://github.com/sebastianbergmann/cli-parser.git",
+ "reference": "7d05781b13f7dec9043a629a21d086ed74582a15"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/c1e2df332c905079980b119c4db103117e5e5c90",
- "reference": "c1e2df332c905079980b119c4db103117e5e5c90",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/7d05781b13f7dec9043a629a21d086ed74582a15",
+ "reference": "7d05781b13f7dec9043a629a21d086ed74582a15",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.0"
+ "phpunit/phpunit": "^12.5.25"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-main": "4.2-dev"
}
},
"autoload": {
@@ -1624,40 +2133,64 @@
"role": "lead"
}
],
- "description": "Collection of value objects that represent the PHP code units",
- "homepage": "https://github.com/sebastianbergmann/code-unit",
+ "description": "Library for parsing CLI options",
+ "homepage": "https://github.com/sebastianbergmann/cli-parser",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
+ "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.1"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser",
+ "type": "tidelift"
}
],
- "time": "2020-06-26T12:50:45+00:00"
+ "time": "2026-05-17T05:29:34+00:00"
},
{
- "name": "sebastian/code-unit-reverse-lookup",
- "version": "2.0.2",
+ "name": "sebastian/comparator",
+ "version": "7.1.8",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
- "reference": "ee51f9bb0c6d8a43337055db3120829fa14da819"
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "7c65c1e79836812819705b473a90c12399542485"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ee51f9bb0c6d8a43337055db3120829fa14da819",
- "reference": "ee51f9bb0c6d8a43337055db3120829fa14da819",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/7c65c1e79836812819705b473a90c12399542485",
+ "reference": "7c65c1e79836812819705b473a90c12399542485",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
+ "ext-dom": "*",
+ "ext-mbstring": "*",
+ "php": ">=8.3",
+ "sebastian/diff": "^7.0",
+ "sebastian/exporter": "^7.0.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.0"
+ "phpunit/phpunit": "^12.5.25"
+ },
+ "suggest": {
+ "ext-bcmath": "For comparing BcMath\\Number objects"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-main": "7.1-dev"
}
},
"autoload": {
@@ -1673,44 +2206,77 @@
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
}
],
- "description": "Looks up which function or method a line of code belongs to",
- "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/comparator/issues",
+ "security": "https://github.com/sebastianbergmann/comparator/security/policy",
+ "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.8"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
+ "type": "tidelift"
}
],
- "time": "2020-06-26T12:04:00+00:00"
+ "time": "2026-05-21T04:45:25+00:00"
},
{
- "name": "sebastian/comparator",
- "version": "4.0.3",
+ "name": "sebastian/complexity",
+ "version": "5.0.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f"
+ "url": "https://github.com/sebastianbergmann/complexity.git",
+ "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f",
- "reference": "dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb",
+ "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0",
- "sebastian/diff": "^4.0",
- "sebastian/exporter": "^4.0"
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-main": "5.0-dev"
}
},
"autoload": {
@@ -1725,61 +2291,50 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- },
- {
- "name": "Jeff Welch",
- "email": "whatthejeff@gmail.com"
- },
- {
- "name": "Volker Dusch",
- "email": "github@wallbash.com"
- },
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@2bepublished.at"
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
}
],
- "description": "Provides the functionality to compare PHP values for equality",
- "homepage": "https://github.com/sebastianbergmann/comparator",
- "keywords": [
- "comparator",
- "compare",
- "equality"
- ],
+ "description": "Library for calculating the complexity of PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/complexity",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/complexity/issues",
+ "security": "https://github.com/sebastianbergmann/complexity/security/policy",
+ "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
- "time": "2020-06-26T12:05:46+00:00"
+ "time": "2025-02-07T04:55:25+00:00"
},
{
"name": "sebastian/diff",
- "version": "4.0.2",
+ "version": "7.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113"
+ "reference": "7ab1ea946c012266ca32390913653d844ecd085f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113",
- "reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f",
+ "reference": "7ab1ea946c012266ca32390913653d844ecd085f",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.0",
- "symfony/process": "^4.2 || ^5"
+ "phpunit/phpunit": "^12.0",
+ "symfony/process": "^7.2"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-main": "7.0-dev"
}
},
"autoload": {
@@ -1809,33 +2364,38 @@
"unidiff",
"unified diff"
],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/diff/issues",
+ "security": "https://github.com/sebastianbergmann/diff/security/policy",
+ "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
- "time": "2020-06-30T04:46:02+00:00"
+ "time": "2025-02-07T04:55:46+00:00"
},
{
"name": "sebastian/environment",
- "version": "5.1.2",
+ "version": "8.1.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2"
+ "reference": "9d32c685773823b1983e256ae4ecd48a10d6e439"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2",
- "reference": "0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/9d32c685773823b1983e256ae4ecd48a10d6e439",
+ "reference": "9d32c685773823b1983e256ae4ecd48a10d6e439",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.0"
+ "phpunit/phpunit": "^12.5.26"
},
"suggest": {
"ext-posix": "*"
@@ -1843,7 +2403,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-main": "8.1-dev"
}
},
"autoload": {
@@ -1862,46 +2422,63 @@
}
],
"description": "Provides functionality to handle HHVM/PHP environments",
- "homepage": "http://www.github.com/sebastianbergmann/environment",
+ "homepage": "https://github.com/sebastianbergmann/environment",
"keywords": [
"Xdebug",
"environment",
"hhvm"
],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/environment/issues",
+ "security": "https://github.com/sebastianbergmann/environment/security/policy",
+ "source": "https://github.com/sebastianbergmann/environment/tree/8.1.2"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/environment",
+ "type": "tidelift"
}
],
- "time": "2020-06-26T12:07:24+00:00"
+ "time": "2026-05-25T13:40:20+00:00"
},
{
"name": "sebastian/exporter",
- "version": "4.0.2",
+ "version": "7.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "571d721db4aec847a0e59690b954af33ebf9f023"
+ "reference": "c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/571d721db4aec847a0e59690b954af33ebf9f023",
- "reference": "571d721db4aec847a0e59690b954af33ebf9f023",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23",
+ "reference": "c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0",
- "sebastian/recursion-context": "^4.0"
+ "ext-mbstring": "*",
+ "php": ">=8.3",
+ "sebastian/recursion-context": "^7.0.1"
},
"require-dev": {
- "ext-mbstring": "*",
- "phpunit/phpunit": "^9.2"
+ "phpunit/phpunit": "^12.5.25"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-main": "7.0-dev"
}
},
"autoload": {
@@ -1936,49 +2513,63 @@
}
],
"description": "Provides the functionality to export PHP variables for visualization",
- "homepage": "http://www.github.com/sebastianbergmann/exporter",
+ "homepage": "https://www.github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/exporter/issues",
+ "security": "https://github.com/sebastianbergmann/exporter/security/policy",
+ "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.3"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
+ "type": "tidelift"
}
],
- "time": "2020-06-26T12:08:55+00:00"
+ "time": "2026-05-20T04:37:17+00:00"
},
{
"name": "sebastian/global-state",
- "version": "4.0.0",
+ "version": "8.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72"
+ "reference": "b164d3274d6537ab462591c5755f76a8f5b1aae9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72",
- "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b164d3274d6537ab462591c5755f76a8f5b1aae9",
+ "reference": "b164d3274d6537ab462591c5755f76a8f5b1aae9",
"shasum": ""
},
"require": {
- "php": "^7.3",
- "sebastian/object-reflector": "^2.0",
- "sebastian/recursion-context": "^4.0"
+ "php": ">=8.3",
+ "sebastian/object-reflector": "^5.0",
+ "sebastian/recursion-context": "^7.0.1"
},
"require-dev": {
"ext-dom": "*",
- "phpunit/phpunit": "^9.0"
- },
- "suggest": {
- "ext-uopz": "*"
+ "phpunit/phpunit": "^12.5.28"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-main": "8.0-dev"
}
},
"autoload": {
@@ -1997,38 +2588,60 @@
}
],
"description": "Snapshotting of global state",
- "homepage": "http://www.github.com/sebastianbergmann/global-state",
+ "homepage": "https://www.github.com/sebastianbergmann/global-state",
"keywords": [
"global state"
],
- "time": "2020-02-07T06:11:37+00:00"
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/global-state/issues",
+ "security": "https://github.com/sebastianbergmann/global-state/security/policy",
+ "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-06-01T15:10:33+00:00"
},
{
- "name": "sebastian/object-enumerator",
- "version": "4.0.2",
+ "name": "sebastian/lines-of-code",
+ "version": "4.0.1",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/object-enumerator.git",
- "reference": "074fed2d0a6d08e1677dd8ce9d32aecb384917b8"
+ "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+ "reference": "d543b8ef219dcd8da262cbb958639a96bedba10e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/074fed2d0a6d08e1677dd8ce9d32aecb384917b8",
- "reference": "074fed2d0a6d08e1677dd8ce9d32aecb384917b8",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d543b8ef219dcd8da262cbb958639a96bedba10e",
+ "reference": "d543b8ef219dcd8da262cbb958639a96bedba10e",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0",
- "sebastian/object-reflector": "^2.0",
- "sebastian/recursion-context": "^4.0"
+ "nikic/php-parser": "^5.7.0",
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.0"
+ "phpunit/phpunit": "^12.5.25"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-main": "4.0-dev"
}
},
"autoload": {
@@ -2043,43 +2656,63 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
}
],
- "description": "Traverses array structures and object graphs to enumerate all referenced objects",
- "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "description": "Library for counting the lines of code in PHP source code",
+ "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+ "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.1"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/lines-of-code",
+ "type": "tidelift"
}
],
- "time": "2020-06-26T12:11:32+00:00"
+ "time": "2026-05-19T16:22:07+00:00"
},
{
- "name": "sebastian/object-reflector",
- "version": "2.0.2",
+ "name": "sebastian/object-enumerator",
+ "version": "7.0.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/object-reflector.git",
- "reference": "127a46f6b057441b201253526f81d5406d6c7840"
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/127a46f6b057441b201253526f81d5406d6c7840",
- "reference": "127a46f6b057441b201253526f81d5406d6c7840",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894",
+ "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
+ "php": ">=8.3",
+ "sebastian/object-reflector": "^5.0",
+ "sebastian/recursion-context": "^7.0"
},
"require-dev": {
- "phpunit/phpunit": "^9.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-main": "7.0-dev"
}
},
"autoload": {
@@ -2097,40 +2730,45 @@
"email": "sebastian@phpunit.de"
}
],
- "description": "Allows reflection of object attributes, including inherited and non-public ones",
- "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+ "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
- "time": "2020-06-26T12:12:55+00:00"
+ "time": "2025-02-07T04:57:48+00:00"
},
{
- "name": "sebastian/recursion-context",
- "version": "4.0.2",
+ "name": "sebastian/object-reflector",
+ "version": "5.0.0",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "062231bf61d2b9448c4fa5a7643b5e1829c11d63"
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "4bfa827c969c98be1e527abd576533293c634f6a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/062231bf61d2b9448c4fa5a7643b5e1829c11d63",
- "reference": "062231bf61d2b9448c4fa5a7643b5e1829c11d63",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a",
+ "reference": "4bfa827c969c98be1e527abd576533293c634f6a",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-main": "5.0-dev"
}
},
"autoload": {
@@ -2146,50 +2784,47 @@
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
- },
- {
- "name": "Jeff Welch",
- "email": "whatthejeff@gmail.com"
- },
- {
- "name": "Adam Harvey",
- "email": "aharvey@php.net"
}
],
- "description": "Provides functionality to recursively process PHP variables",
- "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+ "security": "https://github.com/sebastianbergmann/object-reflector/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
- "time": "2020-06-26T12:14:17+00:00"
+ "time": "2025-02-07T04:58:17+00:00"
},
{
- "name": "sebastian/resource-operations",
- "version": "3.0.2",
+ "name": "sebastian/recursion-context",
+ "version": "7.0.1",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/resource-operations.git",
- "reference": "0653718a5a629b065e91f774595267f8dc32e213"
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0653718a5a629b065e91f774595267f8dc32e213",
- "reference": "0653718a5a629b065e91f774595267f8dc32e213",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c",
+ "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-main": "7.0-dev"
}
},
"autoload": {
@@ -2205,42 +2840,67 @@
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
}
],
- "description": "Provides a list of PHP built-in functions that operate on resources",
- "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "https://github.com/sebastianbergmann/recursion-context",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+ "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.1"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
+ "type": "tidelift"
}
],
- "time": "2020-06-26T12:16:22+00:00"
+ "time": "2025-08-13T04:44:59+00:00"
},
{
"name": "sebastian/type",
- "version": "2.1.1",
+ "version": "6.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
- "reference": "56b3ba194e0cbaaf3de7ccd353c289d7a84ed022"
+ "reference": "82ff822c2edc46724be9f7411d3163021f602773"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/56b3ba194e0cbaaf3de7ccd353c289d7a84ed022",
- "reference": "56b3ba194e0cbaaf3de7ccd353c289d7a84ed022",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/82ff822c2edc46724be9f7411d3163021f602773",
+ "reference": "82ff822c2edc46724be9f7411d3163021f602773",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.2"
+ "phpunit/phpunit": "^12.5.25"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.1-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
@@ -2261,35 +2921,52 @@
],
"description": "Collection of value objects that represent the types of the PHP type system",
"homepage": "https://github.com/sebastianbergmann/type",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/type/issues",
+ "security": "https://github.com/sebastianbergmann/type/security/policy",
+ "source": "https://github.com/sebastianbergmann/type/tree/6.0.4"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/type",
+ "type": "tidelift"
}
],
- "time": "2020-06-26T12:17:54+00:00"
+ "time": "2026-05-20T06:45:45+00:00"
},
{
"name": "sebastian/version",
- "version": "3.0.1",
+ "version": "6.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
- "reference": "626586115d0ed31cb71483be55beb759b5af5a3c"
+ "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/626586115d0ed31cb71483be55beb759b5af5a3c",
- "reference": "626586115d0ed31cb71483be55beb759b5af5a3c",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c",
+ "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c",
"shasum": ""
},
"require": {
- "php": "^7.3 || ^8.0"
+ "php": ">=8.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
@@ -2310,118 +2987,118 @@
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/version/issues",
+ "security": "https://github.com/sebastianbergmann/version/security/policy",
+ "source": "https://github.com/sebastianbergmann/version/tree/6.0.0"
+ },
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
- "time": "2020-06-26T12:18:43+00:00"
+ "time": "2025-02-07T05:00:38+00:00"
},
{
- "name": "squizlabs/php_codesniffer",
- "version": "3.5.5",
+ "name": "staabm/side-effects-detector",
+ "version": "1.0.5",
"source": {
"type": "git",
- "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
- "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6"
+ "url": "https://github.com/staabm/side-effects-detector.git",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
- "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
+ "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163",
"shasum": ""
},
"require": {
- "ext-simplexml": "*",
"ext-tokenizer": "*",
- "ext-xmlwriter": "*",
- "php": ">=5.4.0"
+ "php": "^7.4 || ^8.0"
},
"require-dev": {
- "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
+ "phpstan/extension-installer": "^1.4.3",
+ "phpstan/phpstan": "^1.12.6",
+ "phpunit/phpunit": "^9.6.21",
+ "symfony/var-dumper": "^5.4.43",
+ "tomasvotruba/type-coverage": "1.0.0",
+ "tomasvotruba/unused-public": "1.0.0"
},
- "bin": [
- "bin/phpcs",
- "bin/phpcbf"
- ],
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.x-dev"
- }
+ "autoload": {
+ "classmap": [
+ "lib/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "BSD-3-Clause"
+ "MIT"
],
- "authors": [
+ "description": "A static analysis tool to detect side effects in PHP code",
+ "keywords": [
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/staabm/side-effects-detector/issues",
+ "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5"
+ },
+ "funding": [
{
- "name": "Greg Sherwood",
- "role": "lead"
+ "url": "https://github.com/staabm",
+ "type": "github"
}
],
- "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
- "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
- "keywords": [
- "phpcs",
- "standards"
- ],
- "time": "2020-04-17T01:09:41+00:00"
+ "time": "2024-10-20T05:08:20+00:00"
},
{
"name": "symfony/console",
- "version": "v5.1.2",
+ "version": "v8.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "34ac555a3627e324b660e318daa07572e1140123"
+ "reference": "f5a856c6ecb56b3c21ed94a5b7bf940d857d110a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/34ac555a3627e324b660e318daa07572e1140123",
- "reference": "34ac555a3627e324b660e318daa07572e1140123",
+ "url": "https://api.github.com/repos/symfony/console/zipball/f5a856c6ecb56b3c21ed94a5b7bf940d857d110a",
+ "reference": "f5a856c6ecb56b3c21ed94a5b7bf940d857d110a",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php73": "^1.8",
- "symfony/polyfill-php80": "^1.15",
- "symfony/service-contracts": "^1.1|^2",
- "symfony/string": "^5.1"
+ "php": ">=8.4.1",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/polyfill-mbstring": "^1.0",
+ "symfony/polyfill-php85": "^1.32",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/string": "^7.4.6|^8.0.6"
},
"conflict": {
- "symfony/dependency-injection": "<4.4",
- "symfony/dotenv": "<5.1",
- "symfony/event-dispatcher": "<4.4",
- "symfony/lock": "<4.4",
- "symfony/process": "<4.4"
+ "symfony/dependency-injection": "<8.1",
+ "symfony/event-dispatcher": "<8.1"
},
"provide": {
- "psr/log-implementation": "1.0"
- },
- "require-dev": {
- "psr/log": "~1.0",
- "symfony/config": "^4.4|^5.0",
- "symfony/dependency-injection": "^4.4|^5.0",
- "symfony/event-dispatcher": "^4.4|^5.0",
- "symfony/lock": "^4.4|^5.0",
- "symfony/process": "^4.4|^5.0",
- "symfony/var-dumper": "^4.4|^5.0"
- },
- "suggest": {
- "psr/log": "For using the console logger",
- "symfony/event-dispatcher": "",
- "symfony/lock": "",
- "symfony/process": ""
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.1-dev"
- }
+ "psr/log-implementation": "1.0|2.0|3.0"
},
+ "require-dev": {
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^7.4|^8.0",
+ "symfony/dependency-injection": "^8.1",
+ "symfony/event-dispatcher": "^8.1",
+ "symfony/filesystem": "^7.4|^8.0",
+ "symfony/http-foundation": "^7.4|^8.0",
+ "symfony/http-kernel": "^7.4|^8.0",
+ "symfony/lock": "^7.4|^8.0",
+ "symfony/messenger": "^7.4|^8.0",
+ "symfony/mime": "^7.4|^8.0",
+ "symfony/process": "^7.4|^8.0",
+ "symfony/stopwatch": "^7.4|^8.0",
+ "symfony/uid": "^7.4|^8.0",
+ "symfony/validator": "^7.4|^8.0",
+ "symfony/var-dumper": "^7.4|^8.0"
+ },
+ "type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
@@ -2444,8 +3121,17 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony Console Component",
+ "description": "Eases the creation of beautiful and testable command line interfaces",
"homepage": "https://symfony.com",
+ "keywords": [
+ "cli",
+ "command-line",
+ "console",
+ "terminal"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/console/tree/v8.1.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -2455,34 +3141,42 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-06-15T12:59:21+00:00"
+ "time": "2026-05-29T05:06:50+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v2.1.2",
+ "version": "v3.7.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337"
+ "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337",
- "reference": "dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b",
+ "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=8.1"
},
"type": "library",
"extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
"branch-alias": {
- "dev-master": "2.1-dev"
+ "dev-main": "3.7-dev"
}
},
"autoload": {
@@ -2506,6 +3200,9 @@
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -2515,59 +3212,56 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-05-27T08:34:37+00:00"
+ "time": "2026-04-13T15:52:40+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v5.1.2",
+ "version": "v8.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "cc0d059e2e997e79ca34125a52f3e33de4424ac7"
+ "reference": "f249ae3f680958b6f1f9dd76e5747cf0695b4102"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/cc0d059e2e997e79ca34125a52f3e33de4424ac7",
- "reference": "cc0d059e2e997e79ca34125a52f3e33de4424ac7",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f249ae3f680958b6f1f9dd76e5747cf0695b4102",
+ "reference": "f249ae3f680958b6f1f9dd76e5747cf0695b4102",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1",
- "symfony/event-dispatcher-contracts": "^2",
- "symfony/polyfill-php80": "^1.15"
+ "php": ">=8.4.1",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/event-dispatcher-contracts": "^2.5|^3"
},
"conflict": {
- "symfony/dependency-injection": "<4.4"
+ "symfony/security-http": "<7.4",
+ "symfony/service-contracts": "<2.5"
},
"provide": {
"psr/event-dispatcher-implementation": "1.0",
- "symfony/event-dispatcher-implementation": "2.0"
+ "symfony/event-dispatcher-implementation": "2.0|3.0"
},
"require-dev": {
- "psr/log": "~1.0",
- "symfony/config": "^4.4|^5.0",
- "symfony/dependency-injection": "^4.4|^5.0",
- "symfony/expression-language": "^4.4|^5.0",
- "symfony/http-foundation": "^4.4|^5.0",
- "symfony/service-contracts": "^1.1|^2",
- "symfony/stopwatch": "^4.4|^5.0"
- },
- "suggest": {
- "symfony/dependency-injection": "",
- "symfony/http-kernel": ""
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^7.4|^8.0",
+ "symfony/dependency-injection": "^7.4|^8.0",
+ "symfony/error-handler": "^7.4|^8.0",
+ "symfony/expression-language": "^7.4|^8.0",
+ "symfony/framework-bundle": "^7.4|^8.0",
+ "symfony/http-foundation": "^7.4|^8.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/stopwatch": "^7.4|^8.0"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.1-dev"
- }
- },
"autoload": {
"psr-4": {
"Symfony\\Component\\EventDispatcher\\": ""
@@ -2590,8 +3284,11 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony EventDispatcher Component",
+ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/event-dispatcher/tree/v8.1.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -2601,38 +3298,43 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-05-20T17:43:50+00:00"
+ "time": "2026-05-29T05:06:50+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
- "version": "v2.1.2",
+ "version": "v3.7.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
- "reference": "405952c4e90941a17e52ef7489a2bd94870bb290"
+ "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/405952c4e90941a17e52ef7489a2bd94870bb290",
- "reference": "405952c4e90941a17e52ef7489a2bd94870bb290",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/ccba7060602b7fed0b03c85bf025257f76d9ef32",
+ "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
+ "php": ">=8.1",
"psr/event-dispatcher": "^1"
},
- "suggest": {
- "symfony/event-dispatcher-implementation": ""
- },
"type": "library",
"extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
"branch-alias": {
- "dev-master": "2.1-dev"
+ "dev-main": "3.7-dev"
}
},
"autoload": {
@@ -2664,6 +3366,9 @@
"interoperability",
"standards"
],
+ "support": {
+ "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -2673,37 +3378,41 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-05-20T17:43:50+00:00"
+ "time": "2026-01-05T13:30:16+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v5.1.2",
+ "version": "v8.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "6e4320f06d5f2cce0d96530162491f4465179157"
+ "reference": "99aec13b82b4967ec5088222c4a3ecca955949c2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/6e4320f06d5f2cce0d96530162491f4465179157",
- "reference": "6e4320f06d5f2cce0d96530162491f4465179157",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/99aec13b82b4967ec5088222c4a3ecca955949c2",
+ "reference": "99aec13b82b4967ec5088222c4a3ecca955949c2",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/polyfill-ctype": "~1.8"
+ "php": ">=8.4.1",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.8"
},
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.1-dev"
- }
+ "require-dev": {
+ "symfony/process": "^7.4|^8.0"
},
+ "type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
@@ -2726,8 +3435,11 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony Filesystem Component",
+ "description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/filesystem/tree/v8.1.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -2737,36 +3449,38 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-05-30T20:35:19+00:00"
+ "time": "2026-05-29T05:06:50+00:00"
},
{
"name": "symfony/finder",
- "version": "v5.1.2",
+ "version": "v8.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "4298870062bfc667cb78d2b379be4bf5dec5f187"
+ "reference": "58d2e767a66052c1487356f953445634a8194c64"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/4298870062bfc667cb78d2b379be4bf5dec5f187",
- "reference": "4298870062bfc667cb78d2b379be4bf5dec5f187",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/58d2e767a66052c1487356f953445634a8194c64",
+ "reference": "58d2e767a66052c1487356f953445634a8194c64",
"shasum": ""
},
"require": {
- "php": ">=7.2.5"
+ "php": ">=8.4.1"
},
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.1-dev"
- }
+ "require-dev": {
+ "symfony/filesystem": "^7.4|^8.0"
},
+ "type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Finder\\": ""
@@ -2789,8 +3503,11 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony Finder Component",
+ "description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/finder/tree/v8.1.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -2800,38 +3517,36 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-05-20T17:43:50+00:00"
+ "time": "2026-05-29T05:06:50+00:00"
},
{
"name": "symfony/options-resolver",
- "version": "v5.1.2",
+ "version": "v8.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
- "reference": "663f5dd5e14057d1954fe721f9709d35837f2447"
+ "reference": "88f9c561f678a02d54b897014049fa839e33ff82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/options-resolver/zipball/663f5dd5e14057d1954fe721f9709d35837f2447",
- "reference": "663f5dd5e14057d1954fe721f9709d35837f2447",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/88f9c561f678a02d54b897014049fa839e33ff82",
+ "reference": "88f9c561f678a02d54b897014049fa839e33ff82",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1",
- "symfony/polyfill-php80": "^1.15"
+ "php": ">=8.4.1",
+ "symfony/deprecation-contracts": "^2.5|^3"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.1-dev"
- }
- },
"autoload": {
"psr-4": {
"Symfony\\Component\\OptionsResolver\\": ""
@@ -2854,13 +3569,16 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony OptionsResolver Component",
+ "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/v8.1.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -2870,50 +3588,54 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-05-23T13:08:13+00:00"
+ "time": "2026-05-29T05:06:50+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.17.1",
+ "version": "v1.37.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d"
+ "reference": "141046a8f9477948ff284fa65be2095baafb94f2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
- "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2",
+ "reference": "141046a8f9477948ff284fa65be2095baafb94f2",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "1.17-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
- "psr-4": {
- "Symfony\\Polyfill\\Ctype\\": ""
- },
"files": [
"bootstrap.php"
- ]
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -2937,6 +3659,9 @@
"polyfill",
"portable"
],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -2946,50 +3671,51 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-06-06T08:46:27+00:00"
+ "time": "2026-04-10T16:19:22+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.17.1",
+ "version": "v1.38.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "6e4dbcf5e81eba86e36731f94fe56b1726835846"
+ "reference": "e9247d281d694a5120554d9afaf54e070e88a603"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/6e4dbcf5e81eba86e36731f94fe56b1726835846",
- "reference": "6e4dbcf5e81eba86e36731f94fe56b1726835846",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603",
+ "reference": "e9247d281d694a5120554d9afaf54e070e88a603",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "1.17-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
- "psr-4": {
- "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
- },
"files": [
"bootstrap.php"
- ]
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -3015,6 +3741,9 @@
"portable",
"shim"
],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -3024,50 +3753,51 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-06-06T08:46:27+00:00"
+ "time": "2026-05-26T05:58:03+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.17.1",
+ "version": "v1.38.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "40309d1700e8f72447bb9e7b54af756eeea35620"
+ "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/40309d1700e8f72447bb9e7b54af756eeea35620",
- "reference": "40309d1700e8f72447bb9e7b54af756eeea35620",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b",
+ "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "1.17-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
- "psr-4": {
- "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
- },
"files": [
"bootstrap.php"
],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
+ },
"classmap": [
"Resources/stubs"
]
@@ -3096,6 +3826,9 @@
"portable",
"shim"
],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -3105,50 +3838,55 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-06-14T14:40:37+00:00"
+ "time": "2026-05-25T13:48:31+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.17.1",
+ "version": "v1.38.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "7110338d81ce1cbc3e273136e4574663627037a7"
+ "reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7110338d81ce1cbc3e273136e4574663627037a7",
- "reference": "7110338d81ce1cbc3e273136e4574663627037a7",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/14c5439eec4ccff081ac14eca2dc57feb2a66d92",
+ "reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "ext-iconv": "*",
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "1.17-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
- "psr-4": {
- "Symfony\\Polyfill\\Mbstring\\": ""
- },
"files": [
"bootstrap.php"
- ]
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -3173,6 +3911,9 @@
"portable",
"shim"
],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.1"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -3182,48 +3923,48 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-06-06T08:46:27+00:00"
+ "time": "2026-05-26T12:51:13+00:00"
},
{
- "name": "symfony/polyfill-php70",
- "version": "v1.17.1",
+ "name": "symfony/polyfill-php80",
+ "version": "v1.37.0",
"source": {
"type": "git",
- "url": "https://github.com/symfony/polyfill-php70.git",
- "reference": "471b096aede7025bace8eb356b9ac801aaba7e2d"
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/471b096aede7025bace8eb356b9ac801aaba7e2d",
- "reference": "471b096aede7025bace8eb356b9ac801aaba7e2d",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
+ "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
"shasum": ""
},
"require": {
- "paragonie/random_compat": "~1.0|~2.0|~9.99",
- "php": ">=5.3.3"
+ "php": ">=7.2"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "1.17-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
- "psr-4": {
- "Symfony\\Polyfill\\Php70\\": ""
- },
"files": [
"bootstrap.php"
],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php80\\": ""
+ },
"classmap": [
"Resources/stubs"
]
@@ -3233,6 +3974,10 @@
"MIT"
],
"authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
@@ -3242,7 +3987,7 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions",
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
@@ -3250,6 +3995,9 @@
"portable",
"shim"
],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -3259,42 +4007,50 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-06-06T08:46:27+00:00"
+ "time": "2026-04-10T16:19:22+00:00"
},
{
- "name": "symfony/polyfill-php72",
- "version": "v1.17.0",
+ "name": "symfony/polyfill-php81",
+ "version": "v1.38.1",
"source": {
"type": "git",
- "url": "https://github.com/symfony/polyfill-php72.git",
- "reference": "f048e612a3905f34931127360bdd2def19a5e582"
+ "url": "https://github.com/symfony/polyfill-php81.git",
+ "reference": "6bfb9c766cacffbc8e118cb87217d08ed84e5cd7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/f048e612a3905f34931127360bdd2def19a5e582",
- "reference": "f048e612a3905f34931127360bdd2def19a5e582",
+ "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/6bfb9c766cacffbc8e118cb87217d08ed84e5cd7",
+ "reference": "6bfb9c766cacffbc8e118cb87217d08ed84e5cd7",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=7.2"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "1.17-dev"
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
- "psr-4": {
- "Symfony\\Polyfill\\Php72\\": ""
- },
"files": [
"bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php81\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -3311,7 +4067,7 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
+ "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
@@ -3319,6 +4075,9 @@
"portable",
"shim"
],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php81/tree/v1.38.1"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -3328,47 +4087,48 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-05-12T16:47:27+00:00"
+ "time": "2026-05-26T12:45:58+00:00"
},
{
- "name": "symfony/polyfill-php73",
- "version": "v1.17.1",
+ "name": "symfony/polyfill-php84",
+ "version": "v1.38.1",
"source": {
"type": "git",
- "url": "https://github.com/symfony/polyfill-php73.git",
- "reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a"
+ "url": "https://github.com/symfony/polyfill-php84.git",
+ "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fa0837fe02d617d31fbb25f990655861bb27bd1a",
- "reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a",
+ "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa",
+ "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=7.2"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "1.17-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
- "psr-4": {
- "Symfony\\Polyfill\\Php73\\": ""
- },
"files": [
"bootstrap.php"
],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php84\\": ""
+ },
"classmap": [
"Resources/stubs"
]
@@ -3387,7 +4147,7 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
+ "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
@@ -3395,6 +4155,9 @@
"portable",
"shim"
],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php84/tree/v1.38.1"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -3404,47 +4167,48 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-06-06T08:46:27+00:00"
+ "time": "2026-05-26T12:51:13+00:00"
},
{
- "name": "symfony/polyfill-php80",
- "version": "v1.17.1",
+ "name": "symfony/polyfill-php85",
+ "version": "v1.38.1",
"source": {
"type": "git",
- "url": "https://github.com/symfony/polyfill-php80.git",
- "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2"
+ "url": "https://github.com/symfony/polyfill-php85.git",
+ "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4a5b6bba3259902e386eb80dd1956181ee90b5b2",
- "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2",
+ "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1",
+ "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1",
"shasum": ""
},
"require": {
- "php": ">=7.0.8"
+ "php": ">=7.2"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "1.17-dev"
- },
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
- "psr-4": {
- "Symfony\\Polyfill\\Php80\\": ""
- },
"files": [
"bootstrap.php"
],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php85\\": ""
+ },
"classmap": [
"Resources/stubs"
]
@@ -3454,10 +4218,6 @@
"MIT"
],
"authors": [
- {
- "name": "Ion Bazan",
- "email": "ion.bazan@gmail.com"
- },
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
@@ -3467,7 +4227,7 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
@@ -3475,6 +4235,9 @@
"portable",
"shim"
],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php85/tree/v1.38.1"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -3484,37 +4247,35 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-06-06T08:46:27+00:00"
+ "time": "2026-05-26T02:25:22+00:00"
},
{
"name": "symfony/process",
- "version": "v5.1.2",
+ "version": "v8.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "7f6378c1fa2147eeb1b4c385856ce9de0d46ebd1"
+ "reference": "c4a9e58f235a6bf7f97ffbfedae2687353ac79e5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/7f6378c1fa2147eeb1b4c385856ce9de0d46ebd1",
- "reference": "7f6378c1fa2147eeb1b4c385856ce9de0d46ebd1",
+ "url": "https://api.github.com/repos/symfony/process/zipball/c4a9e58f235a6bf7f97ffbfedae2687353ac79e5",
+ "reference": "c4a9e58f235a6bf7f97ffbfedae2687353ac79e5",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/polyfill-php80": "^1.15"
+ "php": ">=8.4.1"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.1-dev"
- }
- },
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
@@ -3537,8 +4298,11 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony Process Component",
+ "description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/process/tree/v8.1.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -3548,44 +4312,56 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-05-30T20:35:19+00:00"
+ "time": "2026-05-29T05:06:50+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v2.1.2",
+ "version": "v3.7.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "66a8f0957a3ca54e4f724e49028ab19d75a8918b"
+ "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/66a8f0957a3ca54e4f724e49028ab19d75a8918b",
- "reference": "66a8f0957a3ca54e4f724e49028ab19d75a8918b",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a",
+ "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "psr/container": "^1.0"
+ "php": ">=8.1",
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3"
},
- "suggest": {
- "symfony/service-implementation": ""
+ "conflict": {
+ "ext-psr": "<1.1|>=2"
},
"type": "library",
"extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
"branch-alias": {
- "dev-master": "2.1-dev"
+ "dev-main": "3.7-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
- }
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -3611,6 +4387,9 @@
"interoperability",
"standards"
],
+ "support": {
+ "source": "https://github.com/symfony/service-contracts/tree/v3.7.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -3620,37 +4399,36 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-05-20T17:43:50+00:00"
+ "time": "2026-03-28T09:44:51+00:00"
},
{
"name": "symfony/stopwatch",
- "version": "v5.1.2",
+ "version": "v8.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/stopwatch.git",
- "reference": "0f7c58cf81dbb5dd67d423a89d577524a2ec0323"
+ "reference": "21c07b026905d596e8379caeb115d87aa479499d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/stopwatch/zipball/0f7c58cf81dbb5dd67d423a89d577524a2ec0323",
- "reference": "0f7c58cf81dbb5dd67d423a89d577524a2ec0323",
+ "url": "https://api.github.com/repos/symfony/stopwatch/zipball/21c07b026905d596e8379caeb115d87aa479499d",
+ "reference": "21c07b026905d596e8379caeb115d87aa479499d",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/service-contracts": "^1.0|^2"
+ "php": ">=8.4.1",
+ "symfony/service-contracts": "^2.5|^3"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.1-dev"
- }
- },
"autoload": {
"psr-4": {
"Symfony\\Component\\Stopwatch\\": ""
@@ -3673,8 +4451,11 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony Stopwatch Component",
+ "description": "Provides a way to profile code",
"homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/stopwatch/tree/v8.1.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -3684,54 +4465,56 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-05-20T17:43:50+00:00"
+ "time": "2026-05-29T05:06:50+00:00"
},
{
"name": "symfony/string",
- "version": "v5.1.2",
+ "version": "v8.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "ac70459db781108db7c6d8981dd31ce0e29e3298"
+ "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/ac70459db781108db7c6d8981dd31ce0e29e3298",
- "reference": "ac70459db781108db7c6d8981dd31ce0e29e3298",
+ "url": "https://api.github.com/repos/symfony/string/zipball/afd5944f4005862d961efb85c8bbd5c523c4e3c9",
+ "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-intl-grapheme": "~1.0",
- "symfony/polyfill-intl-normalizer": "~1.0",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php80": "~1.15"
+ "php": ">=8.4.1",
+ "symfony/polyfill-ctype": "^1.8",
+ "symfony/polyfill-intl-grapheme": "^1.33",
+ "symfony/polyfill-intl-normalizer": "^1.0",
+ "symfony/polyfill-mbstring": "^1.0"
+ },
+ "conflict": {
+ "symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "symfony/error-handler": "^4.4|^5.0",
- "symfony/http-client": "^4.4|^5.0",
- "symfony/translation-contracts": "^1.1|^2",
- "symfony/var-exporter": "^4.4|^5.0"
+ "symfony/emoji": "^7.4|^8.0",
+ "symfony/http-client": "^7.4|^8.0",
+ "symfony/intl": "^7.4|^8.0",
+ "symfony/translation-contracts": "^2.5|^3.0",
+ "symfony/var-exporter": "^7.4|^8.0"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.1-dev"
- }
- },
"autoload": {
- "psr-4": {
- "Symfony\\Component\\String\\": ""
- },
"files": [
"Resources/functions.php"
],
+ "psr-4": {
+ "Symfony\\Component\\String\\": ""
+ },
"exclude-from-classmap": [
"/Tests/"
]
@@ -3750,7 +4533,7 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony String component",
+ "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
"homepage": "https://symfony.com",
"keywords": [
"grapheme",
@@ -3760,6 +4543,9 @@
"utf-8",
"utf8"
],
+ "support": {
+ "source": "https://github.com/symfony/string/tree/v8.1.0"
+ },
"funding": [
{
"url": "https://symfony.com/sponsor",
@@ -3769,32 +4555,36 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2020-06-11T12:16:36+00:00"
+ "time": "2026-05-29T05:06:50+00:00"
},
{
"name": "theseer/tokenizer",
- "version": "1.1.3",
+ "version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
- "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9"
+ "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
- "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4",
+ "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-tokenizer": "*",
"ext-xmlwriter": "*",
- "php": "^7.0"
+ "php": "^8.1"
},
"type": "library",
"autoload": {
@@ -3814,67 +4604,30 @@
}
],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
- "time": "2019-06-13T22:48:21+00:00"
- },
- {
- "name": "webmozart/assert",
- "version": "1.9.0",
- "source": {
- "type": "git",
- "url": "https://github.com/webmozart/assert.git",
- "reference": "9dc4f203e36f2b486149058bade43c851dd97451"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/webmozart/assert/zipball/9dc4f203e36f2b486149058bade43c851dd97451",
- "reference": "9dc4f203e36f2b486149058bade43c851dd97451",
- "shasum": ""
- },
- "require": {
- "php": "^5.3.3 || ^7.0",
- "symfony/polyfill-ctype": "^1.8"
- },
- "conflict": {
- "phpstan/phpstan": "<0.12.20",
- "vimeo/psalm": "<3.9.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^4.8.36 || ^7.5.13"
+ "support": {
+ "issues": "https://github.com/theseer/tokenizer/issues",
+ "source": "https://github.com/theseer/tokenizer/tree/2.0.1"
},
- "type": "library",
- "autoload": {
- "psr-4": {
- "Webmozart\\Assert\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
+ "funding": [
{
- "name": "Bernhard Schussek",
- "email": "bschussek@gmail.com"
+ "url": "https://github.com/theseer",
+ "type": "github"
}
],
- "description": "Assertions to validate method input/output with nice error messages.",
- "keywords": [
- "assert",
- "check",
- "validate"
- ],
- "time": "2020-06-16T10:16:42+00:00"
+ "time": "2025-12-08T11:19:18+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": ">=7.4.0",
- "ext-openssl": ">=7.4.0"
+ "php": ">=8.4.0",
+ "ext-openssl": "*",
+ "ext-session": "*",
+ "ext-mbstring": "*"
},
- "platform-dev": [],
- "plugin-api-version": "1.1.0"
+ "platform-dev": {},
+ "plugin-api-version": "2.9.0"
}
diff --git a/coverage/.gitkeep b/coverage/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..812037d
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,24 @@
+services:
+ mariadb:
+ image: mariadb:10.4
+ environment:
+ - "MYSQL_ALLOW_EMPTY_PASSWORD=yes"
+ - "MYSQL_DATABASE=test_database"
+ restart: "on-failure"
+
+ redis:
+ image: redis:6
+ restart: "on-failure"
+
+ lib:
+ build: ./
+ depends_on:
+ - mariadb
+ - redis
+ environment:
+ - "MYSQL_HOST=mariadb"
+ - "REDIS_HOST=redis"
+ - "XDEBUG_MODE=coverage"
+ volumes:
+ - "./coverage:/app/coverage"
+ restart: "no"
diff --git a/entrypoint.sh b/entrypoint.sh
new file mode 100755
index 0000000..e8b4842
--- /dev/null
+++ b/entrypoint.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+DB_TIMEOUT=${DB_TIMEOUT:-45}
+
+# Check MySQL up
+MYSQL_CMD="mysql -h ${MYSQL_HOST} -P ${MYSQL_PORT:-3306} -u ${MYSQL_USER:-root}"
+echo "Waiting ${DB_TIMEOUT}s for MySQL database to be ready..."
+counter=1
+while ! ${MYSQL_CMD} -e "show databases;" > /dev/null 2>&1; do
+ sleep 1
+ counter=$((counter + 1))
+ if [ ${counter} -gt "${DB_TIMEOUT}" ]; then
+ >&2 echo "ERROR: Failed to connect to MySQL database on $MYSQL_HOST"
+ exit 1
+ fi;
+done
+echo "MySQL database ready!"
+
+exec "$@"
diff --git a/phpcs.xml b/phpcs.xml
deleted file mode 100644
index 317373d..0000000
--- a/phpcs.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
- Session
-
-
-
-
- src
-
-
-
-
\ No newline at end of file
diff --git a/phpunit.xml b/phpunit.xml
index aa208dd..add1e99 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,13 +1,13 @@
-
-
-
- tests
-
-
-
-
-
- src/
-
-
-
\ No newline at end of file
+
+
+
+
+ tests
+
+
+
+
+ src/
+
+
+
diff --git a/src/ArrayManager.php b/src/ArrayManager.php
index cee61d3..e93a8c1 100644
--- a/src/ArrayManager.php
+++ b/src/ArrayManager.php
@@ -4,24 +4,17 @@
namespace Rancoud\Session;
-/**
- * Trait ArrayManager.
- */
trait ArrayManager
{
- /** @var array */
protected static array $flashData = [];
+ /** @throws SessionException */
abstract protected static function startSessionIfNotHasStarted();
+ /** @throws SessionException */
abstract protected static function startSessionIfNotHasStartedForceWrite();
- /**
- * @param string $key
- * @param mixed $value
- *
- * @throws \Exception
- */
+ /** @throws SessionException */
public static function set(string $key, $value): void
{
static::startSessionIfNotHasStartedForceWrite();
@@ -29,13 +22,7 @@ public static function set(string $key, $value): void
$_SESSION[$key] = $value;
}
- /**
- * @param string $key
- *
- * @throws \Exception
- *
- * @return bool
- */
+ /** @throws SessionException */
public static function has(string $key): bool
{
static::startSessionIfNotHasStarted();
@@ -43,14 +30,7 @@ public static function has(string $key): bool
return \array_key_exists($key, $_SESSION);
}
- /**
- * @param string $key
- * @param mixed $value
- *
- * @throws \Exception
- *
- * @return bool
- */
+ /** @throws SessionException */
public static function hasKeyAndValue(string $key, $value): bool
{
static::startSessionIfNotHasStarted();
@@ -58,13 +38,7 @@ public static function hasKeyAndValue(string $key, $value): bool
return \array_key_exists($key, $_SESSION) && $_SESSION[$key] === $value;
}
- /**
- * @param string $key
- *
- * @throws \Exception
- *
- * @return mixed
- */
+ /** @throws SessionException */
public static function get(string $key)
{
static::startSessionIfNotHasStarted();
@@ -72,11 +46,7 @@ public static function get(string $key)
return (static::has($key)) ? $_SESSION[$key] : null;
}
- /**
- * @param string $key
- *
- * @throws \Exception
- */
+ /** @throws SessionException */
public static function remove(string $key): void
{
static::startSessionIfNotHasStartedForceWrite();
@@ -86,11 +56,7 @@ public static function remove(string $key): void
}
}
- /**
- * @throws \Exception
- *
- * @return array
- */
+ /** @throws SessionException */
public static function getAll(): array
{
static::startSessionIfNotHasStarted();
@@ -98,13 +64,7 @@ public static function getAll(): array
return $_SESSION;
}
- /**
- * @param string $key
- *
- * @throws \Exception
- *
- * @return mixed
- */
+ /** @throws SessionException */
public static function getAndRemove(string $key)
{
static::startSessionIfNotHasStartedForceWrite();
@@ -115,53 +75,34 @@ public static function getAndRemove(string $key)
return $value;
}
- /**
- * @param string $key
- * @param mixed $value
- *
- * @throws \Exception
- */
public static function setFlash(string $key, $value): void
{
static::$flashData[$key] = $value;
}
- /**
- * @param string $key
- *
- * @return bool
- */
public static function hasFlash(string $key): bool
{
return \array_key_exists($key, static::$flashData);
}
- /**
- * @param string $key
- * @param mixed $value
- *
- * @return bool
- */
public static function hasFlashKeyAndValue(string $key, $value): bool
{
return \array_key_exists($key, static::$flashData) && static::$flashData[$key] === $value;
}
- /**
- * @param string $key
- *
- * @throws \Exception
- *
- * @return mixed
- */
public static function getFlash(string $key)
{
return (static::hasFlash($key)) ? static::$flashData[$key] : null;
}
- /**
- * @param array $keys
- */
+ public static function removeFlash(string $key): void
+ {
+ if (static::hasFlash($key)) {
+ unset(static::$flashData[$key]);
+ }
+ }
+
+ /** @throws SessionException */
public static function keepFlash(array $keys = []): void
{
static::startSessionIfNotHasStartedForceWrite();
@@ -179,20 +120,6 @@ public static function keepFlash(array $keys = []): void
}
}
- /**
- * @throws \Exception
- */
- public static function restoreFlashData(): void
- {
- $data = static::getAndRemove('flash_data');
- if (null !== $data) {
- static::$flashData = $data;
- }
- }
-
- /**
- * @return array
- */
public static function getAllFlash(): array
{
return static::$flashData;
diff --git a/src/Database.php b/src/Database.php
index da44307..59a3e54 100644
--- a/src/Database.php
+++ b/src/Database.php
@@ -1,202 +1,213 @@
db = new Db($configuration);
- } else {
- $this->db = new Db(new Configurator($configuration));
+ try {
+ if ($configuration instanceof Configurator) {
+ $this->db = new DB($configuration);
+ } else {
+ $this->db = new DB(new Configurator($configuration));
+ }
+ } catch (DatabaseException $e) {
+ throw new SessionException('could not set database: ' . $e->getMessage(), $e->getCode(), $e->getPrevious());
}
}
- /**
- * @param Db $database
- */
- public function setCurrentDatabase($database): void
+ public function setCurrentDatabase(DB $database): void
{
$this->db = $database;
}
- /**
- * @param int $userId
- */
public function setUserId(?int $userId): void
{
$this->userId = $userId;
}
- /**
- * @param string $savePath
- * @param string $sessionName
- *
- * @return bool
- */
- public function open($savePath, $sessionName): bool
+ /** @throws SessionException */
+ public function setLengthSessionID(int $length): void
+ {
+ if ($length < 32) {
+ throw new SessionException('could not set length session ID below 32');
+ }
+
+ $this->lengthSessionID = $length;
+ }
+
+ public function getLengthSessionID(): int
+ {
+ return $this->lengthSessionID;
+ }
+
+ /** @throws SessionException */
+ public function deleteUserSessions(int $userID): void
+ {
+ try {
+ $sql = 'DELETE FROM sessions WHERE id_user = :id_user';
+ $params = ['id_user' => $userID];
+ $this->db->delete($sql, $params);
+ } catch (DatabaseException $e) {
+ throw new SessionException('could not delete sessions: ' . $e->getMessage(), $e->getCode(), $e->getPrevious());
+ }
+ }
+
+ /** @throws SessionException */
+ public function deleteAnonymousSessions(): void
+ {
+ try {
+ $sql = 'DELETE FROM sessions WHERE id_user IS NULL';
+ $this->db->delete($sql);
+ } catch (DatabaseException $e) {
+ throw new SessionException('could not delete sessions: ' . $e->getMessage(), $e->getCode(), $e->getPrevious());
+ }
+ }
+
+ public function open(string $path, string $name): bool
{
return true;
}
- /**
- * @return bool
- */
public function close(): bool
{
return true;
}
- /**
- * @param string $sessionId
- *
- * @throws DatabaseException
- *
- * @return string
- */
- public function read($sessionId): string
+ /** @throws SessionException */
+ public function read(string $id): string
{
- $sql = 'SELECT content FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
+ try {
+ $sql = 'SELECT content FROM sessions WHERE id = :id';
+ $params = ['id' => $id];
- return (string) $this->db->selectVar($sql, $params);
+ return (string) $this->db->selectVar($sql, $params);
+ } catch (DatabaseException $e) {
+ throw new SessionException('could not read session: ' . $e->getMessage(), $e->getCode(), $e->getPrevious());
+ }
}
- /**
- * @param string $sessionId
- * @param string $data
- *
- * @throws DatabaseException
- *
- * @return bool
- */
- public function write($sessionId, $data): bool
+ /** @throws SessionException */
+ public function write(string $id, string $data): bool
{
- $sql = 'REPLACE INTO sessions VALUES(:id, :id_user, NOW(), :content)';
- $params = ['id' => $sessionId, 'id_user' => $this->userId, 'content' => $data];
+ try {
+ $sql = 'REPLACE INTO sessions VALUES(:id, :id_user, UTC_TIMESTAMP(), :content)';
+ $params = ['id' => $id, 'id_user' => $this->userId, 'content' => $data];
- $this->db->exec($sql, $params);
+ $this->db->exec($sql, $params);
- return true;
+ return true;
+ } catch (DatabaseException $e) {
+ throw new SessionException('could not update session: ' . $e->getMessage(), $e->getCode(), $e->getPrevious());
+ }
}
- /**
- * @param string $sessionId
- *
- * @throws DatabaseException
- *
- * @return bool
- */
- public function destroy($sessionId): bool
+ /** @throws SessionException */
+ public function destroy(string $id): bool
{
- $sql = 'DELETE FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
- $this->db->delete($sql, $params);
-
- return true;
+ try {
+ $sql = 'DELETE FROM sessions WHERE id = :id';
+ $params = ['id' => $id];
+ $this->db->delete($sql, $params);
+
+ return true;
+ } catch (DatabaseException $e) {
+ throw new SessionException('could not delete session: ' . $e->getMessage(), $e->getCode(), $e->getPrevious());
+ }
}
- /**
- * @param int $lifetime
- *
- * @throws DatabaseException
- *
- * @return bool
- */
- public function gc($lifetime): bool
+ /** @throws SessionException */
+ #[\ReturnTypeWillChange]
+ public function gc(int $max_lifetime): bool
{
- $sql = 'DELETE FROM sessions WHERE DATE_ADD(last_access, INTERVAL :seconds second) < NOW()';
- $params = ['seconds' => $lifetime];
- $this->db->delete($sql, $params);
-
- return true;
+ try {
+ $sql = 'DELETE FROM sessions WHERE DATE_ADD(last_access, INTERVAL :seconds second) < UTC_TIMESTAMP()';
+ $params = ['seconds' => $max_lifetime];
+ $this->db->delete($sql, $params);
+
+ return true;
+ } catch (DatabaseException $e) {
+ throw new SessionException('could not clean old sessions: ' . $e->getMessage(), $e->getCode(), $e->getPrevious());
+ }
}
/**
* Checks format and id exists, if not session_id will be regenerate.
*
- * @param string $key
- *
- * @throws DatabaseException
- *
- * @return bool
+ * @throws SessionException
*/
- public function validateId($key): bool
+ public function validateId(string $id): bool
{
- if (\preg_match('/^[a-zA-Z0-9-]{127}+$/', $key) !== 1) {
- return false;
+ try {
+ if (\preg_match('/^[a-zA-Z0-9-]{' . $this->lengthSessionID . '}+$/', $id) !== 1) {
+ return false;
+ }
+
+ $sql = 'SELECT COUNT(id) FROM sessions WHERE id=:id';
+ $params = ['id' => $id];
+ $count = $this->db->count($sql, $params);
+
+ return $count === 1;
+ } catch (DatabaseException $e) {
+ throw new SessionException('could not validate id: ' . $e->getMessage(), $e->getCode(), $e->getPrevious());
}
-
- $sql = 'SELECT COUNT(id) FROM sessions WHERE id=:id';
- $params = ['id' => $key];
- $count = $this->db->count($sql, $params);
-
- return $count === 1;
}
/**
* Updates the timestamp of a session when its data didn't change.
*
- * @param string $sessionId
- * @param string $sessionData
- *
- * @throws DatabaseException
- *
- * @return bool
+ * @throws SessionException
*/
- public function updateTimestamp($sessionId, $sessionData): bool
+ public function updateTimestamp(string $id, string $data): bool
{
- return $this->write($sessionId, $sessionData);
+ return $this->write($id, $data);
}
/**
- * @throws \Exception
- * @throws DatabaseException
+ * @throws SessionException
*
- * @return string
+ * @noinspection PhpMethodNamingConventionInspection
*/
public function create_sid(): string
{
- $string = '';
- $caracters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-';
-
- $countCaracters = 62;
- for ($i = 0; $i < 127; ++$i) {
- $string .= $caracters[\random_int(0, $countCaracters)];
- }
-
- $sql = 'SELECT COUNT(id) FROM sessions WHERE id=:id';
- $params = ['id' => $string];
- $count = $this->db->count($sql, $params);
- if ($count !== 0) {
- return $this->create_sid();
+ try {
+ $string = '';
+ $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-';
+
+ $countCharacters = 62;
+ for ($i = 0; $i < $this->lengthSessionID; ++$i) {
+ $string .= $characters[\random_int(0, $countCharacters)];
+ }
+
+ $sql = 'SELECT COUNT(id) FROM sessions WHERE id=:id';
+ $params = ['id' => $string];
+ $count = $this->db->count($sql, $params);
+ if ($count !== 0) {
+ // @codeCoverageIgnoreStart
+ // Could not reach this statement without mocking the function
+ return $this->create_sid();
+ // @codeCoverageIgnoreEnd
+ }
+
+ return $string;
+ } catch (\Exception $e) {
+ throw new SessionException('could not create sid: ' . $e->getMessage(), $e->getCode(), $e->getPrevious());
}
-
- return $string;
}
}
diff --git a/src/DatabaseEncryption.php b/src/DatabaseEncryption.php
index a7c2655..ebd8b79 100644
--- a/src/DatabaseEncryption.php
+++ b/src/DatabaseEncryption.php
@@ -4,43 +4,23 @@
namespace Rancoud\Session;
-use Rancoud\Database\DatabaseException;
-
-/**
- * Class DatabaseEncryption.
- */
class DatabaseEncryption extends Database
{
use Encryption;
- /**
- * @param string $sessionId
- *
- * @throws SessionException
- * @throws DatabaseException
- *
- * @return string
- */
- public function read($sessionId): string
+ /** @throws SessionException */
+ public function read(string $id): string
{
- $encryptedData = parent::read($sessionId);
+ $encryptedData = parent::read($id);
return $this->decrypt($encryptedData);
}
- /**
- * @param string $sessionId
- * @param string $data
- *
- * @throws DatabaseException
- * @throws SessionException
- *
- * @return bool
- */
- public function write($sessionId, $data): bool
+ /** @throws SessionException */
+ public function write(string $id, string $data): bool
{
$cryptedData = $this->encrypt($data);
- return parent::write($sessionId, $cryptedData);
+ return parent::write($id, $cryptedData);
}
}
diff --git a/src/DefaultEncryption.php b/src/DefaultEncryption.php
index 98cd168..9cd462f 100644
--- a/src/DefaultEncryption.php
+++ b/src/DefaultEncryption.php
@@ -4,41 +4,23 @@
namespace Rancoud\Session;
-use SessionHandler;
-
-/**
- * Class DefaultEncryption.
- */
-class DefaultEncryption extends SessionHandler
+class DefaultEncryption extends \SessionHandler
{
use Encryption;
- /**
- * @param string $sessionId
- *
- * @throws SessionException
- *
- * @return string
- */
- public function read($sessionId): string
+ /** @throws SessionException */
+ public function read(string $id): string
{
- $encryptedData = parent::read($sessionId);
+ $encryptedData = parent::read($id);
return $this->decrypt($encryptedData);
}
- /**
- * @param string $sessionId
- * @param string $data
- *
- * @throws SessionException
- *
- * @return bool
- */
- public function write($sessionId, $data): bool
+ /** @throws SessionException */
+ public function write(string $id, string $data): bool
{
$cryptedData = $this->encrypt($data);
- return parent::write($sessionId, $cryptedData);
+ return parent::write($id, $cryptedData);
}
}
diff --git a/src/DriverManager.php b/src/DriverManager.php
index c90ca7a..7ac0308 100644
--- a/src/DriverManager.php
+++ b/src/DriverManager.php
@@ -4,24 +4,20 @@
namespace Rancoud\Session;
-use SessionHandler;
-use SessionHandlerInterface;
+use Predis\Client as PredisClient;
+use Rancoud\Database\Configurator;
+use Rancoud\Database\Database as DB;
-/**
- * Class DriverManager.
- */
abstract class DriverManager
{
- /** @var SessionHandlerInterface */
- protected static ?SessionHandlerInterface $driver = null;
+ protected static ?\SessionHandlerInterface $driver = null;
+ /** @throws SessionException */
abstract protected static function throwExceptionIfHasStarted();
abstract protected static function getLifetimeForRedis();
- /**
- * @throws \Exception
- */
+ /** @throws SessionException */
protected static function configureDriver(): void
{
if (empty(static::$driver)) {
@@ -29,23 +25,16 @@ protected static function configureDriver(): void
}
}
- /**
- * @throws \Exception
- */
+ /** @throws SessionException */
public static function useDefaultDriver(): void
{
static::throwExceptionIfHasStarted();
- static::$driver = new SessionHandler();
+ static::$driver = new \SessionHandler();
}
- /**
- * @param string $key
- * @param string|null $method
- *
- * @throws \Exception
- */
- public static function useDefaultEncryptionDriver(string $key, string $method = null): void
+ /** @throws SessionException */
+ public static function useDefaultEncryptionDriver(string $key, ?string $method = null): void
{
static::throwExceptionIfHasStarted();
@@ -55,9 +44,7 @@ public static function useDefaultEncryptionDriver(string $key, string $method =
static::$driver = $driver;
}
- /**
- * @throws \Exception
- */
+ /** @throws SessionException */
public static function useFileDriver(): void
{
static::throwExceptionIfHasStarted();
@@ -65,13 +52,8 @@ public static function useFileDriver(): void
static::$driver = new File();
}
- /**
- * @param string $key
- * @param string|null $method
- *
- * @throws \Exception
- */
- public static function useFileEncryptionDriver(string $key, string $method = null): void
+ /** @throws SessionException */
+ public static function useFileEncryptionDriver(string $key, ?string $method = null): void
{
static::throwExceptionIfHasStarted();
@@ -81,12 +63,8 @@ public static function useFileEncryptionDriver(string $key, string $method = nul
static::$driver = $driver;
}
- /**
- * @param \Rancoud\Database\Configurator|array $configuration
- *
- * @throws \Exception
- */
- public static function useNewDatabaseDriver($configuration): void
+ /** @throws SessionException */
+ public static function useNewDatabaseDriver(array|Configurator $configuration): void
{
static::throwExceptionIfHasStarted();
@@ -96,12 +74,8 @@ public static function useNewDatabaseDriver($configuration): void
static::$driver = $driver;
}
- /**
- * @param \Rancoud\Database\Database $databaseInstance
- *
- * @throws \Exception
- */
- public static function useCurrentDatabaseDriver($databaseInstance): void
+ /** @throws SessionException */
+ public static function useCurrentDatabaseDriver(DB $databaseInstance): void
{
static::throwExceptionIfHasStarted();
@@ -111,14 +85,8 @@ public static function useCurrentDatabaseDriver($databaseInstance): void
static::$driver = $driver;
}
- /**
- * @param \Rancoud\Database\Configurator|array $configuration
- * @param string $key
- * @param string $method
- *
- * @throws \Exception
- */
- public static function useNewDatabaseEncryptionDriver($configuration, string $key, string $method = null): void
+ /** @throws SessionException */
+ public static function useNewDatabaseEncryptionDriver(array|Configurator $configuration, string $key, ?string $method = null): void
{
static::throwExceptionIfHasStarted();
@@ -129,14 +97,8 @@ public static function useNewDatabaseEncryptionDriver($configuration, string $ke
static::$driver = $driver;
}
- /**
- * @param \Rancoud\Database\Database $databaseInstance
- * @param string $key
- * @param string $method
- *
- * @throws \Exception
- */
- public static function useCurrentDatabaseEncryptionDriver($databaseInstance, string $key, string $method = null): void
+ /** @throws SessionException */
+ public static function useCurrentDatabaseEncryptionDriver(DB $databaseInstance, string $key, ?string $method = null): void
{
static::throwExceptionIfHasStarted();
@@ -147,12 +109,8 @@ public static function useCurrentDatabaseEncryptionDriver($databaseInstance, str
static::$driver = $driver;
}
- /**
- * @param array|string $configuration
- *
- * @throws \Exception
- */
- public static function useNewRedisDriver($configuration): void
+ /** @throws SessionException */
+ public static function useNewRedisDriver(array|string $configuration): void
{
static::throwExceptionIfHasStarted();
@@ -163,12 +121,8 @@ public static function useNewRedisDriver($configuration): void
static::$driver = $driver;
}
- /**
- * @param \Predis\Client $redisInstance
- *
- * @throws \Exception
- */
- public static function useCurrentRedisDriver($redisInstance): void
+ /** @throws SessionException */
+ public static function useCurrentRedisDriver(PredisClient $redisInstance): void
{
static::throwExceptionIfHasStarted();
@@ -179,14 +133,8 @@ public static function useCurrentRedisDriver($redisInstance): void
static::$driver = $driver;
}
- /**
- * @param array|string $configuration
- * @param string $key
- * @param string $method
- *
- * @throws \Exception
- */
- public static function useNewRedisEncryptionDriver($configuration, string $key, string $method = null): void
+ /** @throws SessionException */
+ public static function useNewRedisEncryptionDriver(array|string $configuration, string $key, ?string $method = null): void
{
static::throwExceptionIfHasStarted();
@@ -198,14 +146,8 @@ public static function useNewRedisEncryptionDriver($configuration, string $key,
static::$driver = $driver;
}
- /**
- * @param \Predis\Client $redisInstance
- * @param string $key
- * @param string $method
- *
- * @throws \Exception
- */
- public static function useCurrentRedisEncryptionDriver($redisInstance, string $key, string $method = null): void
+ /** @throws SessionException */
+ public static function useCurrentRedisEncryptionDriver(PredisClient $redisInstance, string $key, ?string $method = null): void
{
static::throwExceptionIfHasStarted();
@@ -218,13 +160,11 @@ public static function useCurrentRedisEncryptionDriver($redisInstance, string $k
}
/**
- * @param Encryption $driver
- * @param $key
- * @param $method
+ * @param Encryption $driver (use Encryption trait)
*
- * @throws \Exception
+ * @throws SessionException
*/
- private static function setKeyAndMethod($driver, $key, $method): void
+ private static function setKeyAndMethod(mixed $driver, string $key, ?string $method): void
{
$driver->setKey($key);
if ($method !== null) {
@@ -232,29 +172,19 @@ private static function setKeyAndMethod($driver, $key, $method): void
}
}
- /**
- * @param SessionHandlerInterface $customDriver
- *
- * @throws \Exception
- */
- public static function useCustomDriver(SessionHandlerInterface $customDriver): void
+ /** @throws SessionException */
+ public static function useCustomDriver(\SessionHandlerInterface $customDriver): void
{
static::throwExceptionIfHasStarted();
static::$driver = $customDriver;
}
- /**
- * @return SessionHandlerInterface
- */
- public static function getDriver(): SessionHandlerInterface
+ public static function getDriver(): \SessionHandlerInterface
{
return static::$driver;
}
- /**
- * @param int $userId
- */
public static function setUserIdForDatabase(int $userId): void
{
if (\method_exists(static::$driver, 'setUserId')) {
@@ -262,13 +192,24 @@ public static function setUserIdForDatabase(int $userId): void
}
}
- /**
- * @param string $prefix
- */
public static function setPrefixForFile(string $prefix): void
{
if (\method_exists(static::$driver, 'setPrefix')) {
static::$driver->setPrefix($prefix);
}
}
+
+ public static function deleteUserSessionsInDatabase(int $userID): void
+ {
+ if (\method_exists(static::$driver, 'deleteUserSessions')) {
+ static::$driver->deleteUserSessions($userID);
+ }
+ }
+
+ public static function deleteAnonymousSessionsInDatabase(): void
+ {
+ if (\method_exists(static::$driver, 'deleteAnonymousSessions')) {
+ static::$driver->deleteAnonymousSessions();
+ }
+ }
}
diff --git a/src/Encryption.php b/src/Encryption.php
index 86b9ca8..863f602 100644
--- a/src/Encryption.php
+++ b/src/Encryption.php
@@ -4,106 +4,119 @@
namespace Rancoud\Session;
-/**
- * Trait Encryption.
- */
trait Encryption
{
- /** @var string */
- protected $key;
+ protected ?string $key = null;
- /** @var string */
- protected $method = 'aes-256-cbc';
+ protected string $method = 'aes-256-cbc';
- /**
- * @param string $key
- */
public function setKey(string $key): void
{
$this->key = $key;
}
- /**
- * @param string $method
- *
- * @throws SessionException
- */
+ /** @throws SessionException */
public function setMethod(string $method): void
{
if (!\in_array($method, $this->getAvailableMethods(), true)) {
- throw new SessionException(\sprintf('Method unknowed: %s', $method));
+ throw new SessionException(\sprintf('Unknown method: %s', $method));
}
$this->method = $method;
}
- /**
- * @return array
- */
public function getAvailableMethods(): array
{
$ciphers = \openssl_get_cipher_methods();
$ciphersAndAliases = \openssl_get_cipher_methods(true);
$cipherAliases = \array_diff($ciphersAndAliases, $ciphers);
- $ciphers = \array_filter($ciphers, function ($n) {
- return \mb_stripos($n, 'ecb') === false;
- });
- $ciphers = \array_filter($ciphers, function ($c) {
- return \mb_stripos($c, 'des') === false;
- });
- $ciphers = \array_filter($ciphers, function ($c) {
- return \mb_stripos($c, 'rc2') === false;
- });
- $ciphers = \array_filter($ciphers, function ($c) {
- return \mb_stripos($c, 'rc4') === false;
- });
- $ciphers = \array_filter($ciphers, function ($c) {
- return \mb_stripos($c, 'md5') === false;
- });
- $ciphers = \array_filter($ciphers, function ($c) {
- return \mb_stripos($c, '-ocb') === false;
- });
- $ciphers = \array_filter($ciphers, function ($c) {
- return \mb_stripos($c, '-ccm') === false;
- });
- $ciphers = \array_filter($ciphers, function ($c) {
- return \mb_stripos($c, '-gcm') === false;
- });
- $ciphers = \array_filter($ciphers, function ($c) {
- return \mb_stripos($c, '-wrap') === false;
+ $ciphers = \array_filter($ciphers, static function ($n) {
+ $excludeMethods = [
+ 'ecb', 'des', 'rc2', 'rc4', 'md5',
+ '-ocb', '-ccm', '-gcm', '-wrap'
+ ];
+ foreach ($excludeMethods as $excludeMethod) {
+ if (\mb_stripos($n, $excludeMethod) !== false) {
+ return false;
+ }
+ }
+
+ return true;
});
- $cipherAliases = \array_filter($cipherAliases, function ($c) {
- return \mb_stripos($c, 'des') === false;
- });
- $cipherAliases = \array_filter($cipherAliases, function ($c) {
- return \mb_stripos($c, 'rc2') === false;
- });
- $cipherAliases = \array_filter($cipherAliases, function ($c) {
- return \mb_stripos($c, '-wrap') === false;
+ $cipherAliases = \array_filter($cipherAliases, static function ($c) {
+ $excludeMethods = [
+ 'des', 'rc2', '-wrap', 'id-'
+ ];
+
+ foreach ($excludeMethods as $excludeMethod) {
+ if (\mb_stripos($c, $excludeMethod) !== false) {
+ return false;
+ }
+ }
+
+ return true;
});
$methods = \array_merge($ciphers, $cipherAliases);
- $methods = \array_filter($methods, function ($c) {
- $forbiddenMethods = ['AES-128-CBC-HMAC-SHA1', 'AES-256-CBC-HMAC-SHA1',
- 'aes-128-cbc-hmac-sha1', 'aes-256-cbc-hmac-sha1'];
-
- return !\in_array($c, $forbiddenMethods, true);
+ return \array_filter($methods, static function ($c) {
+ $forbiddenMethods = [
+ 'aes-128-cbc-hmac-sha1',
+ 'aes-256-cbc-hmac-sha1',
+ 'aes-128-cbc-cts',
+ 'aes-128-cbc-hmac-sha256',
+ 'aes-128-siv',
+ 'aes-192-cbc-cts',
+ 'aes-192-siv',
+ 'aes-256-cbc-cts',
+ 'aes-256-cbc-hmac-sha256',
+ 'aes-256-siv',
+ 'camellia-128-cbc-cts',
+ 'camellia-192-cbc-cts',
+ 'camellia-256-cbc-cts',
+ 'null',
+ 'sm4-xts',
+ '0.3.4401.5.3.1.9.1',
+ '0.3.4401.5.3.1.9.21',
+ '0.3.4401.5.3.1.9.41',
+ '1.2.410.200046.1.1.1',
+ '1.2.410.200046.1.1.11',
+ '1.2.410.200046.1.1.34',
+ '1.2.410.200046.1.1.35',
+ '1.2.410.200046.1.1.36',
+ '1.2.410.200046.1.1.37',
+ '1.2.410.200046.1.1.38',
+ '1.2.410.200046.1.1.39',
+ '1.2.410.200046.1.1.6',
+ '1.2.156.10197.1.104.10',
+ '1.2.840.113549.1.9.16.3.6',
+ '1.3.14.3.2.17',
+ '2.16.840.1.101.3.4.1.1',
+ '2.16.840.1.101.3.4.1.21',
+ '2.16.840.1.101.3.4.1.25',
+ '2.16.840.1.101.3.4.1.26',
+ '2.16.840.1.101.3.4.1.27',
+ '2.16.840.1.101.3.4.1.41',
+ '2.16.840.1.101.3.4.1.45',
+ '2.16.840.1.101.3.4.1.46',
+ '2.16.840.1.101.3.4.1.47',
+ '2.16.840.1.101.3.4.1.5',
+ '2.16.840.1.101.3.4.1.6',
+ '2.16.840.1.101.3.4.1.7',
+ '1.2.156.10197.1.104.1',
+ '1.2.156.10197.1.104.8',
+ '1.2.156.10197.1.104.9',
+ 'chacha20-poly1305'
+ ];
+
+ return !\in_array(\mb_strtolower($c), $forbiddenMethods, true);
});
-
- return $methods;
}
- /**
- * @param string $data
- *
- * @throws SessionException
- *
- * @return string|bool
- */
- public function decrypt(string $data)
+ /** @throws SessionException */
+ public function decrypt(string $data): string
{
$this->throwExceptionIfKeyEmpty();
@@ -111,32 +124,49 @@ public function decrypt(string $data)
return '';
}
- list($encrypted_data, $iv) = \explode('::', \base64_decode($data, true), 2);
+ [$encryptedData, $iv] = \explode('::', \base64_decode($data, true), 2);
+
+ $dataDecrypted = \openssl_decrypt($encryptedData, $this->method, $this->key, 0, $iv);
+ if ($dataDecrypted === false) {
+ // @codeCoverageIgnoreStart
+ // Could not reach this statement without mocking the function
+ throw new SessionException('Could not decrypt with openssl_decrypt');
+ // @codeCoverageIgnoreEnd
+ }
- return \openssl_decrypt($encrypted_data, $this->method, $this->key, 0, $iv);
+ return $dataDecrypted;
}
- /**
- * @param string $data
- *
- * @throws SessionException
- *
- * @return string
- */
+ /** @throws SessionException */
public function encrypt(string $data): string
{
$this->throwExceptionIfKeyEmpty();
- $iv = \openssl_random_pseudo_bytes(\openssl_cipher_iv_length($this->method));
+ try {
+ $length = \openssl_cipher_iv_length($this->method);
+ if ($length === false || $length < 1) {
+ throw new SessionException('IV generation failed');
+ }
+ } catch (\Exception) {
+ throw new SessionException('IV generation failed');
+ }
+
+ /** @noinspection CryptographicallySecureRandomnessInspection */
+ $iv = \openssl_random_pseudo_bytes($length, $cstrong);
+ /** @noinspection PhpStrictComparisonWithOperandsOfDifferentTypesInspection */
+ if ($iv === false || $cstrong === false) {
+ // @codeCoverageIgnoreStart
+ // Could not reach this statement without mocking the function
+ throw new SessionException('IV generation failed');
+ // @codeCoverageIgnoreEnd
+ }
+
$encrypted = \openssl_encrypt($data, $this->method, $this->key, 0, $iv);
- $data = \base64_encode($encrypted . '::' . $iv);
- return $data;
+ return \base64_encode($encrypted . '::' . $iv);
}
- /**
- * @throws SessionException
- */
+ /** @throws SessionException */
protected function throwExceptionIfKeyEmpty(): void
{
if ($this->key === null || $this->key === '') {
diff --git a/src/File.php b/src/File.php
index 0b1dd80..b778896 100644
--- a/src/File.php
+++ b/src/File.php
@@ -4,106 +4,87 @@
namespace Rancoud\Session;
-use SessionHandlerInterface;
-use SessionUpdateTimestampHandlerInterface;
-
-/**
- * Class File.
- */
-class File implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface
+class File implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
{
- /** @var string|null */
protected ?string $savePath = null;
- /** @var string */
protected string $prefix = 'sess_';
- /**
- * @param string $prefix
- */
+ protected int $lengthSessionID = 127;
+
public function setPrefix(string $prefix): void
{
$this->prefix = $prefix;
}
- /**
- * @param string $savePath
- * @param string $sessionName
- *
- * @return bool
- */
- public function open($savePath, $sessionName): bool
+ /** @throws SessionException */
+ public function setLengthSessionID(int $length): void
+ {
+ if ($length < 32) {
+ throw new SessionException('could not set length session ID below 32');
+ }
+
+ $this->lengthSessionID = $length;
+ }
+
+ public function getLengthSessionID(): int
+ {
+ return $this->lengthSessionID;
+ }
+
+ /** @throws SessionException */
+ public function open(string $path, string $name): bool
{
- $this->savePath = $savePath;
+ $this->savePath = $path;
- if (!\is_dir($this->savePath) && !\mkdir($this->savePath, 0750) && !\is_dir($this->savePath)) {
- throw new \RuntimeException(\sprintf('Directory "%s" was not created', $this->savePath));
+ if (!\is_dir($this->savePath) && !\mkdir($this->savePath, 0o750) && !\is_dir($this->savePath)) {
+ // @codeCoverageIgnoreStart
+ // Could not reach this statement without mocking the filesystem
+ throw new SessionException(\sprintf('Directory "%s" was not created', $this->savePath));
+ // @codeCoverageIgnoreEnd
}
return true;
}
- /**
- * @return bool
- */
public function close(): bool
{
return true;
}
- /**
- * @param string $sessionId
- *
- * @return string
- */
- public function read($sessionId): string
+ public function read(string $id): string
{
- $filename = $this->savePath . \DIRECTORY_SEPARATOR . $this->prefix . $sessionId;
- if (\file_exists($filename)) {
+ $filename = $this->savePath . \DIRECTORY_SEPARATOR . $this->prefix . $id;
+ if (\file_exists($filename) && \is_file($filename)) {
return (string) \file_get_contents($filename);
}
return '';
}
- /**
- * @param string $sessionId
- * @param string $data
- *
- * @return bool
- */
- public function write($sessionId, $data): bool
+ public function write(string $id, string $data): bool
{
- $filename = $this->savePath . \DIRECTORY_SEPARATOR . $this->prefix . $sessionId;
+ $filename = $this->savePath . \DIRECTORY_SEPARATOR . $this->prefix . $id;
- return \file_put_contents($filename, $data) === false ? false : true;
+ return !(\file_put_contents($filename, $data) === false);
}
- /**
- * @param string $sessionId
- *
- * @return bool
- */
- public function destroy($sessionId): bool
+ public function destroy(string $id): bool
{
- $filename = $this->savePath . \DIRECTORY_SEPARATOR . $this->prefix . $sessionId;
- if (\file_exists($filename)) {
+ $filename = $this->savePath . \DIRECTORY_SEPARATOR . $this->prefix . $id;
+ if (\file_exists($filename) && \is_file($filename)) {
\unlink($filename);
}
return true;
}
- /**
- * @param int $lifetime
- *
- * @return bool
- */
- public function gc($lifetime): bool
+ #[\ReturnTypeWillChange]
+ public function gc(int $max_lifetime): bool
{
$pattern = $this->savePath . \DIRECTORY_SEPARATOR . $this->prefix . '*';
foreach (\glob($pattern) as $file) {
- if (\filemtime($file) + $lifetime < \time() && \file_exists($file)) {
+ if (\file_exists($file) && \is_file($file) && \filemtime($file) + $max_lifetime < \time()) {
\unlink($file);
}
}
@@ -111,55 +92,54 @@ public function gc($lifetime): bool
return true;
}
- /**
- * Checks format and id exists, if not session_id will be regenerate.
- *
- * @param string $key
- *
- * @return bool
- */
- public function validateId($key): bool
+ /** Checks format and id exists, if not session_id will be regenerate. */
+ public function validateId(string $id): bool
{
- if (\preg_match('/^[a-zA-Z0-9-]{127}+$/', $key) !== 1) {
+ if (\preg_match('/^[a-zA-Z0-9-]{' . $this->lengthSessionID . '}+$/', $id) !== 1) {
return false;
}
- $filename = $this->savePath . \DIRECTORY_SEPARATOR . $this->prefix . $key;
+ $filename = $this->savePath . \DIRECTORY_SEPARATOR . $this->prefix . $id;
return \file_exists($filename);
}
- /**
- * Updates the timestamp of a session when its data didn't change.
- *
- * @param string $sessionId
- * @param string $sessionData
- *
- * @return bool
- */
- public function updateTimestamp($sessionId, $sessionData): bool
+ /** Updates the timestamp of a session when its data didn't change. */
+ public function updateTimestamp(string $id, string $data): bool
{
- return $this->write($sessionId, $sessionData);
+ return $this->write($id, $data);
}
/**
- * @throws \Exception
+ * @throws SessionException
*
- * @return string
+ * @noinspection PhpMethodNamingConventionInspection
*/
public function create_sid(): string
{
$string = '';
- $caracters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-';
+ $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-';
- $countCaracters = 62;
- for ($i = 0; $i < 127; ++$i) {
- $string .= $caracters[\random_int(0, $countCaracters)];
+ try {
+ $countCharacters = 62;
+ for ($i = 0; $i < $this->lengthSessionID; ++$i) {
+ $string .= $characters[\random_int(0, $countCharacters)];
+ }
+ // @codeCoverageIgnoreStart
+ } catch (\Exception $e) {
+ /* If an appropriate source of randomness cannot be found, an Exception will be thrown.
+ * The list of randomness: https://www.php.net/manual/en/function.random-int.php
+ */
+ throw new SessionException('could not create sid: ' . $e->getMessage(), $e->getCode(), $e->getPrevious());
+ // @codeCoverageIgnoreEnd
}
$filename = $this->savePath . \DIRECTORY_SEPARATOR . $this->prefix . $string;
if (\file_exists($filename)) {
+ // @codeCoverageIgnoreStart
+ // Could not reach this statement without mocking the filesystem
return $this->create_sid();
+ // @codeCoverageIgnoreEnd
}
return $string;
diff --git a/src/FileEncryption.php b/src/FileEncryption.php
index cabbd93..e1ff480 100644
--- a/src/FileEncryption.php
+++ b/src/FileEncryption.php
@@ -4,39 +4,23 @@
namespace Rancoud\Session;
-/**
- * Class FileEncryption.
- */
class FileEncryption extends File
{
use Encryption;
- /**
- * @param $sessionId
- *
- * @throws SessionException
- *
- * @return string
- */
- public function read($sessionId): string
+ /** @throws SessionException */
+ public function read(string $id): string
{
- $encryptedData = parent::read($sessionId);
+ $encryptedData = parent::read($id);
return $this->decrypt($encryptedData);
}
- /**
- * @param $sessionId
- * @param $data
- *
- * @throws SessionException
- *
- * @return bool
- */
- public function write($sessionId, $data): bool
+ /** @throws SessionException */
+ public function write(string $id, string $data): bool
{
$cryptedData = $this->encrypt($data);
- return parent::write($sessionId, $cryptedData);
+ return parent::write($id, $cryptedData);
}
}
diff --git a/src/Redis.php b/src/Redis.php
index 13f3d6f..03a5221 100644
--- a/src/Redis.php
+++ b/src/Redis.php
@@ -5,158 +5,129 @@
namespace Rancoud\Session;
use Predis\Client as Predis;
-use SessionHandlerInterface;
-use SessionUpdateTimestampHandlerInterface;
-/**
- * Class Redis.
- */
-class Redis implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface
+class Redis implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
{
- /** @var Predis */
protected Predis $redis;
- /** @var int */
protected int $lifetime = 1440;
- /**
- * @param string|array $configuration
- */
- public function setNewRedis($configuration): void
+ protected int $lengthSessionID = 127;
+
+ public function setNewRedis(array|string $configuration): void
{
$this->redis = new Predis($configuration);
}
- /**
- * @param Predis $redis
- */
- public function setCurrentRedis($redis): void
+ public function setCurrentRedis(Predis $redis): void
{
$this->redis = $redis;
}
- /**
- * @param int $lifetime
- */
public function setLifetime(int $lifetime): void
{
$this->lifetime = $lifetime;
}
- /**
- * @param string $savePath
- * @param string $sessionName
- *
- * @return bool
- */
- public function open($savePath, $sessionName): bool
+ /** @throws SessionException */
+ public function setLengthSessionID(int $length): void
+ {
+ if ($length < 32) {
+ throw new SessionException('could not set length session ID below 32');
+ }
+
+ $this->lengthSessionID = $length;
+ }
+
+ public function getLengthSessionID(): int
+ {
+ return $this->lengthSessionID;
+ }
+
+ public function open(string $path, string $name): bool
{
return true;
}
- /**
- * @return bool
- */
public function close(): bool
{
return true;
}
- /**
- * @param string $sessionId
- *
- * @return string
- */
- public function read($sessionId): string
+ public function read(string $id): string
{
- return (string) $this->redis->get($sessionId);
+ return (string) $this->redis->get($id);
}
- /**
- * @param string $sessionId
- * @param string $data
- *
- * @return bool
- */
- public function write($sessionId, $data): bool
+ public function write(string $id, string $data): bool
{
- $this->redis->set($sessionId, $data);
- $this->redis->expireat($sessionId, \time() + $this->lifetime);
+ $this->redis->set($id, $data);
+ $this->redis->expireat($id, \time() + $this->lifetime);
return true;
}
- /**
- * @param string $sessionId
- *
- * @return bool
- */
- public function destroy($sessionId): bool
+ public function destroy(string $id): bool
{
- $this->redis->del([$sessionId]);
+ $this->redis->del([$id]);
return true;
}
- /**
- * @param int $lifetime
- *
- * @return bool
- */
- public function gc($lifetime): bool
+ #[\ReturnTypeWillChange]
+ public function gc(int $max_lifetime): bool
{
return true;
}
- /**
- * Checks format and id exists, if not session_id will be regenerate.
- *
- * @param string $key
- *
- * @return bool
- */
- public function validateId($key): bool
+ /** Checks format and id exists, if not session_id will be regenerate. */
+ public function validateId(string $id): bool
{
- if (\preg_match('/^[a-zA-Z0-9-]{127}+$/', $key) !== 1) {
+ if (\preg_match('/^[a-zA-Z0-9-]{' . $this->lengthSessionID . '}+$/', $id) !== 1) {
return false;
}
- $exist = $this->redis->exists($key);
+ $exist = $this->redis->exists($id);
return $exist === 1;
}
- /**
- * Updates the timestamp of a session when its data didn't change.
- *
- * @param string $sessionId
- * @param string $sessionData
- *
- * @return bool
- */
- public function updateTimestamp($sessionId, $sessionData): bool
+ /** Updates the timestamp of a session when its data didn't change. */
+ public function updateTimestamp(string $id, string $data): bool
{
- return $this->write($sessionId, $sessionData);
+ return $this->write($id, $data);
}
/**
- * @throws \Exception
+ * @throws SessionException
*
- * @return string
+ * @noinspection PhpMethodNamingConventionInspection
*/
public function create_sid(): string
{
$string = '';
- $caracters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-';
-
- $countCaracters = 62;
- for ($i = 0; $i < 127; ++$i) {
- $string .= $caracters[\random_int(0, $countCaracters)];
+ $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-';
+
+ try {
+ $countCharacters = 62;
+ for ($i = 0; $i < $this->lengthSessionID; ++$i) {
+ $string .= $characters[\random_int(0, $countCharacters)];
+ }
+ // @codeCoverageIgnoreStart
+ } catch (\Exception $e) {
+ /* If an appropriate source of randomness cannot be found, an Exception will be thrown.
+ * The list of randomness: https://www.php.net/manual/en/function.random-int.php
+ */
+ throw new SessionException('could not create sid: ' . $e->getMessage(), $e->getCode(), $e->getPrevious());
+ // @codeCoverageIgnoreEnd
}
$exist = $this->redis->exists($string);
if ($exist !== 0) {
+ // @codeCoverageIgnoreStart
+ // Could not reach this statement without mocking the function
return $this->create_sid();
+ // @codeCoverageIgnoreEnd
}
return $string;
diff --git a/src/RedisEncryption.php b/src/RedisEncryption.php
index cd146ec..d87cae2 100644
--- a/src/RedisEncryption.php
+++ b/src/RedisEncryption.php
@@ -4,39 +4,23 @@
namespace Rancoud\Session;
-/**
- * Class RedisEncryption.
- */
class RedisEncryption extends Redis
{
use Encryption;
- /**
- * @param $sessionId
- *
- * @throws SessionException
- *
- * @return string
- */
- public function read($sessionId): string
+ /** @throws SessionException */
+ public function read(string $id): string
{
- $encryptedData = parent::read($sessionId);
+ $encryptedData = parent::read($id);
return $this->decrypt($encryptedData);
}
- /**
- * @param $sessionId
- * @param $data
- *
- * @throws SessionException
- *
- * @return bool
- */
- public function write($sessionId, $data): bool
+ /** @throws SessionException */
+ public function write(string $id, string $data): bool
{
$cryptedData = $this->encrypt($data);
- return parent::write($sessionId, $cryptedData);
+ return parent::write($id, $cryptedData);
}
}
diff --git a/src/Session.php b/src/Session.php
index d3445f4..927b1fd 100644
--- a/src/Session.php
+++ b/src/Session.php
@@ -4,19 +4,14 @@
namespace Rancoud\Session;
-use Exception;
-
-/**
- * Class Session.
- */
class Session extends DriverManager
{
use ArrayManager;
- /** @var bool */
protected static bool $hasStarted = false;
- /** @var array */
+ protected static bool $hasChanged = true;
+
protected static array $options = [
'read_and_close' => true,
'cookie_httponly' => '1',
@@ -25,11 +20,7 @@ class Session extends DriverManager
'use_strict_mode' => '1'
];
- /**
- * @param array $options
- *
- * @throws Exception
- */
+ /** @throws SessionException */
public static function start(array $options = []): void
{
static::throwExceptionIfHasStarted();
@@ -39,38 +30,42 @@ public static function start(array $options = []): void
static::setupAndStart();
}
- /**
- * @param array $options
- *
- * @throws Exception
- */
+ /** @throws SessionException */
protected static function populateOptions(array $options = []): void
{
- self::validateOptions($options);
+ static::validateOptions($options);
static::setOptions($options);
}
- /**
- * @throws Exception
- */
+ /** @throws SessionException */
protected static function setupAndStart(): void
{
+ if (static::$hasChanged === false) {
+ return;
+ }
+
+ static::$hasChanged = false;
+
static::configureDriver();
static::setupSessionParameters();
static::startSession();
- static::$hasStarted = true;
- if (static::$options['read_and_close']) {
- static::$hasStarted = false;
- } else {
- static::restoreFlashData();
+ $sessionFlashData = $_SESSION['flash_data'] ?? [];
+ foreach ($sessionFlashData as $key => $value) {
+ static::$flashData[$key] = $value;
}
+
+ if (static::$hasStarted === false && !empty(static::$flashData) && static::isReadOnly()) {
+ static::setReadWrite();
+ static::startSession();
+ }
+ unset($_SESSION['flash_data']);
+
+ static::$hasStarted = (static::$options['read_and_close'] === false);
}
- /**
- * @throws SessionException
- */
+ /** @throws SessionException */
protected static function throwExceptionIfHasStarted(): void
{
if (static::hasStarted()) {
@@ -78,27 +73,19 @@ protected static function throwExceptionIfHasStarted(): void
}
}
- /**
- * @throws SessionException
- */
+ /** @throws SessionException */
protected static function setupSessionParameters(): void
{
\session_name(static::getOption('name'));
- \session_set_save_handler(static::$driver);
+ \session_set_save_handler(static::$driver, true);
\session_save_path(static::getOption('save_path'));
static::setupCookieParams();
-
- \register_shutdown_function('session_write_close');
}
- /**
- * @throws SessionException
- *
- * @return bool
- */
+ /** @throws SessionException */
protected static function startSession(): bool
{
static::validateOptions(static::$options);
@@ -108,11 +95,7 @@ protected static function startSession(): bool
return \session_start(static::$options);
}
- /**
- * @param array $options
- *
- * @throws SessionException
- */
+ /** @throws SessionException */
protected static function validateOptions(array $options = []): void
{
if (empty($options)) {
@@ -133,6 +116,7 @@ protected static function validateOptions(array $options = []): void
'cookie_domain',
'cookie_secure',
'cookie_httponly',
+ 'cookie_samesite',
'use_strict_mode',
'use_cookies',
'use_only_cookies',
@@ -162,24 +146,22 @@ protected static function validateOptions(array $options = []): void
}
}
- /**
- * @throws SessionException
- */
+ /** @throws SessionException */
protected static function setupCookieParams(): void
{
- // https://www.php.net/manual/fr/function.session-set-cookie-params.php new signature
\session_set_cookie_params(
- static::getOption('cookie_lifetime'),
- static::getOption('cookie_path'),
- static::getOption('cookie_domain'),
- isset($_SERVER['HTTPS']),
- true
+ [
+ 'lifetime' => static::getOption('cookie_lifetime'),
+ 'path' => static::getOption('cookie_path'),
+ 'domain' => static::getOption('cookie_domain'),
+ 'secure' => isset($_SERVER['HTTPS']),
+ 'httponly' => true,
+ 'samesite' => static::getOption('cookie_samesite')
+ ]
);
}
- /**
- * @throws Exception
- */
+ /** @throws SessionException */
public static function regenerate(): bool
{
static::startSessionIfNotHasStartedForceWrite();
@@ -187,11 +169,9 @@ public static function regenerate(): bool
return \session_regenerate_id(true);
}
- /**
- * @return bool
- */
public static function destroy(): bool
{
+ static::$hasChanged = true;
\session_unset();
return \session_destroy();
@@ -200,57 +180,44 @@ public static function destroy(): bool
public static function commit(): void
{
static::$hasStarted = false;
+ static::$flashData = [];
+ static::$hasChanged = true;
\session_write_close();
}
- /**
- * @return bool
- */
public static function rollback(): bool
{
return \session_reset();
}
- /**
- * @return bool
- */
public static function unsaved(): bool
{
static::$hasStarted = false;
+ static::$flashData = [];
+ static::$hasChanged = true;
return \session_abort();
}
- /**
- * @return bool
- */
public static function hasStarted(): bool
{
return static::$hasStarted;
}
- /**
- * @return string
- */
public static function getId(): string
{
return \session_id();
}
- /**
- * @param string $id
- *
- * @return string
- */
public static function setId(string $id): string
{
+ static::$hasChanged = true;
+
return \session_id($id);
}
- /**
- * @throws Exception
- */
+ /** @throws SessionException */
public static function gc(): void
{
static::startSessionIfNotHasStartedForceWrite();
@@ -258,9 +225,7 @@ public static function gc(): void
\session_gc();
}
- /**
- * @throws Exception
- */
+ /** @throws SessionException */
protected static function startSessionIfNotHasStarted(): void
{
if (!static::hasStarted()) {
@@ -268,67 +233,55 @@ protected static function startSessionIfNotHasStarted(): void
}
}
- /**
- * @throws Exception
- */
+ /** @throws SessionException */
protected static function startSessionIfNotHasStartedForceWrite(): void
{
if (!static::hasStarted()) {
- static::$options['read_and_close'] = false;
+ static::setReadWrite();
static::setupAndStart();
}
}
public static function setReadOnly(): void
{
+ static::$hasChanged = true;
static::$options['read_and_close'] = true;
}
public static function setReadWrite(): void
{
+ static::$hasChanged = true;
static::$options['read_and_close'] = false;
}
- /**
- * @throws SessionException
- *
- * @return int
- */
+ public static function isReadOnly(): bool
+ {
+ return static::$options['read_and_close'] === true;
+ }
+
+ /** @throws SessionException */
protected static function getLifetimeForRedis(): int
{
return (int) static::getOption('cookie_lifetime');
}
- /**
- * @param string $key
- * @param $value
- *
- * @throws SessionException
- */
+ /** @throws SessionException */
public static function setOption(string $key, $value): void
{
+ static::$hasChanged = true;
static::validateOptions([$key => $value]);
static::$options[$key] = $value;
}
- /**
- * @param array $options
- *
- * @throws SessionException
- */
+ /** @throws SessionException */
public static function setOptions(array $options): void
{
+ static::$hasChanged = true;
static::validateOptions($options);
static::$options = $options + static::$options;
}
- /**
- * @param string $key
- *
- * @throws SessionException
- *
- * @return mixed
- */
+ /** @throws SessionException */
public static function getOption(string $key)
{
if (\array_key_exists($key, static::$options)) {
diff --git a/src/SessionException.php b/src/SessionException.php
index de4c753..fe4068a 100644
--- a/src/SessionException.php
+++ b/src/SessionException.php
@@ -4,11 +4,4 @@
namespace Rancoud\Session;
-use Exception;
-
-/**
- * Class SessionException.
- */
-class SessionException extends Exception
-{
-}
+class SessionException extends \Exception {}
diff --git a/tests/DatabaseEncryptionTest.php b/tests/DatabaseEncryptionTest.php
index 2eace80..5dcc959 100644
--- a/tests/DatabaseEncryptionTest.php
+++ b/tests/DatabaseEncryptionTest.php
@@ -1,488 +1,368 @@
- 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
- ]);
- static::$db = new \Rancoud\Database\Database($conf);
-
- $sql = '
- CREATE TABLE IF NOT EXISTS `sessions` (
- `id` varchar(128) NOT NULL,
- `id_user` int(10) unsigned DEFAULT NULL,
- `last_access` datetime NOT NULL,
- `content` text NOT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- ';
- try {
- static::$db->exec($sql);
- static::$db->truncateTables('sessions');
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- }
-
- protected function setUp(): void
- {
- try {
- static::$db->truncateTables('sessions');
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- }
-
- public function testOpen(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
-
- $database->setCurrentDatabase(static::$db);
-
- $savePath = '';
- $sessionName = '';
- $success = $database->open($savePath, $sessionName);
- static::assertTrue($success);
- }
-
- public function testClose(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
-
- $database->setCurrentDatabase(static::$db);
-
- $success = $database->close();
- static::assertTrue($success);
- }
-
- /**
- * @throws DatabaseException
- * @throws \Rancoud\Session\SessionException
- */
- public function testWrite(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
-
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $sql = 'SELECT * FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
- $row = static::$db->selectRow($sql, $params);
- static::assertNotEmpty($row);
- static::assertNotEquals($data, $row['content']);
-
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
- $encryptionTrait->setKey('randomKey');
- $dataInDatabaseDecrypted = $encryptionTrait->decrypt($row['content']);
- static::assertEquals($data, $dataInDatabaseDecrypted);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testRead(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
-
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- try {
- $database->write($sessionId, $data);
- $dataOutput = $database->read($sessionId);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertNotEmpty($dataOutput);
- static::assertIsString($dataOutput);
- static::assertEquals($data, $dataOutput);
-
- $sessionId = '';
- try {
- $dataOutput = $database->read($sessionId);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertEmpty($dataOutput);
- static::assertIsString($dataOutput);
- }
-
- /**
- * @throws DatabaseException
- * @throws \Rancoud\Session\SessionException
- */
- public function testDestroy(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
-
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'todelete';
- try {
- $success = $database->destroy($sessionId);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- try {
- $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
-
- $sql = 'SELECT COUNT(id) FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
- $isRowExist = (static::$db->count($sql, $params) === 1);
-
- static::assertTrue($isRowExist);
- try {
- $success = $database->destroy($sessionId);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
- $isRowNotExist = (static::$db->count($sql, $params) === 0);
- static::assertTrue($isRowNotExist);
- }
-
- /**
- * @throws DatabaseException
- * @throws \Rancoud\Session\SessionException
- */
- public function testGc(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
-
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $sql = 'SELECT COUNT(id) FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
-
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $isRowExist = (static::$db->count($sql, $params) === 1);
- static::assertTrue($isRowExist);
-
- $lifetime = -1000;
- try {
- $success = $database->gc($lifetime);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $isRowNotExist = (static::$db->count($sql, $params) === 0);
- static::assertTrue($isRowNotExist);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testSetUserId(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
-
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $userId = 5;
- $database->setUserId($userId);
-
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $sql = 'SELECT id_user FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
- try {
- $userIdInDatabase = static::$db->selectVar($sql, $params);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertNotNull($userIdInDatabase);
- static::assertEquals($userId, $userIdInDatabase);
-
- $userId = null;
- $database->setUserId($userId);
-
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $sql = 'SELECT id_user FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
- try {
- $userIdInDatabase = static::$db->selectVar($sql, $params);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertNull($userIdInDatabase);
- static::assertEquals($userId, $userIdInDatabase);
- }
-
- /**
- * @throws DatabaseException
- * @throws \Rancoud\Session\SessionException
- */
- public function testSetNewDatabaseWithArray(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
-
- $params = [
- 'engine' => 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
- ];
- $database->setNewDatabase($params);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
-
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
- }
-
- /**
- * @throws DatabaseException
- * @throws \Rancoud\Session\SessionException
- */
- public function testSetNewDatabaseWithConfigurator(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
-
- $params = [
- 'engine' => 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
- ];
- $conf = new Configurator($params);
- $database->setNewDatabase($conf);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
-
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
- }
-
- /**
- * @throws DatabaseException
- * @throws \Rancoud\Session\SessionException
- */
- public function testValidateId(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
- $database->setCurrentDatabase(static::$db);
-
- $baseId = 'DiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
- $endId1 = 'Dj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
- $endId2 = 'Dklezfoipvfk0lferijkoefzjklgrvefLlnMr';
-
- try {
- $database->write($baseId . $endId1, 'a');
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
-
- static::assertTrue($database->validateId($baseId . $endId1));
- static::assertFalse($database->validateId($baseId . $endId2));
- static::assertFalse($database->validateId('kjlfez/fez'));
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testUpdateTimestamp(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
-
- $success = false;
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $sql = 'SELECT * FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
-
- try {
- $row1 = static::$db->selectRow($sql, $params);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
-
- static::assertNotEmpty($row1);
- static::assertNotEquals($data, $row1['content']);
-
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
- $encryptionTrait->setKey('randomKey');
- $dataInDatabaseDecrypted = $encryptionTrait->decrypt($row1['content']);
- static::assertEquals($data, $dataInDatabaseDecrypted);
-
- sleep(1);
-
- try {
- $success = $database->updateTimestamp($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
-
- static::assertTrue($success);
-
- $sql = 'SELECT * FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
-
- try {
- $row2 = static::$db->selectRow($sql, $params);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
-
- static::assertNotEmpty($row2);
- static::assertNotEquals($data, $row2['content']);
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
- $encryptionTrait->setKey('randomKey');
- $dataInDatabaseDecrypted = $encryptionTrait->decrypt($row2['content']);
- static::assertEquals($data, $dataInDatabaseDecrypted);
-
- static::assertTrue($row1['last_access'] < $row2['last_access']);
- }
-
- /**
- * @throws DatabaseException
- */
- public function testCreateId(): void
- {
- $database = new DatabaseEncryption();
- $database->setKey('randomKey');
- $database->setCurrentDatabase(static::$db);
-
- $string = $database->create_sid();
-
- static::assertSame(preg_match('/^[a-zA-Z0-9-]{127}+$/', $string), 1);
- }
-}
+ 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $mysqlHost = \getenv('MYSQL_HOST', true);
+ $conf->setHost(($mysqlHost !== false) ? $mysqlHost : '127.0.0.1');
+
+ static::$db = new DB($conf);
+
+ $sql = <<<'SQL'
+ CREATE TABLE IF NOT EXISTS `sessions` (
+ `id` varchar(128) NOT NULL,
+ `id_user` int(10) unsigned DEFAULT NULL,
+ `last_access` datetime NOT NULL,
+ `content` text NOT NULL,
+ PRIMARY KEY (`id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+ SQL;
+
+ static::$db->exec($sql);
+ static::$db->truncateTables('sessions');
+ }
+
+ /** @throws DatabaseException */
+ protected function setUp(): void
+ {
+ static::$db->truncateTables('sessions');
+ }
+
+ public function testOpen(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+
+ $database->setCurrentDatabase(static::$db);
+
+ $savePath = '';
+ $sessionName = '';
+
+ static::assertTrue($database->open($savePath, $sessionName));
+ }
+
+ public function testClose(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+
+ $database->setCurrentDatabase(static::$db);
+
+ static::assertTrue($database->close());
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testWrite(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ static::assertTrue($database->write($sessionId, $data));
+
+ $sql = 'SELECT * FROM sessions WHERE id = :id';
+ $params = ['id' => $sessionId];
+ $row = static::$db->selectRow($sql, $params);
+ static::assertNotEmpty($row);
+ static::assertNotSame($data, $row['content']);
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+ $encryptionTrait->setKey('randomKey');
+ $dataInDatabaseDecrypted = $encryptionTrait->decrypt($row['content']);
+ static::assertSame($data, $dataInDatabaseDecrypted);
+ }
+
+ /** @throws SessionException */
+ public function testRead(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ $database->write($sessionId, $data);
+ $dataOutput = $database->read($sessionId);
+
+ static::assertNotEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ static::assertSame($data, $dataOutput);
+
+ $sessionId = '';
+ $dataOutput = $database->read($sessionId);
+
+ static::assertEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testDestroy(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'todelete';
+ static::assertTrue($database->destroy($sessionId));
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $database->write($sessionId, $data);
+
+ $sql = 'SELECT COUNT(id) FROM sessions WHERE id = :id';
+ $params = ['id' => $sessionId];
+ $isRowExist = (static::$db->count($sql, $params) === 1);
+
+ static::assertTrue($isRowExist);
+ static::assertTrue($database->destroy($sessionId));
+ $isRowNotExist = (static::$db->count($sql, $params) === 0);
+ static::assertTrue($isRowNotExist);
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testGc(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $sql = 'SELECT COUNT(id) FROM sessions WHERE id = :id';
+ $params = ['id' => $sessionId];
+
+ static::assertTrue($database->write($sessionId, $data));
+
+ $isRowExist = (static::$db->count($sql, $params) === 1);
+ static::assertTrue($isRowExist);
+
+ $lifetime = -1000;
+ static::assertTrue($database->gc($lifetime));
+
+ $isRowNotExist = (static::$db->count($sql, $params) === 0);
+ static::assertTrue($isRowNotExist);
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testSetUserId(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $userId = 5;
+ $database->setUserId($userId);
+
+ static::assertTrue($database->write($sessionId, $data));
+
+ $sql = 'SELECT id_user FROM sessions WHERE id = :id';
+ $params = ['id' => $sessionId];
+ $userIdInDatabase = (int) static::$db->selectVar($sql, $params);
+ static::assertNotNull($userIdInDatabase);
+ static::assertSame($userId, $userIdInDatabase);
+
+ $userId = null;
+ $database->setUserId($userId);
+
+ static::assertTrue($database->write($sessionId, $data));
+
+ $userIdInDatabase = static::$db->selectVar($sql, $params);
+ static::assertNull($userIdInDatabase);
+ static::assertSame($userId, $userIdInDatabase);
+ }
+
+ /** @throws SessionException */
+ public function testSetNewDatabaseWithArray(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+
+ $params = [
+ 'driver' => 'mysql',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+ ];
+
+ $mysqlHost = \getenv('MYSQL_HOST', true);
+ $params['host'] = ($mysqlHost !== false) ? $mysqlHost : '127.0.0.1';
+
+ $database->setNewDatabase($params);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ static::assertTrue($database->write($sessionId, $data));
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testSetNewDatabaseWithConfigurator(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+
+ $conf = new Configurator([
+ 'driver' => 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $mysqlHost = \getenv('MYSQL_HOST', true);
+ $conf->setHost(($mysqlHost !== false) ? $mysqlHost : '127.0.0.1');
+
+ $database->setNewDatabase($conf);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ static::assertTrue($database->write($sessionId, $data));
+ }
+
+ /** @throws SessionException */
+ public function testSetNewDatabaseSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not set database: "invalid" settings is not recognized');
+
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+ $database->setNewDatabase([
+ 'invalid' => 'invalid'
+ ]);
+ }
+
+ /** @throws SessionException */
+ public function testValidateId(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+ $database->setCurrentDatabase(static::$db);
+
+ $baseId = 'DiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
+ $endId1 = 'Dj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
+ $endId2 = 'Dklezfoipvfk0lferijkoefzjklgrvefLlnMr';
+
+ $database->write($baseId . $endId1, 'a');
+
+ static::assertTrue($database->validateId($baseId . $endId1));
+ static::assertFalse($database->validateId($baseId . $endId2));
+ static::assertFalse($database->validateId('kjlfez/fez'));
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testUpdateTimestamp(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ static::assertTrue($database->write($sessionId, $data));
+
+ $sql = 'SELECT * FROM sessions WHERE id = :id';
+ $params = ['id' => $sessionId];
+
+ $row1 = static::$db->selectRow($sql, $params);
+ static::assertNotEmpty($row1);
+ static::assertNotSame($data, $row1['content']);
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+ $encryptionTrait->setKey('randomKey');
+ $dataInDatabaseDecrypted = $encryptionTrait->decrypt($row1['content']);
+ static::assertSame($data, $dataInDatabaseDecrypted);
+
+ \sleep(1);
+
+ static::assertTrue($database->updateTimestamp($sessionId, $data));
+
+ $row2 = static::$db->selectRow($sql, $params);
+
+ static::assertNotEmpty($row2);
+ static::assertNotSame($data, $row2['content']);
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+ $encryptionTrait->setKey('randomKey');
+ $dataInDatabaseDecrypted = $encryptionTrait->decrypt($row2['content']);
+ static::assertSame($data, $dataInDatabaseDecrypted);
+
+ static::assertTrue($row1['last_access'] < $row2['last_access']);
+ }
+
+ /** @throws SessionException */
+ public function testCreateId(): void
+ {
+ $database = new DatabaseEncryption();
+ $database->setKey('randomKey');
+ $database->setCurrentDatabase(static::$db);
+
+ $string = $database->create_sid();
+
+ static::assertMatchesRegularExpression('/^[a-zA-Z0-9-]{127}+$/', $string);
+ }
+}
diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php
index 90ad1d5..223d3d0 100644
--- a/tests/DatabaseTest.php
+++ b/tests/DatabaseTest.php
@@ -1,438 +1,574 @@
- 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
- ]);
- static::$db = new \Rancoud\Database\Database($conf);
-
- $sql = '
- CREATE TABLE IF NOT EXISTS `sessions` (
- `id` varchar(128) NOT NULL,
- `id_user` int(10) unsigned DEFAULT NULL,
- `last_access` datetime NOT NULL,
- `content` text NOT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- ';
- try {
- static::$db->exec($sql);
- static::$db->truncateTables('sessions');
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- }
-
- protected function setUp(): void
- {
- try {
- static::$db->truncateTables('sessions');
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- }
-
- public function testOpen(): void
- {
- $database = new Database();
- $database->setCurrentDatabase(static::$db);
-
- $savePath = '';
- $sessionName = '';
- $success = $database->open($savePath, $sessionName);
- static::assertTrue($success);
- }
-
- public function testClose(): void
- {
- $database = new Database();
- $database->setCurrentDatabase(static::$db);
-
- $success = $database->close();
- static::assertTrue($success);
- }
-
- /**
- * @throws DatabaseException
- */
- public function testWrite(): void
- {
- $database = new Database();
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $sql = 'SELECT * FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
- $row = static::$db->selectRow($sql, $params);
- static::assertNotEmpty($row);
- static::assertEquals($data, $row['content']);
- }
-
- public function testRead(): void
- {
- $database = new Database();
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- try {
- $database->write($sessionId, $data);
- $dataOutput = $database->read($sessionId);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertNotEmpty($dataOutput);
- static::assertIsString($dataOutput);
- static::assertEquals($data, $dataOutput);
-
- $sessionId = '';
- try {
- $dataOutput = $database->read($sessionId);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertEmpty($dataOutput);
- static::assertIsString($dataOutput);
- }
-
- /**
- * @throws DatabaseException
- */
- public function testDestroy(): void
- {
- $database = new Database();
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'todelete';
- try {
- $success = $database->destroy($sessionId);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- try {
- $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
-
- $sql = 'SELECT COUNT(id) FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
- $isRowExist = (static::$db->count($sql, $params) === 1);
-
- static::assertTrue($isRowExist);
- try {
- $success = $database->destroy($sessionId);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
- $isRowNotExist = (static::$db->count($sql, $params) === 0);
- static::assertTrue($isRowNotExist);
- }
-
- /**
- * @throws DatabaseException
- */
- public function testGc(): void
- {
- $database = new Database();
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $sql = 'SELECT COUNT(id) FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
-
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $isRowExist = (static::$db->count($sql, $params) === 1);
- static::assertTrue($isRowExist);
-
- $lifetime = -1000;
- try {
- $success = $database->gc($lifetime);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $isRowNotExist = (static::$db->count($sql, $params) === 0);
- static::assertTrue($isRowNotExist);
- }
-
- public function testSetUserId(): void
- {
- $database = new Database();
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $userId = 5;
- $database->setUserId($userId);
-
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $sql = 'SELECT id_user FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
- try {
- $userIdInDatabase = static::$db->selectVar($sql, $params);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertNotNull($userIdInDatabase);
- static::assertEquals($userId, $userIdInDatabase);
-
- $userId = null;
- $database->setUserId($userId);
-
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $sql = 'SELECT id_user FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
- try {
- $userIdInDatabase = static::$db->selectVar($sql, $params);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertNull($userIdInDatabase);
- static::assertEquals($userId, $userIdInDatabase);
- }
-
- /**
- * @throws DatabaseException
- */
- public function testSetNewDatabaseWithArray(): void
- {
- $database = new Database();
- $params = [
- 'engine' => 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
- ];
- $database->setNewDatabase($params);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
-
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
- }
-
- /**
- * @throws DatabaseException
- */
- public function testSetNewDatabaseWithConfigurator(): void
- {
- $database = new Database();
- $params = [
- 'engine' => 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
- ];
- $conf = new Configurator($params);
- $database->setNewDatabase($conf);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
-
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
- }
-
- /**
- * @throws DatabaseException
- */
- public function testValidateId(): void
- {
- $database = new Database();
- $database->setCurrentDatabase(static::$db);
-
- $baseId = 'DiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
- $endId1 = 'Dj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
- $endId2 = 'Dklezfoipvfk0lferijkoefzjklgrvefLlnMr';
-
- try {
- $database->write($baseId . $endId1, 'a');
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
-
- static::assertTrue($database->validateId($baseId . $endId1));
- static::assertFalse($database->validateId($baseId . $endId2));
- static::assertFalse($database->validateId('kjlfez/fez'));
- }
-
- public function testUpdateTimestamp(): void
- {
- $database = new Database();
- $database->setCurrentDatabase(static::$db);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
-
- $success = false;
- try {
- $success = $database->write($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
- static::assertTrue($success);
-
- $sql = 'SELECT * FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
-
- try {
- $row1 = static::$db->selectRow($sql, $params);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
-
- static::assertNotEmpty($row1);
- static::assertEquals($data, $row1['content']);
-
- sleep(1);
-
- try {
- $success = $database->updateTimestamp($sessionId, $data);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
-
- static::assertTrue($success);
-
- $sql = 'SELECT * FROM sessions WHERE id = :id';
- $params = ['id' => $sessionId];
-
- try {
- $row2 = static::$db->selectRow($sql, $params);
- } catch (DatabaseException $e) {
- var_dump(static::$db->getErrors());
-
- return;
- }
-
- static::assertNotEmpty($row2);
- static::assertEquals($data, $row2['content']);
-
- static::assertTrue($row1['last_access'] < $row2['last_access']);
- }
-
- /**
- * @throws DatabaseException
- */
- public function testCreateId(): void
- {
- $database = new Database();
- $database->setCurrentDatabase(static::$db);
-
- $string = $database->create_sid();
-
- static::assertSame(preg_match('/^[a-zA-Z0-9-]{127}+$/', $string), 1);
- }
-}
+ 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $mysqlHost = \getenv('MYSQL_HOST', true);
+ $conf->setHost(($mysqlHost !== false) ? $mysqlHost : '127.0.0.1');
+
+ static::$db = new DB($conf);
+
+ $sql = <<<'SQL'
+ CREATE TABLE IF NOT EXISTS `sessions` (
+ `id` varchar(128) NOT NULL,
+ `id_user` int(10) unsigned DEFAULT NULL,
+ `last_access` datetime NOT NULL,
+ `content` text NOT NULL,
+ PRIMARY KEY (`id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+ SQL;
+
+ static::$db->exec($sql);
+ static::$db->truncateTables('sessions');
+ }
+
+ /** @throws DatabaseException */
+ protected function setUp(): void
+ {
+ static::$db->truncateTables('sessions');
+ }
+
+ public function testOpen(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ $savePath = '';
+ $sessionName = '';
+
+ static::assertTrue($database->open($savePath, $sessionName));
+ }
+
+ public function testClose(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ static::assertTrue($database->close());
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testWrite(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ static::assertTrue($database->write($sessionId, $data));
+
+ $sql = 'SELECT * FROM sessions WHERE id = :id';
+ $params = ['id' => $sessionId];
+ $row = static::$db->selectRow($sql, $params);
+ static::assertNotEmpty($row);
+ static::assertSame($data, $row['content']);
+ }
+
+ /** @throws SessionException */
+ public function testWriteSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not update session: Error Connecting Database');
+
+ $database = new Database();
+ $database->setNewDatabase([
+ 'driver' => 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'invalid',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $database->write('invalid_session_id', '');
+ }
+
+ /** @throws SessionException */
+ public function testRead(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ $database->write($sessionId, $data);
+ $dataOutput = $database->read($sessionId);
+
+ static::assertNotEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ static::assertSame($data, $dataOutput);
+
+ $sessionId = '';
+ $dataOutput = $database->read($sessionId);
+
+ static::assertEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ }
+
+ /** @throws SessionException */
+ public function testReadSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not read session: Error Connecting Database');
+
+ $database = new Database();
+ $database->setNewDatabase([
+ 'driver' => 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'invalid',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $database->read('invalid_session_id');
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testDestroy(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'todelete';
+ static::assertTrue($database->destroy($sessionId));
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $database->write($sessionId, $data);
+
+ $sql = 'SELECT COUNT(id) FROM sessions WHERE id = :id';
+ $params = ['id' => $sessionId];
+ $isRowExist = (static::$db->count($sql, $params) === 1);
+
+ static::assertTrue($isRowExist);
+ static::assertTrue($database->destroy($sessionId));
+ $isRowNotExist = static::$db->count($sql, $params) === 0;
+ static::assertTrue($isRowNotExist);
+ }
+
+ /** @throws SessionException */
+ public function testDestroySessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not delete session: Error Connecting Database');
+
+ $database = new Database();
+ $database->setNewDatabase([
+ 'driver' => 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'invalid',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $database->destroy('invalid_session_id');
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testGc(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $sql = 'SELECT COUNT(id) FROM sessions WHERE id = :id';
+ $params = ['id' => $sessionId];
+
+ static::assertTrue($database->write($sessionId, $data));
+
+ $isRowExist = (static::$db->count($sql, $params) === 1);
+ static::assertTrue($isRowExist);
+
+ $lifetime = -1000;
+ static::assertTrue($database->gc($lifetime));
+
+ $isRowNotExist = (static::$db->count($sql, $params) === 0);
+ static::assertTrue($isRowNotExist);
+ }
+
+ /** @throws SessionException */
+ public function testGcSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not clean old sessions: Error Connecting Database');
+
+ $database = new Database();
+ $database->setNewDatabase([
+ 'driver' => 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'invalid',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $database->gc(-1000);
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testSetUserId(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $userId = 5;
+ $database->setUserId($userId);
+
+ static::assertTrue($database->write($sessionId, $data));
+
+ $sql = 'SELECT id_user FROM sessions WHERE id = :id';
+ $params = ['id' => $sessionId];
+ $userIdInDatabase = (int) static::$db->selectVar($sql, $params);
+ static::assertNotNull($userIdInDatabase);
+ static::assertSame($userId, $userIdInDatabase);
+
+ $userId = null;
+ $database->setUserId($userId);
+
+ static::assertTrue($database->write($sessionId, $data));
+
+ $userIdInDatabase = static::$db->selectVar($sql, $params);
+ static::assertNull($userIdInDatabase);
+ static::assertSame($userId, $userIdInDatabase);
+ }
+
+ /** @throws SessionException */
+ public function testSetNewDatabaseWithArray(): void
+ {
+ $database = new Database();
+ $params = [
+ 'driver' => 'mysql',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+ ];
+
+ $mysqlHost = \getenv('MYSQL_HOST', true);
+ $params['host'] = ($mysqlHost !== false) ? $mysqlHost : '127.0.0.1';
+
+ $database->setNewDatabase($params);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ static::assertTrue($database->write($sessionId, $data));
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testSetNewDatabaseWithConfigurator(): void
+ {
+ $database = new Database();
+ $conf = new Configurator([
+ 'driver' => 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $mysqlHost = \getenv('MYSQL_HOST', true);
+ $conf->setHost(($mysqlHost !== false) ? $mysqlHost : '127.0.0.1');
+
+ $database->setNewDatabase($conf);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ static::assertTrue($database->write($sessionId, $data));
+ }
+
+ /** @throws SessionException */
+ public function testSetNewDatabaseSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not set database: "invalid" settings is not recognized');
+
+ $database = new Database();
+
+ $database->setNewDatabase([
+ 'invalid' => 'invalid'
+ ]);
+ }
+
+ /** @throws SessionException */
+ public function testValidateId(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ $baseId = 'DiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
+ $endId1 = 'Dj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
+ $endId2 = 'Dklezfoipvfk0lferijkoefzjklgrvefLlnMr';
+
+ $database->write($baseId . $endId1, 'a');
+
+ static::assertTrue($database->validateId($baseId . $endId1));
+ static::assertFalse($database->validateId($baseId . $endId2));
+ static::assertFalse($database->validateId('kjlfez/fez'));
+ }
+
+ /** @throws SessionException */
+ public function testValidateIdSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not validate id: Error Connecting Database');
+
+ $database = new Database();
+ $database->setNewDatabase([
+ 'driver' => 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'invalid',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $database->setLengthSessionID(32);
+ $database->validateId('-------invalid-session-id-------');
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testUpdateTimestamp(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ static::assertTrue($database->write($sessionId, $data));
+
+ $sql = 'SELECT * FROM sessions WHERE id = :id';
+ $params = ['id' => $sessionId];
+
+ $row1 = static::$db->selectRow($sql, $params);
+ static::assertNotEmpty($row1);
+ static::assertSame($data, $row1['content']);
+
+ \sleep(1);
+
+ static::assertTrue($database->updateTimestamp($sessionId, $data));
+
+ $row2 = static::$db->selectRow($sql, $params);
+
+ static::assertNotEmpty($row2);
+ static::assertSame($data, $row2['content']);
+
+ static::assertTrue($row1['last_access'] < $row2['last_access']);
+ }
+
+ /** @throws SessionException */
+ public function testCreateId(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ $string = $database->create_sid();
+
+ static::assertMatchesRegularExpression('/^[a-zA-Z0-9-]{127}+$/', $string);
+ }
+
+ /** @throws SessionException */
+ public function testCreateIdSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not create sid: Error Connecting Database');
+
+ $database = new Database();
+ $database->setNewDatabase([
+ 'driver' => 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'invalid',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $database->create_sid();
+ }
+
+ /** @throws SessionException */
+ public function testLengthSessionID(): void
+ {
+ $database = new Database();
+ $database->setLengthSessionID(50);
+ static::assertSame(50, $database->getLengthSessionID());
+ }
+
+ public function testLengthSessionIDSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not set length session ID below 32');
+
+ $database = new Database();
+ $database->setLengthSessionID(1);
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testDeleteUserSessions(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ $data = 'azerty';
+
+ $database->setUserId(10);
+
+ static::assertTrue($database->write('session_id_10', $data));
+ static::assertTrue($database->write('session_id_20', $data));
+ static::assertTrue($database->write('session_id_30', $data));
+
+ $database->setUserId(20);
+
+ static::assertTrue($database->write('session_id_40', $data));
+ static::assertTrue($database->write('session_id_50', $data));
+ static::assertTrue($database->write('session_id_60', $data));
+
+ $sql = 'SELECT id FROM sessions WHERE id_user = :id_user';
+ $params = ['id_user' => 10];
+ $sessionsFromDatabase = static::$db->selectCol($sql, $params);
+ static::assertSame(['session_id_10', 'session_id_20', 'session_id_30'], $sessionsFromDatabase);
+
+ $sql = 'SELECT id FROM sessions WHERE id_user = :id_user';
+ $params = ['id_user' => 20];
+ $sessionsFromDatabase = static::$db->selectCol($sql, $params);
+ static::assertSame(['session_id_40', 'session_id_50', 'session_id_60'], $sessionsFromDatabase);
+
+ $database->deleteUserSessions(10);
+
+ $sql = 'SELECT id FROM sessions';
+ $sessionsFromDatabase = static::$db->selectCol($sql);
+ static::assertSame(['session_id_40', 'session_id_50', 'session_id_60'], $sessionsFromDatabase);
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testDeleteUserSessionsSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not delete sessions: Error Connecting Database');
+
+ $database = new Database();
+ $database->setNewDatabase([
+ 'driver' => 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'invalid',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $database->deleteUserSessions(1);
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testDeleteAnonymousSessions(): void
+ {
+ $database = new Database();
+ $database->setCurrentDatabase(static::$db);
+
+ $data = 'azerty';
+
+ $database->setUserId(10);
+
+ static::assertTrue($database->write('session_id_10', $data));
+ static::assertTrue($database->write('session_id_20', $data));
+ static::assertTrue($database->write('session_id_30', $data));
+
+ $database->setUserId(null);
+
+ static::assertTrue($database->write('session_id_40', $data));
+ static::assertTrue($database->write('session_id_50', $data));
+ static::assertTrue($database->write('session_id_60', $data));
+
+ $sql = 'SELECT id FROM sessions WHERE id_user = :id_user';
+ $params = ['id_user' => 10];
+ $sessionsFromDatabase = static::$db->selectCol($sql, $params);
+ static::assertSame(['session_id_10', 'session_id_20', 'session_id_30'], $sessionsFromDatabase);
+
+ $sql = 'SELECT id FROM sessions WHERE id_user IS NULL';
+ $sessionsFromDatabase = static::$db->selectCol($sql);
+ static::assertSame(['session_id_40', 'session_id_50', 'session_id_60'], $sessionsFromDatabase);
+
+ $database->deleteAnonymousSessions(10);
+
+ $sql = 'SELECT id FROM sessions';
+ $sessionsFromDatabase = static::$db->selectCol($sql);
+ static::assertSame(['session_id_10', 'session_id_20', 'session_id_30'], $sessionsFromDatabase);
+ }
+
+ /**
+ * @throws DatabaseException
+ * @throws SessionException
+ */
+ public function testDeleteAnonymousSessionsSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not delete sessions: Error Connecting Database');
+
+ $database = new Database();
+ $database->setNewDatabase([
+ 'driver' => 'mysql',
+ 'host' => 'mariadb',
+ 'user' => 'invalid',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $database->deleteAnonymousSessions();
+ }
+}
diff --git a/tests/DefaultEncryptionTest.php b/tests/DefaultEncryptionTest.php
index d0308f6..3c1477d 100644
--- a/tests/DefaultEncryptionTest.php
+++ b/tests/DefaultEncryptionTest.php
@@ -1,69 +1,66 @@
foundSessionFile();
static::assertNotFalse($data);
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
$encryptionTrait->setKey('randomKey');
$dataDecrypted = $encryptionTrait->decrypt($data);
- static::assertEquals('a|s:1:"b";', $dataDecrypted);
+ static::assertSame('a|s:1:"b";', $dataDecrypted);
}
}
diff --git a/tests/EncryptionTest.php b/tests/EncryptionTest.php
index 6094095..755dfc8 100644
--- a/tests/EncryptionTest.php
+++ b/tests/EncryptionTest.php
@@ -1,64 +1,161 @@
-getObjectForTrait('Rancoud\Session\Encryption');
-
- $dataToEncrypt = 'this is something to encrypt';
-
- $encryptionTrait->setKey('my key');
- $encryptedData = $encryptionTrait->encrypt($dataToEncrypt);
-
- $finalData = $encryptionTrait->decrypt($encryptedData);
- static::assertEquals($dataToEncrypt, $finalData);
- }
-
- public function testAllEncryptionMethods(): void
- {
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
-
- $dataToEncrypt = 'this is something to encrypt';
-
- $encryptionTrait->setKey('my key');
- $methods = $encryptionTrait->getAvailableMethods();
- foreach ($methods as $method) {
- $encryptionTrait->setMethod($method);
- $encryptedData = $encryptionTrait->encrypt($dataToEncrypt);
-
- $finalData = $encryptionTrait->decrypt($encryptedData);
- static::assertEquals($dataToEncrypt, $finalData, $method . ' fail!');
- }
- }
-
- public function testExceptionMethod(): void
- {
- $this->expectException(SessionException::class);
- $this->expectExceptionMessage('Method unknowed: method');
-
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
- $encryptionTrait->setMethod('method');
- }
-
- public function testExceptionEmptyKey(): void
- {
- $this->expectException(SessionException::class);
- $this->expectExceptionMessage('Key has to be a non-empty string');
-
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
- $dataToEncrypt = 'this is something to encrypt';
- $encryptionTrait->encrypt($dataToEncrypt);
- }
-}
+setKey('my key');
+ $encryptedData = $encryptionTrait->encrypt($dataToEncrypt);
+
+ $finalData = $encryptionTrait->decrypt($encryptedData);
+ static::assertSame($dataToEncrypt, $finalData);
+ }
+
+ public function testAllEncryptionMethods(): void
+ {
+ $failedMethods = [];
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+
+ $dataToEncrypt = 'this is something to encrypt';
+
+ $encryptionTrait->setKey('my key');
+ $methods = $encryptionTrait->getAvailableMethods();
+ foreach ($methods as $method) {
+ try {
+ $encryptionTrait->setMethod($method);
+ $encryptedData = $encryptionTrait->encrypt($dataToEncrypt);
+
+ $finalData = $encryptionTrait->decrypt($encryptedData);
+ static::assertSame($dataToEncrypt, $finalData, $method . ' fail!');
+ } catch (\Exception) {
+ $failedMethods[] = $method;
+
+ continue;
+ }
+ }
+
+ if (\count($failedMethods) > 0) {
+ static::fail('Methods ' . \implode(', ', $failedMethods) . ' fail!');
+ }
+ }
+
+ public function testExceptionMethod(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('Unknown method: method');
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+ $encryptionTrait->setMethod('method');
+ }
+
+ public function testExceptionMethodForced(): void
+ {
+ $forbiddenMethods = [
+ 'aes-128-cbc-hmac-sha1',
+ 'aes-256-cbc-hmac-sha1',
+ 'aes-128-cbc-cts',
+ 'aes-128-cbc-hmac-sha256',
+ 'aes-128-siv',
+ 'aes-192-cbc-cts',
+ 'aes-192-siv',
+ 'aes-256-cbc-cts',
+ 'aes-256-cbc-hmac-sha256',
+ 'aes-256-siv',
+ 'camellia-128-cbc-cts',
+ 'camellia-192-cbc-cts',
+ 'camellia-256-cbc-cts',
+ 'null',
+ '0.3.4401.5.3.1.9.1',
+ '0.3.4401.5.3.1.9.21',
+ '0.3.4401.5.3.1.9.41',
+ '1.2.410.200046.1.1.1',
+ '1.2.410.200046.1.1.11',
+ '1.2.410.200046.1.1.34',
+ '1.2.410.200046.1.1.35',
+ '1.2.410.200046.1.1.36',
+ '1.2.410.200046.1.1.37',
+ '1.2.410.200046.1.1.38',
+ '1.2.410.200046.1.1.39',
+ '1.2.410.200046.1.1.6',
+ '1.2.840.113549.1.9.16.3.6',
+ '1.3.14.3.2.17',
+ '2.16.840.1.101.3.4.1.1',
+ '2.16.840.1.101.3.4.1.21',
+ '2.16.840.1.101.3.4.1.25',
+ '2.16.840.1.101.3.4.1.26',
+ '2.16.840.1.101.3.4.1.27',
+ '2.16.840.1.101.3.4.1.41',
+ '2.16.840.1.101.3.4.1.45',
+ '2.16.840.1.101.3.4.1.46',
+ '2.16.840.1.101.3.4.1.47',
+ '2.16.840.1.101.3.4.1.5',
+ '2.16.840.1.101.3.4.1.6',
+ '2.16.840.1.101.3.4.1.7',
+ 'chacha20-poly1305'
+ ];
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+
+ public function setMethod(string $method): void
+ {
+ $this->method = $method;
+ }
+ };
+
+ $dataToEncrypt = 'this is something to encrypt';
+
+ $encryptionTrait->setKey('my key');
+
+ $countInvalidMethods = \count($forbiddenMethods);
+ foreach ($forbiddenMethods as $method) {
+ try {
+ $encryptionTrait->setMethod($method);
+ $finalData = $encryptionTrait->encrypt($dataToEncrypt);
+ static::assertNotSame($dataToEncrypt, $finalData);
+ --$countInvalidMethods;
+ } catch (\Exception $e) {
+ static::assertThat($e->getMessage(), static::logicalOr(
+ static::equalTo('IV generation failed'),
+ static::equalTo('openssl_encrypt(): A tag should be provided when using AEAD mode')
+ ));
+ --$countInvalidMethods;
+ }
+ }
+
+ static::assertSame(0, $countInvalidMethods);
+ }
+
+ public function testExceptionEmptyKey(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('Key has to be a non-empty string');
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+ $dataToEncrypt = 'this is something to encrypt';
+ $encryptionTrait->encrypt($dataToEncrypt);
+ }
+}
diff --git a/tests/FileEncryptionTest.php b/tests/FileEncryptionTest.php
index 4acc2df..20645fc 100644
--- a/tests/FileEncryptionTest.php
+++ b/tests/FileEncryptionTest.php
@@ -1,256 +1,250 @@
-open($this->getPath(), '');
- static::assertTrue($success);
- }
-
- public function testOpen(): void
- {
- $fileEncryption = new FileEncryption();
- $fileEncryption->setKey('randomKey');
-
- $savePath = $this->getPath();
- $sessionName = '';
- $success = $fileEncryption->open($savePath, $sessionName);
- static::assertTrue($success);
-
- $savePathNotCreated = $savePath . DIRECTORY_SEPARATOR . 'tests';
- $success = $fileEncryption->open($savePathNotCreated, $sessionName);
- static::assertTrue($success);
- $success = file_exists($savePathNotCreated);
- static::assertTrue($success);
- }
-
- public function testClose(): void
- {
- $fileEncryption = new FileEncryption();
- $fileEncryption->setKey('randomKey');
- $success = $fileEncryption->close();
- static::assertTrue($success);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testWrite(): void
- {
- $fileEncryption = new FileEncryption();
- $fileEncryption->setKey('randomKey');
-
- $this->openSessionForSavingSavePath($fileEncryption);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $fileEncryption->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataInFile = file_get_contents($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertNotEquals($data, $dataInFile);
-
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
- $encryptionTrait->setKey('randomKey');
- $dataInFileDecrypted = $encryptionTrait->decrypt($dataInFile);
- static::assertEquals($data, $dataInFileDecrypted);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testRead(): void
- {
- $fileEncryption = new FileEncryption();
- $fileEncryption->setKey('randomKey');
-
- $this->openSessionForSavingSavePath($fileEncryption);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $fileEncryption->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataOutput = $fileEncryption->read($sessionId);
- static::assertNotEmpty($dataOutput);
- static::assertIsString($dataOutput);
- static::assertEquals($data, $dataOutput);
-
- $sessionId = '';
- $dataOutput = $fileEncryption->read($sessionId);
- static::assertEmpty($dataOutput);
- static::assertIsString($dataOutput);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testDestroy(): void
- {
- $fileEncryption = new FileEncryption();
- $fileEncryption->setKey('randomKey');
-
- $this->openSessionForSavingSavePath($fileEncryption);
-
- $sessionId = 'todelete';
- $success = $fileEncryption->destroy($sessionId);
- static::assertTrue($success);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $fileEncryption->write($sessionId, $data);
- static::assertTrue($success);
-
- $isFileExist = file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertTrue($isFileExist);
- $success = $fileEncryption->destroy($sessionId);
- static::assertTrue($success);
- $isFileNotExist = !file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertTrue($isFileNotExist);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testGc(): void
- {
- $fileEncryption = new FileEncryption();
- $fileEncryption->setKey('randomKey');
-
- $this->openSessionForSavingSavePath($fileEncryption);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $fileEncryption->write($sessionId, $data);
- static::assertTrue($success);
-
- $isFileExist = file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertTrue($isFileExist);
-
- $lifetime = -1000;
- $success = $fileEncryption->gc($lifetime);
- static::assertTrue($success);
-
- $isFileNotExist = !file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertTrue($isFileNotExist);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testValidateId(): void
- {
- $fileEncryption = new FileEncryption();
- $fileEncryption->setKey('randomKey');
-
- $this->openSessionForSavingSavePath($fileEncryption);
-
- $baseId = 'TiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
- $endId1 = 'Tj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
- $endId2 = 'Tklezfoipvfk0lferijkoefzjklgrvefLlnMr';
-
- $fileEncryption->write($baseId . $endId1, 'a');
-
- static::assertTrue($fileEncryption->validateId($baseId . $endId1));
- static::assertFalse($fileEncryption->validateId($baseId . $endId2));
- static::assertFalse($fileEncryption->validateId('kjlfez/fez'));
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testUpdateTimestamp(): void
- {
- $fileEncryption = new FileEncryption();
- $fileEncryption->setKey('randomKey');
-
- $this->openSessionForSavingSavePath($fileEncryption);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $fileEncryption->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataInFile = file_get_contents($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- $oldFileModifiedTime = filemtime($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertNotEquals($data, $dataInFile);
-
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
- $encryptionTrait->setKey('randomKey');
- $dataInFileDecrypted = $encryptionTrait->decrypt($dataInFile);
- static::assertEquals($data, $dataInFileDecrypted);
-
- sleep(1);
- $success = $fileEncryption->updateTimestamp($sessionId, $data);
- static::assertTrue($success);
-
- clearstatcache();
-
- $dataInFile2 = file_get_contents($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertNotEquals($data, $dataInFile2);
-
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
- $encryptionTrait->setKey('randomKey');
- $dataInFileDecrypted = $encryptionTrait->decrypt($dataInFile2);
- static::assertEquals($data, $dataInFileDecrypted);
- static::assertNotEquals($dataInFile, $dataInFile2);
-
- $newFileModifiedTime = filemtime($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
-
- static::assertTrue($oldFileModifiedTime < $newFileModifiedTime);
- }
-
- /**
- * @throws \Exception
- */
- public function testCreateId(): void
- {
- $fileEncryption = new FileEncryption();
- $fileEncryption->setKey('randomKey');
-
- $string = $fileEncryption->create_sid();
-
- static::assertSame(preg_match('/^[a-zA-Z0-9-]{127}+$/', $string), 1);
- }
-}
+open($this->getPath(), '');
+ static::assertTrue($success);
+ }
+
+ /** @throws SessionException */
+ public function testOpen(): void
+ {
+ $fileEncryption = new FileEncryption();
+ $fileEncryption->setKey('randomKey');
+
+ $savePath = $this->getPath();
+ $sessionName = '';
+ $success = $fileEncryption->open($savePath, $sessionName);
+ static::assertTrue($success);
+
+ $savePathNotCreated = $savePath . \DIRECTORY_SEPARATOR . 'tests';
+ $success = $fileEncryption->open($savePathNotCreated, $sessionName);
+ static::assertTrue($success);
+ $success = \file_exists($savePathNotCreated);
+ static::assertTrue($success);
+ }
+
+ public function testClose(): void
+ {
+ $fileEncryption = new FileEncryption();
+ $fileEncryption->setKey('randomKey');
+ $success = $fileEncryption->close();
+ static::assertTrue($success);
+ }
+
+ /** @throws SessionException */
+ public function testWrite(): void
+ {
+ $fileEncryption = new FileEncryption();
+ $fileEncryption->setKey('randomKey');
+
+ $this->openSessionForSavingSavePath($fileEncryption);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $fileEncryption->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInFile = \file_get_contents($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertNotSame($data, $dataInFile);
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+ $encryptionTrait->setKey('randomKey');
+ $dataInFileDecrypted = $encryptionTrait->decrypt($dataInFile);
+ static::assertSame($data, $dataInFileDecrypted);
+ }
+
+ /** @throws SessionException */
+ public function testRead(): void
+ {
+ $fileEncryption = new FileEncryption();
+ $fileEncryption->setKey('randomKey');
+
+ $this->openSessionForSavingSavePath($fileEncryption);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $fileEncryption->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataOutput = $fileEncryption->read($sessionId);
+ static::assertNotEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ static::assertSame($data, $dataOutput);
+
+ $sessionId = '';
+ $dataOutput = $fileEncryption->read($sessionId);
+ static::assertEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ }
+
+ /** @throws SessionException */
+ public function testDestroy(): void
+ {
+ $fileEncryption = new FileEncryption();
+ $fileEncryption->setKey('randomKey');
+
+ $this->openSessionForSavingSavePath($fileEncryption);
+
+ $sessionId = 'todelete';
+ $success = $fileEncryption->destroy($sessionId);
+ static::assertTrue($success);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $fileEncryption->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $isFileExist = \file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertTrue($isFileExist);
+ $success = $fileEncryption->destroy($sessionId);
+ static::assertTrue($success);
+ $isFileNotExist = !\file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertTrue($isFileNotExist);
+ }
+
+ /** @throws SessionException */
+ public function testGc(): void
+ {
+ $fileEncryption = new FileEncryption();
+ $fileEncryption->setKey('randomKey');
+
+ $this->openSessionForSavingSavePath($fileEncryption);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $fileEncryption->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $isFileExist = \file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertTrue($isFileExist);
+
+ $lifetime = -1000;
+ $success = $fileEncryption->gc($lifetime);
+ static::assertTrue($success);
+
+ $isFileNotExist = !\file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertTrue($isFileNotExist);
+ }
+
+ /** @throws SessionException */
+ public function testValidateId(): void
+ {
+ $fileEncryption = new FileEncryption();
+ $fileEncryption->setKey('randomKey');
+
+ $this->openSessionForSavingSavePath($fileEncryption);
+
+ $baseId = 'TiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
+ $endId1 = 'Tj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
+ $endId2 = 'Tklezfoipvfk0lferijkoefzjklgrvefLlnMr';
+
+ $fileEncryption->write($baseId . $endId1, 'a');
+
+ static::assertTrue($fileEncryption->validateId($baseId . $endId1));
+ static::assertFalse($fileEncryption->validateId($baseId . $endId2));
+ static::assertFalse($fileEncryption->validateId('kjlfez/fez'));
+ }
+
+ /** @throws SessionException */
+ public function testUpdateTimestamp(): void
+ {
+ $fileEncryption = new FileEncryption();
+ $fileEncryption->setKey('randomKey');
+
+ $this->openSessionForSavingSavePath($fileEncryption);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $fileEncryption->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInFile = \file_get_contents($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ $oldFileModifiedTime = \filemtime($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertNotSame($data, $dataInFile);
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+ $encryptionTrait->setKey('randomKey');
+ $dataInFileDecrypted = $encryptionTrait->decrypt($dataInFile);
+ static::assertSame($data, $dataInFileDecrypted);
+
+ \sleep(1);
+ $success = $fileEncryption->updateTimestamp($sessionId, $data);
+ static::assertTrue($success);
+
+ \clearstatcache();
+
+ $dataInFile2 = \file_get_contents($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertNotSame($data, $dataInFile2);
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+ $encryptionTrait->setKey('randomKey');
+ $dataInFileDecrypted = $encryptionTrait->decrypt($dataInFile2);
+ static::assertSame($data, $dataInFileDecrypted);
+ static::assertNotSame($dataInFile, $dataInFile2);
+
+ $newFileModifiedTime = \filemtime($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+
+ static::assertTrue($oldFileModifiedTime < $newFileModifiedTime);
+ }
+
+ /** @throws \Exception */
+ public function testCreateId(): void
+ {
+ $fileEncryption = new FileEncryption();
+ $fileEncryption->setKey('randomKey');
+
+ $string = $fileEncryption->create_sid();
+
+ static::assertMatchesRegularExpression('/^[a-zA-Z0-9-]{127}+$/', $string);
+ }
+}
diff --git a/tests/FileTest.php b/tests/FileTest.php
index f0e08a7..1856afd 100644
--- a/tests/FileTest.php
+++ b/tests/FileTest.php
@@ -1,220 +1,235 @@
-open($this->getPath(), '');
- static::assertTrue($success);
- }
-
- public function testOpen(): void
- {
- $file = new File();
- $savePath = $this->getPath();
- $sessionName = '';
- $success = $file->open($savePath, $sessionName);
- static::assertTrue($success);
-
- $savePathNotCreated = $savePath . DIRECTORY_SEPARATOR . 'tests';
- $success = $file->open($savePathNotCreated, $sessionName);
- static::assertTrue($success);
- $success = file_exists($savePathNotCreated);
- static::assertTrue($success);
- }
-
- public function testClose(): void
- {
- $file = new File();
- $success = $file->close();
- static::assertTrue($success);
- }
-
- public function testWrite(): void
- {
- $file = new File();
-
- $this->openSessionForSavingSavePath($file);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $file->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataInFile = file_get_contents($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertEquals($data, $dataInFile);
- }
-
- public function testRead(): void
- {
- $file = new File();
-
- $this->openSessionForSavingSavePath($file);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $file->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataOutput = $file->read($sessionId);
- static::assertNotEmpty($dataOutput);
- static::assertIsString($dataOutput);
- static::assertEquals($data, $dataOutput);
-
- $sessionId = '';
- $dataOutput = $file->read($sessionId);
- static::assertEmpty($dataOutput);
- static::assertIsString($dataOutput);
- }
-
- public function testDestroy(): void
- {
- $file = new File();
-
- $this->openSessionForSavingSavePath($file);
-
- $sessionId = 'todelete';
- $success = $file->destroy($sessionId);
- static::assertTrue($success);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $file->write($sessionId, $data);
- static::assertTrue($success);
-
- $isFileExist = file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertTrue($isFileExist);
- $success = $file->destroy($sessionId);
- static::assertTrue($success);
- $isFileNotExist = !file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertTrue($isFileNotExist);
- }
-
- public function testGc(): void
- {
- $file = new File();
-
- $this->openSessionForSavingSavePath($file);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $file->write($sessionId, $data);
- static::assertTrue($success);
-
- $isFileExist = file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertTrue($isFileExist);
-
- $lifetime = -1000;
- $success = $file->gc($lifetime);
- static::assertTrue($success);
-
- $isFileNotExist = !file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertTrue($isFileNotExist);
- }
-
- public function testValidateId(): void
- {
- $file = new File();
-
- $this->openSessionForSavingSavePath($file);
-
- $baseId = 'XiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
- $endId1 = 'Xj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
- $endId2 = 'Xklezfoipvfk0lferijkoefzjklgrvefLlnMr';
-
- $file->write($baseId . $endId1, 'a');
-
- static::assertTrue($file->validateId($baseId . $endId1));
- static::assertFalse($file->validateId($baseId . $endId2));
- static::assertFalse($file->validateId('kjlfez/fez'));
- }
-
- public function testUpdateTimestamp(): void
- {
- $file = new File();
-
- $this->openSessionForSavingSavePath($file);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $file->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataInFile = file_get_contents($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- $oldFileModifiedTime = filemtime($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertEquals($data, $dataInFile);
-
- sleep(1);
- $success = $file->updateTimestamp($sessionId, $data);
- static::assertTrue($success);
-
- clearstatcache();
-
- $dataInFile2 = file_get_contents($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
- static::assertEquals($data, $dataInFile2);
- static::assertEquals($dataInFile, $dataInFile2);
- $newFileModifiedTime = filemtime($this->getPath() . DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
-
- static::assertTrue($oldFileModifiedTime < $newFileModifiedTime);
- }
-
- /**
- * @throws \Exception
- */
- public function testCreateId(): void
- {
- $file = new File();
-
- $string = $file->create_sid();
-
- static::assertSame(preg_match('/^[a-zA-Z0-9-]{127}+$/', $string), 1);
- }
-}
+open($this->getPath(), '');
+ static::assertTrue($success);
+ }
+
+ /** @throws SessionException */
+ public function testOpen(): void
+ {
+ $file = new File();
+ $savePath = $this->getPath();
+ $sessionName = '';
+ $success = $file->open($savePath, $sessionName);
+ static::assertTrue($success);
+
+ $savePathNotCreated = $savePath . \DIRECTORY_SEPARATOR . 'tests';
+ $success = $file->open($savePathNotCreated, $sessionName);
+ static::assertTrue($success);
+ $success = \file_exists($savePathNotCreated);
+ static::assertTrue($success);
+ }
+
+ public function testClose(): void
+ {
+ $file = new File();
+ $success = $file->close();
+ static::assertTrue($success);
+ }
+
+ /** @throws SessionException */
+ public function testWrite(): void
+ {
+ $file = new File();
+
+ $this->openSessionForSavingSavePath($file);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $file->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInFile = \file_get_contents($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertSame($data, $dataInFile);
+ }
+
+ /** @throws SessionException */
+ public function testRead(): void
+ {
+ $file = new File();
+
+ $this->openSessionForSavingSavePath($file);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $file->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataOutput = $file->read($sessionId);
+ static::assertNotEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ static::assertSame($data, $dataOutput);
+
+ $sessionId = '';
+ $dataOutput = $file->read($sessionId);
+ static::assertEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ }
+
+ /** @throws SessionException */
+ public function testDestroy(): void
+ {
+ $file = new File();
+
+ $this->openSessionForSavingSavePath($file);
+
+ $sessionId = 'todelete';
+ $success = $file->destroy($sessionId);
+ static::assertTrue($success);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $file->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $isFileExist = \file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertTrue($isFileExist);
+ $success = $file->destroy($sessionId);
+ static::assertTrue($success);
+ $isFileNotExist = !\file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertTrue($isFileNotExist);
+ }
+
+ /** @throws SessionException */
+ public function testGc(): void
+ {
+ $file = new File();
+
+ $this->openSessionForSavingSavePath($file);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $file->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $isFileExist = \file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertTrue($isFileExist);
+
+ $lifetime = -1000;
+ $success = $file->gc($lifetime);
+ static::assertTrue($success);
+
+ $isFileNotExist = !\file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertTrue($isFileNotExist);
+ }
+
+ /** @throws SessionException */
+ public function testValidateId(): void
+ {
+ $file = new File();
+
+ $this->openSessionForSavingSavePath($file);
+
+ $baseId = 'XiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
+ $endId1 = 'Xj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
+ $endId2 = 'Xklezfoipvfk0lferijkoefzjklgrvefLlnMr';
+
+ $file->write($baseId . $endId1, 'a');
+
+ static::assertTrue($file->validateId($baseId . $endId1));
+ static::assertFalse($file->validateId($baseId . $endId2));
+ static::assertFalse($file->validateId('kjlfez/fez'));
+ }
+
+ /** @throws SessionException */
+ public function testUpdateTimestamp(): void
+ {
+ $file = new File();
+
+ $this->openSessionForSavingSavePath($file);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $file->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInFile = \file_get_contents($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ $oldFileModifiedTime = \filemtime($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertSame($data, $dataInFile);
+
+ \sleep(1);
+ $success = $file->updateTimestamp($sessionId, $data);
+ static::assertTrue($success);
+
+ \clearstatcache();
+
+ $dataInFile2 = \file_get_contents($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+ static::assertSame($data, $dataInFile2);
+ static::assertSame($dataInFile, $dataInFile2);
+ $newFileModifiedTime = \filemtime($this->getPath() . \DIRECTORY_SEPARATOR . 'sess_' . $sessionId);
+
+ static::assertTrue($oldFileModifiedTime < $newFileModifiedTime);
+ }
+
+ /** @throws \Exception */
+ public function testCreateId(): void
+ {
+ $file = new File();
+
+ $string = $file->create_sid();
+
+ static::assertMatchesRegularExpression('/^[a-zA-Z0-9-]{127}+$/', $string);
+ }
+
+ /** @throws SessionException */
+ public function testLengthSessionID(): void
+ {
+ $file = new File();
+ $file->setLengthSessionID(50);
+ static::assertSame(50, $file->getLengthSessionID());
+ }
+
+ public function testLengthSessionIDSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not set length session ID below 32');
+
+ $file = new File();
+ $file->setLengthSessionID(1);
+ }
+}
diff --git a/tests/FileWithNewPrefixTest.php b/tests/FileWithNewPrefixTest.php
index 762ab30..e0738e4 100644
--- a/tests/FileWithNewPrefixTest.php
+++ b/tests/FileWithNewPrefixTest.php
@@ -1,230 +1,226 @@
-open($this->getPath(), '');
- static::assertTrue($success);
- }
-
- public function testOpen(): void
- {
- $file = new File();
- $file->setPrefix('myprefix_');
- $savePath = $this->getPath();
- $sessionName = '';
- $success = $file->open($savePath, $sessionName);
- static::assertTrue($success);
-
- $savePathNotCreated = $savePath . DIRECTORY_SEPARATOR . 'tests';
- $success = $file->open($savePathNotCreated, $sessionName);
- static::assertTrue($success);
- $success = file_exists($savePathNotCreated);
- static::assertTrue($success);
- }
-
- public function testClose(): void
- {
- $file = new File();
- $file->setPrefix('myprefix_');
- $success = $file->close();
- static::assertTrue($success);
- }
-
- public function testWrite(): void
- {
- $file = new File();
- $file->setPrefix('myprefix_');
-
- $this->openSessionForSavingSavePath($file);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $file->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataInFile = file_get_contents($this->getPath() . DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
- static::assertEquals($data, $dataInFile);
- }
-
- public function testRead(): void
- {
- $file = new File();
- $file->setPrefix('myprefix_');
-
- $this->openSessionForSavingSavePath($file);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $file->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataOutput = $file->read($sessionId);
- static::assertNotEmpty($dataOutput);
- static::assertIsString($dataOutput);
- static::assertEquals($data, $dataOutput);
-
- $sessionId = '';
- $dataOutput = $file->read($sessionId);
- static::assertEmpty($dataOutput);
- static::assertIsString($dataOutput);
- }
-
- public function testDestroy(): void
- {
- $file = new File();
- $file->setPrefix('myprefix_');
-
- $this->openSessionForSavingSavePath($file);
-
- $sessionId = 'todelete';
- $success = $file->destroy($sessionId);
- static::assertTrue($success);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $file->write($sessionId, $data);
- static::assertTrue($success);
-
- $isFileExist = file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
- static::assertTrue($isFileExist);
- $success = $file->destroy($sessionId);
- static::assertTrue($success);
- $isFileNotExist = !file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
- static::assertTrue($isFileNotExist);
- }
-
- public function testGc(): void
- {
- $file = new File();
- $file->setPrefix('myprefix_');
-
- $this->openSessionForSavingSavePath($file);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $file->write($sessionId, $data);
- static::assertTrue($success);
-
- $isFileExist = file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
- static::assertTrue($isFileExist);
-
- $lifetime = -1000;
- $success = $file->gc($lifetime);
- static::assertTrue($success);
-
- $isFileNotExist = !file_exists($this->getPath() . DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
- static::assertTrue($isFileNotExist);
- }
-
- public function testValidateId(): void
- {
- $file = new File();
- $file->setPrefix('myprefix_');
-
- $this->openSessionForSavingSavePath($file);
-
- $baseId = 'YiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
- $endId1 = 'Yj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
- $endId2 = 'Yklezfoipvfk0lferijkoefzjklgrvefLlnMr';
-
- $file->write($baseId . $endId1, 'a');
-
- static::assertTrue($file->validateId($baseId . $endId1));
- static::assertFalse($file->validateId($baseId . $endId2));
- static::assertFalse($file->validateId('kjlfez/fez'));
- }
-
- public function testUpdateTimestamp(): void
- {
- $file = new File();
- $file->setPrefix('myprefix_');
-
- $this->openSessionForSavingSavePath($file);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $file->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataInFile = file_get_contents($this->getPath() . DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
- $oldFileModifiedTime = filemtime($this->getPath() . DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
- static::assertEquals($data, $dataInFile);
-
- sleep(1);
- $success = $file->updateTimestamp($sessionId, $data);
- static::assertTrue($success);
-
- clearstatcache();
-
- $dataInFile2 = file_get_contents($this->getPath() . DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
- static::assertEquals($data, $dataInFile2);
- static::assertEquals($dataInFile, $dataInFile2);
- $newFileModifiedTime = filemtime($this->getPath() . DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
-
- static::assertTrue($oldFileModifiedTime < $newFileModifiedTime);
- }
-
- /**
- * @throws \Exception
- */
- public function testCreateId(): void
- {
- $file = new File();
- $file->setPrefix('myprefix_');
-
- $string = $file->create_sid();
-
- static::assertSame(preg_match('/^[a-zA-Z0-9-]{127}+$/', $string), 1);
- }
-}
+open($this->getPath(), '');
+ static::assertTrue($success);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testOpen(): void
+ {
+ $file = new File();
+ $file->setPrefix('myprefix_');
+ $savePath = $this->getPath();
+ $sessionName = '';
+ $success = $file->open($savePath, $sessionName);
+ static::assertTrue($success);
+
+ $savePathNotCreated = $savePath . \DIRECTORY_SEPARATOR . 'tests';
+ $success = $file->open($savePathNotCreated, $sessionName);
+ static::assertTrue($success);
+ $success = \file_exists($savePathNotCreated);
+ static::assertTrue($success);
+ }
+
+ public function testClose(): void
+ {
+ $file = new File();
+ $file->setPrefix('myprefix_');
+ $success = $file->close();
+ static::assertTrue($success);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testWrite(): void
+ {
+ $file = new File();
+ $file->setPrefix('myprefix_');
+
+ $this->openSessionForSavingSavePath($file);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $file->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInFile = \file_get_contents($this->getPath() . \DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
+ static::assertSame($data, $dataInFile);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testRead(): void
+ {
+ $file = new File();
+ $file->setPrefix('myprefix_');
+
+ $this->openSessionForSavingSavePath($file);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $file->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataOutput = $file->read($sessionId);
+ static::assertNotEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ static::assertSame($data, $dataOutput);
+
+ $sessionId = '';
+ $dataOutput = $file->read($sessionId);
+ static::assertEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testDestroy(): void
+ {
+ $file = new File();
+ $file->setPrefix('myprefix_');
+
+ $this->openSessionForSavingSavePath($file);
+
+ $sessionId = 'todelete';
+ $success = $file->destroy($sessionId);
+ static::assertTrue($success);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $file->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $isFileExist = \file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
+ static::assertTrue($isFileExist);
+ $success = $file->destroy($sessionId);
+ static::assertTrue($success);
+ $isFileNotExist = !\file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
+ static::assertTrue($isFileNotExist);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testGc(): void
+ {
+ $file = new File();
+ $file->setPrefix('myprefix_');
+
+ $this->openSessionForSavingSavePath($file);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $file->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $isFileExist = \file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
+ static::assertTrue($isFileExist);
+
+ $lifetime = -1000;
+ $success = $file->gc($lifetime);
+ static::assertTrue($success);
+
+ $isFileNotExist = !\file_exists($this->getPath() . \DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
+ static::assertTrue($isFileNotExist);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testValidateId(): void
+ {
+ $file = new File();
+ $file->setPrefix('myprefix_');
+
+ $this->openSessionForSavingSavePath($file);
+
+ $baseId = 'YiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
+ $endId1 = 'Yj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
+ $endId2 = 'Yklezfoipvfk0lferijkoefzjklgrvefLlnMr';
+
+ $file->write($baseId . $endId1, 'a');
+
+ static::assertTrue($file->validateId($baseId . $endId1));
+ static::assertFalse($file->validateId($baseId . $endId2));
+ static::assertFalse($file->validateId('kjlfez/fez'));
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testUpdateTimestamp(): void
+ {
+ $file = new File();
+ $file->setPrefix('myprefix_');
+
+ $this->openSessionForSavingSavePath($file);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $file->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInFile = \file_get_contents($this->getPath() . \DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
+ $oldFileModifiedTime = \filemtime($this->getPath() . \DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
+ static::assertSame($data, $dataInFile);
+
+ \sleep(1);
+ $success = $file->updateTimestamp($sessionId, $data);
+ static::assertTrue($success);
+
+ \clearstatcache();
+
+ $dataInFile2 = \file_get_contents($this->getPath() . \DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
+ static::assertSame($data, $dataInFile2);
+ static::assertSame($dataInFile, $dataInFile2);
+ $newFileModifiedTime = \filemtime($this->getPath() . \DIRECTORY_SEPARATOR . 'myprefix_' . $sessionId);
+
+ static::assertTrue($oldFileModifiedTime < $newFileModifiedTime);
+ }
+
+ /** @throws \Exception */
+ public function testCreateId(): void
+ {
+ $file = new File();
+ $file->setPrefix('myprefix_');
+
+ $string = $file->create_sid();
+
+ static::assertMatchesRegularExpression('/^[a-zA-Z0-9-]{127}+$/', $string);
+ }
+}
diff --git a/tests/RedisEncryptionTest.php b/tests/RedisEncryptionTest.php
index 3be1dc1..99b1547 100644
--- a/tests/RedisEncryptionTest.php
+++ b/tests/RedisEncryptionTest.php
@@ -1,268 +1,261 @@
- 'tcp',
- 'host' => '127.0.0.1',
- 'port' => 6379,
- ];
- static::$redis = new Predis($params);
- static::$redis->flushdb();
- }
-
- protected function setUp(): void
- {
- static::$redis->flushdb();
- }
-
- public function testOpen(): void
- {
- $redis = new RedisEncryption();
- $redis->setKey('randomKey');
-
- $redis->setCurrentRedis(static::$redis);
-
- $savePath = '';
- $sessionName = '';
- $success = $redis->open($savePath, $sessionName);
- static::assertTrue($success);
- }
-
- public function testClose(): void
- {
- $redis = new RedisEncryption();
- $redis->setKey('randomKey');
-
- $redis->setCurrentRedis(static::$redis);
- $success = $redis->close();
- static::assertTrue($success);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testWrite(): void
- {
- $redis = new RedisEncryption();
- $redis->setKey('randomKey');
-
- $redis->setCurrentRedis(static::$redis);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataInRedis = static::$redis->get($sessionId);
- static::assertNotEquals($data, $dataInRedis);
-
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
- $encryptionTrait->setKey('randomKey');
- $dataInRedisDecrypted = $encryptionTrait->decrypt($dataInRedis);
- static::assertEquals($data, $dataInRedisDecrypted);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testRead(): void
- {
- $redis = new RedisEncryption();
- $redis->setKey('randomKey');
-
- $redis->setCurrentRedis(static::$redis);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataOutput = $redis->read($sessionId);
- static::assertNotEmpty($dataOutput);
- static::assertIsString($dataOutput);
- static::assertEquals($data, $dataOutput);
-
- $sessionId = '';
- $dataOutput = $redis->read($sessionId);
- static::assertEmpty($dataOutput);
- static::assertIsString($dataOutput);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testDestroy(): void
- {
- $redis = new RedisEncryption();
- $redis->setKey('randomKey');
-
- $redis->setCurrentRedis(static::$redis);
-
- $sessionId = 'todelete';
- $success = $redis->destroy($sessionId);
- static::assertTrue($success);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
-
- $isKeyExist = static::$redis->exists($sessionId) === 1;
- static::assertTrue($isKeyExist);
- $success = $redis->destroy($sessionId);
- static::assertTrue($success);
- $isKeyNotExist = static::$redis->exists($sessionId) === 0;
- static::assertTrue($isKeyNotExist);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testGc(): void
- {
- $redis = new RedisEncryption();
- $redis->setKey('randomKey');
-
- $redis->setCurrentRedis(static::$redis);
- $redis->setLifetime(1);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
-
- $isKeyExist = static::$redis->exists($sessionId) === 1;
- static::assertTrue($isKeyExist);
-
- sleep(2);
-
- $lifetime = 0;
- $success = $redis->gc($lifetime);
- static::assertTrue($success);
-
- $isKeyNotExist = static::$redis->exists($sessionId) === 0;
- static::assertTrue($isKeyNotExist);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testSetNewRedis(): void
- {
- $redis = new RedisEncryption();
- $redis->setKey('randomKey');
-
- $params = [
- 'scheme' => 'tcp',
- 'host' => '127.0.0.1',
- 'port' => 6379,
- ];
- $redis->setNewRedis($params);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
-
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testValidateId(): void
- {
- $redis = new RedisEncryption();
- $redis->setKey('randomKey');
-
- $redis->setCurrentRedis(static::$redis);
-
- $baseId = 'DiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
- $endId1 = 'Dj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
- $endId2 = 'Dklezfoipvfk0lferijkoefzjklgrvefLlnMr';
-
- $redis->write($baseId . $endId1, 'a');
-
- static::assertTrue($redis->validateId($baseId . $endId1));
- static::assertFalse($redis->validateId($baseId . $endId2));
- static::assertFalse($redis->validateId('kjlfez/fez'));
- }
-
- /**
- * @throws \Rancoud\Session\SessionException
- */
- public function testUpdateTimestamp(): void
- {
- $redis = new RedisEncryption();
- $redis->setKey('randomKey');
-
- $redis->setCurrentRedis(static::$redis);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
-
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataInRedis = static::$redis->get($sessionId);
- static::assertNotEquals($data, $dataInRedis);
- $ttl1 = static::$redis->ttl($sessionId);
-
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
- $encryptionTrait->setKey('randomKey');
- $dataInRedisDecrypted = $encryptionTrait->decrypt($dataInRedis);
- static::assertEquals($data, $dataInRedisDecrypted);
-
- sleep(2);
-
- $ttl2 = static::$redis->ttl($sessionId);
-
- $success = $redis->updateTimestamp($sessionId, $data);
- static::assertTrue($success);
-
- $dataInRedis2 = static::$redis->get($sessionId);
- static::assertNotEquals($data, $dataInRedis2);
- $ttl3 = static::$redis->ttl($sessionId);
-
- $encryptionTrait = $this->getObjectForTrait('Rancoud\Session\Encryption');
- $encryptionTrait->setKey('randomKey');
- $dataInRedisDecrypted = $encryptionTrait->decrypt($dataInRedis2);
- static::assertEquals($data, $dataInRedisDecrypted);
-
- static::assertTrue($ttl2 < $ttl1);
- static::assertTrue($ttl3 > $ttl2);
- }
-
- /**
- * @throws \Exception
- */
- public function testCreateId(): void
- {
- $redis = new RedisEncryption();
- $redis->setKey('randomKey');
-
- $redis->setCurrentRedis(static::$redis);
-
- $string = $redis->create_sid();
-
- static::assertSame(preg_match('/^[a-zA-Z0-9-]{127}+$/', $string), 1);
- }
-}
+ 'tcp',
+ 'port' => 6379,
+ ];
+
+ $redisHost = \getenv('REDIS_HOST', true);
+ $params['host'] = ($redisHost !== false) ? $redisHost : '127.0.0.1';
+
+ static::$redis = new Predis($params);
+ static::$redis->flushdb();
+ }
+
+ protected function setUp(): void
+ {
+ static::$redis->flushdb();
+ }
+
+ public function testOpen(): void
+ {
+ $redis = new RedisEncryption();
+ $redis->setKey('randomKey');
+
+ $redis->setCurrentRedis(static::$redis);
+
+ $savePath = '';
+ $sessionName = '';
+ $success = $redis->open($savePath, $sessionName);
+ static::assertTrue($success);
+ }
+
+ public function testClose(): void
+ {
+ $redis = new RedisEncryption();
+ $redis->setKey('randomKey');
+
+ $redis->setCurrentRedis(static::$redis);
+ $success = $redis->close();
+ static::assertTrue($success);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testWrite(): void
+ {
+ $redis = new RedisEncryption();
+ $redis->setKey('randomKey');
+
+ $redis->setCurrentRedis(static::$redis);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInRedis = static::$redis->get($sessionId);
+ static::assertNotSame($data, $dataInRedis);
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+ $encryptionTrait->setKey('randomKey');
+ $dataInRedisDecrypted = $encryptionTrait->decrypt($dataInRedis);
+ static::assertSame($data, $dataInRedisDecrypted);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testRead(): void
+ {
+ $redis = new RedisEncryption();
+ $redis->setKey('randomKey');
+
+ $redis->setCurrentRedis(static::$redis);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataOutput = $redis->read($sessionId);
+ static::assertNotEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ static::assertSame($data, $dataOutput);
+
+ $sessionId = '';
+ $dataOutput = $redis->read($sessionId);
+ static::assertEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testDestroy(): void
+ {
+ $redis = new RedisEncryption();
+ $redis->setKey('randomKey');
+
+ $redis->setCurrentRedis(static::$redis);
+
+ $sessionId = 'todelete';
+ $success = $redis->destroy($sessionId);
+ static::assertTrue($success);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $isKeyExist = static::$redis->exists($sessionId) === 1;
+ static::assertTrue($isKeyExist);
+ $success = $redis->destroy($sessionId);
+ static::assertTrue($success);
+ $isKeyNotExist = static::$redis->exists($sessionId) === 0;
+ static::assertTrue($isKeyNotExist);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testGc(): void
+ {
+ $redis = new RedisEncryption();
+ $redis->setKey('randomKey');
+
+ $redis->setCurrentRedis(static::$redis);
+ $redis->setLifetime(1);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $isKeyExist = static::$redis->exists($sessionId) === 1;
+ static::assertTrue($isKeyExist);
+
+ \sleep(2);
+
+ $lifetime = 0;
+ $success = $redis->gc($lifetime);
+ static::assertTrue($success);
+
+ $isKeyNotExist = static::$redis->exists($sessionId) === 0;
+ static::assertTrue($isKeyNotExist);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testSetNewRedis(): void
+ {
+ $redis = new RedisEncryption();
+ $redis->setKey('randomKey');
+
+ $params = [
+ 'scheme' => 'tcp',
+ 'port' => 6379,
+ ];
+
+ $redisHost = \getenv('REDIS_HOST', true);
+ $params['host'] = ($redisHost !== false) ? $redisHost : '127.0.0.1';
+
+ $redis->setNewRedis($params);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testValidateId(): void
+ {
+ $redis = new RedisEncryption();
+ $redis->setKey('randomKey');
+
+ $redis->setCurrentRedis(static::$redis);
+
+ $baseId = 'DiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
+ $endId1 = 'Dj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
+ $endId2 = 'Dklezfoipvfk0lferijkoefzjklgrvefLlnMr';
+
+ $redis->write($baseId . $endId1, 'a');
+
+ static::assertTrue($redis->validateId($baseId . $endId1));
+ static::assertFalse($redis->validateId($baseId . $endId2));
+ static::assertFalse($redis->validateId('kjlfez/fez'));
+ }
+
+ /** @throws \Rancoud\Session\SessionException */
+ public function testUpdateTimestamp(): void
+ {
+ $redis = new RedisEncryption();
+ $redis->setKey('randomKey');
+
+ $redis->setCurrentRedis(static::$redis);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInRedis = static::$redis->get($sessionId);
+ static::assertNotSame($data, $dataInRedis);
+ $ttl1 = static::$redis->ttl($sessionId);
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+ $encryptionTrait->setKey('randomKey');
+ $dataInRedisDecrypted = $encryptionTrait->decrypt($dataInRedis);
+ static::assertSame($data, $dataInRedisDecrypted);
+
+ \sleep(2);
+
+ $ttl2 = static::$redis->ttl($sessionId);
+
+ $success = $redis->updateTimestamp($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInRedis2 = static::$redis->get($sessionId);
+ static::assertNotSame($data, $dataInRedis2);
+ $ttl3 = static::$redis->ttl($sessionId);
+
+ $encryptionTrait = new class() {
+ use \Rancoud\Session\Encryption;
+ };
+ $encryptionTrait->setKey('randomKey');
+ $dataInRedisDecrypted = $encryptionTrait->decrypt($dataInRedis2);
+ static::assertSame($data, $dataInRedisDecrypted);
+
+ static::assertTrue($ttl2 < $ttl1);
+ static::assertTrue($ttl3 > $ttl2);
+ }
+
+ /** @throws \Exception */
+ public function testCreateId(): void
+ {
+ $redis = new RedisEncryption();
+ $redis->setKey('randomKey');
+
+ $redis->setCurrentRedis(static::$redis);
+
+ $string = $redis->create_sid();
+
+ static::assertMatchesRegularExpression('/^[a-zA-Z0-9-]{127}+$/', $string);
+ }
+}
diff --git a/tests/RedisTest.php b/tests/RedisTest.php
index b4155f2..bf9108a 100644
--- a/tests/RedisTest.php
+++ b/tests/RedisTest.php
@@ -1,212 +1,231 @@
- 'tcp',
- 'host' => '127.0.0.1',
- 'port' => 6379,
- ];
- static::$redis = new Predis($params);
- static::$redis->flushdb();
- }
-
- protected function setUp(): void
- {
- static::$redis->flushdb();
- }
-
- public function testOpen(): void
- {
- $redis = new Redis();
- $redis->setCurrentRedis(static::$redis);
-
- $savePath = '';
- $sessionName = '';
- $success = $redis->open($savePath, $sessionName);
- static::assertTrue($success);
- }
-
- public function testClose(): void
- {
- $redis = new Redis();
- $redis->setCurrentRedis(static::$redis);
- $success = $redis->close();
- static::assertTrue($success);
- }
-
- public function testWrite(): void
- {
- $redis = new Redis();
- $redis->setCurrentRedis(static::$redis);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataInRedis = static::$redis->get($sessionId);
- static::assertEquals($data, $dataInRedis);
- }
-
- public function testRead(): void
- {
- $redis = new Redis();
- $redis->setCurrentRedis(static::$redis);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataOutput = $redis->read($sessionId);
- static::assertNotEmpty($dataOutput);
- static::assertIsString($dataOutput);
- static::assertEquals($data, $dataOutput);
-
- $sessionId = '';
- $dataOutput = $redis->read($sessionId);
- static::assertEmpty($dataOutput);
- static::assertIsString($dataOutput);
- }
-
- public function testDestroy(): void
- {
- $redis = new Redis();
- $redis->setCurrentRedis(static::$redis);
-
- $sessionId = 'todelete';
- $success = $redis->destroy($sessionId);
- static::assertTrue($success);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
-
- $isKeyExist = static::$redis->exists($sessionId) === 1;
- static::assertTrue($isKeyExist);
- $success = $redis->destroy($sessionId);
- static::assertTrue($success);
- $isKeyNotExist = static::$redis->exists($sessionId) === 0;
- static::assertTrue($isKeyNotExist);
- }
-
- public function testGc(): void
- {
- $redis = new Redis();
- $redis->setCurrentRedis(static::$redis);
- $redis->setLifetime(1);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
-
- $isKeyExist = static::$redis->exists($sessionId) === 1;
- static::assertTrue($isKeyExist);
-
- sleep(2);
-
- $lifetime = 0;
- $success = $redis->gc($lifetime);
- static::assertTrue($success);
-
- $isKeyNotExist = static::$redis->exists($sessionId) === 0;
- static::assertTrue($isKeyNotExist);
- }
-
- public function testSetNewRedis(): void
- {
- $redis = new Redis();
- $params = [
- 'scheme' => 'tcp',
- 'host' => '127.0.0.1',
- 'port' => 6379,
- ];
- $redis->setNewRedis($params);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
-
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
- }
-
- public function testValidateId(): void
- {
- $redis = new Redis();
- $redis->setCurrentRedis(static::$redis);
-
- $baseId = 'DiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
- $endId1 = 'Dj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
- $endId2 = 'Dklezfoipvfk0lferijkoefzjklgrvefLlnMr';
-
- $redis->write($baseId . $endId1, 'a');
-
- static::assertTrue($redis->validateId($baseId . $endId1));
- static::assertFalse($redis->validateId($baseId . $endId2));
- static::assertFalse($redis->validateId('kjlfez/fez'));
- }
-
- public function testUpdateTimestamp(): void
- {
- $redis = new Redis();
- $redis->setCurrentRedis(static::$redis);
-
- $sessionId = 'sessionId';
- $data = 'azerty';
-
- $success = $redis->write($sessionId, $data);
- static::assertTrue($success);
-
- $dataInRedis = static::$redis->get($sessionId);
- static::assertEquals($data, $dataInRedis);
- $ttl1 = static::$redis->ttl($sessionId);
-
- sleep(2);
-
- $ttl2 = static::$redis->ttl($sessionId);
-
- $success = $redis->updateTimestamp($sessionId, $data);
- static::assertTrue($success);
-
- $dataInRedis2 = static::$redis->get($sessionId);
- static::assertEquals($data, $dataInRedis2);
- $ttl3 = static::$redis->ttl($sessionId);
-
- static::assertTrue($ttl2 < $ttl1);
- static::assertTrue($ttl3 > $ttl2);
- }
-
- /**
- * @throws \Exception
- */
- public function testCreateId(): void
- {
- $redis = new Redis();
- $redis->setCurrentRedis(static::$redis);
-
- $string = $redis->create_sid();
-
- static::assertSame(preg_match('/^[a-zA-Z0-9-]{127}+$/', $string), 1);
- }
-}
+ 'tcp',
+ 'port' => 6379,
+ ];
+
+ $redisHost = \getenv('REDIS_HOST', true);
+ $params['host'] = ($redisHost !== false) ? $redisHost : '127.0.0.1';
+
+ static::$redis = new Predis($params);
+ static::$redis->flushdb();
+ }
+
+ protected function setUp(): void
+ {
+ static::$redis->flushdb();
+ }
+
+ public function testOpen(): void
+ {
+ $redis = new Redis();
+ $redis->setCurrentRedis(static::$redis);
+
+ $savePath = '';
+ $sessionName = '';
+ $success = $redis->open($savePath, $sessionName);
+ static::assertTrue($success);
+ }
+
+ public function testClose(): void
+ {
+ $redis = new Redis();
+ $redis->setCurrentRedis(static::$redis);
+ $success = $redis->close();
+ static::assertTrue($success);
+ }
+
+ public function testWrite(): void
+ {
+ $redis = new Redis();
+ $redis->setCurrentRedis(static::$redis);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInRedis = static::$redis->get($sessionId);
+ static::assertSame($data, $dataInRedis);
+ }
+
+ public function testRead(): void
+ {
+ $redis = new Redis();
+ $redis->setCurrentRedis(static::$redis);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataOutput = $redis->read($sessionId);
+ static::assertNotEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ static::assertSame($data, $dataOutput);
+
+ $sessionId = '';
+ $dataOutput = $redis->read($sessionId);
+ static::assertEmpty($dataOutput);
+ static::assertIsString($dataOutput);
+ }
+
+ public function testDestroy(): void
+ {
+ $redis = new Redis();
+ $redis->setCurrentRedis(static::$redis);
+
+ $sessionId = 'todelete';
+ $success = $redis->destroy($sessionId);
+ static::assertTrue($success);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $isKeyExist = static::$redis->exists($sessionId) === 1;
+ static::assertTrue($isKeyExist);
+ $success = $redis->destroy($sessionId);
+ static::assertTrue($success);
+ $isKeyNotExist = static::$redis->exists($sessionId) === 0;
+ static::assertTrue($isKeyNotExist);
+ }
+
+ public function testGc(): void
+ {
+ $redis = new Redis();
+ $redis->setCurrentRedis(static::$redis);
+ $redis->setLifetime(1);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $isKeyExist = static::$redis->exists($sessionId) === 1;
+ static::assertTrue($isKeyExist);
+
+ \sleep(2);
+
+ $lifetime = 0;
+ $success = $redis->gc($lifetime);
+ static::assertTrue($success);
+
+ $isKeyNotExist = static::$redis->exists($sessionId) === 0;
+ static::assertTrue($isKeyNotExist);
+ }
+
+ public function testSetNewRedis(): void
+ {
+ $redis = new Redis();
+ $params = [
+ 'scheme' => 'tcp',
+ 'port' => 6379,
+ ];
+
+ $redisHost = \getenv('REDIS_HOST', true);
+ $params['host'] = ($redisHost !== false) ? $redisHost : '127.0.0.1';
+
+ $redis->setNewRedis($params);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+ }
+
+ public function testValidateId(): void
+ {
+ $redis = new Redis();
+ $redis->setCurrentRedis(static::$redis);
+
+ $baseId = 'DiqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
+ $endId1 = 'Dj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
+ $endId2 = 'Dklezfoipvfk0lferijkoefzjklgrvefLlnMr';
+
+ $redis->write($baseId . $endId1, 'a');
+
+ static::assertTrue($redis->validateId($baseId . $endId1));
+ static::assertFalse($redis->validateId($baseId . $endId2));
+ static::assertFalse($redis->validateId('kjlfez/fez'));
+ }
+
+ public function testUpdateTimestamp(): void
+ {
+ $redis = new Redis();
+ $redis->setCurrentRedis(static::$redis);
+
+ $sessionId = 'sessionId';
+ $data = 'azerty';
+
+ $success = $redis->write($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInRedis = static::$redis->get($sessionId);
+ static::assertSame($data, $dataInRedis);
+ $ttl1 = static::$redis->ttl($sessionId);
+
+ \sleep(2);
+
+ $ttl2 = static::$redis->ttl($sessionId);
+
+ $success = $redis->updateTimestamp($sessionId, $data);
+ static::assertTrue($success);
+
+ $dataInRedis2 = static::$redis->get($sessionId);
+ static::assertSame($data, $dataInRedis2);
+ $ttl3 = static::$redis->ttl($sessionId);
+
+ static::assertTrue($ttl2 < $ttl1);
+ static::assertTrue($ttl3 > $ttl2);
+ }
+
+ /** @throws \Exception */
+ public function testCreateId(): void
+ {
+ $redis = new Redis();
+ $redis->setCurrentRedis(static::$redis);
+
+ $string = $redis->create_sid();
+
+ static::assertMatchesRegularExpression('/^[a-zA-Z0-9-]{127}+$/', $string);
+ }
+
+ /** @throws SessionException */
+ public function testLengthSessionID(): void
+ {
+ $redis = new Redis();
+ $redis->setLengthSessionID(50);
+ static::assertSame(50, $redis->getLengthSessionID());
+ }
+
+ public function testLengthSessionIDSessionException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('could not set length session ID below 32');
+
+ $redis = new Redis();
+ $redis->setLengthSessionID(1);
+ }
+}
diff --git a/tests/SessionTest.php b/tests/SessionTest.php
index 22e419c..e252bca 100644
--- a/tests/SessionTest.php
+++ b/tests/SessionTest.php
@@ -1,634 +1,626 @@
-expectException(SessionException::class);
- $this->expectExceptionMessage('Session already started');
-
- Session::setReadWrite();
- Session::start();
- Session::start();
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseDefaultDriverWhenAlreadyStartedException(): void
- {
- $this->expectException(SessionException::class);
- $this->expectExceptionMessage('Session already started');
-
- Session::setReadWrite();
- Session::start();
- Session::useDefaultDriver();
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseFileDriverWhenAlreadyStartedException(): void
- {
- $this->expectException(SessionException::class);
- $this->expectExceptionMessage('Session already started');
-
- Session::setReadWrite();
- Session::start();
- Session::useFileDriver();
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseCustomDriverWhenAlreadyStartedException(): void
- {
- $this->expectException(SessionException::class);
- $this->expectExceptionMessage('Session already started');
-
- Session::setReadWrite();
- Session::start();
- Session::useCustomDriver(new File());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseDefaultDriver(): void
- {
- Session::useDefaultDriver();
- Session::start();
-
- static::assertInstanceOf(\SessionHandler::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseDefaultEncryptionDriver(): void
- {
- Session::useDefaultEncryptionDriver('randomKey');
- Session::start();
-
- static::assertInstanceOf(\Rancoud\Session\DefaultEncryption::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseFileDriver(): void
- {
- Session::useFileDriver();
- Session::start();
-
- static::assertInstanceOf(File::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseFileDriverWithPrefix(): void
- {
- $prefix = 'youhou_';
- Session::useFileDriver();
- Session::setPrefixForFile($prefix);
- Session::setReadWrite();
- Session::start(['lazy_write' => '0']);
- $sessionId = Session::getId();
- $path = Session::getOption('save_path');
- Session::commit();
-
- static::assertInstanceOf(File::class, Session::getDriver());
- static::assertFileExists($path . DIRECTORY_SEPARATOR . $prefix . $sessionId);
-
- $pattern = $path . DIRECTORY_SEPARATOR . 'youhou_*';
- foreach (glob($pattern) as $file) {
- if (file_exists($file)) {
- unlink($file);
- }
- }
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseFileEncryptionDriver(): void
- {
- Session::useFileEncryptionDriver('randomKey');
- Session::start();
-
- static::assertInstanceOf(\Rancoud\Session\FileEncryption::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseNewDatabaseDriver(): void
- {
- $params = [
- 'engine' => 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
- ];
- Session::useNewDatabaseDriver($params);
- Session::start();
-
- static::assertInstanceOf(\Rancoud\Session\Database::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseNewDatabaseEncryptionDriver(): void
- {
- $params = [
- 'engine' => 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
- ];
- Session::useNewDatabaseEncryptionDriver($params, 'randomKey');
- Session::start();
-
- static::assertInstanceOf(\Rancoud\Session\DatabaseEncryption::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Rancoud\Database\DatabaseException
- * @throws \Exception
- */
- public function testUseCurrentDatabaseDriver(): void
- {
- $conf = new \Rancoud\Database\Configurator([
- 'engine' => 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
- ]);
- $db = new \Rancoud\Database\Database($conf);
- Session::useCurrentDatabaseDriver($db);
- Session::start();
-
- static::assertInstanceOf(\Rancoud\Session\Database::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Rancoud\Database\DatabaseException
- * @throws \Exception
- */
- public function testUseCurrentDatabaseEncryptionDriver(): void
- {
- $userId = 50;
- $conf = new \Rancoud\Database\Configurator([
- 'engine' => 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
- ]);
- $db = new \Rancoud\Database\Database($conf);
- Session::useCurrentDatabaseEncryptionDriver($db, 'randomKey');
- static::assertInstanceOf(\Rancoud\Session\DatabaseEncryption::class, Session::getDriver());
-
- Session::setUserIdForDatabase($userId);
- Session::setOption('lazy_write', '0');
- Session::set('a', 'b');
- $sessionId = Session::getId();
- Session::commit();
-
- $userIdInTable = $db->selectVar('SELECT id_user FROM sessions WHERE id = :id', ['id' => $sessionId]);
- static::assertEquals($userId, $userIdInTable);
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseNewRedisDriver(): void
- {
- $params = [
- 'scheme' => 'tcp',
- 'host' => '127.0.0.1',
- 'port' => 6379,
- ];
- Session::useNewRedisDriver($params);
- Session::start();
-
- static::assertInstanceOf(\Rancoud\Session\Redis::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseNewRedisEncryptionDriver(): void
- {
- $params = [
- 'scheme' => 'tcp',
- 'host' => '127.0.0.1',
- 'port' => 6379,
- ];
- Session::useNewRedisEncryptionDriver($params, 'randomKey');
- Session::start();
-
- static::assertInstanceOf(\Rancoud\Session\RedisEncryption::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseCurrentRedisDriver(): void
- {
- $params = [
- 'scheme' => 'tcp',
- 'host' => '127.0.0.1',
- 'port' => 6379,
- ];
- $redis = new \Predis\Client($params);
- Session::useCurrentRedisDriver($redis);
- Session::start();
-
- static::assertInstanceOf(\Rancoud\Session\Redis::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseCurrentRedisEncryptionDriver(): void
- {
- $params = [
- 'scheme' => 'tcp',
- 'host' => '127.0.0.1',
- 'port' => 6379,
- ];
- $redis = new \Predis\Client($params);
- Session::useCurrentRedisEncryptionDriver($redis, 'randomKey');
- Session::start();
-
- static::assertInstanceOf(\Rancoud\Session\RedisEncryption::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseCustomDriver(): void
- {
- Session::useCustomDriver(new File());
- Session::start();
-
- static::assertInstanceOf(File::class, Session::getDriver());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUseEncryptionDriverThrowExceptionWhenMethodIncrorrect(): void
- {
- $this->expectException(SessionException::class);
- $this->expectExceptionMessage('Method unknowed: incorrect');
-
- Session::useFileEncryptionDriver('randomKey', 'incorrect');
- }
-
- //exception quand methode pas bonne dans les encryption
-
- /**
- * @runInSeparateProcess
- * @throws SessionException
- * @throws \Exception
- */
- public function testSetOption(): void
- {
- $defaultOption = Session::getOption('name');
- static::assertEquals($defaultOption, ini_get('session.name'));
-
- Session::setOption('name', 'my_custom_name');
- $customOption = Session::getOption('name');
-
- static::assertEquals('my_custom_name', $customOption);
-
- Session::start(['name' => 'my_other_name']);
-
- $customOption = Session::getOption('name');
- static::assertEquals('my_other_name', $customOption);
- }
-
- /**
- * @runInSeparateProcess
- */
- public function testSetOptionThrowException(): void
- {
- $this->expectException(SessionException::class);
- $this->expectExceptionMessage('Incorrect option: azerty');
-
- Session::getOption('azerty');
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testGetAll(): void
- {
- $sessionValues = Session::getAll();
- static::assertEmpty($sessionValues);
-
- Session::set('a', 'b');
-
- $sessionValues = Session::getAll();
- static::assertEquals(['a' => 'b'], $sessionValues);
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testFlash(): void
- {
- $flaKey1 = 'a';
- $flaValue1 = 'b';
- $flaKey2 = 'y';
- $flaValue2 = 'u';
- $flaKey3 = 'my_key';
- $flaValue3 = null;
- $flaKey4 = '10';
- $flaValue4 = 55;
-
- Session::setFlash($flaKey1, $flaValue1);
- Session::setFlash($flaKey2, $flaValue2);
-
- static::assertTrue(Session::hasFlash($flaKey1));
- static::assertEquals($flaValue1, Session::getFlash($flaKey1));
-
- Session::start(['lazy_write' => '0']);
- Session::keepFlash([$flaKey2]);
-
- static::assertEquals(['flash_data' => [$flaKey2 => $flaValue2]], $_SESSION);
- $sessionId = Session::getId();
- Session::commit();
-
- Session::setId($sessionId);
- Session::setReadWrite();
- Session::start();
-
- static::assertEmpty($_SESSION);
- static::assertTrue(Session::hasFlash($flaKey2));
- static::assertEquals($flaValue2, Session::getFlash($flaKey2));
- static::assertTrue(Session::hasFlashKeyAndValue($flaKey2, $flaValue2));
-
- Session::setFlash($flaKey3, $flaValue3);
- Session::setFlash($flaKey4, $flaValue4);
-
- Session::keepFlash();
-
- Session::commit();
- Session::start();
-
- $expectedFlashValues = [$flaKey2 => $flaValue2, $flaKey3 => $flaValue3, $flaKey4 => $flaValue4];
- static::assertEquals($expectedFlashValues, Session::getAllFlash());
- static::assertEmpty($_SESSION);
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testRollback(): void
- {
- Session::set('a', 'b');
- Session::commit();
-
- static::assertTrue(Session::has('a'));
- Session::set('azerty', 'b');
- static::assertTrue(Session::has('azerty'));
- Session::rollback();
- static::assertFalse(Session::has('azerty'));
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testUnsaved(): void
- {
- Session::set('a', 'b');
- Session::commit();
-
- static::assertTrue(Session::has('a'));
- Session::set('azerty', 'b');
- static::assertTrue(Session::has('azerty'));
- Session::unsaved();
- Session::start();
- static::assertEquals(['a' => 'b'], $_SESSION);
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testRegenerate(): void
- {
- Session::set('a', 'v');
- $sessionId = Session::getId();
- $success = Session::regenerate();
- static::assertTrue($success);
- static::assertNotEquals($sessionId, Session::getId());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testDestroy(): void
- {
- Session::set('a', 'v');
- $sessionId = Session::getId();
- $success = Session::destroy();
- static::assertTrue($success);
- static::assertNotEquals($sessionId, Session::getId());
- static::assertEmpty($_SESSION);
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Exception
- */
- public function testSetReadOnly(): void
- {
- Session::setReadOnly();
- Session::start();
- static::assertFalse(Session::hasStarted());
- }
-
- /**
- * @runInSeparateProcess
- * @throws \Rancoud\Database\DatabaseException
- * @throws \Exception
- */
- public function testGc(): void
- {
- $conf = new \Rancoud\Database\Configurator([
- 'engine' => 'mysql',
- 'host' => '127.0.0.1',
- 'user' => 'root',
- 'password' => '',
- 'database' => 'test_database'
- ]);
- $db = new \Rancoud\Database\Database($conf);
- $db->truncateTables('sessions');
-
- Session::useCurrentDatabaseDriver($db);
- Session::setReadWrite();
- Session::setOption('lazy_write', '0');
- $baseId = 'siqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
- $endId1 = 'Qj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
- $endId2 = 'jklezfoipvfk0lferijkoefzjklgrvefLlnMr';
- Session::setId($baseId . $endId1);
- Session::set('a', 'b');
- Session::commit();
-
- Session::setId($baseId . $endId2);
- Session::set('b', 'a');
- $sessionId = Session::getId();
- Session::commit();
-
- sleep(1);
-
- $sql = 'update sessions set last_access = DATE_ADD(NOW(), INTERVAL 50000 SECOND) WHERE id = :id';
- $params = ['id' => $sessionId];
- $db->update($sql, $params);
-
- Session::setOption('gc_maxlifetime', '1');
-
- sleep(1);
-
- Session::gc();
-
- $count = $db->count('SELECT COUNT(*) FROM sessions');
- static::assertEquals(1, $count);
- }
-}
+setStaticPropertyValue('hasStarted', false);
+
+ $class->setStaticPropertyValue('driver', null);
+
+ $class->setStaticPropertyValue('hasChanged', true);
+
+ $class->setStaticPropertyValue('options', [
+ 'read_and_close' => true,
+ 'cookie_httponly' => '1',
+ 'use_only_cookies' => '1',
+ 'use_trans_sid' => '0',
+ 'use_strict_mode' => '1'
+ ]);
+
+ $path = \ini_get('session.save_path');
+ if (empty($path)) {
+ $path = \DIRECTORY_SEPARATOR . 'tmp';
+ }
+
+ $pattern = $path . \DIRECTORY_SEPARATOR . 'sess_*';
+ foreach (\glob($pattern) as $file) {
+ if (\file_exists($file)) {
+ \unlink($file);
+ }
+ }
+ }
+
+ /** @throws \Exception */
+ public function testGetNull(): void
+ {
+ $value = Session::get('emptykey');
+ static::assertNull($value);
+ }
+
+ /** @throws \Exception */
+ public function testSet(): void
+ {
+ Session::set('a', 'b');
+ $value = Session::get('a');
+ static::assertSame('b', $value);
+ }
+
+ /** @throws \Exception */
+ public function testHas(): void
+ {
+ Session::set('c', 'd');
+
+ $value = Session::has('c');
+ static::assertTrue($value);
+
+ $value = Session::has('empty');
+ static::assertFalse($value);
+ }
+
+ /** @throws \Exception */
+ public function testHasKeyAndValue(): void
+ {
+ Session::set('e', 'f');
+
+ $value = Session::hasKeyAndValue('e', 'f');
+ static::assertTrue($value);
+
+ $value = Session::has('empty');
+ static::assertFalse($value);
+
+ $value = Session::hasKeyAndValue('e', 'empty');
+ static::assertFalse($value);
+ }
+
+ /** @throws \Exception */
+ public function testRemove(): void
+ {
+ Session::set('g', 'h');
+
+ Session::remove('g');
+ $value = Session::get('g');
+ static::assertNull($value);
+
+ Session::remove('empty');
+ $value = Session::get('empty');
+ static::assertNull($value);
+ }
+
+ /** @throws \Exception */
+ public function testGetAndRemove(): void
+ {
+ Session::set('i', 'j');
+
+ $value = Session::getAndRemove('i');
+ static::assertSame('j', $value);
+
+ $value = Session::getAndRemove('empty');
+ static::assertNull($value);
+ }
+
+ /** @throws \Exception */
+ public function testStartException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('Session already started');
+
+ Session::setReadWrite();
+ Session::start();
+ Session::start();
+ }
+
+ /** @throws \Exception */
+ public function testUseDefaultDriverWhenAlreadyStartedException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('Session already started');
+
+ Session::setReadWrite();
+ Session::start();
+ Session::useDefaultDriver();
+ }
+
+ /** @throws \Exception */
+ public function testUseFileDriverWhenAlreadyStartedException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('Session already started');
+
+ Session::setReadWrite();
+ Session::start();
+ Session::useFileDriver();
+ }
+
+ /** @throws \Exception */
+ public function testUseCustomDriverWhenAlreadyStartedException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('Session already started');
+
+ Session::setReadWrite();
+ Session::start();
+ Session::useCustomDriver(new File());
+ }
+
+ /** @throws \Exception */
+ public function testUseDefaultDriver(): void
+ {
+ Session::useDefaultDriver();
+ Session::start();
+
+ static::assertInstanceOf(\SessionHandler::class, Session::getDriver());
+ }
+
+ /** @throws \Exception */
+ public function testUseDefaultEncryptionDriver(): void
+ {
+ Session::useDefaultEncryptionDriver('randomKey');
+ Session::start();
+
+ static::assertInstanceOf(\Rancoud\Session\DefaultEncryption::class, Session::getDriver());
+ }
+
+ /** @throws \Exception */
+ public function testUseFileDriver(): void
+ {
+ Session::useFileDriver();
+ Session::start();
+
+ static::assertInstanceOf(File::class, Session::getDriver());
+ }
+
+ /** @throws \Exception */
+ public function testUseFileDriverWithPrefix(): void
+ {
+ $prefix = 'youhou_';
+ Session::useFileDriver();
+ Session::setPrefixForFile($prefix);
+ Session::setReadWrite();
+ Session::start(['lazy_write' => '0']);
+ $sessionId = Session::getId();
+ $path = Session::getOption('save_path');
+ Session::commit();
+
+ static::assertInstanceOf(File::class, Session::getDriver());
+ static::assertFileExists($path . \DIRECTORY_SEPARATOR . $prefix . $sessionId);
+
+ $pattern = $path . \DIRECTORY_SEPARATOR . 'youhou_*';
+ foreach (\glob($pattern) as $file) {
+ if (\file_exists($file)) {
+ \unlink($file);
+ }
+ }
+ }
+
+ /** @throws \Exception */
+ public function testUseFileEncryptionDriver(): void
+ {
+ Session::useFileEncryptionDriver('randomKey');
+ Session::start();
+
+ static::assertInstanceOf(\Rancoud\Session\FileEncryption::class, Session::getDriver());
+ }
+
+ /** @throws \Exception */
+ public function testUseNewDatabaseDriver(): void
+ {
+ $params = [
+ 'driver' => 'mysql',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+ ];
+
+ $mysqlHost = \getenv('MYSQL_HOST', true);
+ $params['host'] = ($mysqlHost !== false) ? $mysqlHost : '127.0.0.1';
+
+ Session::useNewDatabaseDriver($params);
+ Session::start();
+
+ static::assertInstanceOf(\Rancoud\Session\Database::class, Session::getDriver());
+ }
+
+ /** @throws \Exception */
+ public function testUseNewDatabaseEncryptionDriver(): void
+ {
+ $params = [
+ 'driver' => 'mysql',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+ ];
+
+ $mysqlHost = \getenv('MYSQL_HOST', true);
+ $params['host'] = ($mysqlHost !== false) ? $mysqlHost : '127.0.0.1';
+
+ Session::useNewDatabaseEncryptionDriver($params, 'randomKey');
+ Session::start();
+
+ static::assertInstanceOf(\Rancoud\Session\DatabaseEncryption::class, Session::getDriver());
+ }
+
+ /**
+ * @throws \Exception
+ * @throws \Rancoud\Database\DatabaseException
+ */
+ public function testUseCurrentDatabaseDriver(): void
+ {
+ $conf = new \Rancoud\Database\Configurator([
+ 'driver' => 'mysql',
+ 'host' => 'mysql',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $mysqlHost = \getenv('MYSQL_HOST', true);
+ $conf->setHost(($mysqlHost !== false) ? $mysqlHost : '127.0.0.1');
+
+ $db = new \Rancoud\Database\Database($conf);
+ Session::useCurrentDatabaseDriver($db);
+ Session::start();
+
+ static::assertInstanceOf(\Rancoud\Session\Database::class, Session::getDriver());
+ }
+
+ /**
+ * @throws \Exception
+ * @throws \Rancoud\Database\DatabaseException
+ */
+ public function testUseCurrentDatabaseEncryptionDriver(): void
+ {
+ $userId = 50;
+ $conf = new \Rancoud\Database\Configurator([
+ 'driver' => 'mysql',
+ 'host' => 'mysql',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $mysqlHost = \getenv('MYSQL_HOST', true);
+ $conf->setHost(($mysqlHost !== false) ? $mysqlHost : '127.0.0.1');
+
+ $db = new \Rancoud\Database\Database($conf);
+ Session::useCurrentDatabaseEncryptionDriver($db, 'randomKey');
+ static::assertInstanceOf(\Rancoud\Session\DatabaseEncryption::class, Session::getDriver());
+
+ Session::setUserIdForDatabase($userId);
+ Session::setOption('lazy_write', '0');
+ Session::set('a', 'b');
+ $sessionId = Session::getId();
+ Session::commit();
+
+ $sql = 'REPLACE INTO sessions VALUES(:id, null, UTC_TIMESTAMP(), :content)';
+ $params = ['id' => 'session_123', 'content' => 'content'];
+ $db->insert($sql, $params);
+
+ static::assertSame(1, $db->count('SELECT COUNT(id) FROM sessions WHERE id_user IS NULL'));
+ static::assertSame(1, $db->count('SELECT COUNT(id) FROM sessions WHERE id_user IS NOT NULL'));
+
+ $userIdInTable = (int) $db->selectVar('SELECT id_user FROM sessions WHERE id = :id', ['id' => $sessionId]);
+ static::assertSame($userId, $userIdInTable);
+
+ Session::deleteAnonymousSessionsInDatabase();
+
+ static::assertEmpty($db->count('SELECT COUNT(id) FROM sessions WHERE id_user IS NULL'));
+ static::assertSame(1, $db->count('SELECT COUNT(id) FROM sessions WHERE id_user IS NOT NULL'));
+
+ Session::deleteUserSessionsInDatabase($userId);
+
+ static::assertEmpty($db->count('SELECT COUNT(id) FROM sessions WHERE id = :id', ['id' => $sessionId]));
+ }
+
+ /** @throws \Exception */
+ public function testUseNewRedisDriver(): void
+ {
+ $params = [
+ 'scheme' => 'tcp',
+ 'port' => 6379,
+ ];
+
+ $redisHost = \getenv('REDIS_HOST', true);
+ $params['host'] = ($redisHost !== false) ? $redisHost : '127.0.0.1';
+
+ Session::useNewRedisDriver($params);
+ Session::start();
+
+ static::assertInstanceOf(\Rancoud\Session\Redis::class, Session::getDriver());
+ }
+
+ /** @throws \Exception */
+ public function testUseNewRedisEncryptionDriver(): void
+ {
+ $params = [
+ 'scheme' => 'tcp',
+ 'port' => 6379,
+ ];
+
+ $redisHost = \getenv('REDIS_HOST', true);
+ $params['host'] = ($redisHost !== false) ? $redisHost : '127.0.0.1';
+
+ Session::useNewRedisEncryptionDriver($params, 'randomKey');
+ Session::start();
+
+ static::assertInstanceOf(\Rancoud\Session\RedisEncryption::class, Session::getDriver());
+ }
+
+ /** @throws \Exception */
+ public function testUseCurrentRedisDriver(): void
+ {
+ $params = [
+ 'scheme' => 'tcp',
+ 'port' => 6379,
+ ];
+
+ $redisHost = \getenv('REDIS_HOST', true);
+ $params['host'] = ($redisHost !== false) ? $redisHost : '127.0.0.1';
+
+ $redis = new \Predis\Client($params);
+ Session::useCurrentRedisDriver($redis);
+ Session::start();
+
+ static::assertInstanceOf(\Rancoud\Session\Redis::class, Session::getDriver());
+ }
+
+ /** @throws \Exception */
+ public function testUseCurrentRedisEncryptionDriver(): void
+ {
+ $params = [
+ 'scheme' => 'tcp',
+ 'port' => 6379,
+ ];
+
+ $redisHost = \getenv('REDIS_HOST', true);
+ $params['host'] = ($redisHost !== false) ? $redisHost : '127.0.0.1';
+
+ $redis = new \Predis\Client($params);
+ Session::useCurrentRedisEncryptionDriver($redis, 'randomKey');
+ Session::start();
+
+ static::assertInstanceOf(\Rancoud\Session\RedisEncryption::class, Session::getDriver());
+ }
+
+ /** @throws \Exception */
+ public function testUseCustomDriver(): void
+ {
+ Session::useCustomDriver(new File());
+ Session::start();
+
+ static::assertInstanceOf(File::class, Session::getDriver());
+ }
+
+ /** @throws \Exception */
+ public function testUseEncryptionDriverThrowExceptionWhenMethodIncrorrect(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('Unknown method: incorrect');
+
+ Session::useFileEncryptionDriver('randomKey', 'incorrect');
+ }
+
+ /**
+ * @throws \Exception
+ * @throws SessionException
+ */
+ public function testSetOption(): void
+ {
+ $defaultOption = Session::getOption('name');
+ static::assertSame($defaultOption, \ini_get('session.name'));
+
+ Session::setOption('name', 'my_custom_name');
+ $customOption = Session::getOption('name');
+
+ static::assertSame('my_custom_name', $customOption);
+
+ Session::start(['name' => 'my_other_name']);
+
+ $customOption = Session::getOption('name');
+ static::assertSame('my_other_name', $customOption);
+ }
+
+ public function testSetOptionThrowException(): void
+ {
+ $this->expectException(SessionException::class);
+ $this->expectExceptionMessage('Incorrect option: azerty');
+
+ Session::getOption('azerty');
+ }
+
+ /** @throws \Exception */
+ public function testGetAll(): void
+ {
+ $sessionValues = Session::getAll();
+ static::assertEmpty($sessionValues);
+
+ Session::set('a', 'b');
+
+ $sessionValues = Session::getAll();
+ static::assertSame(['a' => 'b'], $sessionValues);
+ }
+
+ /** @throws \Exception */
+ public function testFlash(): void
+ {
+ $flaKey1 = 'a';
+ $flaValue1 = 'b';
+
+ $flaKey2 = 'y';
+ $flaValue2 = 'u';
+
+ $flaKey3 = 'my_key';
+ $flaValue3 = null;
+
+ $flaKey4 = '10';
+ $flaValue4 = 55;
+
+ Session::setFlash($flaKey1, $flaValue1);
+ Session::setFlash($flaKey2, $flaValue2);
+
+ static::assertTrue(Session::hasFlash($flaKey1));
+ static::assertSame($flaValue1, Session::getFlash($flaKey1));
+ static::assertSame([$flaKey1 => $flaValue1, $flaKey2 => $flaValue2], Session::getAllFlash());
+
+ Session::start(['lazy_write' => '0']);
+
+ Session::keepFlash([$flaKey2]);
+ static::assertSame(['flash_data' => [$flaKey2 => $flaValue2]], $_SESSION);
+
+ $sessionId = Session::getId();
+ Session::commit();
+
+ static::assertSame([], Session::getAllFlash());
+
+ Session::setId($sessionId);
+ Session::setReadWrite();
+ Session::start();
+
+ static::assertEmpty($_SESSION);
+ static::assertTrue(Session::hasFlash($flaKey2));
+ static::assertSame($flaValue2, Session::getFlash($flaKey2));
+ static::assertTrue(Session::hasFlashKeyAndValue($flaKey2, $flaValue2));
+
+ Session::setFlash($flaKey3, $flaValue3);
+ Session::setFlash($flaKey4, $flaValue4);
+
+ Session::keepFlash();
+
+ Session::commit();
+
+ static::assertSame([], Session::getAllFlash());
+
+ Session::start();
+
+ $expectedFlashValues = [$flaKey2 => $flaValue2, $flaKey3 => $flaValue3, $flaKey4 => $flaValue4];
+ static::assertSame($expectedFlashValues, Session::getAllFlash());
+ static::assertEmpty($_SESSION);
+
+ Session::removeFlash($flaKey2);
+ Session::removeFlash($flaKey3);
+ static::assertSame([$flaKey4 => $flaValue4], Session::getAllFlash());
+ }
+
+ /** @throws \Exception */
+ public function testRollback(): void
+ {
+ Session::set('a', 'b');
+ Session::commit();
+
+ static::assertTrue(Session::has('a'));
+ Session::set('azerty', 'b');
+ static::assertTrue(Session::has('azerty'));
+ Session::rollback();
+ static::assertFalse(Session::has('azerty'));
+ }
+
+ /** @throws \Exception */
+ public function testUnsaved(): void
+ {
+ Session::set('a', 'b');
+ Session::commit();
+
+ static::assertTrue(Session::has('a'));
+ Session::set('azerty', 'b');
+ static::assertTrue(Session::has('azerty'));
+ Session::unsaved();
+ Session::start();
+ static::assertSame(['a' => 'b'], $_SESSION);
+ }
+
+ /** @throws \Exception */
+ public function testRegenerate(): void
+ {
+ Session::set('a', 'v');
+ $sessionId = Session::getId();
+ $success = Session::regenerate();
+ static::assertTrue($success);
+ static::assertNotSame($sessionId, Session::getId());
+ }
+
+ /** @throws \Exception */
+ public function testDestroy(): void
+ {
+ Session::set('a', 'v');
+ $sessionId = Session::getId();
+ $success = Session::destroy();
+ static::assertTrue($success);
+ static::assertNotSame($sessionId, Session::getId());
+ static::assertEmpty($_SESSION);
+ }
+
+ /** @throws \Exception */
+ public function testSetReadOnly(): void
+ {
+ Session::setReadOnly();
+ Session::start();
+ static::assertFalse(Session::hasStarted());
+ }
+
+ /**
+ * @throws \Exception
+ * @throws \Rancoud\Database\DatabaseException
+ */
+ public function testGc(): void
+ {
+ $conf = new \Rancoud\Database\Configurator([
+ 'driver' => 'mysql',
+ 'host' => 'mysql',
+ 'user' => 'root',
+ 'password' => '',
+ 'database' => 'test_database'
+ ]);
+
+ $mysqlHost = \getenv('MYSQL_HOST', true);
+ $conf->setHost(($mysqlHost !== false) ? $mysqlHost : '127.0.0.1');
+
+ $db = new \Rancoud\Database\Database($conf);
+ $db->truncateTables('sessions');
+
+ Session::useCurrentDatabaseDriver($db);
+ Session::setReadWrite();
+ Session::setOption('lazy_write', '0');
+ $baseId = 'siqKrZDUGp5ubt3klF0oorIlFiADXC9jxig9e8leUcCYuZ9w0mXh0b1foEGIBs7SSsdOuLor58vU5liBRVPsTobnvt';
+ $endId1 = 'Qj8hh65DlR3tTFI1SGX3mFciDA9rMOa4LlnMr';
+ $endId2 = 'jklezfoipvfk0lferijkoefzjklgrvefLlnMr';
+ Session::setId($baseId . $endId1);
+ Session::set('a', 'b');
+ Session::commit();
+
+ Session::setId($baseId . $endId2);
+ Session::set('b', 'a');
+ $sessionId = Session::getId();
+ Session::commit();
+
+ \sleep(1);
+
+ $sql = 'UPDATE sessions SET last_access = DATE_ADD(NOW(), INTERVAL 50000 SECOND) WHERE id = :id';
+ $params = ['id' => $sessionId];
+ $db->update($sql, $params);
+
+ Session::setOption('gc_maxlifetime', '1');
+
+ \sleep(1);
+
+ Session::gc();
+
+ $count = $db->count('SELECT COUNT(*) FROM sessions');
+ static::assertSame(1, $count);
+ }
+}