更新vendor

This commit is contained in:
mkm 2024-06-22 18:21:05 +08:00
parent 2a02ac8213
commit 40aff5aeb3
267 changed files with 4544 additions and 5351 deletions

1375
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -9,8 +9,8 @@ return array(
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php',
'9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',

View File

@ -10,8 +10,8 @@ class ComposerStaticInitcefecbcff919f3c1c8084830bbb72adc
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'662a729f963d39afe703c9d9b7ab4a8c' => __DIR__ . '/..' . '/symfony/polyfill-php83/bootstrap.php',
'9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',

File diff suppressed because it is too large Load Diff

View File

@ -74,9 +74,9 @@
'dev_requirement' => false,
),
'ezyang/htmlpurifier' => array(
'pretty_version' => 'v4.17.0',
'version' => '4.17.0.0',
'reference' => 'bbc513d79acf6691fa9cf10f192c90dd2957f18c',
'pretty_version' => 'v4.16.0',
'version' => '4.16.0.0',
'reference' => '523407fb06eb9e5f3d59889b3978d5bfe94299c8',
'type' => 'library',
'install_path' => __DIR__ . '/../ezyang/htmlpurifier',
'aliases' => array(),
@ -155,36 +155,36 @@
'dev_requirement' => false,
),
'hyperf/context' => array(
'pretty_version' => 'v3.1.15',
'version' => '3.1.15.0',
'reference' => 'ad913fd50eb5f738c038e172c120bc6956c0da69',
'pretty_version' => 'v3.1.27',
'version' => '3.1.27.0',
'reference' => 'e7d169e587eac3692e523aed26d1896fd6a548fe',
'type' => 'library',
'install_path' => __DIR__ . '/../hyperf/context',
'aliases' => array(),
'dev_requirement' => false,
),
'hyperf/contract' => array(
'pretty_version' => 'v3.1.15',
'version' => '3.1.15.0',
'reference' => '9950abe963cc6b30c6d3506fa5b3adbd58cb1945',
'pretty_version' => 'v3.1.27',
'version' => '3.1.27.0',
'reference' => 'f6465a1d9b9f9ac5a48fa5d250c45d00a874cc19',
'type' => 'library',
'install_path' => __DIR__ . '/../hyperf/contract',
'aliases' => array(),
'dev_requirement' => false,
),
'hyperf/engine' => array(
'pretty_version' => 'v2.11.0',
'version' => '2.11.0.0',
'reference' => '26e0b65fc2a63a00266e7124e221c6f3fb2c8e95',
'pretty_version' => 'v2.10.5',
'version' => '2.10.5.0',
'reference' => 'b3e1a025e388815612815a0b08fc4f2439140676',
'type' => 'library',
'install_path' => __DIR__ . '/../hyperf/engine',
'aliases' => array(),
'dev_requirement' => false,
),
'hyperf/engine-contract' => array(
'pretty_version' => 'v1.10.1',
'version' => '1.10.1.0',
'reference' => '2714a8ba6d6b916e5bd373ff680df9569a4c9eef',
'pretty_version' => 'v1.9.1',
'version' => '1.9.1.0',
'reference' => 'fec2e45f35404b2e5b4c3eaf1b0dce67d60771eb',
'type' => 'library',
'install_path' => __DIR__ . '/../hyperf/engine-contract',
'aliases' => array(),
@ -200,17 +200,17 @@
'dev_requirement' => false,
),
'illuminate/collections' => array(
'pretty_version' => 'v10.48.10',
'version' => '10.48.10.0',
'reference' => 'f9589f1063a449111dcaa1d68285b507d9483a95',
'pretty_version' => 'v10.48.13',
'version' => '10.48.13.0',
'reference' => '994cedcd2060b65918efe46da805ac31b0563034',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/collections',
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/conditionable' => array(
'pretty_version' => 'v10.48.10',
'version' => '10.48.10.0',
'pretty_version' => 'v10.48.13',
'version' => '10.48.13.0',
'reference' => 'd0958e4741fc9d6f516a552060fd1b829a85e009',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/conditionable',
@ -218,8 +218,8 @@
'dev_requirement' => false,
),
'illuminate/contracts' => array(
'pretty_version' => 'v10.48.10',
'version' => '10.48.10.0',
'pretty_version' => 'v10.48.14',
'version' => '10.48.14.0',
'reference' => '8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/contracts',
@ -227,8 +227,8 @@
'dev_requirement' => false,
),
'illuminate/macroable' => array(
'pretty_version' => 'v10.48.10',
'version' => '10.48.10.0',
'pretty_version' => 'v10.48.14',
'version' => '10.48.14.0',
'reference' => 'dff667a46ac37b634dcf68909d9d41e94dc97c27',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/macroable',
@ -236,8 +236,8 @@
'dev_requirement' => false,
),
'illuminate/redis' => array(
'pretty_version' => 'v10.48.10',
'version' => '10.48.10.0',
'pretty_version' => 'v10.48.13',
'version' => '10.48.13.0',
'reference' => '8a438aa70f4bf48973dfe8de9af3ad91cc5361a7',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/redis',
@ -245,9 +245,9 @@
'dev_requirement' => false,
),
'illuminate/support' => array(
'pretty_version' => 'v10.48.10',
'version' => '10.48.10.0',
'reference' => 'ee3a1aaed36d916654ce0ae09dfbd38644a4f582',
'pretty_version' => 'v10.48.13',
'version' => '10.48.13.0',
'reference' => '263f389d81488c237846b69469f91387ca2729f3',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/support',
'aliases' => array(),
@ -263,9 +263,9 @@
'dev_requirement' => false,
),
'intervention/image' => array(
'pretty_version' => '3.6.4',
'version' => '3.6.4.0',
'reference' => '193324ec88bc5ad4039e57ce9b926ae28dfde813',
'pretty_version' => '3.6.5',
'version' => '3.6.5.0',
'reference' => 'd428433aa74836ab75e8d4a5241628bebb7f4077',
'type' => 'library',
'install_path' => __DIR__ . '/../intervention/image',
'aliases' => array(),
@ -332,9 +332,9 @@
),
),
'nesbot/carbon' => array(
'pretty_version' => '2.72.3',
'version' => '2.72.3.0',
'reference' => '0c6fd108360c562f6e4fd1dedb8233b423e91c83',
'pretty_version' => '2.72.4',
'version' => '2.72.4.0',
'reference' => '117671bd1a44c819b941dcd152bd0268466464e0',
'type' => 'library',
'install_path' => __DIR__ . '/../nesbot/carbon',
'aliases' => array(),
@ -386,9 +386,9 @@
'dev_requirement' => false,
),
'overtrue/socialite' => array(
'pretty_version' => '4.10.1',
'version' => '4.10.1.0',
'reference' => '457b48f31414dc00d3fb445d6ab9355595067afe',
'pretty_version' => '4.11.0',
'version' => '4.11.0.0',
'reference' => '4929bbb9241818783c5954151ebbbef36d4953f4',
'type' => 'library',
'install_path' => __DIR__ . '/../overtrue/socialite',
'aliases' => array(),
@ -606,9 +606,9 @@
),
),
'qcloud/cos-sdk-v5' => array(
'pretty_version' => 'v2.6.9',
'version' => '2.6.9.0',
'reference' => '85e11f94ff4e13f3f866c4720902e991221b8baa',
'pretty_version' => 'v2.6.10',
'version' => '2.6.10.0',
'reference' => 'ab37936e870459d662281e5a3e9756ce97f8a4d3',
'type' => 'library',
'install_path' => __DIR__ . '/../qcloud/cos-sdk-v5',
'aliases' => array(),
@ -633,18 +633,18 @@
'dev_requirement' => false,
),
'symfony/cache' => array(
'pretty_version' => 'v6.4.7',
'version' => '6.4.7.0',
'reference' => 'b9e9b93c9817ec6c789c7943f5e54b57a041c16a',
'pretty_version' => 'v6.4.8',
'version' => '6.4.8.0',
'reference' => '287142df5579ce223c485b3872df3efae8390984',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/cache',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/cache-contracts' => array(
'pretty_version' => 'v3.5.0',
'version' => '3.5.0.0',
'reference' => 'df6a1a44c890faded49a5fca33c2d5c5fd3c2197',
'pretty_version' => 'v3.4.0',
'version' => '3.4.0.0',
'reference' => '1d74b127da04ffa87aa940abe15446fa89653778',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/cache-contracts',
'aliases' => array(),
@ -657,36 +657,36 @@
),
),
'symfony/console' => array(
'pretty_version' => 'v6.4.7',
'version' => '6.4.7.0',
'reference' => 'a170e64ae10d00ba89e2acbb590dc2e54da8ad8f',
'pretty_version' => 'v6.4.8',
'version' => '6.4.8.0',
'reference' => 'be5854cee0e8c7b110f00d695d11debdfa1a2a91',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/deprecation-contracts' => array(
'pretty_version' => 'v3.5.0',
'version' => '3.5.0.0',
'reference' => '0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1',
'pretty_version' => 'v3.3.0',
'version' => '3.3.0.0',
'reference' => '7c3aff79d10325257a001fcf92d991f24fc967cf',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/http-client' => array(
'pretty_version' => 'v6.4.7',
'version' => '6.4.7.0',
'reference' => '3683d8107cf1efdd24795cc5f7482be1eded34ac',
'pretty_version' => 'v6.4.5',
'version' => '6.4.5.0',
'reference' => 'f3c86a60a3615f466333a11fd42010d4382a82c7',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-client',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/http-client-contracts' => array(
'pretty_version' => 'v3.5.0',
'version' => '3.5.0.0',
'reference' => '20414d96f391677bf80078aa55baece78b82647d',
'pretty_version' => 'v3.4.0',
'version' => '3.4.0.0',
'reference' => '1ee70e699b41909c209a0c930f11034b93578654',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-client-contracts',
'aliases' => array(),
@ -699,18 +699,18 @@
),
),
'symfony/http-foundation' => array(
'pretty_version' => 'v6.4.7',
'version' => '6.4.7.0',
'reference' => 'b4db6b833035477cb70e18d0ae33cb7c2b521759',
'pretty_version' => 'v6.4.8',
'version' => '6.4.8.0',
'reference' => '27de8cc95e11db7a50b027e71caaab9024545947',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-foundation',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/mime' => array(
'pretty_version' => 'v6.4.7',
'version' => '6.4.7.0',
'reference' => 'decadcf3865918ecfcbfa90968553994ce935a5e',
'pretty_version' => 'v6.4.8',
'version' => '6.4.8.0',
'reference' => '618597ab8b78ac86d1c75a9d0b35540cda074f33',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/mime',
'aliases' => array(),
@ -726,18 +726,18 @@
'dev_requirement' => false,
),
'symfony/polyfill-intl-grapheme' => array(
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'reference' => '32a9da87d7b3245e09ac426c83d334ae9f06f80f',
'pretty_version' => 'v1.30.0',
'version' => '1.30.0.0',
'reference' => '64647a7c30b2283f5d49b874d84a18fc22054b7a',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-idn' => array(
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'reference' => 'a287ed7475f85bf6f61890146edbc932c0fff919',
'pretty_version' => 'v1.30.0',
'version' => '1.30.0.0',
'reference' => 'a6e83bdeb3c84391d1dfe16f42e40727ce524a5c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',
'aliases' => array(),
@ -780,63 +780,63 @@
'dev_requirement' => false,
),
'symfony/polyfill-php81' => array(
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'reference' => 'c565ad1e63f30e7477fc40738343c62b40bc672d',
'pretty_version' => 'v1.30.0',
'version' => '1.30.0.0',
'reference' => '3fb075789fb91f9ad9af537c4012d523085bd5af',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php81',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php83' => array(
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'reference' => '86fcae159633351e5fd145d1c47de6c528f8caff',
'pretty_version' => 'v1.30.0',
'version' => '1.30.0.0',
'reference' => 'dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php83',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/psr-http-message-bridge' => array(
'pretty_version' => 'v6.4.7',
'version' => '6.4.7.0',
'reference' => 'e8adf6b1b46d9115f5d9247fa74bbefc459680c0',
'pretty_version' => 'v2.3.1',
'version' => '2.3.1.0',
'reference' => '581ca6067eb62640de5ff08ee1ba6850a0ee472e',
'type' => 'symfony-bridge',
'install_path' => __DIR__ . '/../symfony/psr-http-message-bridge',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/service-contracts' => array(
'pretty_version' => 'v3.5.0',
'version' => '3.5.0.0',
'reference' => 'bd1d9e59a81d8fa4acdcea3f617c581f7475a80f',
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'reference' => '4b426aac47d6427cc1a1d0f7e2ac724627f5966c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/service-contracts',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/string' => array(
'pretty_version' => 'v6.4.7',
'version' => '6.4.7.0',
'reference' => 'ffeb9591c61f65a68d47f77d12b83fa530227a69',
'pretty_version' => 'v6.4.8',
'version' => '6.4.8.0',
'reference' => 'a147c0f826c4a1f3afb763ab8e009e37c877a44d',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/string',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/translation' => array(
'pretty_version' => 'v6.4.7',
'version' => '6.4.7.0',
'reference' => '7495687c58bfd88b7883823747b0656d90679123',
'pretty_version' => 'v6.4.8',
'version' => '6.4.8.0',
'reference' => 'a002933b13989fc4bd0b58e04bf7eec5210e438a',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/translation-contracts' => array(
'pretty_version' => 'v3.5.0',
'version' => '3.5.0.0',
'reference' => 'b9d2189887bb6b2e0367a9fc7136c5239ab9b05a',
'pretty_version' => 'v3.4.1',
'version' => '3.4.1.0',
'reference' => '06450585bf65e978026bda220cdebca3f867fde7',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation-contracts',
'aliases' => array(),
@ -849,18 +849,18 @@
),
),
'symfony/var-dumper' => array(
'pretty_version' => 'v6.4.7',
'version' => '6.4.7.0',
'reference' => '7a9cd977cd1c5fed3694bee52990866432af07d7',
'pretty_version' => 'v6.4.8',
'version' => '6.4.8.0',
'reference' => 'ad23ca4312395f0a8a8633c831ef4c4ee542ed25',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-dumper',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/var-exporter' => array(
'pretty_version' => 'v6.4.7',
'version' => '6.4.7.0',
'reference' => '825f9b00c37bbe1c1691cc1aff9b5451fc9b4405',
'pretty_version' => 'v6.4.8',
'version' => '6.4.8.0',
'reference' => '792ca836f99b340f2e9ca9497c7953948c49a504',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-exporter',
'aliases' => array(),
@ -930,9 +930,9 @@
'dev_requirement' => false,
),
'vlucas/phpdotenv' => array(
'pretty_version' => 'v5.6.0',
'version' => '5.6.0.0',
'reference' => '2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4',
'pretty_version' => 'v5.5.0',
'version' => '5.5.0.0',
'reference' => '1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7',
'type' => 'library',
'install_path' => __DIR__ . '/../vlucas/phpdotenv',
'aliases' => array(),
@ -948,18 +948,18 @@
'dev_requirement' => false,
),
'w7corp/easywechat' => array(
'pretty_version' => '6.15.1',
'version' => '6.15.1.0',
'reference' => '8902917ceeaa20354301e533ff3725f0044c04ca',
'pretty_version' => '6.8.0',
'version' => '6.8.0.0',
'reference' => '60f0b4ba2ac3144df1a2291193daa34beb949d26',
'type' => 'library',
'install_path' => __DIR__ . '/../w7corp/easywechat',
'aliases' => array(),
'dev_requirement' => false,
),
'webman/console' => array(
'pretty_version' => 'v1.3.8',
'version' => '1.3.8.0',
'reference' => '9e866344882601cbdefe76b44e6b61532c7fb98e',
'pretty_version' => 'v1.3.4',
'version' => '1.3.4.0',
'reference' => 'ee50a1eca292eea5bf70661aa2ef722e1294814c',
'type' => 'library',
'install_path' => __DIR__ . '/../webman/console',
'aliases' => array(),
@ -975,18 +975,18 @@
'dev_requirement' => false,
),
'webman/push' => array(
'pretty_version' => 'v1.0.17',
'version' => '1.0.17.0',
'reference' => 'f87a588e6775a613a8cd2339bf90b76fdde626da',
'pretty_version' => 'v1.0.18',
'version' => '1.0.18.0',
'reference' => 'bad36cef656e6e6b7998b44fd09b6b794f0469e7',
'type' => 'library',
'install_path' => __DIR__ . '/../webman/push',
'aliases' => array(),
'dev_requirement' => false,
),
'webman/redis-queue' => array(
'pretty_version' => 'v1.3.2',
'version' => '1.3.2.0',
'reference' => '80b9ddca0405bbb6d02e6b368e8036b3b1a13814',
'pretty_version' => 'v1.3.1',
'version' => '1.3.1.0',
'reference' => '6fd491b19acb006d60931724aa2577a046ccb612',
'type' => 'library',
'install_path' => __DIR__ . '/../webman/redis-queue',
'aliases' => array(),
@ -1065,9 +1065,9 @@
'dev_requirement' => false,
),
'yansongda/artful' => array(
'pretty_version' => 'v1.1.0',
'version' => '1.1.0.0',
'reference' => '9e852f589728b4908c3ae0f0dd0a5bd11cd42a3f',
'pretty_version' => 'v1.1.1',
'version' => '1.1.1.0',
'reference' => '4118bce8a6cd506580dd36957c833ce222d0dc2e',
'type' => 'library',
'install_path' => __DIR__ . '/../yansongda/artful',
'aliases' => array(),
@ -1083,9 +1083,9 @@
'dev_requirement' => false,
),
'yansongda/supports' => array(
'pretty_version' => 'v4.0.9',
'version' => '4.0.9.0',
'reference' => 'c3479723be665360a5635c15f184a1d0a8dc995a',
'pretty_version' => 'v4.0.10',
'version' => '4.0.10.0',
'reference' => '11cc73776e6d4d763a84c8c733f64820abdc44e5',
'type' => 'library',
'install_path' => __DIR__ . '/../yansongda/supports',
'aliases' => array(),

View File

@ -0,0 +1,6 @@
# [4.16.0](https://github.com/ezyang/htmlpurifier/compare/v4.15.0...v4.16.0) (2022-09-18)
### Features
* add semantic release ([#307](https://github.com/ezyang/htmlpurifier/issues/307)) ([db31243](https://github.com/ezyang/htmlpurifier/commit/db312435cb9d8d73395f75f9642a43ba6de5e903)), closes [#322](https://github.com/ezyang/htmlpurifier/issues/322) [#323](https://github.com/ezyang/htmlpurifier/issues/323) [#326](https://github.com/ezyang/htmlpurifier/issues/326) [#327](https://github.com/ezyang/htmlpurifier/issues/327) [#328](https://github.com/ezyang/htmlpurifier/issues/328) [#329](https://github.com/ezyang/htmlpurifier/issues/329) [#330](https://github.com/ezyang/htmlpurifier/issues/330) [#331](https://github.com/ezyang/htmlpurifier/issues/331) [#332](https://github.com/ezyang/htmlpurifier/issues/332) [#333](https://github.com/ezyang/htmlpurifier/issues/333) [#337](https://github.com/ezyang/htmlpurifier/issues/337) [#335](https://github.com/ezyang/htmlpurifier/issues/335) [ezyang/htmlpurifier#334](https://github.com/ezyang/htmlpurifier/issues/334) [#336](https://github.com/ezyang/htmlpurifier/issues/336) [#338](https://github.com/ezyang/htmlpurifier/issues/338)

View File

@ -1 +1 @@
4.17.0
4.15.0

View File

@ -13,7 +13,7 @@
}
],
"require": {
"php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0"
"php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0"
},
"require-dev": {
"cerdic/css-tidy": "^1.7 || ^2.0",
@ -38,8 +38,7 @@
"repositories": [
{
"type": "vcs",
"url": "https://github.com/ezyang/simpletest.git",
"no-api": true
"url": "https://github.com/ezyang/simpletest.git"
}
]
}

View File

@ -7,7 +7,7 @@
* primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS
* FILE, changes will be overwritten the next time the script is run.
*
* @version 4.17.0
* @version 4.15.0
*
* @warning
* You must *not* include any other HTML Purifier files before this file,

View File

@ -19,7 +19,7 @@
*/
/*
HTML Purifier 4.17.0 - Standards Compliant HTML Filtering
HTML Purifier 4.15.0 - Standards Compliant HTML Filtering
Copyright (C) 2006-2008 Edward Z. Yang
This library is free software; you can redistribute it and/or
@ -58,12 +58,12 @@ class HTMLPurifier
* Version of HTML Purifier.
* @type string
*/
public $version = '4.17.0';
public $version = '4.15.0';
/**
* Constant with version of HTML Purifier.
*/
const VERSION = '4.17.0';
const VERSION = '4.15.0';
/**
* Global configuration object.

View File

@ -10,21 +10,23 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
public function __construct()
{
// Lowercase letters
$l = range('a', 'z');
// Uppercase letters
$u = range('A', 'Z');
// Digits
$d = range('0', '9');
// Special bytes used by UTF-8
$b = array_map('chr', range(0x80, 0xFF));
// All valid characters for the mask
$c = array_merge($l, $u, $d, $b);
// Concatenate all valid characters into a string
// Use '_- ' as an initial value
$this->mask = array_reduce($c, function ($carry, $value) {
return $carry . $value;
}, '_- ');
$this->mask = '_- ';
for ($c = 'a'; $c <= 'z'; $c++) {
$this->mask .= $c;
}
for ($c = 'A'; $c <= 'Z'; $c++) {
$this->mask .= $c;
}
for ($c = '0'; $c <= '9'; $c++) {
$this->mask .= $c;
} // cast-y, but should be fine
// special bytes used by UTF-8
for ($i = 0x80; $i <= 0xFF; $i++) {
// We don't bother excluding invalid bytes in this range,
// because the our restriction of well-formed UTF-8 will
// prevent these from ever occurring.
$this->mask .= chr($i);
}
/*
PHP's internal strcspn implementation is

View File

@ -106,7 +106,7 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
// If we have Net_IDNA2 support, we can support IRIs by
// punycoding them. (This is the most portable thing to do,
// since otherwise we have to assume browsers support
} elseif ($config->get('Core.EnableIDNA') && class_exists('Net_IDNA2')) {
} elseif ($config->get('Core.EnableIDNA')) {
$idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true));
// we need to encode each period separately
$parts = explode('.', $string);

View File

@ -33,11 +33,7 @@ class HTMLPurifier_AttrTransform_TargetBlank extends HTMLPurifier_AttrTransform
// XXX Kind of inefficient
$url = $this->parser->parse($attr['href']);
// Ignore invalid schemes (e.g. `javascript:`)
if (!($scheme = $url->getSchemeObj($config, $context))) {
return $attr;
}
$scheme = $url->getSchemeObj($config, $context);
if ($scheme->browsable && !$url->isBenign($config, $context)) {
$attr['target'] = '_blank';

View File

@ -79,11 +79,44 @@ class HTMLPurifier_Bootstrap
public static function registerAutoload()
{
$autoload = array('HTMLPurifier_Bootstrap', 'autoload');
if (spl_autoload_functions() === false) {
if (($funcs = spl_autoload_functions()) === false) {
spl_autoload_register($autoload);
} else {
// prepend flag exists, no need for shenanigans
spl_autoload_register($autoload, true, true);
} elseif (function_exists('spl_autoload_unregister')) {
if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
// prepend flag exists, no need for shenanigans
spl_autoload_register($autoload, true, true);
} else {
$buggy = version_compare(PHP_VERSION, '5.2.11', '<');
$compat = version_compare(PHP_VERSION, '5.1.2', '<=') &&
version_compare(PHP_VERSION, '5.1.0', '>=');
foreach ($funcs as $func) {
if ($buggy && is_array($func)) {
// :TRICKY: There are some compatibility issues and some
// places where we need to error out
$reflector = new ReflectionMethod($func[0], $func[1]);
if (!$reflector->isStatic()) {
throw new Exception(
'HTML Purifier autoloader registrar is not compatible
with non-static object methods due to PHP Bug #44144;
Please do not use HTMLPurifier.autoload.php (or any
file that includes this file); instead, place the code:
spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\'))
after your own autoloaders.'
);
}
// Suprisingly, spl_autoload_register supports the
// Class::staticMethod callback format, although call_user_func doesn't
if ($compat) {
$func = implode('::', $func);
}
}
spl_autoload_unregister($func);
}
spl_autoload_register($autoload);
foreach ($funcs as $func) {
spl_autoload_register($func);
}
}
}
}
}

View File

@ -13,7 +13,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
* Assoc array of attribute name to definition object.
* @type HTMLPurifier_AttrDef[]
*/
public $info = [];
public $info = array();
/**
* Constructs the info array. The meat of this class.
@ -22,7 +22,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
protected function doSetup($config)
{
$this->info['text-align'] = new HTMLPurifier_AttrDef_Enum(
['left', 'right', 'center', 'justify'],
array('left', 'right', 'center', 'justify'),
false
);
@ -31,7 +31,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['border-right-style'] =
$this->info['border-left-style'] =
$this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum(
[
array(
'none',
'hidden',
'dotted',
@ -42,42 +42,42 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
'ridge',
'inset',
'outset'
],
),
false
);
$this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style);
$this->info['clear'] = new HTMLPurifier_AttrDef_Enum(
['none', 'left', 'right', 'both'],
array('none', 'left', 'right', 'both'),
false
);
$this->info['float'] = new HTMLPurifier_AttrDef_Enum(
['none', 'left', 'right'],
array('none', 'left', 'right'),
false
);
$this->info['font-style'] = new HTMLPurifier_AttrDef_Enum(
['normal', 'italic', 'oblique'],
array('normal', 'italic', 'oblique'),
false
);
$this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum(
['normal', 'small-caps'],
array('normal', 'small-caps'),
false
);
$uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite(
[
new HTMLPurifier_AttrDef_Enum(['none']),
array(
new HTMLPurifier_AttrDef_Enum(array('none')),
new HTMLPurifier_AttrDef_CSS_URI()
]
)
);
$this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum(
['inside', 'outside'],
array('inside', 'outside'),
false
);
$this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum(
[
array(
'disc',
'circle',
'square',
@ -87,7 +87,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
'lower-alpha',
'upper-alpha',
'none'
],
),
false
);
$this->info['list-style-image'] = $uri_or_none;
@ -95,34 +95,34 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config);
$this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum(
['capitalize', 'uppercase', 'lowercase', 'none'],
array('capitalize', 'uppercase', 'lowercase', 'none'),
false
);
$this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['background-image'] = $uri_or_none;
$this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum(
['repeat', 'repeat-x', 'repeat-y', 'no-repeat']
array('repeat', 'repeat-x', 'repeat-y', 'no-repeat')
);
$this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum(
['scroll', 'fixed']
array('scroll', 'fixed')
);
$this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition();
$this->info['background-size'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_Enum(
[
array(
'auto',
'cover',
'contain',
'initial',
'inherit',
]
)
),
new HTMLPurifier_AttrDef_CSS_Percentage(),
new HTMLPurifier_AttrDef_CSS_Length()
]
)
);
$border_color =
@ -131,10 +131,10 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['border-left-color'] =
$this->info['border-right-color'] =
$this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
new HTMLPurifier_AttrDef_Enum(['transparent']),
array(
new HTMLPurifier_AttrDef_Enum(array('transparent')),
new HTMLPurifier_AttrDef_CSS_Color()
]
)
);
$this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config);
@ -146,32 +146,32 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['border-bottom-width'] =
$this->info['border-left-width'] =
$this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
new HTMLPurifier_AttrDef_Enum(['thin', 'medium', 'thick']),
array(
new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')),
new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative
]
)
);
$this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width);
$this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
new HTMLPurifier_AttrDef_Enum(['normal']),
array(
new HTMLPurifier_AttrDef_Enum(array('normal')),
new HTMLPurifier_AttrDef_CSS_Length()
]
)
);
$this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
new HTMLPurifier_AttrDef_Enum(['normal']),
array(
new HTMLPurifier_AttrDef_Enum(array('normal')),
new HTMLPurifier_AttrDef_CSS_Length()
]
)
);
$this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_Enum(
[
array(
'xx-small',
'x-small',
'small',
@ -181,20 +181,20 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
'xx-large',
'larger',
'smaller'
]
)
),
new HTMLPurifier_AttrDef_CSS_Percentage(),
new HTMLPurifier_AttrDef_CSS_Length()
]
)
);
$this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
new HTMLPurifier_AttrDef_Enum(['normal']),
array(
new HTMLPurifier_AttrDef_Enum(array('normal')),
new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives
new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_CSS_Percentage(true)
]
)
);
$margin =
@ -202,11 +202,11 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['margin-bottom'] =
$this->info['margin-left'] =
$this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_CSS_Length(),
new HTMLPurifier_AttrDef_CSS_Percentage(),
new HTMLPurifier_AttrDef_Enum(['auto'])
]
new HTMLPurifier_AttrDef_Enum(array('auto'))
)
);
$this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin);
@ -217,41 +217,41 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['padding-bottom'] =
$this->info['padding-left'] =
$this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_CSS_Percentage(true)
]
)
);
$this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding);
$this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_CSS_Length(),
new HTMLPurifier_AttrDef_CSS_Percentage()
]
)
);
$trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_CSS_Percentage(true),
new HTMLPurifier_AttrDef_Enum(['auto', 'initial', 'inherit'])
]
new HTMLPurifier_AttrDef_Enum(array('auto', 'initial', 'inherit'))
)
);
$trusted_min_wh = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_CSS_Percentage(true),
new HTMLPurifier_AttrDef_Enum(['initial', 'inherit'])
]
new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit'))
)
);
$trusted_max_wh = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_CSS_Length('0'),
new HTMLPurifier_AttrDef_CSS_Percentage(true),
new HTMLPurifier_AttrDef_Enum(['none', 'initial', 'inherit'])
]
new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit'))
)
);
$max = $config->get('CSS.MaxImgLength');
@ -263,10 +263,10 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
'img',
// For img tags:
new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_CSS_Length('0', $max),
new HTMLPurifier_AttrDef_Enum(['auto'])
]
new HTMLPurifier_AttrDef_Enum(array('auto'))
)
),
// For everyone else:
$trusted_wh
@ -279,10 +279,10 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
'img',
// For img tags:
new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_CSS_Length('0', $max),
new HTMLPurifier_AttrDef_Enum(['initial', 'inherit'])
]
new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit'))
)
),
// For everyone else:
$trusted_min_wh
@ -295,39 +295,22 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
'img',
// For img tags:
new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_CSS_Length('0', $max),
new HTMLPurifier_AttrDef_Enum(['none', 'initial', 'inherit'])
]
new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit'))
)
),
// For everyone else:
$trusted_max_wh
);
// text-decoration and related shorthands
$this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration();
$this->info['text-decoration-line'] = new HTMLPurifier_AttrDef_Enum(
['none', 'underline', 'overline', 'line-through', 'initial', 'inherit']
);
$this->info['text-decoration-style'] = new HTMLPurifier_AttrDef_Enum(
['solid', 'double', 'dotted', 'dashed', 'wavy', 'initial', 'inherit']
);
$this->info['text-decoration-color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['text-decoration-thickness'] = new HTMLPurifier_AttrDef_CSS_Composite([
new HTMLPurifier_AttrDef_CSS_Length(),
new HTMLPurifier_AttrDef_CSS_Percentage(),
new HTMLPurifier_AttrDef_Enum(['auto', 'from-font', 'initial', 'inherit'])
]);
$this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily();
// this could use specialized code
$this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum(
[
array(
'normal',
'bold',
'bolder',
@ -341,7 +324,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
'700',
'800',
'900'
],
),
false
);
@ -357,21 +340,21 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config);
$this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum(
['collapse', 'separate']
array('collapse', 'separate')
);
$this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum(
['top', 'bottom']
array('top', 'bottom')
);
$this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum(
['auto', 'fixed']
array('auto', 'fixed')
);
$this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_Enum(
[
array(
'baseline',
'sub',
'super',
@ -380,11 +363,11 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
'middle',
'bottom',
'text-bottom'
]
)
),
new HTMLPurifier_AttrDef_CSS_Length(),
new HTMLPurifier_AttrDef_CSS_Percentage()
]
)
);
$this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2);
@ -392,7 +375,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
// These CSS properties don't work on many browsers, but we live
// in THE FUTURE!
$this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(
['nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line']
array('nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line')
);
if ($config->get('CSS.Proprietary')) {
@ -439,21 +422,21 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
// more CSS3
$this->info['page-break-after'] =
$this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum(
[
array(
'auto',
'always',
'avoid',
'left',
'right'
]
)
);
$this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(['auto', 'avoid']);
$this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(array('auto', 'avoid'));
$border_radius = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_CSS_Percentage(true), // disallow negative
new HTMLPurifier_AttrDef_CSS_Length('0') // disallow negative
]);
));
$this->info['border-top-left-radius'] =
$this->info['border-top-right-radius'] =
@ -470,7 +453,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
protected function doSetupTricky($config)
{
$this->info['display'] = new HTMLPurifier_AttrDef_Enum(
[
array(
'inline',
'block',
'list-item',
@ -489,12 +472,12 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
'table-cell',
'table-caption',
'none'
]
)
);
$this->info['visibility'] = new HTMLPurifier_AttrDef_Enum(
['visible', 'hidden', 'collapse']
array('visible', 'hidden', 'collapse')
);
$this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(['visible', 'hidden', 'auto', 'scroll']);
$this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll'));
$this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
}
@ -504,23 +487,23 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
protected function doSetupTrusted($config)
{
$this->info['position'] = new HTMLPurifier_AttrDef_Enum(
['static', 'relative', 'absolute', 'fixed']
array('static', 'relative', 'absolute', 'fixed')
);
$this->info['top'] =
$this->info['left'] =
$this->info['right'] =
$this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_CSS_Length(),
new HTMLPurifier_AttrDef_CSS_Percentage(),
new HTMLPurifier_AttrDef_Enum(['auto']),
]
new HTMLPurifier_AttrDef_Enum(array('auto')),
)
);
$this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite(
[
array(
new HTMLPurifier_AttrDef_Integer(),
new HTMLPurifier_AttrDef_Enum(['auto']),
]
new HTMLPurifier_AttrDef_Enum(array('auto')),
)
);
}

View File

@ -21,7 +21,7 @@ class HTMLPurifier_Config
* HTML Purifier's version
* @type string
*/
public $version = '4.17.0';
public $version = '4.15.0';
/**
* Whether or not to automatically finalize

View File

@ -287,14 +287,13 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac
} elseif (filegroup($dir) === posix_getgid()) {
$chmod = $chmod | 0070;
} else {
// PHP's probably running as nobody, it is
// not obvious how to fix this (777 is probably
// bad if you are multi-user), let the user figure it out
$chmod = null;
// PHP's probably running as nobody, so we'll
// need to give global permissions
$chmod = $chmod | 0777;
}
trigger_error(
'Directory ' . $dir . ' not writable. ' .
($chmod === null ? '' : 'Please chmod to ' . decoct($chmod)),
'Directory ' . $dir . ' not writable, ' .
'please chmod to ' . decoct($chmod),
E_USER_WARNING
);
} else {

View File

@ -71,7 +71,7 @@ class HTMLPurifier_DefinitionCacheFactory
return $this->caches[$method][$type];
}
if (isset($this->implementations[$method]) &&
class_exists($class = $this->implementations[$method])) {
class_exists($class = $this->implementations[$method], false)) {
$cache = new $class($type);
} else {
if ($method != 'Serializer') {

View File

@ -146,179 +146,175 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
foreach ($this->_tidy->css as $k => $decls) {
// $decls are all CSS declarations inside an @ selector
$new_decls = array();
if (is_array($decls)) {
foreach ($decls as $selector => $style) {
$selector = trim($selector);
if ($selector === '') {
continue;
} // should not happen
// Parse the selector
// Here is the relevant part of the CSS grammar:
//
// ruleset
// : selector [ ',' S* selector ]* '{' ...
// selector
// : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]?
// combinator
// : '+' S*
// : '>' S*
// simple_selector
// : element_name [ HASH | class | attrib | pseudo ]*
// | [ HASH | class | attrib | pseudo ]+
// element_name
// : IDENT | '*'
// ;
// class
// : '.' IDENT
// ;
// attrib
// : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
// [ IDENT | STRING ] S* ]? ']'
// ;
// pseudo
// : ':' [ IDENT | FUNCTION S* [IDENT S*]? ')' ]
// ;
//
// For reference, here are the relevant tokens:
//
// HASH #{name}
// IDENT {ident}
// INCLUDES ==
// DASHMATCH |=
// STRING {string}
// FUNCTION {ident}\(
//
// And the lexical scanner tokens
//
// name {nmchar}+
// nmchar [_a-z0-9-]|{nonascii}|{escape}
// nonascii [\240-\377]
// escape {unicode}|\\[^\r\n\f0-9a-f]
// unicode \\{h}}{1,6}(\r\n|[ \t\r\n\f])?
// ident -?{nmstart}{nmchar*}
// nmstart [_a-z]|{nonascii}|{escape}
// string {string1}|{string2}
// string1 \"([^\n\r\f\\"]|\\{nl}|{escape})*\"
// string2 \'([^\n\r\f\\"]|\\{nl}|{escape})*\'
//
// We'll implement a subset (in order to reduce attack
// surface); in particular:
//
// - No Unicode support
// - No escapes support
// - No string support (by proxy no attrib support)
// - element_name is matched against allowed
// elements (some people might find this
// annoying...)
// - Pseudo-elements one of :first-child, :link,
// :visited, :active, :hover, :focus
foreach ($decls as $selector => $style) {
$selector = trim($selector);
if ($selector === '') {
continue;
} // should not happen
// Parse the selector
// Here is the relevant part of the CSS grammar:
//
// ruleset
// : selector [ ',' S* selector ]* '{' ...
// selector
// : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]?
// combinator
// : '+' S*
// : '>' S*
// simple_selector
// : element_name [ HASH | class | attrib | pseudo ]*
// | [ HASH | class | attrib | pseudo ]+
// element_name
// : IDENT | '*'
// ;
// class
// : '.' IDENT
// ;
// attrib
// : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
// [ IDENT | STRING ] S* ]? ']'
// ;
// pseudo
// : ':' [ IDENT | FUNCTION S* [IDENT S*]? ')' ]
// ;
//
// For reference, here are the relevant tokens:
//
// HASH #{name}
// IDENT {ident}
// INCLUDES ==
// DASHMATCH |=
// STRING {string}
// FUNCTION {ident}\(
//
// And the lexical scanner tokens
//
// name {nmchar}+
// nmchar [_a-z0-9-]|{nonascii}|{escape}
// nonascii [\240-\377]
// escape {unicode}|\\[^\r\n\f0-9a-f]
// unicode \\{h}}{1,6}(\r\n|[ \t\r\n\f])?
// ident -?{nmstart}{nmchar*}
// nmstart [_a-z]|{nonascii}|{escape}
// string {string1}|{string2}
// string1 \"([^\n\r\f\\"]|\\{nl}|{escape})*\"
// string2 \'([^\n\r\f\\"]|\\{nl}|{escape})*\'
//
// We'll implement a subset (in order to reduce attack
// surface); in particular:
//
// - No Unicode support
// - No escapes support
// - No string support (by proxy no attrib support)
// - element_name is matched against allowed
// elements (some people might find this
// annoying...)
// - Pseudo-elements one of :first-child, :link,
// :visited, :active, :hover, :focus
// handle ruleset
$selectors = array_map('trim', explode(',', $selector));
$new_selectors = array();
foreach ($selectors as $sel) {
// split on +, > and spaces
$basic_selectors = preg_split('/\s*([+> ])\s*/', $sel, -1, PREG_SPLIT_DELIM_CAPTURE);
// even indices are chunks, odd indices are
// delimiters
$nsel = null;
$delim = null; // guaranteed to be non-null after
// two loop iterations
for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) {
$x = $basic_selectors[$i];
if ($i % 2) {
// delimiter
if ($x === ' ') {
$delim = ' ';
} else {
$delim = ' ' . $x . ' ';
}
// handle ruleset
$selectors = array_map('trim', explode(',', $selector));
$new_selectors = array();
foreach ($selectors as $sel) {
// split on +, > and spaces
$basic_selectors = preg_split('/\s*([+> ])\s*/', $sel, -1, PREG_SPLIT_DELIM_CAPTURE);
// even indices are chunks, odd indices are
// delimiters
$nsel = null;
$delim = null; // guaranteed to be non-null after
// two loop iterations
for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) {
$x = $basic_selectors[$i];
if ($i % 2) {
// delimiter
if ($x === ' ') {
$delim = ' ';
} else {
// simple selector
$components = preg_split('/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE);
$sdelim = null;
$nx = null;
for ($j = 0, $cc = count($components); $j < $cc; $j++) {
$y = $components[$j];
if ($j === 0) {
if ($y === '*' || isset($html_definition->info[$y = strtolower($y)])) {
$nx = $y;
} else {
// $nx stays null; this matters
// if we don't manage to find
// any valid selector content,
// in which case we ignore the
// outer $delim
}
} elseif ($j % 2) {
// set delimiter
$sdelim = $y;
$delim = ' ' . $x . ' ';
}
} else {
// simple selector
$components = preg_split('/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE);
$sdelim = null;
$nx = null;
for ($j = 0, $cc = count($components); $j < $cc; $j++) {
$y = $components[$j];
if ($j === 0) {
if ($y === '*' || isset($html_definition->info[$y = strtolower($y)])) {
$nx = $y;
} else {
$attrdef = null;
if ($sdelim === '#') {
$attrdef = $this->_id_attrdef;
} elseif ($sdelim === '.') {
$attrdef = $this->_class_attrdef;
} elseif ($sdelim === ':') {
$attrdef = $this->_enum_attrdef;
} else {
throw new HTMLPurifier_Exception('broken invariant sdelim and preg_split');
}
$r = $attrdef->validate($y, $config, $context);
if ($r !== false) {
if ($r !== true) {
$y = $r;
}
if ($nx === null) {
$nx = '';
}
$nx .= $sdelim . $y;
}
}
}
if ($nx !== null) {
if ($nsel === null) {
$nsel = $nx;
} else {
$nsel .= $delim . $nx;
// $nx stays null; this matters
// if we don't manage to find
// any valid selector content,
// in which case we ignore the
// outer $delim
}
} elseif ($j % 2) {
// set delimiter
$sdelim = $y;
} else {
// delimiters to the left of invalid
// basic selector ignored
$attrdef = null;
if ($sdelim === '#') {
$attrdef = $this->_id_attrdef;
} elseif ($sdelim === '.') {
$attrdef = $this->_class_attrdef;
} elseif ($sdelim === ':') {
$attrdef = $this->_enum_attrdef;
} else {
throw new HTMLPurifier_Exception('broken invariant sdelim and preg_split');
}
$r = $attrdef->validate($y, $config, $context);
if ($r !== false) {
if ($r !== true) {
$y = $r;
}
if ($nx === null) {
$nx = '';
}
$nx .= $sdelim . $y;
}
}
}
}
if ($nsel !== null) {
if (!empty($scopes)) {
foreach ($scopes as $s) {
$new_selectors[] = "$s $nsel";
if ($nx !== null) {
if ($nsel === null) {
$nsel = $nx;
} else {
$nsel .= $delim . $nx;
}
} else {
$new_selectors[] = $nsel;
// delimiters to the left of invalid
// basic selector ignored
}
}
}
if (empty($new_selectors)) {
if ($nsel !== null) {
if (!empty($scopes)) {
foreach ($scopes as $s) {
$new_selectors[] = "$s $nsel";
}
} else {
$new_selectors[] = $nsel;
}
}
}
if (empty($new_selectors)) {
continue;
}
$selector = implode(', ', $new_selectors);
foreach ($style as $name => $value) {
if (!isset($css_definition->info[$name])) {
unset($style[$name]);
continue;
}
$selector = implode(', ', $new_selectors);
foreach ($style as $name => $value) {
if (!isset($css_definition->info[$name])) {
unset($style[$name]);
continue;
}
$def = $css_definition->info[$name];
$ret = $def->validate($value, $config, $context);
if ($ret === false) {
unset($style[$name]);
} else {
$style[$name] = $ret;
}
$def = $css_definition->info[$name];
$ret = $def->validate($value, $config, $context);
if ($ret === false) {
unset($style[$name]);
} else {
$style[$name] = $ret;
}
$new_decls[$selector] = $style;
}
} else {
continue;
$new_decls[$selector] = $style;
}
$new_css[$k] = $new_decls;
}

View File

@ -221,7 +221,6 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
*/
public function makeFixes()
{
return array();
}
}

View File

@ -109,7 +109,7 @@ class HTMLPurifier_LanguageFactory
} else {
$class = 'HTMLPurifier_Language_' . $pcode;
$file = $this->dir . '/Language/classes/' . $code . '.php';
if (file_exists($file) || class_exists($class)) {
if (file_exists($file) || class_exists($class, false)) {
$lang = new $class($config, $context);
} else {
// Go fallback

View File

@ -101,7 +101,7 @@ class HTMLPurifier_Lexer
break;
}
if (class_exists('DOMDocument') &&
if (class_exists('DOMDocument', false) &&
method_exists('DOMDocument', 'loadHTML') &&
!extension_loaded('domxml')
) {

View File

@ -104,6 +104,7 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
* To iterate is human, to recurse divine - L. Peter Deutsch
* @param DOMNode $node DOMNode to be tokenized.
* @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens.
* @return HTMLPurifier_Token of node appended to previously passed tokens.
*/
protected function tokenizeDOM($node, &$tokens, $config)
{

View File

@ -32,11 +32,6 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
*/
protected $compress = false;
/**
* @var HTMLPurifier_Config
*/
protected $genConfig;
/**
* @param string $name Form element name for directives to be stuffed into
* @param string $doc_url String documentation URL, will have fragment tagged on

View File

@ -33,11 +33,11 @@ class HTMLPurifier_URIScheme_tel extends HTMLPurifier_URIScheme
$uri->host = null;
$uri->port = null;
// Delete all non-numeric characters, commas, and non-x characters
// Delete all non-numeric characters, non-x characters
// from phone number, EXCEPT for a leading plus sign.
$uri->path = preg_replace('/(?!^\+)[^\dx,]/', '',
$uri->path = preg_replace('/(?!^\+)[^\dx]/', '',
// Normalize e(x)tension to lower-case
str_replace('X', 'x', rawurldecode($uri->path)));
str_replace('X', 'x', $uri->path));
return true;
}

View File

@ -261,7 +261,7 @@ class HTMLPurifier_UnitConverter
*/
private function round($n, $sigfigs)
{
$new_log = (int)floor(log(abs((float)$n), 10)); // Number of digits left of decimal - 1
$new_log = (int)floor(log(abs($n), 10)); // Number of digits left of decimal - 1
$rp = $sigfigs - $new_log - 1; // Number of decimal places needed
$neg = $n < 0 ? '-' : ''; // Negative sign
if ($this->bcmath) {
@ -276,7 +276,7 @@ class HTMLPurifier_UnitConverter
}
return $n;
} else {
return $this->scale(round((float)$n, $sigfigs - $new_log - 1), $rp + 1);
return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1);
}
}
@ -300,7 +300,7 @@ class HTMLPurifier_UnitConverter
// Now we return it, truncating the zero that was rounded off.
return substr($precise, 0, -1) . str_repeat('0', -$scale + 1);
}
return number_format((float)$r, $scale, '.', '');
return sprintf('%.' . $scale . 'f', (float)$r);
}
}

View File

@ -10,10 +10,10 @@
],
"homepage": "https://hyperf.io",
"support": {
"docs": "https://hyperf.wiki",
"issues": "https://github.com/hyperf/hyperf/issues",
"pull-request": "https://github.com/hyperf/hyperf/pulls",
"source": "https://github.com/hyperf/hyperf"
"source": "https://github.com/hyperf/hyperf",
"docs": "https://hyperf.wiki",
"pull-request": "https://github.com/hyperf/hyperf/pulls"
},
"require": {
"php": ">=8.1",

View File

@ -9,10 +9,10 @@
],
"homepage": "https://hyperf.io",
"support": {
"docs": "https://hyperf.wiki",
"issues": "https://github.com/hyperf/hyperf/issues",
"pull-request": "https://github.com/hyperf/hyperf/pulls",
"source": "https://github.com/hyperf/hyperf"
"source": "https://github.com/hyperf/hyperf",
"docs": "https://hyperf.wiki",
"pull-request": "https://github.com/hyperf/hyperf/pulls"
},
"require": {
"php": ">=8.1"

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Contract\Http;
use Stringable;
interface Http
{
public const DEFAULT_PROTOCOL_VERSION = '1.1';
public static function packRequest(string $method, string|Stringable $path, array $headers = [], string|Stringable $body = '', string $protocolVersion = self::DEFAULT_PROTOCOL_VERSION): string;
public static function packResponse(int $statusCode, string $reasonPhrase = '', array $headers = [], string|Stringable $body = '', string $protocolVersion = self::DEFAULT_PROTOCOL_VERSION): string;
}

View File

@ -24,7 +24,7 @@
},
"require": {
"php": ">=8.0",
"hyperf/engine-contract": "~1.10.0"
"hyperf/engine-contract": "~1.9.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.0",
@ -52,7 +52,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "2.11-dev"
"dev-master": "2.10-dev"
},
"hyperf": {
"config": "Hyperf\\Engine\\ConfigProvider"

View File

@ -122,7 +122,7 @@ class Coroutine implements CoroutineInterface
return SwooleCo::stats();
}
public static function exists(?int $id = null): bool
public static function exists(int $id = null): bool
{
return SwooleCo::exists($id);
}

View File

@ -1,56 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Http;
use Hyperf\Engine\Contract\Http\Http as HttpContract;
use Stringable;
class Http implements HttpContract
{
public static function packRequest(string $method, string|Stringable $path, array $headers = [], string|Stringable $body = '', string $protocolVersion = HttpContract::DEFAULT_PROTOCOL_VERSION): string
{
$headerString = '';
foreach ($headers as $key => $values) {
foreach ((array) $values as $value) {
$headerString .= sprintf("%s: %s\r\n", $key, $value);
}
}
return sprintf(
"%s %s HTTP/%s\r\n%s\r\n%s",
$method,
$path,
$protocolVersion,
$headerString,
$body
);
}
public static function packResponse(int $statusCode, string $reasonPhrase = '', array $headers = [], string|Stringable $body = '', string $protocolVersion = HttpContract::DEFAULT_PROTOCOL_VERSION): string
{
$headerString = '';
foreach ($headers as $key => $values) {
foreach ((array) $values as $value) {
$headerString .= sprintf("%s: %s\r\n", $key, $value);
}
}
return sprintf(
"HTTP/%s %s %s\r\n%s\r\n%s",
$protocolVersion,
$statusCode,
$reasonPhrase,
$headerString,
$body
);
}
}

View File

@ -13,7 +13,6 @@ declare(strict_types=1);
namespace Hyperf\Engine\WebSocket;
use Hyperf\Engine\Contract\WebSocket\WebSocketInterface;
use Psr\Log\LoggerInterface;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Swoole\WebSocket\CloseFrame;
@ -28,7 +27,7 @@ class WebSocket implements WebSocketInterface
*/
protected array $events = [];
public function __construct(Response $connection, Request $request, protected ?LoggerInterface $logger = null)
public function __construct(Response $connection, Request $request)
{
$this->connection = $connection;
$this->connection->upgrade();
@ -43,18 +42,7 @@ class WebSocket implements WebSocketInterface
{
while (true) {
/** @var false|string|SwFrame $frame */
$frame = $this->connection->recv(-1);
if ($frame === false) {
$this->logger?->warning(
sprintf(
'%s:(%s) %s',
'Websocket recv failed:',
swoole_last_error(),
swoole_strerror(swoole_last_error(), 9)
)
);
}
$frame = $this->connection->recv();
if ($frame === false || $frame instanceof CloseFrame || $frame === '') {
if ($callback = $this->events[static::ON_CLOSE] ?? null) {
$callback($this->connection, $this->connection->fd);

View File

@ -7,6 +7,7 @@ use ArrayIterator;
use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString;
use Illuminate\Support\Traits\EnumeratesValues;
use Illuminate\Support\Traits\Macroable;
use InvalidArgumentException;
use stdClass;
use Traversable;
@ -1124,17 +1125,23 @@ class Collection implements ArrayAccess, CanBeEscapedWhenCastToString, Enumerabl
*
* @param int $count
* @return static<int, TValue>|TValue|null
*
* @throws \InvalidArgumentException
*/
public function shift($count = 1)
{
if ($count === 1) {
return array_shift($this->items);
if ($count < 0) {
throw new InvalidArgumentException('Number of shifted items may not be less than zero.');
}
if ($this->isEmpty()) {
if ($count === 0 || $this->isEmpty()) {
return new static;
}
if ($count === 1) {
return array_shift($this->items);
}
$results = [];
$collectionCount = $this->count();

View File

@ -1305,14 +1305,13 @@ class Str
$minorWords = [
'and', 'as', 'but', 'for', 'if', 'nor', 'or', 'so', 'yet', 'a', 'an',
'the', 'at', 'by', 'for', 'in', 'of', 'off', 'on', 'per', 'to', 'up', 'via',
'et', 'ou', 'un', 'une', 'la', 'le', 'les', 'de', 'du', 'des', 'par', 'à',
];
$endPunctuation = ['.', '!', '?', ':', '—', ','];
$words = preg_split('/\s+/', $value, -1, PREG_SPLIT_NO_EMPTY);
$words[0] = ucfirst(mb_strtolower($words[0]));
for ($i = 0; $i < count($words); $i++) {
$lowercaseWord = mb_strtolower($words[$i]);
@ -1320,7 +1319,9 @@ class Str
$hyphenatedWords = explode('-', $lowercaseWord);
$hyphenatedWords = array_map(function ($part) use ($minorWords) {
return (in_array($part, $minorWords) && mb_strlen($part) <= 3) ? $part : ucfirst($part);
return (in_array($part, $minorWords) && mb_strlen($part) <= 3)
? $part
: mb_strtoupper(mb_substr($part, 0, 1)).mb_substr($part, 1);
}, $hyphenatedWords);
$words[$i] = implode('-', $hyphenatedWords);
@ -1330,7 +1331,7 @@ class Str
! ($i === 0 || in_array(mb_substr($words[$i - 1], -1), $endPunctuation))) {
$words[$i] = $lowercaseWord;
} else {
$words[$i] = ucfirst($lowercaseWord);
$words[$i] = mb_strtoupper(mb_substr($lowercaseWord, 0, 1)).mb_substr($lowercaseWord, 1);
}
}
}

View File

@ -64,6 +64,7 @@ abstract class AbstractDriver implements DriverInterface
/**
* {@inheritdoc}
*
* @throws NotSupportedException
* @see DriverInterface::specializeMultiple()
*/
public function specializeMultiple(array $objects): array

View File

@ -72,6 +72,7 @@ class Driver extends AbstractDriver
/**
* {@inheritdoc}
*
* @throws RuntimeException
* @see DriverInterface::createAnimation()
*/
public function createAnimation(callable $init): ImageInterface

View File

@ -14,6 +14,6 @@ class CoverDownModifier extends CoverModifier
*/
public function getResizeSize(SizeInterface $size): SizeInterface
{
return $size->scaleDown($this->width, $this->height);
return $size->resizeDown($this->width, $this->height);
}
}

View File

@ -71,6 +71,7 @@ class Driver extends AbstractDriver
/**
* {@inheritdoc}
*
* @throws RuntimeException
* @see DriverInterface::createAnimation()
*/
public function createAnimation(callable $init): ImageInterface

View File

@ -14,6 +14,6 @@ class CoverDownModifier extends CoverModifier
*/
public function getResizeSize(SizeInterface $size): SizeInterface
{
return $size->scaleDown($this->width, $this->height);
return $size->resizeDown($this->width, $this->height);
}
}

View File

@ -38,6 +38,6 @@ class CoverModifier extends SpecializableModifier
*/
public function getResizeSize(SizeInterface $size): SizeInterface
{
return $size->scale($this->width, $this->height);
return $size->resize($this->width, $this->height);
}
}

View File

@ -92,8 +92,8 @@
},
"extra": {
"branch-alias": {
"dev-3.x": "3.x-dev",
"dev-master": "2.x-dev"
"dev-master": "3.x-dev",
"dev-2.x": "2.x-dev"
},
"laravel": {
"providers": [

View File

@ -123,8 +123,8 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
<a title="Онлайн казино 777 Україна" href="https://777.ua/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Онлайн казино" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/7e572d50-1ce8-4d69-ae12-86cc80371373/ok-ua-777.png" width="64" height="64"></a>
<a title="#1 Guide To Online Gambling In Canada" href="https://casinohex.org/canada/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="CasinoHex Canada" src="https://opencollective-production.s3.us-west-1.amazonaws.com/79fdbcc0-a997-11eb-abbc-25e48b63c6dc.jpg" width="85" height="64"></a>
<a title="Znajdź najlepsze zakłady bukmacherskie w Polsce w 2023 roku. Probukmacher.pl to Twoje kompendium wiedzy na temat bukmacherów!" href="https://www.probukmacher.pl?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Probukmacher" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/caf50271-4560-4ffe-a434-ea15239168db/Screenshot_1.png" width="89" height="64"></a>
<a title="Gives a fun for our users" href="https://slotoking.ua/games/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Игровые автоматы" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/94601d07-3205-4c60-9c2d-9b8194dbefb7/skg-blue.png" width="64" height="64"></a>
<a title="Casino-portugal.pt" href="https://casino-portugal.pt/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Casino-portugal.pt" src="https://logo.clearbit.com/casino-portugal.pt" width="64" height="64"></a>
<a title="Gives a fun for our users" href="https://slotoking.ua/games/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Игровые автоматы" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/94601d07-3205-4c60-9c2d-9b8194dbefb7/skg-blue.png" width="64" height="64"></a>
<a title="Slots City® ➢ Лучшее лицензионно казино онлайн и оффлайн на гривны в Украине. 【 Более1500 игровых автоматов и слотов】✅ Официально и Безопасно" href="https://slotscity.ua/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Slots City" src="https://opencollective-production.s3.us-west-1.amazonaws.com/d7e298c0-7abe-11ed-8553-230872f5e54d.png" width="90" height="64"></a>
<a title="inkedin" href="https://inkedin.com?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="inkedin" src="https://logo.clearbit.com/inkedin.com" width="64" height="64"></a>
<a title="Актуальний та повносправний рейтинг онлайн казино України, ґрунтований на відгуках реальних гравців." href="https://uk.onlinecasino.in.ua/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Онлайн казино України" src="https://opencollective-production.s3.us-west-1.amazonaws.com/c0b4b090-eef8-11ec-9cb7-0527a205b226.png" width="64" height="64"></a>
@ -142,10 +142,11 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
<a title="Siti Non AAMS" href="https://www.outlookindia.com/outlook-spotlight/migliori-siti-non-aams-siti-scommesse-senza-licenza-sicuri-news-294715?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Migliori Siti Non AAMS" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/392810da-6cb6-4938-a3cb-38bd0e1eb7de/migliori-siti-non-aams.png" width="42" height="42"></a>
<a title="List of trusted non GamStop casino reviews" href="https://nongamstopcasinos.org?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="UK NonGamStopCasinos" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/cbda0ee1-26ea-4252-9580-f1f9b317b1f7/nongamstopcasinos-uk.png" width="42" height="42"></a>
<a title="Online TikTok Video Download Tool" href="https://snaptik.pro?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="SnapTik" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/546bcd53-6615-457d-ab21-1db1c52b3af5/logo.jpg" width="42" height="42"></a>
<a title="IG Downloader is an Instagram Downloader service that offers a variety of tools to download Instagram content for free. Listed below are all the tools" href="https://indownloader.app/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="IG Downloader" src="https://logo.clearbit.com/indownloader.app" width="42" height="42"></a>
<a title="Proxidize is a mobile proxy creation and management platform that provides all needed components from hardware to cloud software and SIM cards." href="https://proxidize.com/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Proxidize" src="https://logo.clearbit.com/proxidize.com" width="42" height="42"></a>
<a title="Blastup offers Instagram growth services like buying likes, views, and followers, emphasizing real user engagement and instant delivery." href="https://blastup.com/buy-instagram-likes?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Blastup" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/955a0beb-9fe8-4753-ad92-fae8ef5382fc/favicon--dark.jpg" width="42" height="42"></a>
<a title="A self-hosted web radio management suite, including turnkey installer tools and an easy-to-use web app to manage your stations." href="https://azuracast.com?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="AzuraCast" src="https://opencollective-production.s3.us-west-1.amazonaws.com/3c12ea10-cdfb-11eb-9cf4-3760b386b76d.png" width="42" height="42"></a>
<a title="IG Downloader is an Instagram Downloader service that offers a variety of tools to download Instagram content for free. Listed below are all the tools" href="https://indownloader.app/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="IG Downloader" src="https://logo.clearbit.com/indownloader.app" width="42" height="42"></a>
<a title="Buy Instagram Likes - Real Likes &amp; Instant Delivery!" href="https://blastup.com/buy-instagram-likes?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Blastup" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/955a0beb-9fe8-4753-ad92-fae8ef5382fc/favicon--dark.jpg" width="42" height="42"></a>
<a title="We will boost your Social Media Likes, Followers , Comments &amp; Views. 24/7 hour support. Privacy Assured." href="https://organicsocialboost.com/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Organic Social Boost" src="https://logo.clearbit.com/organicsocialboost.com" width="84" height="42"></a>
<a title="A self-hosted web radio management suite, including turnkey installer tools and an easy-to-use web app to manage your stations." href="https://azuracast.com/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="AzuraCast" src="https://opencollective-production.s3.us-west-1.amazonaws.com/3c12ea10-cdfb-11eb-9cf4-3760b386b76d.png" width="42" height="42"></a>
<a title="Triplebyte is the first software engineering job platform that is on the developer&#039;s side. Take our coding quiz!" href="https://triplebyte.com/os/opencollective?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Triplebyte" src="https://opencollective-production.s3.us-west-1.amazonaws.com/43e4f9d0-30cd-11ea-9c6b-e1142996e8b2.png" width="42" height="42"></a>
<a title="Connect your Collective to GitHub Sponsors: https://docs.opencollective.com/help/collectives/github-sponsors" href="https://github.com/sponsors/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="GitHub Sponsors" src="https://opencollective-production.s3.us-west-1.amazonaws.com/87b1d240-f617-11ea-9960-fd7e8ab20fe4.png" width="48" height="42"></a>
<a title="Salesforce" href="https://engineering.salesforce.com?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img alt="Salesforce" src="https://opencollective-production.s3.us-west-1.amazonaws.com/24d34880-df8d-11e9-949c-6bc2037b6bd5.png" width="42" height="42"></a>

View File

@ -994,6 +994,13 @@ trait Comparison
return $this->year === (int) $tester;
}
if (preg_match('/^(?:Jan|January|Feb|February|Mar|March|Apr|April|May|Jun|June|Jul|July|Aug|August|Sep|September|Oct|October|Nov|November|Dec|December)$/i', $tester)) {
return $this->isSameMonth(
$this->transmitFactory(static fn () => static::parse($tester)),
false,
);
}
if (preg_match('/^\d{3,}-\d{1,2}$/', $tester)) {
return $this->isSameMonth(static::parse($tester));
}

View File

@ -96,9 +96,9 @@ trait Options
'v' => '([0-9]{1,3})',
'e' => '([a-zA-Z]{1,5})|([a-zA-Z]*\\/[a-zA-Z]*)',
'I' => '(0|1)',
'O' => '([+-](1[012]|0[0-9])[0134][05])',
'P' => '([+-](1[012]|0[0-9]):[0134][05])',
'p' => '(Z|[+-](1[012]|0[0-9]):[0134][05])',
'O' => '([+-](1[0123]|0[0-9])[0134][05])',
'P' => '([+-](1[0123]|0[0-9]):[0134][05])',
'p' => '(Z|[+-](1[0123]|0[0-9]):[0134][05])',
'T' => '([a-zA-Z]{1,5})',
'Z' => '(-?[1-5]?[0-9]{1,4})',
'U' => '([0-9]*)',

View File

@ -56,7 +56,7 @@ $socialite = new SocialiteManager($config);
$url = $socialite->create('github')->redirect();
return redirect($url);
return redirect($url);
```
`callback.php`:
@ -122,7 +122,7 @@ $config = [
'client_secret' => 'your-app-secret',
'redirect' => 'http://localhost/socialite/callback.php',
],
// 另外一个名字叫做 bar 的 github 应用
'bar' => [
'provider' => 'github', // <-- provider name
@ -130,7 +130,7 @@ $config = [
'client_secret' => 'your-app-secret',
'redirect' => 'http://localhost/socialite/callback.php',
],
//...
];
@ -159,7 +159,7 @@ $config = [
];
$socialite = new SocialiteManager($config);
$socialite->extend('myprovider', function(array $config) {
return new MyCustomProvider($config);
});
@ -172,7 +172,7 @@ $app = $socialite->create('foo');
>👋🏻 你的自定义服务提供类必须实现`Overtrue\Socialite\Contracts\ProviderInterface` 接口
```php
class MyCustomProvider implements \Overtrue\Socialite\Contracts\ProviderInterface
class MyCustomProvider implements \Overtrue\Socialite\Contracts\ProviderInterface
{
//...
}
@ -208,8 +208,8 @@ $app = $socialite->create('foo');
$config = [
'alipay' => [
// 这个键名还能像官方文档那样叫做 'app_id'
'client_id' => 'your-app-id',
'client_id' => 'your-app-id',
// 请根据官方文档,在官方管理后台配置 RSA2
// 注意: 这是你自己的私钥
// 注意: 不允许私钥内容有其他字符
@ -219,7 +219,7 @@ $config = [
// 确保这里的值与你在服务后台绑定的地址值一致
// 这个键名还能像官方文档那样叫做 'redirect_url'
'redirect' => 'http://localhost/socialite/callback.php',
// 沙箱模式接入地址见 https://opendocs.alipay.com/open/220/105337#%E5%85%B3%E4%BA%8E%E6%B2%99%E7%AE%B1
'sandbox' => false,
]
@ -252,7 +252,7 @@ $config = [
// or 'app_id'
'client_id' => 'your app id',
// or 'app_secret'
// or 'app_secret'
'client_secret' => 'your app secret',
// or 'redirect_url'
@ -361,7 +361,7 @@ $config = [
// or 'app_id'
'client_id' => 'your app id',
// or 'app_secret'
// or 'app_secret'
'client_secret' => 'your app secret',
// or 'redirect_url'
@ -391,7 +391,7 @@ $config = [
// or 'app_id'
'client_id' => 'your app id',
// or 'app_secret'
// or 'app_secret'
'client_secret' => 'your app secret',
// or 'redirect_url'
@ -413,7 +413,7 @@ $larkDriver->withDefaultMode()->withAppTicket('app_ticket')->userFromCode('here
### [淘宝](https://open.taobao.com/doc.htm?docId=102635&docType=1&source=search)
其他配置与其他平台的一样,你能选择你想要展示的重定向页面类型通过使用 `withView()`
其他配置与其他平台的一样,你能选择你想要展示的重定向页面类型通过使用 `withView()`
```php
$authUrl = $socialite->create('taobao')->withView('wap')->redirect();
@ -456,7 +456,7 @@ $authUrl = $socialite->create('taobao')->withView('wap')->redirect();
```php
$config = [
'coding' => [
'team_url' => 'https://{your-team}.coding.net',
'team_url' => 'https://{your-team}.coding.net',
'client_id' => 'your app id',
'client_secret' => 'your app secret',
'redirect' => 'redirect URL',
@ -464,6 +464,24 @@ $config = [
];
```
### [PayPal](https://developer.paypal.com/docs/log-in-with-paypal/)
您可能需要设置responseType可以使用`withResponseType`函数进行设置,默认是`code` 还可以设置为`id_token``code` & `id_token`
> https://developer.paypal.com/docs/log-in-with-paypal/integrate/generate-button/
```php
$config = [
'paypal' => [
'client_id' => 'AT******************',
'client_secret' => 'EK**************',
'sandbox' => false,
'redirect_url'=>"nativexo://paypalpay",
],
];
```
## 其他一些技巧
### Scopes
@ -498,7 +516,7 @@ $socialite->withRedirectUrl($url)->redirect();
```php
<?php
session_start();
$config = [
//...
];
@ -510,7 +528,7 @@ $socialite = new SocialiteManager($config);
$url = $socialite->create('github')->withState($state)->redirect();
return redirect($url);
return redirect($url);
```
### 检验回调的 `state`
@ -520,10 +538,10 @@ return redirect($url);
```php
<?php
session_start();
$state = request()->query('state');
$code = request()->query('code');
// Check the state received with current session id
if ($state != hash('sha256', session_id())) {
exit('State does not match!');
@ -596,7 +614,7 @@ mixed $user->getId();
?string $user->getEmail();
?string $user->getAvatar();
?string $user->getRaw();
?string $user->getAccessToken();
?string $user->getAccessToken();
?string $user->getRefreshToken();
?int $user->getExpiresIn();
?array $user->getTokenResponse();
@ -648,6 +666,7 @@ $user = $socialite->userFromToken($accessToken);
- [Tapd - 用户授权说明](https://www.tapd.cn/help/show#1120003271001000093)
- [Line - OAuth 2.0](https://developers.line.biz/en/docs/line-login/integrate-line-login/)
- [Gitee - OAuth文档](https://gitee.com/api/v5/oauth_doc#/)
- [PayPal - OAuth文档](https://developer.paypal.com/docs/log-in-with-paypal/)

View File

@ -443,6 +443,26 @@ $config = [
];
```
### [PayPal](https://developer.paypal.com/docs/log-in-with-paypal/)
You may need to set the responseType, which can be set using the `withResponseType` function. The default is `code` and can also be set to `id_token` or `code` & `id_token`
> https://developer.paypal.com/docs/log-in-with-paypal/integrate/generate-button/
```php
$config = [
'paypal' => [
'client_id' => 'AT******************',
'client_secret' => 'EK**************',
'sandbox' => false,
'redirect_url'=>"nativexo://paypalpay",
],
];
```
## Some Skill
### Scopes
@ -627,6 +647,7 @@ $user = $socialite->userFromToken($accessToken);
- [Tapd - 用户授权说明](https://www.tapd.cn/help/show#1120003271001000093)
- [Line - OAuth 2.0](https://developers.line.biz/en/docs/line-login/integrate-line-login/)
- [Gitee - OAuth文档](https://gitee.com/api/v5/oauth_doc#/)
- [PayPal - OAuth文档](https://developer.paypal.com/docs/log-in-with-paypal/)
[![Sponsor me](https://github.com/overtrue/overtrue/blob/master/sponsor-me.svg?raw=true)](https://github.com/sponsors/overtrue)

View File

@ -0,0 +1,169 @@
<?php
namespace Overtrue\Socialite\Providers;
use JetBrains\PhpStorm\Pure;
use Overtrue\Socialite\Contracts;
use Overtrue\Socialite\User;
/**
* Class PayPal
* @author zhiqiang
* @package Overtrue\Socialite\Providers
* @see https://developer.paypal.com/docs/log-in-with-paypal/
*/
class PayPal extends Base
{
public const NAME = 'paypal';
protected string $scopeSeparator = ' ';
/**
* @var string|null
* code or id_token
*/
protected ?string $responseType = Contracts\RFC6749_ABNF_CODE;
protected string $flowEntry = 'static';
protected string $authUrl = 'https://www.paypal.com/signin/authorize';
protected string $tokenURL = "https://api.sandbox.paypal.com/v1/oauth2/token";
protected string $userinfoURL = "https://api.paypal.com/v1/identity/openidconnect/userinfo";
protected array $scopes = [
'openid', 'profile', 'email', 'address'
];
protected bool $sandbox = true;
public function __construct(array $config)
{
parent::__construct($config);
$this->sandbox = (bool)$this->config->get('sandbox', false);
if ($this->sandbox) {
$this->authUrl = 'https://www.sandbox.paypal.com/signin/authorize';
$this->tokenURL = 'https://api-m.sandbox.paypal.com/v1/oauth2/token';
$this->userinfoURL = 'https://api-m.sandbox.paypal.com/v1/identity/openidconnect/userinfo';
}
}
/**
* @param string|null $responseType
* @return $this
* @see https://developer.paypal.com/docs/log-in-with-paypal/integrate/generate-button/
*/
public function withResponseType(?string $responseType)
{
$this->responseType = $responseType;
return $this;
}
protected function getAuthUrl(): string
{
return $this->buildAuthUrlFromBase($this->authUrl);
}
protected function getCodeFields(): array
{
$fields = \array_merge(
[
'flowEntry' => $this->flowEntry,
Contracts\RFC6749_ABNF_CLIENT_ID => $this->getClientId(),
Contracts\RFC6749_ABNF_RESPONSE_TYPE => $this->responseType,
Contracts\RFC6749_ABNF_SCOPE => $this->formatScopes($this->scopes, $this->scopeSeparator),
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
],
$this->parameters
);
if ($this->state) {
$fields[Contracts\RFC6749_ABNF_STATE] = $this->state;
}
return $fields;
}
protected function getTokenUrl(): string
{
return $this->tokenURL;
}
/**
* @param string $code
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Overtrue\Socialite\Exceptions\AuthorizeFailedException
* @see https://developer.paypal.com/docs/log-in-with-paypal/integrate/#link-getaccesstoken
*/
public function tokenFromCode(string $code): array
{
$response = $this->getHttpClient()->post(
$this->getTokenUrl(),
[
'form_params' => [
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
Contracts\RFC6749_ABNF_CODE => $code,
],
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Basic ' . \base64_encode(\sprintf('%s:%s', $this->getClientId(), $this->getClientSecret())),
],
]
);
return $this->normalizeAccessTokenResponse((string)$response->getBody());
}
/**
* @param string $refreshToken
* @return mixed
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Overtrue\Socialite\Exceptions\AuthorizeFailedException
* @see https://developer.paypal.com/docs/log-in-with-paypal/integrate/#link-exchangerefreshtokenforaccesstoken
*/
public function refreshToken(string $refreshToken): mixed
{
$response = $this->getHttpClient()->post(
$this->getTokenUrl(),
[
'form_params' => [
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_REFRESH_TOKEN,
Contracts\RFC6749_ABNF_REFRESH_TOKEN => $refreshToken,
],
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Basic ' . \base64_encode(\sprintf('%s:%s', $this->getClientId(), $this->getClientSecret())),
],
]
);
return $this->normalizeAccessTokenResponse((string)$response->getBody());
}
/**
* @param string $token
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
* @see https://developer.paypal.com/docs/api/identity/v1/#userinfo_get
*/
protected function getUserByToken(string $token): array
{
$response = $this->getHttpClient()->get(
$this->userinfoURL,
[
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
'Authorization' => 'Bearer ' . $token,
],
]
);
return $this->fromJsonBody($response);
}
#[Pure]
protected function mapUserToObject(array $user): Contracts\UserInterface
{
$user[Contracts\ABNF_ID] = $user['user_id'] ?? null;
$user[Contracts\ABNF_NICKNAME] = $user['given_name'] ?? $user['family_name'] ?? $user['middle_name'] ?? null;
$user[Contracts\ABNF_NAME] = $user['name'] ?? '';
$user[Contracts\ABNF_EMAIL] = $user[Contracts\ABNF_EMAIL] ?? null;
$user[Contracts\ABNF_AVATAR] = $user['picture'] ?? null;
return new User($user);
}
}

View File

@ -40,6 +40,7 @@ class SocialiteManager implements Contracts\FactoryInterface
Providers\WeWork::NAME => Providers\WeWork::class,
Providers\Weibo::NAME => Providers\Weibo::class,
Providers\XiGua::NAME => Providers\XiGua::class,
Providers\PayPal::NAME => Providers\PayPal::class,
];
#[Pure]

View File

@ -3,9 +3,9 @@ cos-php-sdk-v5 Upgrade Guide
2.6.8 to 2.6.9
---------
1. 开通智能语音服务
2. 开通智能语音服务
3. 查询智能语音服务
4. 关闭智能语音服务
2. 查询智能语音服务
3. 关闭智能语音服务
4. 更新智能语音队列
5. 查询智能语音队列
6. 创建音频降噪模板
7. 更新音频降噪模板

View File

@ -36,6 +36,7 @@
"ext-json": "*",
"ext-simplexml": "*",
"ext-mbstring": "*",
"ext-libxml": "*",
"guzzlehttp/guzzle": "^6.2.1 || ^7.0",
"guzzlehttp/guzzle-services": "^1.1",
"guzzlehttp/psr7": "^1.3.1 || ^2.0"

View File

@ -0,0 +1,102 @@
<?php
/**
* 第一步:获取临时密钥
* 该demo为临时密钥获取sdk的使用示例具体情参考sdk git地址 https://github.com/tencentyun/qcloud-cos-sts-sdk
* 参考文档 https://cloud.tencent.com/document/product/436/14048
* $config 配置中的 allowCiSource 字段为万象资源配置为true时授予万象资源权限
* 拿到临时密钥后可以在cos php sdk中使用 https://github.com/tencentyun/cos-php-sdk-v5
* Array
* (
* [expiredTime] => 1700828878
* [expiration] => 2023-11-24T12:27:58Z
* [credentials] => Array
* (
* [sessionToken] => token
* [tmpSecretId] => secretId
* [tmpSecretKey] => secretKey
* )
*
* [requestId] => 2a521211-b212-xxxx-xxxx-c9976a3966bd
* [startTime] => 1700810878
* )
*/
require_once __DIR__ . '/vendor/autoload.php';
$bucket = 'examplebucket-1250000000';
$secretKey = 'SECRETKEY';
$secretId = 'SECRETID';
$region = "ap-beijing";
$sts = new QCloud\COSSTS\Sts();
$config = array(
'url' => 'https://sts.tencentcloudapi.com/', // url和domain保持一致
'domain' => 'sts.tencentcloudapi.com', // 域名,非必须,默认为 sts.tencentcloudapi.com
'proxy' => '',
'secretId' => $secretId, // 固定密钥,若为明文密钥,请直接以'xxx'形式填入不要填写到getenv()函数中
'secretKey' => $secretKey, // 固定密钥,若为明文密钥,请直接以'xxx'形式填入不要填写到getenv()函数中
'bucket' => $bucket, // 换成你的 bucket
'region' => $region, // 换成 bucket 所在园区
'durationSeconds' => 1800*10, // 密钥有效期
'allowPrefix' => array('/*'), // 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径,例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
'allowCiSource' => true, // 万象资源配置,授予万象资源权限
'allowActions' => array (
'name/cos:*',
'name/ci:*',
// 具体action按需设置
),
// // 临时密钥生效条件关于condition的详细设置规则和COS支持的condition类型可以参考 https://cloud.tencent.com/document/product/436/71306
// "condition" => array(
// "ip_equal" => array(
// "qcs:ip" => array(
// "10.217.182.3/24",
// "111.21.33.72/24",
// )
// )
// )
);
try {
// 获取临时密钥,计算签名
$tempKeys = $sts->getTempKeys($config);
print_r($tempKeys);
} catch (Exception $e) {
echo $e;
}
/**
* 第二步在cos php sdk中使用临时密钥
* 创建临时密钥生成的Client以文本同步审核为例
*/
// 临时密钥
$tmpSecretId = 'secretId'; // 第一步获取到的 $tempKeys['credentials']['tmpSecretId']
$tmpSecretKey = 'secretKey'; // 第一步获取到的 $tempKeys['credentials']['tmpSecretKey']
$token = 'token'; // 第一步获取到的 $tempKeys['credentials']['sessionToken']
$tokenClient = new Qcloud\Cos\Client(
array(
'region' => $region,
'scheme' => 'https', //协议头部默认为http
'credentials'=> array(
'secretId' => $tmpSecretId ,
'secretKey' => $tmpSecretKey,
'token' => $token,
)
)
);
try {
$content = '敏感词';
$result = $tokenClient->detectText(array(
'Bucket' => 'examplebucket-1250000000', //存储桶名称由BucketName-Appid 组成可以在COS控制台查看 https://console.cloud.tencent.com/cos5/bucket
'Input' => array(
'Content' => base64_encode($content), // 文本需base64_encode
),
));
// 请求成功
print_r($result);
} catch (\Exception $e) {
// 请求失败
echo($e);
}

View File

@ -248,10 +248,10 @@ use GuzzleHttp\Psr7\Uri;
* @method object CreateMediaTargetRecJobs(array $args) 提交视频目标检测任务
* @method object CreateMediaSegmentVideoBodyJobs(array $args) 提交视频人像抠图任务
* @method object OpenAsrService(array $args) 开通智能语音服务
* @method object GetAsrBucketList(array $args) 开通智能语音服务
* @method object CloseAsrService(array $args) 查询智能语音服务
* @method object GetAsrQueueList(array $args) 关闭智能语音服务
* @method object UpdateAsrQueue(array $args) 查询智能语音队列
* @method object GetAsrBucketList(array $args) 查询智能语音服务
* @method object CloseAsrService(array $args) 关闭智能语音服务
* @method object GetAsrQueueList(array $args) 查询智能语音队列
* @method object UpdateAsrQueue(array $args) 更新智能语音队列
* @method object CreateMediaNoiseReductionTemplate(array $args) 创建音频降噪模板
* @method object UpdateMediaNoiseReductionTemplate(array $args) 更新音频降噪模板
* @method object CreateVoiceSoundHoundJobs(array $args) 提交听歌识曲任务
@ -297,6 +297,7 @@ class Client extends GuzzleClient {
'locationWithScheme' => false,
'autoChange' => true,
'limit_flag' => false,
'isCheckRequestPath' => true,
];
public function __construct(array $cosConfig) {
@ -304,6 +305,9 @@ class Client extends GuzzleClient {
$this->cosConfig = processCosConfig(array_replace_recursive($this->cosConfig, $cosConfig));
global $globalCosConfig;
$globalCosConfig = $this->cosConfig;
// check config
$this->inputCheck();
@ -409,6 +413,7 @@ class Client extends GuzzleClient {
null);
}
public function inputCheck() {
$message = null;
//检查Region
@ -458,7 +463,7 @@ class Client extends GuzzleClient {
public function responseToResultTransformer(ResponseInterface $response, RequestInterface $request, CommandInterface $command)
{
$transformer = new ResultTransformer($this->cosConfig, $this->operation);
$transformer = new ResultTransformer($this->cosConfig, $this->operation);
$transformer->writeDataToLocal($command, $request, $response);
$deseri = new Deserializer($this->desc, true);
$result = $deseri($response, $request, $command);
@ -469,7 +474,7 @@ class Client extends GuzzleClient {
$result = $transformer->ciContentInfoTransformer($command, $result);
return $result;
}
public function __destruct() {
}
@ -553,10 +558,29 @@ class Client extends GuzzleClient {
return $rt;
}
public static function simplifyPath($path) {
$names = explode("/", $path);
$stack = array();
foreach ($names as $name) {
if ($name == "..") {
if (!empty($stack)) {
array_pop($stack);
}
} elseif ($name && $name != ".") {
array_push($stack, $name);
}
}
return "/" . implode("/", $stack);
}
public function download($bucket, $key, $saveAs, $options = array()) {
$options['PartSize'] = isset($options['PartSize']) ? $options['PartSize'] : RangeDownload::DEFAULT_PART_SIZE;
$versionId = isset($options['VersionId']) ? $options['VersionId'] : '';
if ($this->cosConfig['isCheckRequestPath'] && "/" == self::simplifyPath($key)) {
$e = new Exception\CosException('Getobject Key is illegal');
$e->setExceptionCode('404');
throw $e;
}
$rt = $this->headObject(array(
'Bucket'=>$bucket,
'Key'=>$key,
@ -664,6 +688,12 @@ class Client extends GuzzleClient {
}
public static function explodeKey($key) {
global $globalCosConfig;
if ($globalCosConfig['isCheckRequestPath'] && "/" == self::simplifyPath($key)) {
$e = new Exception\CosException('Getobject Key is illegal');
$e->setExceptionCode('404');
throw $e;
}
// Remove a leading slash if one is found
$split_key = explode('/', $key && $key[0] == '/' ? substr($key, 1) : $key);
// Remove empty element

View File

@ -86,6 +86,9 @@ class ResultTransformer {
$length = intval($result['ContentLength']);
if($length > 0){
$content = $this->geCiContentInfo($result, $length);
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
libxml_disable_entity_loader(true);
}
$obj = simplexml_load_string($content, "SimpleXMLElement", LIBXML_NOCDATA);
$xmlData = json_decode(json_encode($obj),true);
if ($picRuleSize == 1 && isset($xmlData['ProcessResults']['Object'])){
@ -101,6 +104,9 @@ class ResultTransformer {
$length = intval($result['ContentLength']);
if($length > 0){
$content = $this->geCiContentInfo($result, $length);
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
libxml_disable_entity_loader(true);
}
$obj = simplexml_load_string($content, "SimpleXMLElement", LIBXML_NOCDATA);
$arr = json_decode(json_encode($obj),true);
$result['GuetzliStatus'] = isset($arr[0]) ? $arr[0] : '';
@ -111,6 +117,9 @@ class ResultTransformer {
$length = intval($result['ContentLength']);
if($length > 0){
$content = $this->geCiContentInfo($result, $length);
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
libxml_disable_entity_loader(true);
}
$obj = simplexml_load_string($content, "SimpleXMLElement", LIBXML_NOCDATA);
$arr = json_decode(json_encode($obj),true);
$result['CIStatus'] = isset($arr[0]) ? $arr[0] : '';
@ -122,6 +131,9 @@ class ResultTransformer {
$length = intval($result['ContentLength']);
if($length > 0){
$content = $this->geCiContentInfo($result, $length);
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
libxml_disable_entity_loader(true);
}
$obj = simplexml_load_string($content, "SimpleXMLElement", LIBXML_NOCDATA);
$arr = json_decode(json_encode($obj),true);
$result['OriginProtectStatus'] = isset($arr[0]) ? $arr[0] : '';
@ -133,6 +145,9 @@ class ResultTransformer {
$length = intval($result['ContentLength']);
if($length > 0){
$content = $this->geCiContentInfo($result, $length);
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
libxml_disable_entity_loader(true);
}
$obj = simplexml_load_string($content, "SimpleXMLElement", LIBXML_NOCDATA);
$arr = json_decode(json_encode($obj),true);
$result['Hotlink'] = $arr;
@ -144,6 +159,9 @@ class ResultTransformer {
$length = intval($result['ContentLength']);
if($length > 0){
$content = $this->geCiContentInfo($result, $length);
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
libxml_disable_entity_loader(true);
}
$obj = simplexml_load_string($content, "SimpleXMLElement", LIBXML_NOCDATA);
$arr = json_decode(json_encode($obj),true);
$result['TranslationResult'] = isset($arr[0]) ? $arr[0] : '';
@ -204,6 +222,9 @@ class ResultTransformer {
$length = intval($result['ContentLength']);
if($length > 0){
$content = $this->geCiContentInfo($result, $length);
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
libxml_disable_entity_loader(true);
}
$obj = simplexml_load_string($content, "SimpleXMLElement", LIBXML_NOCDATA);
$xmlData = json_decode(json_encode($obj),true);
$result['Response'] = $xmlData;

View File

@ -3843,10 +3843,10 @@ class Service {
'CreateMediaTargetRecJobs' => Descriptions::CreateMediaTargetRecJobs(), // 提交视频目标检测任务
'CreateMediaSegmentVideoBodyJobs' => Descriptions::CreateMediaSegmentVideoBodyJobs(), // 提交视频人像抠图任务
'OpenAsrService' => Descriptions::OpenAsrService(), //开通智能语音服务
'GetAsrBucketList' => Descriptions::GetAsrBucketList(), // 开通智能语音服务
'CloseAsrService' => Descriptions::CloseAsrService(), // 查询智能语音服务
'GetAsrQueueList' => Descriptions::GetAsrQueueList(), // 关闭智能语音服务
'UpdateAsrQueue' => Descriptions::UpdateAsrQueue(), // 查询智能语音队列
'GetAsrBucketList' => Descriptions::GetAsrBucketList(), // 查询智能语音服务
'CloseAsrService' => Descriptions::CloseAsrService(), // 关闭智能语音服务
'GetAsrQueueList' => Descriptions::GetAsrQueueList(), // 查询智能语音队列
'UpdateAsrQueue' => Descriptions::UpdateAsrQueue(), // 更新智能语音队列
'CreateMediaNoiseReductionTemplate' => Descriptions::CreateMediaNoiseReductionTemplate(), // 创建音频降噪模板
'UpdateMediaNoiseReductionTemplate' => Descriptions::UpdateMediaNoiseReductionTemplate(), // 更新音频降噪模板
'CreateVoiceSoundHoundJobs' => Descriptions::CreateVoiceSoundHoundJobs(), // 提交听歌识曲任务

View File

@ -44,7 +44,7 @@ interface CacheInterface
*
* @throws InvalidArgumentException When $key is not valid or when $beta is negative
*/
public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed;
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed;
/**
* Removes an item from the pool.

View File

@ -25,7 +25,7 @@ class_exists(InvalidArgumentException::class);
*/
trait CacheTrait
{
public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed
public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed
{
return $this->doGet($this, $key, $callback, $beta, $metadata);
}
@ -35,7 +35,7 @@ trait CacheTrait
return $this->deleteItem($key);
}
private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, ?array &$metadata = null, ?LoggerInterface $logger = null): mixed
private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null, LoggerInterface $logger = null): mixed
{
if (0 > $beta ??= 1.0) {
throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException {};

View File

@ -25,7 +25,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "3.5-dev"
"dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",

View File

@ -517,7 +517,7 @@ trait RedisTrait
}
$this->doDelete($keys);
}
} while ($cursor = (int) $cursor);
} while ($cursor);
}
return $cleared;

View File

@ -276,6 +276,11 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->replicaof(...\func_get_args());
}
public function waitaof($numlocal, $numremote, $timeout): \Relay\Relay|array|false
{
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->waitaof(...\func_get_args());
}
public function restore($key, $ttl, $value, $options = null): \Relay\Relay|bool
{
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->restore(...\func_get_args());

View File

@ -25,7 +25,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "3.5-dev"
"dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",

View File

@ -90,7 +90,7 @@ interface HttpClientInterface
* @param ResponseInterface|iterable<array-key, ResponseInterface> $responses One or more responses created by the current HTTP client
* @param float|null $timeout The idle timeout before yielding timeout chunks
*/
public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface;
public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface;
/**
* Returns a new instance of the client with new default options.

View File

@ -105,5 +105,5 @@ interface ResponseInterface
* @return mixed An array of all available info, or one of them when $type is
* provided, or null when an unsupported type is requested
*/
public function getInfo(?string $type = null): mixed;
public function getInfo(string $type = null): mixed;
}

View File

@ -28,12 +28,6 @@ abstract class HttpClientTestCase extends TestCase
TestHttpServer::start();
}
public static function tearDownAfterClass(): void
{
TestHttpServer::stop(8067);
TestHttpServer::stop(8077);
}
abstract protected function getHttpClient(string $testCase): HttpClientInterface;
public function testGetRequest()

View File

@ -45,11 +45,4 @@ class TestHttpServer
return $process;
}
public static function stop(int $port = 8057)
{
if (isset(self::$process[$port])) {
self::$process[$port]->stop();
}
}
}

View File

@ -27,7 +27,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "3.5-dev"
"dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",

View File

@ -51,9 +51,6 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
private ?LoggerInterface $logger = null;
private int $maxHostConnections;
private int $maxPendingPushes;
/**
* An internal object to share state between the client and its responses.
*/
@ -72,22 +69,18 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\CurlHttpClient" as the "curl" extension is not installed.');
}
$this->maxHostConnections = $maxHostConnections;
$this->maxPendingPushes = $maxPendingPushes;
$this->defaultOptions['buffer'] ??= self::shouldBuffer(...);
if ($defaultOptions) {
[, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions);
}
$this->multi = new CurlClientState($maxHostConnections, $maxPendingPushes);
}
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
if (isset($this->multi)) {
$this->multi->logger = $logger;
}
$this->logger = $this->multi->logger = $logger;
}
/**
@ -95,8 +88,6 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
*/
public function request(string $method, string $url, array $options = []): ResponseInterface
{
$multi = $this->ensureState();
[$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions);
$scheme = $url['scheme'];
$authority = $url['authority'];
@ -174,24 +165,24 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
}
// curl's resolve feature varies by host:port but ours varies by host only, let's handle this with our own DNS map
if (isset($multi->dnsCache->hostnames[$host])) {
$options['resolve'] += [$host => $multi->dnsCache->hostnames[$host]];
if (isset($this->multi->dnsCache->hostnames[$host])) {
$options['resolve'] += [$host => $this->multi->dnsCache->hostnames[$host]];
}
if ($options['resolve'] || $multi->dnsCache->evictions) {
if ($options['resolve'] || $this->multi->dnsCache->evictions) {
// First reset any old DNS cache entries then add the new ones
$resolve = $multi->dnsCache->evictions;
$multi->dnsCache->evictions = [];
$resolve = $this->multi->dnsCache->evictions;
$this->multi->dnsCache->evictions = [];
if ($resolve && 0x072A00 > CurlClientState::$curlVersion['version_number']) {
// DNS cache removals require curl 7.42 or higher
$multi->reset();
$this->multi->reset();
}
foreach ($options['resolve'] as $host => $ip) {
$resolve[] = null === $ip ? "-$host:$port" : "$host:$port:$ip";
$multi->dnsCache->hostnames[$host] = $ip;
$multi->dnsCache->removals["-$host:$port"] = "-$host:$port";
$this->multi->dnsCache->hostnames[$host] = $ip;
$this->multi->dnsCache->removals["-$host:$port"] = "-$host:$port";
}
$curlopts[\CURLOPT_RESOLVE] = $resolve;
@ -250,8 +241,9 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
if (isset($options['normalized_headers']['content-length'][0])) {
$curlopts[\CURLOPT_INFILESIZE] = (int) substr($options['normalized_headers']['content-length'][0], \strlen('Content-Length: '));
} elseif (!isset($options['normalized_headers']['transfer-encoding'])) {
$curlopts[\CURLOPT_INFILESIZE] = -1;
}
if (!isset($options['normalized_headers']['transfer-encoding'])) {
$curlopts[\CURLOPT_HTTPHEADER][] = 'Transfer-Encoding:'.(isset($curlopts[\CURLOPT_INFILESIZE]) ? '' : ' chunked');
}
if ('POST' !== $method) {
@ -293,8 +285,8 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
$curlopts += $options['extra']['curl'];
}
if ($pushedResponse = $multi->pushedResponses[$url] ?? null) {
unset($multi->pushedResponses[$url]);
if ($pushedResponse = $this->multi->pushedResponses[$url] ?? null) {
unset($this->multi->pushedResponses[$url]);
if (self::acceptPushForRequest($method, $options, $pushedResponse)) {
$this->logger?->debug(sprintf('Accepting pushed response: "%s %s"', $method, $url));
@ -302,7 +294,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
// Reinitialize the pushed response with request's options
$ch = $pushedResponse->handle;
$pushedResponse = $pushedResponse->response;
$pushedResponse->__construct($multi, $url, $options, $this->logger);
$pushedResponse->__construct($this->multi, $url, $options, $this->logger);
} else {
$this->logger?->debug(sprintf('Rejecting pushed response: "%s"', $url));
$pushedResponse = null;
@ -312,7 +304,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
if (!$pushedResponse) {
$ch = curl_init();
$this->logger?->info(sprintf('Request: "%s %s"', $method, $url));
$curlopts += [\CURLOPT_SHARE => $multi->share];
$curlopts += [\CURLOPT_SHARE => $this->multi->share];
}
foreach ($curlopts as $opt => $value) {
@ -322,7 +314,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
}
}
return $pushedResponse ?? new CurlResponse($multi, $ch, $options, $this->logger, $method, self::createRedirectResolver($options, $host, $port), CurlClientState::$curlVersion['version_number'], $url);
return $pushedResponse ?? new CurlResponse($this->multi, $ch, $options, $this->logger, $method, self::createRedirectResolver($options, $host, $port), CurlClientState::$curlVersion['version_number'], $url);
}
public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
@ -331,11 +323,9 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
$responses = [$responses];
}
$multi = $this->ensureState();
if ($multi->handle instanceof \CurlMultiHandle) {
if ($this->multi->handle instanceof \CurlMultiHandle) {
$active = 0;
while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($multi->handle, $active)) {
while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->multi->handle, $active)) {
}
}
@ -344,9 +334,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
public function reset(): void
{
if (isset($this->multi)) {
$this->multi->reset();
}
$this->multi->reset();
}
/**
@ -446,16 +434,6 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
};
}
private function ensureState(): CurlClientState
{
if (!isset($this->multi)) {
$this->multi = new CurlClientState($this->maxHostConnections, $this->maxPendingPushes);
$this->multi->logger = $this->logger;
}
return $this->multi;
}
private function findConstantName(int $opt): ?string
{
$constants = array_filter(get_defined_constants(), static fn ($v, $k) => $v === $opt && 'C' === $k[0] && (str_starts_with($k, 'CURLOPT_') || str_starts_with($k, 'CURLINFO_')), \ARRAY_FILTER_USE_BOTH);

View File

@ -121,7 +121,7 @@ final class EventSourceHttpClient implements HttpClientInterface, ResetInterface
return;
}
$rx = '/((?:\r\n){2,}|\r{2,}|\n{2,})/';
$rx = '/((?:\r\n|[\r\n]){2,})/';
$content = $state->buffer.$chunk->getContent();
if ($chunk->isLast()) {

View File

@ -21,7 +21,7 @@ class JsonMockResponse extends MockResponse
public function __construct(mixed $body = [], array $info = [])
{
try {
$json = json_encode($body, \JSON_THROW_ON_ERROR | \JSON_PRESERVE_ZERO_FRACTION);
$json = json_encode($body, \JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
throw new InvalidArgumentException('JSON encoding failed: '.$e->getMessage(), $e->getCode(), $e);
}

View File

@ -25,7 +25,7 @@
"php": ">=8.1",
"psr/log": "^1|^2|^3",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/http-client-contracts": "^3.4.1",
"symfony/http-client-contracts": "^3",
"symfony/service-contracts": "^2.5|^3"
},
"require-dev": {
@ -33,7 +33,7 @@
"amphp/http-client": "^4.2.1",
"amphp/http-tunnel": "^1.0",
"amphp/socket": "^1.1",
"guzzlehttp/promises": "^1.4|^2.0",
"guzzlehttp/promises": "^1.4",
"nyholm/psr7": "^1.0",
"php-http/httplug": "^1.0|^2.0",
"psr/http-client": "^1.0",

View File

@ -286,7 +286,11 @@ class HeaderUtils
}
foreach ($partMatches as $matches) {
$parts[] = '' === $separators ? self::unquote($matches[0][0]) : self::groupParts($matches, $separators, false);
if ('' === $separators && '' !== $unquoted = self::unquote($matches[0][0])) {
$parts[] = $unquoted;
} elseif ($groupedParts = self::groupParts($matches, $separators, false)) {
$parts[] = $groupedParts;
}
}
return $parts;

View File

@ -130,11 +130,11 @@ class Message extends RawMessage
*/
public function ensureValidity()
{
if (!$this->headers->has('To') && !$this->headers->has('Cc') && !$this->headers->has('Bcc')) {
if (!$this->headers->get('To')?->getBody() && !$this->headers->get('Cc')?->getBody() && !$this->headers->get('Bcc')?->getBody()) {
throw new LogicException('An email must have a "To", "Cc", or "Bcc" header.');
}
if (!$this->headers->has('From') && !$this->headers->has('Sender')) {
if (!$this->headers->get('From')?->getBody() && !$this->headers->get('Sender')?->getBody()) {
throw new LogicException('An email must have a "From" or a "Sender" header.');
}

View File

@ -123,7 +123,11 @@ class TextPart extends AbstractPart
public function getBody(): string
{
if ($this->body instanceof File) {
return file_get_contents($this->body->getPath());
if (false === $ret = @file_get_contents($this->body->getPath())) {
throw new InvalidArgumentException(error_get_last()['message']);
}
return $ret;
}
if (null === $this->seekable) {

View File

@ -280,10 +280,6 @@ final class Idn
switch ($data['status']) {
case 'disallowed':
$info->errors |= self::ERROR_DISALLOWED;
// no break.
case 'valid':
$str .= mb_chr($codePoint, 'utf-8');
@ -294,7 +290,7 @@ final class Idn
break;
case 'mapped':
$str .= $data['mapping'];
$str .= $transitional && 0x1E9E === $codePoint ? 'ss' : $data['mapping'];
break;
@ -346,6 +342,18 @@ final class Idn
$validationOptions = $options;
if ('xn--' === substr($label, 0, 4)) {
// Step 4.1. If the label contains any non-ASCII code point (i.e., a code point greater than U+007F),
// record that there was an error, and continue with the next label.
if (preg_match('/[^\x00-\x7F]/', $label)) {
$info->errors |= self::ERROR_PUNYCODE;
continue;
}
// Step 4.2. Attempt to convert the rest of the label to Unicode according to Punycode [RFC3492]. If
// that conversion fails, record that there was an error, and continue
// with the next label. Otherwise replace the original label in the string by the results of the
// conversion.
try {
$label = self::punycodeDecode(substr($label, 4));
} catch (\Exception $e) {
@ -516,6 +524,8 @@ final class Idn
if ('-' === substr($label, -1, 1)) {
$info->errors |= self::ERROR_TRAILING_HYPHEN;
}
} elseif ('xn--' === substr($label, 0, 4)) {
$info->errors |= self::ERROR_PUNYCODE;
}
// Step 4. The label must not contain a U+002E (.) FULL STOP.

View File

@ -32,7 +32,7 @@ if (\PHP_VERSION_ID >= 70400 && extension_loaded('curl')) {
}
if (is_object($value) ? !method_exists($value, '__toString') : !is_scalar($value)) {
throw new \TypeError('Cannot assign '.gettype($value).' to property CURLStringFile::$data of type string');
throw new TypeError('Cannot assign '.gettype($value).' to property CURLStringFile::$data of type string');
}
$this->name = 'data://application/octet-stream;base64,'.base64_encode($value);

View File

@ -40,7 +40,7 @@ final class Php83
return \JSON_ERROR_NONE === json_last_error();
}
public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, string $encoding = null): string
public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string
{
if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
@ -90,17 +90,17 @@ final class Php83
throw new \ValueError('str_increment(): Argument #1 ($string) cannot be empty');
}
if (!\preg_match("/^[a-zA-Z0-9]+$/", $string)) {
if (!preg_match('/^[a-zA-Z0-9]+$/', $string)) {
throw new \ValueError('str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters');
}
if (\is_numeric($string)) {
if (is_numeric($string)) {
$offset = stripos($string, 'e');
if ($offset !== false) {
if (false !== $offset) {
$char = $string[$offset];
$char++;
++$char;
$string[$offset] = $char;
$string++;
++$string;
switch ($string[$offset]) {
case 'f':
@ -130,28 +130,28 @@ final class Php83
throw new \ValueError('str_decrement(): Argument #1 ($string) cannot be empty');
}
if (!\preg_match("/^[a-zA-Z0-9]+$/", $string)) {
if (!preg_match('/^[a-zA-Z0-9]+$/', $string)) {
throw new \ValueError('str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters');
}
if (\preg_match('/\A(?:0[aA0]?|[aA])\z/', $string)) {
if (preg_match('/\A(?:0[aA0]?|[aA])\z/', $string)) {
throw new \ValueError(sprintf('str_decrement(): Argument #1 ($string) "%s" is out of decrement range', $string));
}
if (!\in_array(substr($string, -1), ['A', 'a', '0'], true)) {
return join('', array_slice(str_split($string), 0, -1)) . chr(ord(substr($string, -1)) - 1);
return implode('', \array_slice(str_split($string), 0, -1)).\chr(\ord(substr($string, -1)) - 1);
}
$carry = '';
$decremented = '';
for ($i = strlen($string) - 1; $i >= 0; $i--) {
for ($i = \strlen($string) - 1; $i >= 0; --$i) {
$char = $string[$i];
switch ($char) {
case 'A':
if ('' !== $carry) {
$decremented = $carry . $decremented;
$decremented = $carry.$decremented;
$carry = '';
}
$carry = 'Z';
@ -159,7 +159,7 @@ final class Php83
break;
case 'a':
if ('' !== $carry) {
$decremented = $carry . $decremented;
$decremented = $carry.$decremented;
$carry = '';
}
$carry = 'z';
@ -167,7 +167,7 @@ final class Php83
break;
case '0':
if ('' !== $carry) {
$decremented = $carry . $decremented;
$decremented = $carry.$decremented;
$carry = '';
}
$carry = '9';
@ -175,19 +175,19 @@ final class Php83
break;
case '1':
if ('' !== $carry) {
$decremented = $carry . $decremented;
$decremented = $carry.$decremented;
$carry = '';
}
break;
default:
if ('' !== $carry) {
$decremented = $carry . $decremented;
$decremented = $carry.$decremented;
$carry = '';
}
if (!\in_array($char, ['A', 'a', '0'], true)) {
$decremented = chr(ord($char) - 1) . $decremented;
$decremented = \chr(\ord($char) - 1).$decremented;
}
}
}

View File

@ -40,7 +40,7 @@ if (\PHP_VERSION_ID >= 80100) {
}
if (!function_exists('ldap_exop_sync') && function_exists('ldap_exop')) {
function ldap_exop_sync($ldap, string $request_oid, string $request_data = null, array $controls = null, &$response_data = null, &$response_oid = null): bool { return ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data, $response_oid); }
function ldap_exop_sync($ldap, string $request_oid, ?string $request_data = null, ?array $controls = null, &$response_data = null, &$response_oid = null): bool { return ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data, $response_oid); }
}
if (!function_exists('ldap_connect_wallet') && function_exists('ldap_connect')) {

View File

@ -14,7 +14,7 @@ if (\PHP_VERSION_ID >= 80300) {
}
if (!function_exists('ldap_exop_sync') && function_exists('ldap_exop')) {
function ldap_exop_sync(\LDAP\Connection $ldap, string $request_oid, string $request_data = null, array $controls = null, &$response_data = null, &$response_oid = null): bool { return ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data, $response_oid); }
function ldap_exop_sync(\LDAP\Connection $ldap, string $request_oid, ?string $request_data = null, ?array $controls = null, &$response_data = null, &$response_oid = null): bool { return ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data, $response_oid); }
}
if (!function_exists('ldap_connect_wallet') && function_exists('ldap_connect')) {

View File

@ -16,8 +16,7 @@
}
],
"require": {
"php": ">=7.1",
"symfony/polyfill-php80": "^1.14"
"php": ">=7.1"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Php83\\": "" },

View File

@ -0,0 +1,25 @@
<?php
return (new PhpCsFixer\Config())
->setRules([
'@Symfony' => true,
'@Symfony:risky' => true,
'@PHPUnit48Migration:risky' => true,
'php_unit_no_expectation_annotation' => false, // part of `PHPUnitXYMigration:risky` ruleset, to be enabled when PHPUnit 4.x support will be dropped, as we don't want to rewrite exceptions handling twice
'array_syntax' => ['syntax' => 'short'],
'fopen_flags' => false,
'ordered_imports' => true,
'protected_to_private' => false,
// Part of @Symfony:risky in PHP-CS-Fixer 2.13.0. To be removed from the config file once upgrading
'native_function_invocation' => ['include' => ['@compiler_optimized'], 'scope' => 'namespaced'],
// Part of future @Symfony ruleset in PHP-CS-Fixer To be removed from the config file once upgrading
'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'],
])
->setRiskyAllowed(true)
->setFinder(
(new PhpCsFixer\Finder())
->in(__DIR__)
->exclude('vendor')
->name('*.php')
)
;

View File

@ -16,7 +16,8 @@ use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface as BaseValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
/**
@ -25,7 +26,7 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
* @author Iltar van der Berg <kjarli@gmail.com>
* @author Alexander M. Turek <me@derrabus.de>
*/
final class PsrServerRequestResolver implements ValueResolverInterface
final class PsrServerRequestResolver implements ArgumentValueResolverInterface, ValueResolverInterface
{
private const SUPPORTED_TYPES = [
ServerRequestInterface::class => true,
@ -33,11 +34,28 @@ final class PsrServerRequestResolver implements ValueResolverInterface
MessageInterface::class => true,
];
public function __construct(
private readonly HttpMessageFactoryInterface $httpMessageFactory,
) {
private $httpMessageFactory;
public function __construct(HttpMessageFactoryInterface $httpMessageFactory)
{
$this->httpMessageFactory = $httpMessageFactory;
}
/**
* {@inheritdoc}
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
if ($this instanceof BaseValueResolverInterface) {
trigger_deprecation('symfony/psr-http-message-bridge', '2.3', 'Method "%s" is deprecated, call "resolve()" without calling "supports()" first.', __METHOD__);
}
return self::SUPPORTED_TYPES[$argument->getType()] ?? false;
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument): \Traversable
{
if (!isset(self::SUPPORTED_TYPES[$argument->getType()])) {

View File

@ -0,0 +1,26 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PsrHttpMessage\ArgumentValueResolver;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface as BaseValueResolverInterface;
if (interface_exists(BaseValueResolverInterface::class)) {
/** @internal */
interface ValueResolverInterface extends BaseValueResolverInterface
{
}
} else {
/** @internal */
interface ValueResolverInterface
{
}
}

View File

@ -1,109 +1,85 @@
CHANGELOG
=========
6.4
---
# 2.3.1 (2023-07-26)
* Import the bridge into the Symfony monorepo and synchronize releases
* Remove `ArgumentValueResolverInterface` from `PsrServerRequestResolver`
* Support `php-http/discovery` for auto-detecting PSR-17 factories
* Don't rely on `Request::getPayload()` to populate the parsed body
2.3.1
-----
# 2.3.0 (2023-07-25)
* Don't rely on `Request::getPayload()` to populate the parsed body
* Leverage `Request::getPayload()` to populate the parsed body of PSR-7 requests
* Implement `ValueResolverInterface` introduced with Symfony 6.2
2.3.0
-----
# 2.2.0 (2023-04-21)
* Leverage `Request::getPayload()` to populate the parsed body of PSR-7 requests
* Implement `ValueResolverInterface` introduced with Symfony 6.2
* Drop support for Symfony 4
* Bump minimum version of PHP to 7.2
* Support version 2 of the psr/http-message contracts
2.2.0
-----
# 2.1.3 (2022-09-05)
* Drop support for Symfony 4
* Bump minimum version of PHP to 7.2
* Support version 2 of the psr/http-message contracts
* Ignore invalid HTTP headers when creating PSR7 objects
* Fix for wrong type passed to `moveTo()`
2.1.3
-----
# 2.1.2 (2021-11-05)
* Ignore invalid HTTP headers when creating PSR7 objects
* Fix for wrong type passed to `moveTo()`
* Allow Symfony 6
2.1.2
-----
# 2.1.0 (2021-02-17)
* Allow Symfony 6
* Added a `PsrResponseListener` to automatically convert PSR-7 responses returned by controllers
* Added a `PsrServerRequestResolver` that allows injecting PSR-7 request objects into controllers
2.1.0
-----
# 2.0.2 (2020-09-29)
* Added a `PsrResponseListener` to automatically convert PSR-7 responses returned by controllers
* Added a `PsrServerRequestResolver` that allows injecting PSR-7 request objects into controllers
* Fix populating server params from URI in HttpFoundationFactory
* Create cookies as raw in HttpFoundationFactory
* Fix BinaryFileResponse with Content-Range PsrHttpFactory
2.0.2
-----
# 2.0.1 (2020-06-25)
* Fix populating server params from URI in HttpFoundationFactory
* Create cookies as raw in HttpFoundationFactory
* Fix BinaryFileResponse with Content-Range PsrHttpFactory
* Don't normalize query string in PsrHttpFactory
* Fix conversion for HTTPS requests
* Fix populating default port and headers in HttpFoundationFactory
2.0.1
-----
# 2.0.0 (2020-01-02)
* Don't normalize query string in PsrHttpFactory
* Fix conversion for HTTPS requests
* Fix populating default port and headers in HttpFoundationFactory
* Remove DiactorosFactory
2.0.0
-----
# 1.3.0 (2019-11-25)
* Remove DiactorosFactory
* Added support for streamed requests
* Added support for Symfony 5.0+
* Fixed bridging UploadedFile objects
* Bumped minimum version of Symfony to 4.4
1.3.0
-----
# 1.2.0 (2019-03-11)
* Added support for streamed requests
* Added support for Symfony 5.0+
* Fixed bridging UploadedFile objects
* Bumped minimum version of Symfony to 4.4
* Added new documentation links
* Bumped minimum version of PHP to 7.1
* Added support for streamed responses
1.2.0
-----
# 1.1.2 (2019-04-03)
* Added new documentation links
* Bumped minimum version of PHP to 7.1
* Added support for streamed responses
* Fixed createResponse
1.1.2
-----
# 1.1.1 (2019-03-11)
* Fixed createResponse
* Deprecated DiactorosFactory, use PsrHttpFactory instead
* Removed triggering of deprecation
1.1.1
-----
# 1.1.0 (2018-08-30)
* Deprecated DiactorosFactory, use PsrHttpFactory instead
* Removed triggering of deprecation
* Added support for creating PSR-7 messages using PSR-17 factories
1.1.0
-----
# 1.0.2 (2017-12-19)
* Added support for creating PSR-7 messages using PSR-17 factories
* Fixed request target in PSR7 Request (mtibben)
1.0.2
-----
# 1.0.1 (2017-12-04)
* Fixed request target in PSR7 Request (mtibben)
* Added support for Symfony 4 (dunglas)
1.0.1
-----
# 1.0.0 (2016-09-14)
* Added support for Symfony 4 (dunglas)
1.0.0
-----
* Initial release
* Initial release

View File

@ -1,14 +1,5 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PsrHttpMessage\EventListener;
use Psr\Http\Message\ResponseInterface;
@ -26,9 +17,9 @@ use Symfony\Component\HttpKernel\KernelEvents;
*/
final class PsrResponseListener implements EventSubscriberInterface
{
private readonly HttpFoundationFactoryInterface $httpFoundationFactory;
private $httpFoundationFactory;
public function __construct(?HttpFoundationFactoryInterface $httpFoundationFactory = null)
public function __construct(HttpFoundationFactoryInterface $httpFoundationFactory = null)
{
$this->httpFoundationFactory = $httpFoundationFactory ?? new HttpFoundationFactory();
}
@ -47,6 +38,9 @@ final class PsrResponseListener implements EventSubscriberInterface
$event->setResponse($this->httpFoundationFactory->createResponse($controllerResult));
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array
{
return [

View File

@ -23,19 +23,28 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
/**
* {@inheritdoc}
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class HttpFoundationFactory implements HttpFoundationFactoryInterface
{
/**
* @param int $responseBufferMaxLength The maximum output buffering size for each iteration when sending the response
* @var int The maximum output buffering size for each iteration when sending the response
*/
public function __construct(
private readonly int $responseBufferMaxLength = 16372,
) {
private $responseBufferMaxLength;
public function __construct(int $responseBufferMaxLength = 16372)
{
$this->responseBufferMaxLength = $responseBufferMaxLength;
}
public function createRequest(ServerRequestInterface $psrRequest, bool $streamed = false): Request
/**
* {@inheritdoc}
*
* @return Request
*/
public function createRequest(ServerRequestInterface $psrRequest, bool $streamed = false)
{
$server = [];
$uri = $psrRequest->getUri();
@ -104,13 +113,20 @@ class HttpFoundationFactory implements HttpFoundationFactoryInterface
/**
* Gets a temporary file path.
*
* @return string
*/
protected function getTemporaryPath(): string
protected function getTemporaryPath()
{
return tempnam(sys_get_temp_dir(), uniqid('symfony', true));
}
public function createResponse(ResponseInterface $psrResponse, bool $streamed = false): Response
/**
* {@inheritdoc}
*
* @return Response
*/
public function createResponse(ResponseInterface $psrResponse, bool $streamed = false)
{
$cookies = $psrResponse->getHeader('Set-Cookie');
$psrResponse = $psrResponse->withoutHeader('Set-Cookie');

View File

@ -11,8 +11,6 @@
namespace Symfony\Bridge\PsrHttpMessage\Factory;
use Http\Discovery\Psr17Factory as DiscoveryPsr17Factory;
use Nyholm\Psr7\Factory\Psr17Factory as NyholmPsr17Factory;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestFactoryInterface;
@ -35,37 +33,25 @@ use Symfony\Component\HttpFoundation\StreamedResponse;
*/
class PsrHttpFactory implements HttpMessageFactoryInterface
{
private readonly ServerRequestFactoryInterface $serverRequestFactory;
private readonly StreamFactoryInterface $streamFactory;
private readonly UploadedFileFactoryInterface $uploadedFileFactory;
private readonly ResponseFactoryInterface $responseFactory;
public function __construct(
?ServerRequestFactoryInterface $serverRequestFactory = null,
?StreamFactoryInterface $streamFactory = null,
?UploadedFileFactoryInterface $uploadedFileFactory = null,
?ResponseFactoryInterface $responseFactory = null,
) {
if (null === $serverRequestFactory || null === $streamFactory || null === $uploadedFileFactory || null === $responseFactory) {
$psr17Factory = match (true) {
class_exists(DiscoveryPsr17Factory::class) => new DiscoveryPsr17Factory(),
class_exists(NyholmPsr17Factory::class) => new NyholmPsr17Factory(),
default => throw new \LogicException(sprintf('You cannot use the "%s" as no PSR-17 factories have been provided. Try running "composer require php-http/discovery psr/http-factory-implementation:*".', self::class)),
};
$serverRequestFactory ??= $psr17Factory;
$streamFactory ??= $psr17Factory;
$uploadedFileFactory ??= $psr17Factory;
$responseFactory ??= $psr17Factory;
}
private $serverRequestFactory;
private $streamFactory;
private $uploadedFileFactory;
private $responseFactory;
public function __construct(ServerRequestFactoryInterface $serverRequestFactory, StreamFactoryInterface $streamFactory, UploadedFileFactoryInterface $uploadedFileFactory, ResponseFactoryInterface $responseFactory)
{
$this->serverRequestFactory = $serverRequestFactory;
$this->streamFactory = $streamFactory;
$this->uploadedFileFactory = $uploadedFileFactory;
$this->responseFactory = $responseFactory;
}
public function createRequest(Request $symfonyRequest): ServerRequestInterface
/**
* {@inheritdoc}
*
* @return ServerRequestInterface
*/
public function createRequest(Request $symfonyRequest)
{
$uri = $symfonyRequest->server->get('QUERY_STRING', '');
$uri = $symfonyRequest->getSchemeAndHttpHost().$symfonyRequest->getBaseUrl().$symfonyRequest->getPathInfo().('' !== $uri ? '?'.$uri : '');
@ -155,7 +141,12 @@ class PsrHttpFactory implements HttpMessageFactoryInterface
);
}
public function createResponse(Response $symfonyResponse): ResponseInterface
/**
* {@inheritdoc}
*
* @return ResponseInterface
*/
public function createResponse(Response $symfonyResponse)
{
$response = $this->responseFactory->createResponse($symfonyResponse->getStatusCode(), Response::$statusTexts[$symfonyResponse->getStatusCode()] ?? '');

View File

@ -21,12 +21,11 @@ use Symfony\Component\HttpFoundation\File\UploadedFile as BaseUploadedFile;
*/
class UploadedFile extends BaseUploadedFile
{
private bool $test = false;
private $psrUploadedFile;
private $test = false;
public function __construct(
private readonly UploadedFileInterface $psrUploadedFile,
callable $getTemporaryPath,
) {
public function __construct(UploadedFileInterface $psrUploadedFile, callable $getTemporaryPath)
{
$error = $psrUploadedFile->getError();
$path = '';
@ -46,9 +45,14 @@ class UploadedFile extends BaseUploadedFile
$psrUploadedFile->getError(),
$this->test
);
$this->psrUploadedFile = $psrUploadedFile;
}
public function move(string $directory, ?string $name = null): File
/**
* {@inheritdoc}
*/
public function move(string $directory, string $name = null): File
{
if (!$this->isValid() || $this->test) {
return parent::move($directory, $name);
@ -59,7 +63,7 @@ class UploadedFile extends BaseUploadedFile
try {
$this->psrUploadedFile->moveTo((string) $target);
} catch (\RuntimeException $e) {
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, $e->getMessage()), 0, $e);
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, $e->getMessage()), 0, $e);
}
@chmod($target, 0666 & ~umask());

View File

@ -25,11 +25,15 @@ interface HttpFoundationFactoryInterface
{
/**
* Creates a Symfony Request instance from a PSR-7 one.
*
* @return Request
*/
public function createRequest(ServerRequestInterface $psrRequest, bool $streamed = false): Request;
public function createRequest(ServerRequestInterface $psrRequest, bool $streamed = false);
/**
* Creates a Symfony Response instance from a PSR-7 one.
*
* @return Response
*/
public function createResponse(ResponseInterface $psrResponse, bool $streamed = false): Response;
public function createResponse(ResponseInterface $psrResponse, bool $streamed = false);
}

View File

@ -25,11 +25,15 @@ interface HttpMessageFactoryInterface
{
/**
* Creates a PSR-7 Request instance from a Symfony one.
*
* @return ServerRequestInterface
*/
public function createRequest(Request $symfonyRequest): ServerRequestInterface;
public function createRequest(Request $symfonyRequest);
/**
* Creates a PSR-7 Response instance from a Symfony one.
*
* @return ResponseInterface
*/
public function createResponse(Response $symfonyResponse): ResponseInterface;
public function createResponse(Response $symfonyResponse);
}

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-present Fabien Potencier
Copyright (c) 2004-2021 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -6,8 +6,14 @@ Provides integration for PSR7.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/psr7.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)
* [Documentation](https://symfony.com/doc/current/components/psr7.html)
Running the tests
-----------------
If you want to run the unit tests, install dev dependencies before
running PHPUnit:
$ cd path/to/Symfony/Bridge/PsrHttpMessage/
$ composer.phar install
$ phpunit

View File

@ -3,7 +3,7 @@
"type": "symfony-bridge",
"description": "PSR HTTP message bridge",
"keywords": ["http", "psr-7", "psr-17", "http-message"],
"homepage": "https://symfony.com",
"homepage": "http://symfony.com",
"license": "MIT",
"authors": [
{
@ -12,32 +12,27 @@
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
"homepage": "http://symfony.com/contributors"
}
],
"require": {
"php": ">=8.1",
"psr/http-message": "^1.0|^2.0",
"symfony/http-foundation": "^5.4|^6.0|^7.0"
"php": ">=7.2.5",
"psr/http-message": "^1.0 || ^2.0",
"symfony/deprecation-contracts": "^2.5 || ^3.0",
"symfony/http-foundation": "^5.4 || ^6.0"
},
"require-dev": {
"symfony/browser-kit": "^5.4|^6.0|^7.0",
"symfony/config": "^5.4|^6.0|^7.0",
"symfony/event-dispatcher": "^5.4|^6.0|^7.0",
"symfony/framework-bundle": "^6.2|^7.0",
"symfony/http-kernel": "^6.2|^7.0",
"symfony/browser-kit": "^5.4 || ^6.0",
"symfony/config": "^5.4 || ^6.0",
"symfony/event-dispatcher": "^5.4 || ^6.0",
"symfony/framework-bundle": "^5.4 || ^6.0",
"symfony/http-kernel": "^5.4 || ^6.0",
"symfony/phpunit-bridge": "^6.2",
"nyholm/psr7": "^1.1",
"php-http/discovery": "^1.15",
"psr/log": "^1.1.4|^2|^3"
"psr/log": "^1.1 || ^2 || ^3"
},
"conflict": {
"php-http/discovery": "<1.15",
"symfony/http-kernel": "<6.2"
},
"config": {
"allow-plugins": {
"php-http/discovery": false
}
"suggest": {
"nyholm/psr7": "For a super lightweight PSR-7/17 implementation"
},
"autoload": {
"psr-4": { "Symfony\\Bridge\\PsrHttpMessage\\": "" },
@ -45,5 +40,9 @@
"/Tests/"
]
},
"minimum-stability": "dev"
"extra": {
"branch-alias": {
"dev-main": "2.3-dev"
}
}
}

View File

@ -0,0 +1,3 @@
vendor/
composer.lock
phpunit.xml

View File

@ -11,15 +11,10 @@
namespace Symfony\Contracts\Service\Attribute;
use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
use Symfony\Contracts\Service\ServiceSubscriberTrait;
/**
* For use as the return value for {@see ServiceSubscriberInterface}.
*
* @example new SubscribedService('http_client', HttpClientInterface::class, false, new Target('githubApi'))
*
* Use with {@see ServiceMethodsSubscriberTrait} to mark a method's return type
* Use with {@see ServiceSubscriberTrait} to mark a method's return type
* as a subscribed service.
*
* @author Kevin Bond <kevinbond@gmail.com>
@ -27,21 +22,12 @@ use Symfony\Contracts\Service\ServiceSubscriberInterface;
#[\Attribute(\Attribute::TARGET_METHOD)]
final class SubscribedService
{
/** @var object[] */
public array $attributes;
/**
* @param string|null $key The key to use for the service
* @param class-string|null $type The service class
* @param bool $nullable Whether the service is optional
* @param object|object[] $attributes One or more dependency injection attributes to use
* @param string|null $key The key to use for the service
* If null, use "ClassName::methodName"
*/
public function __construct(
public ?string $key = null,
public ?string $type = null,
public bool $nullable = false,
array|object $attributes = [],
public ?string $key = null
) {
$this->attributes = \is_array($attributes) ? $attributes : [$attributes];
}
}

View File

@ -1,4 +1,4 @@
Copyright (c) 2018-present Fabien Potencier
Copyright (c) 2018-2022 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -3,7 +3,7 @@ Symfony Service Contracts
A set of abstractions extracted out of the Symfony components.
Can be used to build on semantics that the Symfony components proved useful and
Can be used to build on semantics that the Symfony components proved useful - and
that already have battle tested implementations.
See https://github.com/symfony/contracts/blob/main/README.md for more information.

View File

@ -26,8 +26,5 @@ namespace Symfony\Contracts\Service;
*/
interface ResetInterface
{
/**
* @return void
*/
public function reset();
}

View File

@ -1,26 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Service;
/**
* A ServiceProviderInterface that is also countable and iterable.
*
* @author Kevin Bond <kevinbond@gmail.com>
*
* @template-covariant T of mixed
*
* @extends ServiceProviderInterface<T>
* @extends \IteratorAggregate<string, T>
*/
interface ServiceCollectionInterface extends ServiceProviderInterface, \Countable, \IteratorAggregate
{
}

View File

@ -26,24 +26,34 @@ class_exists(NotFoundExceptionInterface::class);
*/
trait ServiceLocatorTrait
{
private array $factories;
private array $loading = [];
private array $providedTypes;
private $factories;
private $loading = [];
private $providedTypes;
/**
* @param array<string, callable> $factories
* @param callable[] $factories
*/
public function __construct(array $factories)
{
$this->factories = $factories;
}
public function has(string $id): bool
/**
* {@inheritdoc}
*
* @return bool
*/
public function has(string $id)
{
return isset($this->factories[$id]);
}
public function get(string $id): mixed
/**
* {@inheritdoc}
*
* @return mixed
*/
public function get(string $id)
{
if (!isset($this->factories[$id])) {
throw $this->createNotFoundException($id);
@ -65,9 +75,12 @@ trait ServiceLocatorTrait
}
}
/**
* {@inheritdoc}
*/
public function getProvidedServices(): array
{
if (!isset($this->providedTypes)) {
if (null === $this->providedTypes) {
$this->providedTypes = [];
foreach ($this->factories as $name => $factory) {

View File

@ -1,80 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Contracts\Service;
use Psr\Container\ContainerInterface;
use Symfony\Contracts\Service\Attribute\Required;
use Symfony\Contracts\Service\Attribute\SubscribedService;
/**
* Implementation of ServiceSubscriberInterface that determines subscribed services
* from methods that have the #[SubscribedService] attribute.
*
* Service ids are available as "ClassName::methodName" so that the implementation
* of subscriber methods can be just `return $this->container->get(__METHOD__);`.
*
* @author Kevin Bond <kevinbond@gmail.com>
*/
trait ServiceMethodsSubscriberTrait
{
protected ContainerInterface $container;
public static function getSubscribedServices(): array
{
$services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : [];
foreach ((new \ReflectionClass(self::class))->getMethods() as $method) {
if (self::class !== $method->getDeclaringClass()->name) {
continue;
}
if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) {
continue;
}
if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {
throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name));
}
if (!$returnType = $method->getReturnType()) {
throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class));
}
/* @var SubscribedService $attribute */
$attribute = $attribute->newInstance();
$attribute->key ??= self::class.'::'.$method->name;
$attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType;
$attribute->nullable = $returnType->allowsNull();
if ($attribute->attributes) {
$services[] = $attribute;
} else {
$services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type;
}
}
return $services;
}
#[Required]
public function setContainer(ContainerInterface $container): ?ContainerInterface
{
$ret = null;
if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) {
$ret = parent::setContainer($container);
}
$this->container = $container;
return $ret;
}
}

Some files were not shown because too many files have changed in this diff Show More