Changeset 3752647
- Timestamp:
- 10/18/2026 07:01:52 AM (6 days ago)
- Location:
- wp-otp/trunk
- Files:
-
- 94 added
- 39 deleted
- 66 edited
-
. (modified) (1 prop)
-
admin/class-wp-otp-admin.php (modified) (10 diffs)
-
admin/css/wp-otp-admin.css (modified) (2 diffs)
-
admin/images/authenticator.png (added)
-
admin/images/mozilla-firefox.png (added)
-
admin/images/ms-edge.png (added)
-
admin/images/play-store.png (modified) ( previous)
-
admin/partials/wp-otp-profile-display.php (modified) (3 diffs)
-
includes/class-wp-otp-user-meta.php (modified) (2 diffs)
-
public/class-wp-otp-public.php (modified) (8 diffs)
-
readme.txt (modified) (9 diffs)
-
vendor/autoload.php (modified) (1 diff)
-
vendor/beberlei (deleted)
-
vendor/chillerlan/php-qrcode/.github (deleted)
-
vendor/chillerlan/php-qrcode/.gitignore (deleted)
-
vendor/chillerlan/php-qrcode/.phan (deleted)
-
vendor/chillerlan/php-qrcode/.scrutinizer.yml (deleted)
-
vendor/chillerlan/php-qrcode/.travis.yml (deleted)
-
vendor/chillerlan/php-qrcode/LICENSE (deleted)
-
vendor/chillerlan/php-qrcode/LICENSE-ASL-2.0 (added)
-
vendor/chillerlan/php-qrcode/LICENSE-MIT (added)
-
vendor/chillerlan/php-qrcode/NOTICE (added)
-
vendor/chillerlan/php-qrcode/README.md (modified) (2 diffs)
-
vendor/chillerlan/php-qrcode/composer.json (modified) (2 diffs)
-
vendor/chillerlan/php-qrcode/docs (deleted)
-
vendor/chillerlan/php-qrcode/examples (deleted)
-
vendor/chillerlan/php-qrcode/phpdoc.xml (deleted)
-
vendor/chillerlan/php-qrcode/phpmd.xml (deleted)
-
vendor/chillerlan/php-qrcode/phpunit.xml (deleted)
-
vendor/chillerlan/php-qrcode/public (deleted)
-
vendor/chillerlan/php-qrcode/src/Common (added)
-
vendor/chillerlan/php-qrcode/src/Common/BitBuffer.php (added)
-
vendor/chillerlan/php-qrcode/src/Common/ECICharset.php (added)
-
vendor/chillerlan/php-qrcode/src/Common/EccLevel.php (added)
-
vendor/chillerlan/php-qrcode/src/Common/GDLuminanceSource.php (added)
-
vendor/chillerlan/php-qrcode/src/Common/GF256.php (added)
-
vendor/chillerlan/php-qrcode/src/Common/GenericGFPoly.php (added)
-
vendor/chillerlan/php-qrcode/src/Common/IMagickLuminanceSource.php (added)
-
vendor/chillerlan/php-qrcode/src/Common/LuminanceSourceAbstract.php (added)
-
vendor/chillerlan/php-qrcode/src/Common/LuminanceSourceInterface.php (added)
-
vendor/chillerlan/php-qrcode/src/Common/MaskPattern.php (added)
-
vendor/chillerlan/php-qrcode/src/Common/Mode.php (added)
-
vendor/chillerlan/php-qrcode/src/Common/Version.php (added)
-
vendor/chillerlan/php-qrcode/src/Data/AlphaNum.php (modified) (2 diffs)
-
vendor/chillerlan/php-qrcode/src/Data/Byte.php (modified) (1 diff)
-
vendor/chillerlan/php-qrcode/src/Data/ECI.php (added)
-
vendor/chillerlan/php-qrcode/src/Data/Hanzi.php (added)
-
vendor/chillerlan/php-qrcode/src/Data/Kanji.php (modified) (1 diff)
-
vendor/chillerlan/php-qrcode/src/Data/MaskPatternTester.php (deleted)
-
vendor/chillerlan/php-qrcode/src/Data/Number.php (modified) (4 diffs)
-
vendor/chillerlan/php-qrcode/src/Data/QRCodeDataException.php (modified) (2 diffs)
-
vendor/chillerlan/php-qrcode/src/Data/QRData.php (added)
-
vendor/chillerlan/php-qrcode/src/Data/QRDataAbstract.php (deleted)
-
vendor/chillerlan/php-qrcode/src/Data/QRDataInterface.php (deleted)
-
vendor/chillerlan/php-qrcode/src/Data/QRDataModeAbstract.php (added)
-
vendor/chillerlan/php-qrcode/src/Data/QRDataModeInterface.php (added)
-
vendor/chillerlan/php-qrcode/src/Data/QRMatrix.php (modified) (18 diffs)
-
vendor/chillerlan/php-qrcode/src/Data/ReedSolomonEncoder.php (added)
-
vendor/chillerlan/php-qrcode/src/Decoder (added)
-
vendor/chillerlan/php-qrcode/src/Decoder/Binarizer.php (added)
-
vendor/chillerlan/php-qrcode/src/Decoder/BitMatrix.php (added)
-
vendor/chillerlan/php-qrcode/src/Decoder/Decoder.php (added)
-
vendor/chillerlan/php-qrcode/src/Decoder/DecoderResult.php (added)
-
vendor/chillerlan/php-qrcode/src/Decoder/QRCodeDecoderException.php (added)
-
vendor/chillerlan/php-qrcode/src/Decoder/ReedSolomonDecoder.php (added)
-
vendor/chillerlan/php-qrcode/src/Detector (added)
-
vendor/chillerlan/php-qrcode/src/Detector/AlignmentPattern.php (added)
-
vendor/chillerlan/php-qrcode/src/Detector/AlignmentPatternFinder.php (added)
-
vendor/chillerlan/php-qrcode/src/Detector/Detector.php (added)
-
vendor/chillerlan/php-qrcode/src/Detector/FinderPattern.php (added)
-
vendor/chillerlan/php-qrcode/src/Detector/FinderPatternFinder.php (added)
-
vendor/chillerlan/php-qrcode/src/Detector/GridSampler.php (added)
-
vendor/chillerlan/php-qrcode/src/Detector/PerspectiveTransform.php (added)
-
vendor/chillerlan/php-qrcode/src/Detector/QRCodeDetectorException.php (added)
-
vendor/chillerlan/php-qrcode/src/Detector/ResultPoint.php (added)
-
vendor/chillerlan/php-qrcode/src/Helpers (deleted)
-
vendor/chillerlan/php-qrcode/src/Output/CssColorModuleValueTrait.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRCodeOutputException.php (modified) (2 diffs)
-
vendor/chillerlan/php-qrcode/src/Output/QREps.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRFpdf.php (modified) (4 diffs)
-
vendor/chillerlan/php-qrcode/src/Output/QRGdImage.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRGdImageAVIF.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRGdImageBMP.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRGdImageGIF.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRGdImageJPEG.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRGdImagePNG.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRGdImageWEBP.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRImage.php (deleted)
-
vendor/chillerlan/php-qrcode/src/Output/QRImagick.php (modified) (4 diffs)
-
vendor/chillerlan/php-qrcode/src/Output/QRInterventionImage.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRMarkup.php (modified) (1 diff)
-
vendor/chillerlan/php-qrcode/src/Output/QRMarkupHTML.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRMarkupSVG.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRMarkupXML.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php (modified) (4 diffs)
-
vendor/chillerlan/php-qrcode/src/Output/QROutputInterface.php (modified) (2 diffs)
-
vendor/chillerlan/php-qrcode/src/Output/QRString.php (deleted)
-
vendor/chillerlan/php-qrcode/src/Output/QRStringJSON.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/QRStringText.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/RGBArrayModuleValueTrait.php (added)
-
vendor/chillerlan/php-qrcode/src/Output/qrcode.schema.json (added)
-
vendor/chillerlan/php-qrcode/src/Output/qrcode.schema.xsd (added)
-
vendor/chillerlan/php-qrcode/src/QRCode.php (modified) (3 diffs)
-
vendor/chillerlan/php-qrcode/src/QRCodeException.php (modified) (2 diffs)
-
vendor/chillerlan/php-qrcode/src/QRCodeReaderOptionsTrait.php (added)
-
vendor/chillerlan/php-qrcode/src/QROptions.php (modified) (2 diffs)
-
vendor/chillerlan/php-qrcode/src/QROptionsTrait.php (modified) (6 diffs)
-
vendor/chillerlan/php-qrcode/tests (deleted)
-
vendor/chillerlan/php-settings-container/.github (deleted)
-
vendor/chillerlan/php-settings-container/.gitignore (deleted)
-
vendor/chillerlan/php-settings-container/.phan (deleted)
-
vendor/chillerlan/php-settings-container/.phpstan (added)
-
vendor/chillerlan/php-settings-container/.phpstan/baseline-lt-8.4.neon (added)
-
vendor/chillerlan/php-settings-container/.phpstan/ignore-by-php-version.php (added)
-
vendor/chillerlan/php-settings-container/.scrutinizer.yml (deleted)
-
vendor/chillerlan/php-settings-container/.travis.yml (deleted)
-
vendor/chillerlan/php-settings-container/README.md (modified) (8 diffs)
-
vendor/chillerlan/php-settings-container/composer.json (modified) (3 diffs)
-
vendor/chillerlan/php-settings-container/examples (deleted)
-
vendor/chillerlan/php-settings-container/phpmd.xml (deleted)
-
vendor/chillerlan/php-settings-container/phpunit.xml (deleted)
-
vendor/chillerlan/php-settings-container/rules-magic-access.neon (added)
-
vendor/chillerlan/php-settings-container/src/Attributes (added)
-
vendor/chillerlan/php-settings-container/src/Attributes/ThrowOnInvalidProperty.php (added)
-
vendor/chillerlan/php-settings-container/src/SettingsContainerAbstract.php (modified) (9 diffs)
-
vendor/chillerlan/php-settings-container/src/SettingsContainerInterface.php (modified) (4 diffs)
-
vendor/chillerlan/php-settings-container/tests (deleted)
-
vendor/composer/ClassLoader.php (modified) (27 diffs)
-
vendor/composer/InstalledVersions.php (modified) (2 diffs)
-
vendor/composer/autoload_classmap.php (modified) (1 diff)
-
vendor/composer/autoload_files.php (modified) (1 diff)
-
vendor/composer/autoload_namespaces.php (modified) (1 diff)
-
vendor/composer/autoload_psr4.php (modified) (2 diffs)
-
vendor/composer/autoload_real.php (modified) (3 diffs)
-
vendor/composer/autoload_static.php (modified) (2 diffs)
-
vendor/composer/installed.json (modified) (9 diffs)
-
vendor/composer/installed.php (modified) (1 diff)
-
vendor/composer/platform_check.php (modified) (2 diffs)
-
vendor/paragonie/constant_time_encoding/.gitignore (deleted)
-
vendor/paragonie/constant_time_encoding/.travis.yml (deleted)
-
vendor/paragonie/constant_time_encoding/LICENSE.txt (modified) (1 diff)
-
vendor/paragonie/constant_time_encoding/README.md (modified) (5 diffs)
-
vendor/paragonie/constant_time_encoding/composer.json (modified) (2 diffs)
-
vendor/paragonie/constant_time_encoding/phpunit.xml.dist (deleted)
-
vendor/paragonie/constant_time_encoding/psalm.xml (deleted)
-
vendor/paragonie/constant_time_encoding/src/Base32.php (modified) (30 diffs)
-
vendor/paragonie/constant_time_encoding/src/Base32Hex.php (modified) (7 diffs)
-
vendor/paragonie/constant_time_encoding/src/Base64.php (modified) (12 diffs)
-
vendor/paragonie/constant_time_encoding/src/Base64DotSlash.php (modified) (3 diffs)
-
vendor/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php (modified) (3 diffs)
-
vendor/paragonie/constant_time_encoding/src/Base64UrlSafe.php (modified) (3 diffs)
-
vendor/paragonie/constant_time_encoding/src/Binary.php (modified) (3 diffs)
-
vendor/paragonie/constant_time_encoding/src/EncoderInterface.php (modified) (3 diffs)
-
vendor/paragonie/constant_time_encoding/src/Encoding.php (modified) (20 diffs)
-
vendor/paragonie/constant_time_encoding/src/Hex.php (modified) (5 diffs)
-
vendor/paragonie/constant_time_encoding/src/RFC4648.php (modified) (12 diffs)
-
vendor/paragonie/constant_time_encoding/tests (deleted)
-
vendor/psr (added)
-
vendor/psr/clock (added)
-
vendor/psr/clock/CHANGELOG.md (added)
-
vendor/psr/clock/LICENSE (added)
-
vendor/psr/clock/README.md (added)
-
vendor/psr/clock/composer.json (added)
-
vendor/psr/clock/src (added)
-
vendor/psr/clock/src/ClockInterface.php (added)
-
vendor/spomky-labs/otphp/.github (deleted)
-
vendor/spomky-labs/otphp/.php_cs.dist (deleted)
-
vendor/spomky-labs/otphp/README.md (added)
-
vendor/spomky-labs/otphp/RELEASES.md (added)
-
vendor/spomky-labs/otphp/SECURITY.md (added)
-
vendor/spomky-labs/otphp/composer.json (modified) (2 diffs)
-
vendor/spomky-labs/otphp/phpstan.neon (deleted)
-
vendor/spomky-labs/otphp/src/Exception (added)
-
vendor/spomky-labs/otphp/src/Exception/InvalidLabelException.php (added)
-
vendor/spomky-labs/otphp/src/Exception/InvalidParameterException.php (added)
-
vendor/spomky-labs/otphp/src/Exception/InvalidProvisioningUriException.php (added)
-
vendor/spomky-labs/otphp/src/Exception/OTPExceptionInterface.php (added)
-
vendor/spomky-labs/otphp/src/Exception/ParameterNotFoundException.php (added)
-
vendor/spomky-labs/otphp/src/Exception/SecretDecodingException.php (added)
-
vendor/spomky-labs/otphp/src/Factory.php (modified) (2 diffs)
-
vendor/spomky-labs/otphp/src/FactoryInterface.php (modified) (1 diff)
-
vendor/spomky-labs/otphp/src/HOTP.php (modified) (3 diffs)
-
vendor/spomky-labs/otphp/src/HOTPInterface.php (modified) (3 diffs)
-
vendor/spomky-labs/otphp/src/InternalClock.php (added)
-
vendor/spomky-labs/otphp/src/OTP.php (modified) (4 diffs)
-
vendor/spomky-labs/otphp/src/OTPInterface.php (modified) (4 diffs)
-
vendor/spomky-labs/otphp/src/ParameterTrait.php (deleted)
-
vendor/spomky-labs/otphp/src/TOTP.php (modified) (1 diff)
-
vendor/spomky-labs/otphp/src/TOTPInterface.php (modified) (3 diffs)
-
vendor/spomky-labs/otphp/src/Url.php (added)
-
vendor/symfony (added)
-
vendor/symfony/deprecation-contracts (added)
-
vendor/symfony/deprecation-contracts/CHANGELOG.md (added)
-
vendor/symfony/deprecation-contracts/LICENSE (added)
-
vendor/symfony/deprecation-contracts/README.md (added)
-
vendor/symfony/deprecation-contracts/composer.json (added)
-
vendor/symfony/deprecation-contracts/function.php (added)
-
vendor/thecodingmachine (deleted)
-
wp-otp.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
wp-otp/trunk
- Property svn:ignore
-
old new 4 4 .gitignore 5 5 .gitlab-ci.yml 6 .scrutinizer.yml7 6 composer.json 8 7 composer.lock 9 8 deploy.sh 9 phpcs.xml 10 10 phpcs.xml.dist
-
- Property svn:ignore
-
wp-otp/trunk/admin/class-wp-otp-admin.php
r2466054 r3752647 12 12 use chillerlan\QRCode\QRCode; 13 13 use chillerlan\QRCode\QROptions; 14 use OTPHP\InternalClock; 14 15 use OTPHP\TOTP; 15 16 use ParagonIE\ConstantTime\Base32; … … 70 71 } 71 72 72 check_admin_referer( 'wp_otp_ nonce', 'wp_otp_nonce' );73 check_admin_referer( 'wp_otp_setup', 'wp_otp_nonce' ); 73 74 74 75 $user = get_userdata( $user_id ); … … 76 77 $user_meta_data = Wp_Otp_User_Meta::get_instance(); 77 78 78 // Get the secret.79 79 $secret = $user_meta_data->get( 'secret', $this->get_random_secret() ); 80 80 81 $otp = TOTP::create ( $secret );82 $otp->setLabel( $user->user_login );81 $otp = TOTP::createFromSecret( $secret, new InternalClock() ) 82 ->withLabel( $user->user_login ); 83 83 84 84 $otp_code = sanitize_key( $_POST['wp-otp-code'] ?? '' ); … … 125 125 */ 126 126 public function admin_init(): void { 127 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 127 if ( ! isset( $_GET['wp_otp_nonce'] ) ) { 128 return; 129 } 130 128 131 if ( 'yes' === ( sanitize_key( $_GET['wp-otp-reconfigure'] ?? '' ) ) ) { 132 check_admin_referer( 'wp_otp_reconfigure', 'wp_otp_nonce' ); 133 129 134 Wp_Otp_User_Meta::clear(); 130 135 wp_safe_redirect( get_edit_profile_url() . '#wp-otp' ); … … 132 137 } 133 138 134 // phpcs:ignore WordPress.Security.NonceVerification.Recommended135 139 if ( 'yes' === ( sanitize_key( $_GET['wp-otp-new-recovery-codes'] ?? '' ) ) ) { 140 check_admin_referer( 'wp_otp_new_recovery_codes', 'wp_otp_nonce' ); 141 136 142 $otp_recovery_codes = $this->get_random_recovery_codes(); 137 143 Wp_Otp_User_Meta::get_instance()->set_all( [ … … 230 236 * @return string 231 237 */ 232 public function get_random_hash( $length = 0 ): string {238 public function get_random_hash( int $length = 0 ): string { 233 239 try { 234 240 $random_hash = Base32::encode( random_bytes( 64 ) ); 235 } catch ( Throwable $e) {241 } catch ( Throwable ) { 236 242 $random_hash = Base32::encode( md5( microtime( true ) ) . md5( microtime( true ) ) ); 237 243 } … … 258 264 $user_meta_data->set( 'secret', $secret, true ); 259 265 260 $otp = TOTP::create ( $secret );261 $otp->setLabel( $user->user_login );266 $otp = TOTP::createFromSecret( $secret, new InternalClock() ) 267 ->withLabel( $user->user_login ); 262 268 263 269 // Issuer isn't allowed to have any colon. 264 $otp ->setIssuer( str_replace( [ ':', '%3a', '%3A' ], '', get_bloginfo( 'name' ) ) );270 $otp = $otp->withIssuer( str_replace( [ ':', '%3a', '%3A' ], '', get_bloginfo( 'name' ) ) ); 265 271 266 272 $qr_code_provisioning_uri_default = 'https://api.qrserver.com/v1/create-qr-code/?data={PROVISIONING_URI}&qzone=2'; … … 303 309 ], 304 310 [ 305 'name' => 'andOTP', 306 'uri' => 'https://github.com/andOTP/andOTP', 307 'uri_play_store' => 'https://play.google.com/store/apps/details?id=org.shadowice.flocke.andotp', 308 'uri_f_droid' => 'https://f-droid.org/packages/org.shadowice.flocke.andotp', 309 'uri_logo' => plugins_url( 'images/andotp.png', __FILE__ ), 310 ], 311 [ 312 'name' => 'OneTimePass', 313 'uri' => 'https://github.com/OneTimePass/OneTimePass', 314 'uri_f_droid' => 'https://f-droid.org/en/packages/com.github.onetimepass', 315 'uri_logo' => plugins_url( 'images/onetimepass.png', __FILE__ ), 311 'name' => 'Authenticator.cc', 312 'uri' => 'https://github.com/Authenticator-Extension/Authenticator', 313 'uri_play_store' => 'https://chrome.google.com/webstore/detail/authenticator/bhghoamapcdpbohphigoooaddinpkbai', 314 'uri_mozilla' => 'https://addons.mozilla.org/en-US/firefox/addon/auth-helper?src=external-github', 315 'uri_microsoft' => 'https://microsoftedge.microsoft.com/addons/detail/ocglkepbibnalbgmbachknglpdipeoio', 316 'uri_logo' => plugins_url( 'images/authenticator.png', __FILE__ ), 316 317 ], 317 318 [ … … 343 344 'name' => 'App Store', 344 345 'uri_logo' => plugins_url( 'images/app-store.png', __FILE__ ), 346 ], 347 'mozilla' => [ 348 'name' => 'Firefox AddOns', 349 'uri_logo' => plugins_url( 'images/mozilla-firefox.png', __FILE__ ), 350 ], 351 'microsoft' => [ 352 'name' => 'Microsoft Edge AddOns', 353 'uri_logo' => plugins_url( 'images/ms-edge.png', __FILE__ ), 345 354 ], 346 355 ]; … … 388 397 389 398 if ( $user_meta_data->get( 'enabled' ) ) { 390 $recovery_codes = array_filter( $user_meta_data->get( 'recovery_codes' ) ); 391 $recovery_codes_count = count( $recovery_codes ); 399 $recovery_codes_count = count( array_filter( $user_meta_data->get( 'recovery_codes' ) ?? [] ) ); 392 400 if ( $recovery_codes_count < 3 ) { 393 401 $this->show_user_notification( [ 394 402 '<strong>' . esc_html__( 'Important', 'wp-otp' ) . '</strong>', 395 sprintf( 396 _n( // phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment 397 'You have %d WP-OTP recovery code left. You should generate new ones.', 398 'You have %d WP-OTP recovery codes left. You should generate new ones.', 399 $recovery_codes_count, 400 'wp-otp' 401 ), 402 $recovery_codes_count 403 ), 403 // translators: %d is the number of WP-OTP recovery codes left. 404 sprintf( _n( 405 'You have %d WP-OTP recovery code left. You should generate new ones.', 406 'You have %d WP-OTP recovery codes left. You should generate new ones.', 407 $recovery_codes_count, 408 'wp-otp' 409 ), $recovery_codes_count ), 404 410 sprintf( 405 411 '<a href="%1$s" class="button">%2$s</a>', 406 esc_url( add_query_arg( 'wp-otp-new-recovery-codes', 'yes', get_edit_profile_url()) ),412 esc_url( wp_nonce_url( add_query_arg( 'wp-otp-new-recovery-codes', 'yes', get_edit_profile_url() ), 'wp_otp_new_recovery_codes', 'wp_otp_nonce' ) ), 407 413 esc_html_x( 'Regenerate', 'Link to regenerate the WP-OTP recovery codes', 'wp-otp' ) 408 414 ), -
wp-otp/trunk/admin/css/wp-otp-admin.css
r2466054 r3752647 2 2 background-color: #fff; 3 3 display: inline-block; 4 margin: 8px 16px;4 margin: 8px; 5 5 padding: 4px 8px; 6 border-radius: 3px; 7 } 8 9 .wp-otp-app-box > span { 10 display: block; 11 font-weight: bold; 12 margin-bottom: .5em; 13 } 14 15 .wp-otp-app-box a { 16 display: inline-block; 6 17 } 7 18 … … 12 23 } 13 24 14 .wp-otp-recovery-codes-box del,15 .wp-otp-recovery-codes-box span {16 display: block;17 font-weight: normal;18 margin: 4px;19 }20 21 .wp-otp-recovery-codes-box del {22 color: #800;23 }24 25 25 #wp-otp-qr-code { 26 26 background-color: #fff; 27 27 width: 222px; 28 28 } 29 30 code.wp-otp-secret { 31 display: inline-block; 32 user-select: all; 33 white-space: nowrap; 34 } 35 36 th.wp-otp-info-column { 37 display: flex; 38 flex-direction: column; 39 gap: 1rem; 40 } -
wp-otp/trunk/admin/partials/wp-otp-profile-display.php
r2477335 r3752647 8 8 */ 9 9 10 defined( 'WPINC' ) || exit; 10 11 ?> 11 12 … … 14 15 <table class="form-table"> 15 16 <tr> 16 <th scope="row"> 17 <?php esc_html_e( 'OTP Secret', 'wp-otp' ); ?>:<br> 18 <?php echo esc_html( chunk_split( $secret, 4, ' ' ) ); ?><br><br> 17 <th scope="row" class="wp-otp-info-column"> 18 <div> 19 <span><?php esc_html_e( 'OTP Secret', 'wp-otp' ); ?>:</span> 20 <code class="wp-otp-secret"><?php echo esc_html( chunk_split( $secret, 4, ' ' ) ); ?></code> 21 </div> 19 22 <?php if ( $otp_enabled ) : ?> 20 <?php 21 printf( 22 '<em>%1$s</em><br><a href="%2$s" class="button button-small wp-otp-link-reconfigure">%3$s</a>', 23 esc_html__( 'WP-OTP has been configured successfully.', 'wp-otp' ), 24 esc_url( add_query_arg( 'wp-otp-reconfigure', 'yes' ) ), 25 esc_html_x( 'Reconfigure', 'Link to reset and reconfigure WP-OTP secret', 'wp-otp' ) 26 ); 27 ?> 28 <br><br> 29 <div class="wp-otp-recovery-codes-box"> 30 <?php esc_html_e( 'Recovery codes', 'wp-otp' ); ?>:<br> 23 <div> 24 <div> 25 <?php 26 $recovery_codes_count = count( array_filter( $user_meta_data->get( 'recovery_codes' ) ?? [] ) ); 27 28 echo esc_html( 29 sprintf( 30 // translators: %d is the number of WP-OTP recovery codes left. 31 _n( '%s recovery code left', '%s recovery codes left', $recovery_codes_count, 'wp-otp' ), 32 $recovery_codes_count 33 ) 34 ); 35 ?> 36 </div> 31 37 <?php 32 foreach ( $user_meta_data->get( 'recovery_codes' ) as $code => $unused ) {33 printf( '<%1$s>%2$s</%1$s>', $unused ? 'span' : 'del', $code ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped34 }35 38 printf( 36 39 '<a href="%1$s" class="button button-small wp-otp-link-new-recovery-codes">%2$s</a>', 37 esc_url( add_query_arg( 'wp-otp-new-recovery-codes', 'yes' ) ),40 esc_url( wp_nonce_url( add_query_arg( 'wp-otp-new-recovery-codes', 'yes' ), 'wp_otp_new_recovery_codes', 'wp_otp_nonce' ) ), 38 41 esc_html_x( 'Regenerate', 'Link to regenerate the WP-OTP recovery codes', 'wp-otp' ) 39 42 ); 40 43 ?> 41 44 </div> 45 <div> 46 <div><?php esc_html_e( 'WP-OTP has been configured successfully.', 'wp-otp' ); ?></div> 47 <?php 48 printf( 49 '<a href="%1$s" class="button button-small wp-otp-link-reconfigure">%2$s</a>', 50 esc_url( wp_nonce_url( add_query_arg( 'wp-otp-reconfigure', 'yes' ), 'wp_otp_reconfigure', 'wp_otp_nonce' ) ), 51 esc_html_x( 'Reconfigure', 'Link to reset and reconfigure WP-OTP secret', 'wp-otp' ) 52 ); 53 ?> 54 </div> 42 55 <?php else : ?> 43 <em><?php esc_html_e( 'To activate WP-OTP, enter the One Time Password from your authenticator app and save your profile.', 'wp-otp' ); ?></em><br><br> 44 <label for="wp-otp-code"><?php esc_html_e( 'One Time Password', 'wp-otp' ); ?></label><br> 45 <input type="text" class="input" name="wp-otp-code" id="wp-otp-code"/> 56 <div> 57 <em><?php esc_html_e( 'To activate WP-OTP, enter the One Time Password from your authenticator app and save your profile.', 'wp-otp' ); ?></em><br><br> 58 <label for="wp-otp-code"><?php esc_html_e( 'One Time Password', 'wp-otp' ); ?></label><br> 59 <input type="text" class="input" name="wp-otp-code" id="wp-otp-code"/> 60 </div> 46 61 <?php endif; ?> 47 <?php wp_nonce_field( 'wp_otp_ nonce', 'wp_otp_nonce', false ); ?>62 <?php wp_nonce_field( 'wp_otp_setup', 'wp_otp_nonce', false ); ?> 48 63 </th> 49 64 <td> … … 57 72 <?php foreach ( $otp_apps as $otp_app ) : ?> 58 73 <span class="wp-otp-app-box"> 59 <s trong><?php echo esc_html( $otp_app['name'] ); ?></strong><br>74 <span><?php echo esc_html( $otp_app['name'] ); ?></span> 60 75 <a href="<?php echo esc_html( $otp_app['uri'] ); ?>" target="_blank"> 61 76 <img src="<?php echo esc_url( $otp_app['uri_logo'] ); ?>" -
wp-otp/trunk/includes/class-wp-otp-user-meta.php
r2466054 r3752647 122 122 * @return mixed Requested option value. 123 123 */ 124 public function get( $key = null, $default = null ) { 124 public function get( $key = null, $default = null ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound 125 125 if ( null !== $key ) { 126 126 if ( isset( self::$user_meta[ $key ] ) ) { … … 165 165 * @return Wp_Otp_User_Meta Instance of this class. 166 166 */ 167 public function set( string $key, $value, bool $save = false ): Wp_Otp_User_Meta { 168 if ( null !== $key ) { 169 if ( null !== $value ) { 170 self::$user_meta[ $key ] = $value; 171 } else { 172 unset( self::$user_meta[ $key ] ); 173 } 167 public function set( string $key, mixed $value, bool $save = false ): Wp_Otp_User_Meta { 168 if ( null !== $value ) { 169 self::$user_meta[ $key ] = $value; 170 } else { 171 unset( self::$user_meta[ $key ] ); 174 172 } 175 173 -
wp-otp/trunk/public/class-wp-otp-public.php
r2466054 r3752647 12 12 namespace Wp_Otp; 13 13 14 use OTPHP\InternalClock; 14 15 use OTPHP\TOTP; 15 16 use OTPHP\TOTPInterface; … … 54 55 ?> 55 56 <p> 56 <label for="wp-otp-code"><?php echo wp_kses_data( $otp_text ); ?></label><br />57 <label for="wp-otp-code"><?php echo wp_kses_data( $otp_text ); ?></label><br> 57 58 <?php '' !== $otp_text_sub && print wp_kses_data( sprintf( '<em>%s</em>', $otp_text_sub ) ); ?> 58 59 <input type="text" class="input" name="wp-otp-code" id="wp-otp-code"/> … … 85 86 86 87 // If this is a valid OTP code, all good! 87 if ( $this->verify_otp( $otp, $otp_code ) ) {88 if ( $this->verify_otp( $otp, $otp_code, $user->ID ) ) { 88 89 return $user; 89 90 } … … 142 143 143 144 // First let's check for a valid OTP code input. 144 $otp_code = substr( $password, -6 );145 $ tmp_pass = substr( $password, 0, -6 );146 if ( wp_check_password( $ tmp_pass, $user->user_pass, $user->ID ) && $this->verify_otp( $otp, $otp_code) ) {147 $password = (string) $tmp_pass;145 $otp_code = substr( $password, -6 ); 146 $real_pass = substr( $password, 0, -6 ); 147 if ( wp_check_password( $real_pass, $user->user_pass, $user->ID ) && $this->verify_otp( $otp, $otp_code, $user->ID ) ) { 148 $password = $real_pass; 148 149 return; 149 150 } … … 157 158 } 158 159 159 $ tmp_pass = substr( $password, 0, -strlen( $recovery_code ) );160 if ( wp_check_password( $ tmp_pass, $user->user_pass, $user->ID ) ) {160 $real_pass = substr( $password, 0, -strlen( $recovery_code ) ); 161 if ( wp_check_password( $real_pass, $user->user_pass, $user->ID ) ) { 161 162 // Unset the recovery code that has just been used. 162 163 $recovery_codes[ $otp_code ] = false; 163 164 $user_meta_data->set( 'recovery_codes', $recovery_codes, true ); 164 $password = (string) $tmp_pass;165 $password = $real_pass; 165 166 return; 166 167 } … … 179 180 private function get_otp_if_enabled( Wp_Otp_User_Meta $user_meta_data ): ?TOTPInterface { 180 181 if ( $user_meta_data->get( 'enabled' ) && null !== $user_meta_data->get( 'secret' ) ) { 181 return TOTP::create ( $user_meta_data->get( 'secret') );182 return TOTP::createFromSecret( $user_meta_data->get( 'secret' ), new InternalClock() ); 182 183 } 183 184 … … 186 187 187 188 /** 188 * Verify the OTP code using the passed TOTP object.189 * Verify the OTP code using the passed user and TOTP object. 189 190 * 190 191 * @since 0.3.0 191 192 * 192 * @param TOTPInterface $otp OTP object.193 * @param TOTPInterface $otp TOTP object. 193 194 * @param string $otp_code OTP code to be verified. 195 * @param int $user_id User ID. 194 196 * 195 197 * @return bool 196 198 */ 197 private function verify_otp( TOTPInterface $otp, string $otp_code ): bool { 199 private function verify_otp( TOTPInterface $otp, string $otp_code, int $user_id ): bool { 200 $otp_codes_used = get_transient( 'wp-otp-codes-used-' . $user_id ) ?: []; 201 202 if ( in_array( $otp_code, $otp_codes_used, true ) ) { 203 return false; 204 } 205 198 206 /** 199 207 * Filter for the OTP code expiration window. … … 201 209 * @since 0.1.0 202 210 * 203 * @param string$otp_window211 * @param int $otp_window 204 212 */ 205 213 $otp_window = (int) apply_filters( 'wp_otp_code_expiration_window', 2 ); 206 214 207 return $otp->verify( $otp_code, null, $otp_window ); 215 $verified = $otp->verify( $otp_code, null, $otp_window ); 216 217 if ( $verified ) { 218 $otp_codes_used[] = $otp_code; 219 set_transient( 'wp-otp-codes-used-' . $user_id, $otp_codes_used, $otp->getPeriod() * $otp_window ); 220 } 221 222 return $verified; 208 223 } 209 224 } -
wp-otp/trunk/readme.txt
r2477335 r3752647 2 2 Contributors: noplanman 3 3 Donate link: https://noplanman.ch/donate 4 Tags: login, 2fa, two factor, otp, totp, one time password, security, recovery, google authenticator5 Requires at least: 4.66 Tested up to: 5.67 Stable tag: 0. 6.18 Requires PHP: 7.44 Tags: 2fa, two factor, otp, one time password, login 5 Requires at least: 6.4 6 Tested up to: 7.1 7 Stable tag: 0.7.0 8 Requires PHP: 8.2 9 9 Author URI: https://noplanman.ch 10 Plugin URI: https://git .feneas.org/noplanman/wp-otp10 Plugin URI: https://gitlab.com/noplanman/wp-otp 11 11 License: GPLv2 or later 12 12 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 16 16 == Description == 17 17 18 With WP-OTP you can easilyset up 2 Factor Authentication with One Time Passwords for your WordPress login.19 This extra layer makes your WordPress site a lotmore secure.18 With WP-OTP you can set up 2 Factor Authentication with One Time Passwords for your WordPress login. 19 This extra layer makes your WordPress site more secure. 20 20 21 The new stealth mode allows for invisible OTP code entry, making your login screen look like any other, no extra OTP code input field. 21 Stealth mode allows for invisible OTP code entry, making your login screen look like any other, no extra OTP code input field. 22 23 For a more comprehensive solution, use [Two Factor](https://wordpress.org/plugins/two-factor/) by WordPress instead! 22 24 23 25 = Getting started = … … 25 27 26 28 It's as easy as scanning the provided QR Code or entering the OTP secret to any OTP generator app. 27 Then justactivate it by entering the generated OTP and voilà, all set up.29 Then activate it by entering the generated OTP and voilà, all set up. 28 30 Now, the login requires an OTP code to succeed. 29 31 … … 32 34 = Development = 33 35 This plugin is completely open source and a work of passion. 34 If you would like to be part of it and join in, make your way over to the [project page](https://git.feneas.org/noplanman/wp-otp) now. 35 Also, if you have an idea you would like to see in this plugin or if you've found a bug, please [let me know](https://git.feneas.org/noplanman/wp-otp/issues/new). 36 If you would like to be part of it and join in, make your way over to the [project page](https://gitlab.com/noplanman/wp-otp) now. 36 37 37 38 = Configuration = … … 51 52 52 53 = Minimum requirements = 53 WordPress 4.6, PHP 7.4.54 WordPress 6.4, PHP 8.2. 54 55 55 56 = Donate / Support = … … 57 58 All [donations](https://noplanman.ch/donate) are much appreciated, thank you 🙏 58 59 59 [Get professional support for this plugin with a Tidelift subscription](https://tidelift.com/subscription/pkg/wordpress-wp-otp?utm_source=wordpress-wp-otp&utm_medium=referral&utm_campaign=readme)60 *Tidelift helps make open source sustainable for maintainers while giving companies assurances about security, maintenance, and licensing for their dependencies.*61 62 60 = Security = 63 61 64 To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.62 To report a security vulnerability, please email me at `security@noplanman.ch`. 65 63 66 64 == Installation == 67 65 68 You can either use the built in WordPress installer or install the plugin manually.66 You can either use the built-in WordPress installer or install the plugin manually. 69 67 70 68 For an automated installation: … … 87 85 88 86 = Can I reset my OTP secret key? = 89 Yes, justclick the `Reconfigure` button on the profile page.87 Yes, click the `Reconfigure` button on the profile page. 90 88 91 89 = Why is there no OTP input field on the login form? = … … 94 92 95 93 == Changelog == 94 95 = 0.7.0 = 96 * Require at least WP 6.4 and PHP 8.2. 97 * Update OTPHP to 11.5 and use immutable API and explicit PSR clock. 98 * Update chillerlan/php-qrcode integration for v6. 99 * Secured sensitive actions with nonces. 96 100 97 101 = 0.6.1 = … … 154 158 == Upgrade Notice == 155 159 160 = 0.7.0 = 161 Minimum requirements are now WP 6.4 and PHP 8.2. 162 156 163 = 0.6.0 = 157 Minimum requirements are now WP 4.6 and PHP 7.4, supporting PHP 8.0 !164 Minimum requirements are now WP 4.6 and PHP 7.4, supporting PHP 8.0. 158 165 159 166 = 0.4.0 = 160 Minimum requirements are now WP 4.6 and PHP 7.1 !167 Minimum requirements are now WP 4.6 and PHP 7.1. -
wp-otp/trunk/vendor/autoload.php
r2477335 r3752647 3 3 // autoload.php @generated by Composer 4 4 5 if (PHP_VERSION_ID < 50600) { 6 if (!headers_sent()) { 7 header('HTTP/1.1 500 Internal Server Error'); 8 } 9 $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; 10 if (!ini_get('display_errors')) { 11 if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { 12 fwrite(STDERR, $err); 13 } elseif (!headers_sent()) { 14 echo $err; 15 } 16 } 17 throw new RuntimeException($err); 18 } 19 5 20 require_once __DIR__ . '/composer/autoload_real.php'; 6 21 7 return ComposerAutoloaderInit c7ff053f14f929092d06e37035c6064c::getLoader();22 return ComposerAutoloaderInit0cde52f04200d0b097061008ff484a30::getLoader(); -
wp-otp/trunk/vendor/chillerlan/php-qrcode/README.md
r2466054 r3752647 1 1 # chillerlan/php-qrcode 2 2 3 A PHP 7.4+ QR Code library based on the [implementation](https://github.com/kazuhikoarase/qrcode-generator) by [Kazuhiko Arase](https://github.com/kazuhikoarase),4 namespaced, cleaned up, improved and other stuff.3 A PHP QR Code generator based on the [implementation by Kazuhiko Arase](https://github.com/kazuhikoarase/qrcode-generator), namespaced, cleaned up, improved and other stuff. <br> 4 It also features a QR Code reader based on a [PHP port](https://github.com/khanamiryan/php-qrcode-detector-decoder) of the [ZXing library](https://github.com/zxing/zxing). 5 5 6 **Attention:** there is now also a javascript port on NPM: [@chillerlan/qrcode](https://www.npmjs.com/package/@chillerlan/qrcode). 7 8 [![PHP Version Support][php-badge]][php] 6 9 [![Packagist version][packagist-badge]][packagist] 7 [![License][license-badge]][license] 8 [![Travis CI][travis-badge]][travis] 10 [![Continuous Integration][gh-action-badge]][gh-action] 9 11 [![CodeCov][coverage-badge]][coverage] 10 [![ Scrunitizer CI][scrutinizer-badge]][scrutinizer]12 [![Codacy][codacy-badge]][codacy] 11 13 [![Packagist downloads][downloads-badge]][downloads] 12 [![ PayPal donate][donate-badge]][donate]14 [![Documentation][readthedocs-badge]][readthedocs] 13 15 14 [![Continuous Integration][gh-action-badge]][gh-action] [![phpDocs][gh-docs-badge]][gh-docs] 16 [php-badge]: https://img.shields.io/packagist/php-v/chillerlan/php-qrcode?logo=php&color=8892BF&logoColor=fff 17 [php]: https://www.php.net/supported-versions.php 18 [packagist-badge]: https://img.shields.io/packagist/v/chillerlan/php-qrcode.svg?logo=packagist&logoColor=fff 19 [packagist]: https://packagist.org/packages/chillerlan/php-qrcode 20 [gh-action-badge]: https://img.shields.io/github/actions/workflow/status/chillerlan/php-qrcode/ci.yml?branch=v6.0.x&logo=github&logoColor=fff 21 [gh-action]: https://github.com/chillerlan/php-qrcode/actions/workflows/ci.yml?query=branch%3Amain 22 [coverage-badge]: https://img.shields.io/codecov/c/github/chillerlan/php-qrcode/v6.0.x?logo=codecov&logoColor=fff 23 [coverage]: https://app.codecov.io/gh/chillerlan/php-qrcode/tree/v6.0.x 24 [codacy-badge]: https://img.shields.io/codacy/grade/edccfc4fe5a34b74b1c53ee03f097b8d/v6.0.x?logo=codacy&logoColor=fff 25 [codacy]: https://app.codacy.com/gh/chillerlan/php-qrcode/dashboard?branch=v6.0.x 26 [downloads-badge]: https://img.shields.io/packagist/dt/chillerlan/php-qrcode?logo=packagist&logoColor=fff 27 [downloads]: https://packagist.org/packages/chillerlan/php-qrcode/stats 28 [readthedocs-badge]: https://img.shields.io/readthedocs/php-qrcode/v6.0.x?logo=readthedocs&logoColor=fff 29 [readthedocs]: https://php-qrcode.readthedocs.io/en/v6.0.x/ 15 30 16 [packagist-badge]: https://img.shields.io/packagist/v/chillerlan/php-qrcode.svg?style=flat-square 17 [packagist]: https://packagist.org/packages/chillerlan/php-qrcode 18 [license-badge]: https://img.shields.io/github/license/chillerlan/php-qrcode.svg?style=flat-square 19 [license]: https://github.com/chillerlan/php-qrcode/blob/main/LICENSE 20 [travis-badge]: https://img.shields.io/travis/chillerlan/php-qrcode.svg?style=flat-square 21 [travis]: https://travis-ci.org/chillerlan/php-qrcode 22 [coverage-badge]: https://img.shields.io/codecov/c/github/chillerlan/php-qrcode.svg?style=flat-square 23 [coverage]: https://codecov.io/github/chillerlan/php-qrcode 24 [scrutinizer-badge]: https://img.shields.io/scrutinizer/g/chillerlan/php-qrcode.svg?style=flat-square 25 [scrutinizer]: https://scrutinizer-ci.com/g/chillerlan/php-qrcode 26 [downloads-badge]: https://img.shields.io/packagist/dt/chillerlan/php-qrcode.svg?style=flat-square 27 [downloads]: https://packagist.org/packages/chillerlan/php-qrcode/stats 28 [donate-badge]: https://img.shields.io/badge/donate-paypal-ff33aa.svg?style=flat-square 29 [donate]: https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4 30 [gh-action-badge]: https://github.com/chillerlan/php-qrcode/workflows/Continuous%20Integration/badge.svg 31 [gh-action]: https://github.com/chillerlan/php-qrcode/actions?query=workflow%3A%22Continuous+Integration%22 32 [gh-docs-badge]: https://github.com/chillerlan/php-qrcode/workflows/Docs/badge.svg 33 [gh-docs]: https://github.com/chillerlan/php-qrcode/actions?query=workflow%3ADocs 31 # Overview 34 32 35 ## Documentation33 ## Features 36 34 37 See [the wiki](https://github.com/chillerlan/php-qrcode/wiki) for advanced documentation. 38 An API documentation created with [phpDocumentor](https://www.phpdoc.org/) can be found at https://chillerlan.github.io/php-qrcode/ (WIP). 35 - Creation of [Model 2 QR Codes](https://www.qrcode.com/en/codes/model12.html), [Version 1 to 40](https://www.qrcode.com/en/about/version.html) 36 - [ECC Levels](https://www.qrcode.com/en/about/error_correction.html) L/M/Q/H supported 37 - Mixed mode support (encoding modes can be combined within a QR symbol). Supported modes: 38 - numeric 39 - alphanumeric 40 - 8-bit binary 41 - [ECI support](https://en.wikipedia.org/wiki/Extended_Channel_Interpretation) 42 - 13-bit double-byte: 43 - kanji (Japanese, Shift-JIS) 44 - hanzi (simplified Chinese, GB2312/GB18030) as [defined in GBT18284-2000](https://www.chinesestandard.net/PDF/English.aspx/GBT18284-2000) 45 - Flexible, easily extensible output modules, built-in support for the following output formats: 46 - [GdImage](https://www.php.net/manual/book.image) (raster graphics: avif, bmp, gif, jpeg, png, webp) 47 - [ImageMagick](https://www.php.net/manual/book.imagick) ([multiple supported image formats](https://imagemagick.org/script/formats.php)) 48 - Markup types: SVG, HTML, etc. 49 - String types: JSON, plain text, etc. 50 - Encapsulated Postscript (EPS) 51 - PDF via [FPDF](https://github.com/setasign/fpdf) 52 - QR Code reader (via GD and ImageMagick) 39 53 40 ### Requirements 41 - PHP 7.4+ 42 - `ext-mbstring` 43 - optional: 44 - `ext-json`, `ext-gd` 45 - `ext-imagick` with [ImageMagick](https://imagemagick.org) installed 54 55 ## Requirements 56 57 - PHP 8.2+ 58 - [`ext-mbstring`](https://www.php.net/manual/book.mbstring.php) 59 - optional: 60 - [`ext-gd`](https://www.php.net/manual/book.image) for `QRGdImage` based output 61 - [`ext-imagick`](https://github.com/Imagick/imagick) with [ImageMagick](https://imagemagick.org) installed 62 - [`ext-fileinfo`](https://www.php.net/manual/book.fileinfo.php) required by `QRImagick` output 46 63 - [`setasign/fpdf`](https://github.com/setasign/fpdf) for the PDF output module 64 - [`intervention/image`](https://github.com/Intervention/image) for alternative GD/ImageMagick output 47 65 48 ### Installation 49 **requires [composer](https://getcomposer.org)** 66 For the QR Code reader, either `ext-gd` or `ext-imagick` is required! 50 67 51 via terminal: `composer require chillerlan/php-qrcode`52 68 53 *composer.json* 69 # Documentation 70 71 - The user manual is at https://php-qrcode.readthedocs.io/ ([sources](https://github.com/chillerlan/php-qrcode/tree/v6.0.x/docs)) 72 - An API documentation created with [phpDocumentor](https://www.phpdoc.org/) can be found at https://chillerlan.github.io/php-qrcode/ 73 - The documentation for the `QROptions` container is here: [chillerlan/php-settings-container](https://github.com/chillerlan/php-settings-container#readme) 74 - Benchmark results can be found in the [`benchmark` branch](https://github.com/chillerlan/php-qrcode/tree/benchmark/markdown) 75 76 **Important: Please use the examples from the branch that matches your installed php-qrcode version ( 77 [v4.x](https://github.com/chillerlan/php-qrcode/tree/v4.3.x/examples), 78 [v5.x](https://github.com/chillerlan/php-qrcode/tree/v5.0.x/examples), 79 [v6.x](https://github.com/chillerlan/php-qrcode/tree/v6.0.x/examples), 80 [dev-main](https://github.com/chillerlan/php-qrcode/tree/main/examples) 81 )!**<br/> 82 The `main` (default) branch is the active development for future major versions, and it is most likely incompatible with the latest release versions. 83 84 ## Installation with [composer](https://getcomposer.org) 85 86 See [the installation guide](https://php-qrcode.readthedocs.io/en/v6.0.x/Usage/Installation.html) for more info! 87 88 89 ### Terminal 90 91 ``` 92 composer require chillerlan/php-qrcode 93 ``` 94 95 96 ### composer.json 97 54 98 ```json 55 99 { 56 100 "require": { 57 "php": "^ 7.4",58 "chillerlan/php-qrcode": " dev-main"101 "php": "^8.2", 102 "chillerlan/php-qrcode": "v6.0.x-dev#<commit_hash>" 59 103 } 60 104 } 61 105 ``` 62 106 63 Note: replace `dev-main` with a [version constraint](https://getcomposer.org/doc/articles/versions.md#writing-version-constraints), e.g. `^3.2` - see [releases](https://github.com/chillerlan/php-qrcode/releases) for valid versions. 64 For PHP version ... 65 - 7.4+ use `^4.2` 66 - 7.2+ use `^3.3` 67 - 7.0+ use `^2.0` (PHP 7.0 and 7.1 are EOL!) 68 - 5.6+ use `^1.0` (please let PHP 5 die!) 107 Note: replace `v6.0.x-dev` with a [version constraint](https://getcomposer.org/doc/articles/versions.md#writing-version-constraints), e.g. `^5.0` - see [releases](https://github.com/chillerlan/php-qrcode/releases) for valid versions. 69 108 70 ### Quickstart 109 110 ## Quickstart 111 71 112 We want to encode this URI for a mobile authenticator into a QRcode image: 113 72 114 ```php 73 115 $data = 'otpauth://totp/test?secret=B3JX4VCVJDVNXNZ5&issuer=chillerlan.net'; … … 77 119 ``` 78 120 121 Wait, what was that? Please again, slower! See [Advanced usage](https://php-qrcode.readthedocs.io/en/v6.0.x/Usage/Advanced-usage.html) in the manual. 122 Also, have a look [in the examples folder](https://github.com/chillerlan/php-qrcode/tree/v6.0.x/examples) for some more usage examples. 123 79 124 <p align="center"> 80 <img alt="QR codes are awesome!" src="https://raw.githubusercontent.com/chillerlan/php-qrcode/main/examples/example_image.png"> 81 <img alt="QR codes are awesome!" src="https://raw.githubusercontent.com/chillerlan/php-qrcode/main/examples/example_svg.png"> 125 <img alt="QR codes are awesome!" style="width: auto; height: 530px;" src="https://raw.githubusercontent.com/chillerlan/php-qrcode/v6.0.x/.github/images/example.svg"> 82 126 </p> 83 127 84 Wait, what was that? Please again, slower! See [Advanced usage](https://github.com/chillerlan/php-qrcode/wiki/Advanced-usage) on the wiki.85 128 86 ### Framework Integration 87 - Drupal [Google Authenticator Login `ga_login`](https://www.drupal.org/project/ga_login) 88 - WordPress [`wp-two-factor-auth`](https://github.com/sjinks/wp-two-factor-auth) 89 - WordPress [Simple 2FA `simple-2fa`](https://wordpress.org/plugins/simple-2fa/) 90 - WoltLab Suite [two-step-verification](http://pluginstore.woltlab.com/file/3007-two-step-verification/) 91 - [Cachet](https://github.com/CachetHQ/Cachet) 92 - [Appwrite](https://github.com/appwrite/appwrite) 93 - other uses: [dependents](https://github.com/chillerlan/php-qrcode/network/dependents) / [packages](https://github.com/chillerlan/php-qrcode/network/dependents?dependent_type=PACKAGE) 129 # Disclaimer! 94 130 95 ### Shameless advertising96 Hi, please check out my other projects that are way cooler than qrcodes!97 98 - [php-oauth-core](https://github.com/chillerlan/php-oauth-core) - an OAuth 1/2 client library along with a bunch of [providers](https://github.com/chillerlan/php-oauth-providers)99 - [php-httpinterface](https://github.com/chillerlan/php-httpinterface) - a PSR-7/15/17/18 implemetation100 - [php-database](https://github.com/chillerlan/php-database) - a database client & querybuilder for MySQL, Postgres, SQLite, MSSQL, Firebird101 102 ### Disclaimer!103 131 I don't take responsibility for molten CPUs, misled applications, failed log-ins etc.. Use at your own risk! 104 132 105 #### Trademark Notice106 133 107 The word "QR Code" is registered trademark of *DENSO WAVE INCORPORATED*<br> 108 http://www.denso-wave.com/qrcode/faqpatent-e.html 134 ## License notice 135 136 - Parts of this code are [ported to PHP](https://github.com/codemasher/php-qrcode-decoder) from the [ZXing project](https://github.com/zxing/zxing) and licensed under the [Apache License, Version 2.0](./NOTICE). 137 - [The documentation](https://github.com/chillerlan/php-qrcode/tree/v6.0.x/docs) is licensed under the [Creative Commons Attribution 4.0 International (CC BY 4.0) License](https://creativecommons.org/licenses/by/4.0/). 138 139 140 ## Trademark Notice 141 142 The word "QR Code" is a registered trademark of *DENSO WAVE INCORPORATED*<br> 143 https://www.qrcode.com/en/faq.html#patentH2Title -
wp-otp/trunk/vendor/chillerlan/php-qrcode/composer.json
r2466054 r3752647 1 1 { 2 "$schema": "https://getcomposer.org/schema.json", 2 3 "name": "chillerlan/php-qrcode", 3 "description": "A QR code generator. PHP 7.4+",4 "description": "A QR Code generator and reader with a user-friendly API. PHP 8.2+", 4 5 "homepage": "https://github.com/chillerlan/php-qrcode", 5 "license": "MIT", 6 "minimum-stability": "stable", 6 "license": [ 7 "MIT", "Apache-2.0" 8 ], 7 9 "type": "library", 8 10 "keywords": [ 9 "QR code", "qrcode", "qr", "qrcode-generator", "phpqrcode" 11 "QR code", "qrcode", "qr", "qrcode-generator", "phpqrcode", "qrcode-reader", "qr-reader" 10 12 ], 11 13 "authors": [ 12 14 { 13 15 "name": "Kazuhiko Arase", 14 "homepage": "https://github.com/kazuhikoarase" 16 "homepage": "https://github.com/kazuhikoarase/qrcode-generator" 17 }, 18 { 19 "name":"ZXing Authors", 20 "homepage": "https://github.com/zxing/zxing" 21 }, 22 { 23 "name": "Ashot Khanamiryan", 24 "homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder" 15 25 }, 16 26 { … … 24 34 } 25 35 ], 36 "funding": [ 37 { 38 "type": "Ko-Fi", 39 "url": "https://ko-fi.com/codemasher" 40 } 41 ], 42 "support": { 43 "docs": "https://php-qrcode.readthedocs.io", 44 "issues": "https://github.com/chillerlan/php-qrcode/issues", 45 "source": "https://github.com/chillerlan/php-qrcode" 46 }, 47 "minimum-stability": "stable", 48 "prefer-stable": true, 26 49 "require": { 27 "php": "^ 7.4 || ^8.0",50 "php": "^8.2", 28 51 "ext-mbstring": "*", 29 "chillerlan/php-settings-container": "^ 2.1"52 "chillerlan/php-settings-container": "^3.2.1" 30 53 }, 31 54 "require-dev": { 32 "phpunit/phpunit": "^9.4", 33 "phan/phan": "^3.2.2", 34 "setasign/fpdf": "^1.8.2" 55 "ext-fileinfo": "*", 56 "chillerlan/php-authenticator": "^5.3", 57 "intervention/image": "^3.11", 58 "phan/phan": "^6.0.1", 59 "phpbench/phpbench": "^1.4", 60 "phpunit/phpunit": "^11.5", 61 "phpmd/phpmd": "^2.15", 62 "phpstan/phpstan": "^2.1.40", 63 "phpstan/phpstan-deprecation-rules": "^2.0.4", 64 "setasign/fpdf": "^1.8.6", 65 "slevomat/coding-standard": "^8.28", 66 "squizlabs/php_codesniffer": "^4.0" 35 67 }, 36 68 "suggest": { 37 69 "chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.", 38 "setasign/fpdf": "Required to use the QR FPDF output." 70 "intervention/image": "More advanced GD and ImageMagick output.", 71 "setasign/fpdf": "Required to use the QR FPDF output.", 72 "simple-icons/simple-icons": "SVG icons that you can use to embed as logos in the QR Code" 39 73 }, 40 74 "autoload": { 41 75 "psr-4": { 42 "chillerlan\\QRCode\\": "src /"76 "chillerlan\\QRCode\\": "src" 43 77 } 44 78 }, 45 79 "autoload-dev": { 46 80 "psr-4": { 47 "chillerlan\\QRCodePublic\\": "public/", 48 "chillerlan\\QRCodeTest\\": "tests/", 49 "chillerlan\\QRCodeExamples\\": "examples/" 81 "chillerlan\\QRCodeBenchmark\\": "benchmark", 82 "chillerlan\\QRCodeTest\\": "tests" 83 } 84 }, 85 "scripts": { 86 "phan": "@php vendor/bin/phan", 87 "phpbench":[ 88 "Composer\\Config::disableProcessTimeout", 89 "@php vendor/bin/phpbench run" 90 ], 91 "phpcs": "@php vendor/bin/phpcs", 92 "phpmd": "@php vendor/bin/phpmd src text ./phpmd.xml.dist", 93 "phpstan": "@php vendor/bin/phpstan", 94 "phpstan-baseline": "@php vendor/bin/phpstan --generate-baseline", 95 "phpunit": "@php vendor/bin/phpunit" 96 }, 97 "config": { 98 "lock": false, 99 "sort-packages": true, 100 "platform-check": true, 101 "allow-plugins": { 102 "dealerdirect/phpcodesniffer-composer-installer": true 50 103 } 51 104 } -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Data/AlphaNum.php
r2466054 r3752647 3 3 * Class AlphaNum 4 4 * 5 * @filesource AlphaNum.php6 5 * @created 25.11.2015 7 * @package chillerlan\QRCode\Data8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2015 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode\Data; 14 13 15 use chillerlan\QRCode\QRCode; 16 17 use function ord, sprintf; 14 use chillerlan\QRCode\Common\{BitBuffer, Mode}; 15 use function ceil, intdiv, preg_match, strpos; 18 16 19 17 /** … … 23 21 * ISO/IEC 18004:2000 Section 8.4.3 24 22 */ 25 final class AlphaNum extends QRDataAbstract{ 26 27 protected int $datamode = QRCode::DATA_ALPHANUM; 28 29 protected array $lengthBits = [9, 11, 13]; 23 final class AlphaNum extends QRDataModeAbstract{ 30 24 31 25 /** 32 * @inheritdoc 26 * ISO/IEC 18004:2000 Table 5 27 * 28 * @var string 33 29 */ 34 pr otected function write(string $data):void{30 private const CHAR_MAP = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'; 35 31 36 for($i = 0; $i + 1 < $this->strlen; $i += 2){ 37 $this->bitBuffer->put($this->getCharCode($data[$i]) * 45 + $this->getCharCode($data[$i + 1]), 11); 32 public const DATAMODE = Mode::ALPHANUM; 33 34 public function getLengthInBits():int{ 35 return (int)ceil($this->getCharCount() * (11 / 2)); 36 } 37 38 public static function validateString(string $string):bool{ 39 return (bool)preg_match('/^[A-Z\d %$*+\-.:\/]+$/', $string); 40 } 41 42 public function write(BitBuffer $bitBuffer, int $versionNumber):static{ 43 $len = $this->getCharCount(); 44 45 $bitBuffer 46 ->put(self::DATAMODE, 4) 47 ->put($len, $this->getLengthBits($versionNumber)) 48 ; 49 50 // encode 2 characters in 11 bits 51 for($i = 0; ($i + 1) < $len; $i += 2){ 52 $bitBuffer->put( 53 ($this->ord($this->data[$i]) * 45 + $this->ord($this->data[($i + 1)])), 54 11, 55 ); 38 56 } 39 57 40 if($i < $this->strlen){ 41 $this->bitBuffer->put($this->getCharCode($data[$i]), 6); 58 // encode a remaining character in 6 bits 59 if($i < $len){ 60 $bitBuffer->put($this->ord($this->data[$i]), 6); 42 61 } 43 62 63 return $this; 44 64 } 45 65 46 66 /** 47 * get the code for the given character67 * @inheritDoc 48 68 * 49 * @throws \chillerlan\QRCode\Data\QRCodeDataException on an illegal character occurence69 * @throws \chillerlan\QRCode\Data\QRCodeDataException 50 70 */ 51 protected function getCharCode(string $chr):int{ 71 public function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{ 72 $length = $bitBuffer->read($this->getLengthBits($versionNumber)); 73 $result = ''; 74 // Read two characters at a time 75 while($length > 1){ 52 76 53 if(!isset($this::CHAR_MAP_ALPHANUM[$chr])){ 54 throw new QRCodeDataException(sprintf('illegal char: "%s" [%d]', $chr, ord($chr))); 77 if($bitBuffer->available() < 11){ 78 throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore 79 } 80 81 $nextTwoCharsBits = $bitBuffer->read(11); 82 $result .= $this->chr(intdiv($nextTwoCharsBits, 45)); 83 $result .= $this->chr($nextTwoCharsBits % 45); 84 $length -= 2; 55 85 } 56 86 57 return $this::CHAR_MAP_ALPHANUM[$chr]; 87 if($length === 1){ 88 // special case: one character left 89 if($bitBuffer->available() < 6){ 90 throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore 91 } 92 93 $result .= $this->chr($bitBuffer->read(6)); 94 } 95 96 return $result; 97 } 98 99 /** 100 * @throws \chillerlan\QRCode\Data\QRCodeDataException 101 */ 102 private function ord(string $chr):int{ 103 /** @phan-suppress-next-line PhanParamSuspiciousOrder */ 104 $ord = strpos(self::CHAR_MAP, $chr); 105 106 if($ord === false){ 107 throw new QRCodeDataException('invalid character'); // @codeCoverageIgnore 108 } 109 110 return $ord; 111 } 112 113 /** 114 * @throws \chillerlan\QRCode\Data\QRCodeDataException 115 */ 116 private function chr(int $ord):string{ 117 118 if($ord < 0 || $ord > 44){ 119 throw new QRCodeDataException('invalid character code'); // @codeCoverageIgnore 120 } 121 122 return self::CHAR_MAP[$ord]; 58 123 } 59 124 -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Data/Byte.php
r2466054 r3752647 3 3 * Class Byte 4 4 * 5 * @filesource Byte.php6 5 * @created 25.11.2015 7 * @package chillerlan\QRCode\Data8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2015 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode\Data; 14 13 15 use chillerlan\QRCode\QRCode; 16 17 use function ord; 14 use chillerlan\QRCode\Common\{BitBuffer, Mode}; 15 use function chr, ord; 18 16 19 17 /** 20 * Byte mode, ISO-8859-1 or UTF-818 * 8-bit Byte mode, ISO-8859-1 or UTF-8 21 19 * 22 20 * ISO/IEC 18004:2000 Section 8.3.4 23 21 * ISO/IEC 18004:2000 Section 8.4.4 24 22 */ 25 final class Byte extends QRData Abstract{23 final class Byte extends QRDataModeAbstract{ 26 24 27 p rotected int $datamode = QRCode::DATA_BYTE;25 public const DATAMODE = Mode::BYTE; 28 26 29 protected array $lengthBits = [8, 16, 16]; 27 public function getLengthInBits():int{ 28 return ($this->getCharCount() * 8); 29 } 30 30 31 /** 32 * @inheritdoc 33 */ 34 protected function write(string $data):void{ 31 public static function validateString(string $string):bool{ 32 return $string !== ''; 33 } 34 35 public function write(BitBuffer $bitBuffer, int $versionNumber):static{ 36 $len = $this->getCharCount(); 37 38 $bitBuffer 39 ->put(self::DATAMODE, 4) 40 ->put($len, $this->getLengthBits($versionNumber)) 41 ; 42 35 43 $i = 0; 36 44 37 while($i < $ this->strlen){38 $ this->bitBuffer->put(ord($data[$i]), 8);45 while($i < $len){ 46 $bitBuffer->put(ord($this->data[$i]), 8); 39 47 $i++; 40 48 } 41 49 50 return $this; 51 } 52 53 /** 54 * @inheritDoc 55 * 56 * @throws \chillerlan\QRCode\Data\QRCodeDataException 57 */ 58 public function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{ 59 $length = $bitBuffer->read($this->getLengthBits($versionNumber)); 60 61 if($bitBuffer->available() < (8 * $length)){ 62 throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore 63 } 64 65 $readBytes = ''; 66 67 for($i = 0; $i < $length; $i++){ 68 $readBytes .= chr($bitBuffer->read(8)); 69 } 70 71 return $readBytes; 42 72 } 43 73 -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Data/Kanji.php
r2466054 r3752647 3 3 * Class Kanji 4 4 * 5 * @filesource Kanji.php6 5 * @created 25.11.2015 7 * @package chillerlan\QRCode\Data8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2015 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode\Data; 14 13 15 use chillerlan\QRCode\QRCode; 16 17 use function mb_strlen, ord, sprintf, strlen; 14 use chillerlan\QRCode\Common\{BitBuffer, Mode}; 15 use Throwable; 16 use function chr, implode, intdiv, is_string, mb_convert_encoding, mb_detect_encoding, 17 mb_internal_encoding, mb_strlen, ord, sprintf, strlen; 18 18 19 19 /** 20 * Kanji mode: double-byte characters from the ShiftJIS character set20 * Kanji mode: 13-bit double-byte characters from the Shift-JIS character set 21 21 * 22 22 * ISO/IEC 18004:2000 Section 8.3.5 23 23 * ISO/IEC 18004:2000 Section 8.4.5 24 * 25 * @see https://en.wikipedia.org/wiki/Shift_JIS#As_defined_in_JIS_X_0208:1997 26 * @see http://www.rikai.com/library/kanjitables/kanji_codes.sjis.shtml 27 * @see https://gist.github.com/codemasher/d07d3e6e9346c08e7a41b8b978784952 24 28 */ 25 final class Kanji extends QRDataAbstract{ 26 27 protected int $datamode = QRCode::DATA_KANJI; 28 29 protected array $lengthBits = [8, 10, 12]; 29 final class Kanji extends QRDataModeAbstract{ 30 30 31 31 /** 32 * @inheritdoc 32 * possible values: SJIS, SJIS-2004 33 * 34 * SJIS-2004 may produce errors in PHP < 8 35 * 36 * @var string 33 37 */ 34 protected function getLength(string $data):int{ 35 return mb_strlen($data, 'SJIS'); 38 public const ENCODING = 'SJIS'; 39 40 public const DATAMODE = Mode::KANJI; 41 42 protected function getCharCount():int{ 43 return mb_strlen($this->data, self::ENCODING); 44 } 45 46 public function getLengthInBits():int{ 47 return ($this->getCharCount() * 13); 48 } 49 50 public static function convertEncoding(string $string):string{ 51 $detected = mb_detect_encoding($string, [mb_internal_encoding(), 'UTF-8', 'SJIS', 'SJIS-2004'], true); 52 53 if($detected === false){ 54 throw new QRCodeDataException('mb_detect_encoding error'); 55 } 56 57 if($detected === self::ENCODING){ 58 return $string; 59 } 60 61 $string = mb_convert_encoding($string, self::ENCODING, $detected); 62 63 if(!is_string($string)){ 64 throw new QRCodeDataException(sprintf('invalid encoding: %s', $detected)); 65 } 66 67 return $string; 36 68 } 37 69 38 70 /** 39 * @inheritdoc 71 * checks if a string qualifies as SJIS Kanji 72 */ 73 public static function validateString(string $string):bool{ 74 75 try{ 76 $string = self::convertEncoding($string); 77 } 78 catch(Throwable){ 79 return false; 80 } 81 82 $len = strlen($string); 83 84 if($len < 2 || ($len % 2) !== 0){ 85 return false; 86 } 87 88 for($i = 0; $i < $len; $i += 2){ 89 $byte1 = ord($string[$i]); 90 $byte2 = ord($string[($i + 1)]); 91 92 // byte 1 unused and vendor ranges 93 if($byte1 < 0x81 || ($byte1 > 0x84 && $byte1 < 0x88) || ($byte1 > 0x9f && $byte1 < 0xe0) || $byte1 > 0xea){ 94 return false; 95 } 96 97 // byte 2 unused ranges 98 if($byte2 < 0x40 || $byte2 === 0x7f || $byte2 > 0xfc){ 99 return false; 100 } 101 102 } 103 104 return true; 105 } 106 107 /** 108 * @inheritDoc 40 109 * 41 110 * @throws \chillerlan\QRCode\Data\QRCodeDataException on an illegal character occurence 42 111 */ 43 protected function write(string $data):void{ 44 $len = strlen($data); 112 public function write(BitBuffer $bitBuffer, int $versionNumber):static{ 45 113 46 for($i = 0; $i + 1 < $len; $i += 2){ 47 $c = ((0xff & ord($data[$i])) << 8) | (0xff & ord($data[$i + 1])); 114 $bitBuffer 115 ->put(self::DATAMODE, 4) 116 ->put($this->getCharCount(), $this->getLengthBits($versionNumber)) 117 ; 48 118 49 if($c >= 0x8140 && $c <= 0x9FFC){ 119 $len = strlen($this->data); 120 121 for($i = 0; ($i + 1) < $len; $i += 2){ 122 $c = (((0xff & ord($this->data[$i])) << 8) | (0xff & ord($this->data[($i + 1)]))); 123 124 if($c >= 0x8140 && $c <= 0x9ffc){ 50 125 $c -= 0x8140; 51 126 } 52 elseif($c >= 0x E040 && $c <= 0xEBBF){53 $c -= 0x C140;127 elseif($c >= 0xe040 && $c <= 0xebbf){ 128 $c -= 0xc140; 54 129 } 55 130 else{ 56 throw new QRCodeDataException(sprintf('illegal char at %d [%d]', $i + 1, $c));131 throw new QRCodeDataException(sprintf('illegal char at %d [%d]', ($i + 1), $c)); 57 132 } 58 133 59 $this->bitBuffer->put(((($c >> 8) & 0xff) * 0xC0) + ($c & 0xff), 13); 60 134 $bitBuffer->put((((($c >> 8) & 0xff) * 0xc0) + ($c & 0xff)), 13); 61 135 } 62 136 63 137 if($i < $len){ 64 throw new QRCodeDataException(sprintf('illegal char at %d', $i + 1));138 throw new QRCodeDataException(sprintf('illegal char at %d', ($i + 1))); 65 139 } 66 140 141 return $this; 142 } 143 144 /** 145 * @inheritDoc 146 * 147 * @throws \chillerlan\QRCode\Data\QRCodeDataException 148 */ 149 public function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{ 150 $length = $bitBuffer->read($this->getLengthBits($versionNumber)); 151 152 if($bitBuffer->available() < ($length * 13)){ 153 throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore 154 } 155 156 // Each character will require 2 bytes. Read the characters as 2-byte pairs and decode as SJIS afterwards 157 $buffer = []; 158 $offset = 0; 159 160 while($length > 0){ 161 // Each 13 bits encodes a 2-byte character 162 $twoBytes = $bitBuffer->read(13); 163 $assembledTwoBytes = ((intdiv($twoBytes, 0x0c0) << 8) | ($twoBytes % 0x0c0)); 164 165 $assembledTwoBytes += ($assembledTwoBytes < 0x01f00) 166 ? 0x08140 // In the 0x8140 to 0x9FFC range 167 : 0x0c140; // In the 0xE040 to 0xEBBF range 168 169 $buffer[$offset] = chr(0xff & ($assembledTwoBytes >> 8)); 170 $buffer[($offset + 1)] = chr(0xff & $assembledTwoBytes); 171 $offset += 2; 172 $length--; 173 } 174 175 $encoded = mb_convert_encoding(implode('', $buffer), mb_internal_encoding(), self::ENCODING); 176 177 if($encoded === false){ 178 throw new QRCodeDataException('mb_convert_encoding() error'); // @codeCoverageIgnore 179 } 180 181 return $encoded; 67 182 } 68 183 -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Data/Number.php
r2466054 r3752647 3 3 * Class Number 4 4 * 5 * @filesource Number.php6 5 * @created 26.11.2015 7 * @package chillerlan\QRCode\Data8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2015 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode\Data; 14 13 15 use chillerlan\QRCode\QRCode; 16 17 use function ord, sprintf, str_split, substr; 14 use chillerlan\QRCode\Common\{BitBuffer, Mode}; 15 use function ceil, intdiv, preg_match, substr, unpack; 18 16 19 17 /** … … 23 21 * ISO/IEC 18004:2000 Section 8.4.2 24 22 */ 25 final class Number extends QRData Abstract{23 final class Number extends QRDataModeAbstract{ 26 24 27 p rotected int $datamode = QRCode::DATA_NUMBER;25 public const DATAMODE = Mode::NUMBER; 28 26 29 protected array $lengthBits = [10, 12, 14]; 27 public function getLengthInBits():int{ 28 return (int)ceil($this->getCharCount() * (10 / 3)); 29 } 30 30 31 /** 32 * @inheritdoc 33 */ 34 protected function write(string $data):void{ 31 public static function validateString(string $string):bool{ 32 return (bool)preg_match('/^\d+$/', $string); 33 } 34 35 public function write(BitBuffer $bitBuffer, int $versionNumber):static{ 36 $len = $this->getCharCount(); 37 38 $bitBuffer 39 ->put(self::DATAMODE, 4) 40 ->put($len, $this->getLengthBits($versionNumber)) 41 ; 42 35 43 $i = 0; 36 44 37 while($i + 2 < $this->strlen){ 38 $this->bitBuffer->put($this->parseInt(substr($data, $i, 3)), 10); 45 // encode numeric triplets in 10 bits 46 while(($i + 2) < $len){ 47 $bitBuffer->put($this->parseInt(substr($this->data, $i, 3)), 10); 39 48 $i += 3; 40 49 } 41 50 42 if($i < $ this->strlen){51 if($i < $len){ 43 52 44 if($this->strlen - $i === 1){ 45 $this->bitBuffer->put($this->parseInt(substr($data, $i, $i + 1)), 4); 53 // encode 2 remaining numbers in 7 bits 54 if(($len - $i) === 2){ 55 $bitBuffer->put($this->parseInt(substr($this->data, $i, 2)), 7); 46 56 } 47 elseif($this->strlen - $i === 2){ 48 $this->bitBuffer->put($this->parseInt(substr($data, $i, $i + 2)), 7); 57 // encode one remaining number in 4 bits 58 elseif(($len - $i) === 1){ 59 $bitBuffer->put($this->parseInt(substr($this->data, $i, 1)), 4); 49 60 } 50 61 51 62 } 52 63 64 return $this; 53 65 } 54 66 … … 56 68 * get the code for the given numeric string 57 69 * 58 * @throws \chillerlan\QRCode\Data\QRCodeDataException on an illegal character occurence70 * @throws \chillerlan\QRCode\Data\QRCodeDataException 59 71 */ 60 pr otectedfunction parseInt(string $string):int{72 private function parseInt(string $string):int{ 61 73 $num = 0; 62 74 63 foreach(str_split($string) as $chr){ 64 $c = ord($chr); 75 $ords = unpack('C*', $string); 65 76 66 if(!isset($this::CHAR_MAP_NUMBER[$chr])){67 throw new QRCodeDataException(sprintf('illegal char: "%s" [%d]', $chr, $c));68 }77 if($ords === false){ 78 throw new QRCodeDataException('unpack() error'); 79 } 69 80 70 $c = $c - 48; // ord('0')71 $num = $num * 10 + $c;81 foreach($ords as $ord){ 82 $num = ($num * 10 + $ord - 48); 72 83 } 73 84 … … 75 86 } 76 87 88 /** 89 * @inheritDoc 90 * 91 * @throws \chillerlan\QRCode\Data\QRCodeDataException 92 */ 93 public function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{ 94 $length = $bitBuffer->read($this->getLengthBits($versionNumber)); 95 $result = ''; 96 // Read three digits at a time 97 while($length >= 3){ 98 // Each 10 bits encodes three digits 99 if($bitBuffer->available() < 10){ 100 throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore 101 } 102 103 $threeDigitsBits = $bitBuffer->read(10); 104 105 if($threeDigitsBits >= 1000){ 106 throw new QRCodeDataException('error decoding numeric value'); 107 } 108 109 $result .= intdiv($threeDigitsBits, 100); 110 $result .= (intdiv($threeDigitsBits, 10) % 10); 111 $result .= ($threeDigitsBits % 10); 112 113 $length -= 3; 114 } 115 116 if($length === 2){ 117 // Two digits left over to read, encoded in 7 bits 118 if($bitBuffer->available() < 7){ 119 throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore 120 } 121 122 $twoDigitsBits = $bitBuffer->read(7); 123 124 if($twoDigitsBits >= 100){ 125 throw new QRCodeDataException('error decoding numeric value'); 126 } 127 128 $result .= intdiv($twoDigitsBits, 10); 129 $result .= ($twoDigitsBits % 10); 130 } 131 elseif($length === 1){ 132 // One digit left over to read 133 if($bitBuffer->available() < 4){ 134 throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore 135 } 136 137 $digitBits = $bitBuffer->read(4); 138 139 if($digitBits >= 10){ 140 throw new QRCodeDataException('error decoding numeric value'); 141 } 142 143 $result .= $digitBits; 144 } 145 146 return $result; 147 } 148 77 149 } -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Data/QRCodeDataException.php
r2331970 r3752647 3 3 * Class QRCodeDataException 4 4 * 5 * @filesource QRCodeDataException.php6 5 * @created 09.12.2015 7 * @package chillerlan\QRCode\Data8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2015 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode\Data; … … 15 14 use chillerlan\QRCode\QRCodeException; 16 15 17 class QRCodeDataException extends QRCodeException{} 16 /** 17 * An exception container 18 */ 19 final class QRCodeDataException extends QRCodeException{ 20 21 } -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Data/QRMatrix.php
r2466054 r3752647 3 3 * Class QRMatrix 4 4 * 5 * @filesource QRMatrix.php6 5 * @created 15.11.2017 7 * @package chillerlan\QRCode\Data8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2017 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode\Data; 14 13 15 use chillerlan\QRCode\QRCode; 16 use Closure; 17 18 use function array_fill, array_key_exists, array_push, array_unshift, count, floor, in_array, max, min, range; 14 use chillerlan\QRCode\Common\{BitBuffer, EccLevel, MaskPattern, Version}; 15 use chillerlan\QRCode\QRCodeException; 16 use function array_fill, array_map, array_reverse, count, intdiv, in_array; 19 17 20 18 /** 21 * Holds a numerical representation of the final QR Code;19 * Holds an array representation of the final QR Code that contains numerical values for later output modifications; 22 20 * maps the ECC coded binary data and applies the mask pattern 23 21 * 24 22 * @see http://www.thonky.com/qr-code-tutorial/format-version-information 23 * 24 * @property Version|null $version 25 * @property EccLevel|null $eccLevel 26 * @property MaskPattern|null $maskPattern 27 * @property int $moduleCount 28 * @property int[][] $matrix 25 29 */ 26 final class QRMatrix{ 27 28 /** @var int */ 29 public const M_NULL = 0x00; 30 /** @var int */ 31 public const M_DARKMODULE = 0x02; 32 /** @var int */ 33 public const M_DATA = 0x04; 34 /** @var int */ 35 public const M_FINDER = 0x06; 36 /** @var int */ 37 public const M_SEPARATOR = 0x08; 38 /** @var int */ 39 public const M_ALIGNMENT = 0x0a; 40 /** @var int */ 41 public const M_TIMING = 0x0c; 42 /** @var int */ 43 public const M_FORMAT = 0x0e; 44 /** @var int */ 45 public const M_VERSION = 0x10; 46 /** @var int */ 47 public const M_QUIETZONE = 0x12; 48 /** @var int */ 49 public const M_LOGO = 0x14; 50 /** @var int */ 51 public const M_FINDER_DOT = 0x16; 52 /** @var int */ 53 public const M_TEST = 0xff; 54 55 /** 56 * ISO/IEC 18004:2000 Annex E, Table E.1 - Row/column coordinates of center module of Alignment Patterns 57 * 58 * version -> pattern 30 class QRMatrix{ 31 32 /* 33 * special values 34 */ 35 36 /** @var int */ 37 public const IS_DARK = 0b100000000000; 38 /** @var int */ 39 public const M_NULL = 0b000000000000; 40 /** @var int */ 41 public const M_LOGO = 0b001000000000; 42 /** @var int */ 43 public const M_LOGO_DARK = 0b101000000000; 44 45 /* 46 * light values 47 */ 48 49 /** @var int */ 50 public const M_DATA = 0b000000000010; 51 /** @var int */ 52 public const M_FINDER = 0b000000000100; 53 /** @var int */ 54 public const M_SEPARATOR = 0b000000001000; 55 /** @var int */ 56 public const M_ALIGNMENT = 0b000000010000; 57 /** @var int */ 58 public const M_TIMING = 0b000000100000; 59 /** @var int */ 60 public const M_FORMAT = 0b000001000000; 61 /** @var int */ 62 public const M_VERSION = 0b000010000000; 63 /** @var int */ 64 public const M_QUIETZONE = 0b000100000000; 65 66 /* 67 * dark values 68 */ 69 70 /** @var int */ 71 public const M_DARKMODULE = 0b100000000001; 72 /** @var int */ 73 public const M_DATA_DARK = 0b100000000010; 74 /** @var int */ 75 public const M_FINDER_DARK = 0b100000000100; 76 /** @var int */ 77 public const M_ALIGNMENT_DARK = 0b100000010000; 78 /** @var int */ 79 public const M_TIMING_DARK = 0b100000100000; 80 /** @var int */ 81 public const M_FORMAT_DARK = 0b100001000000; 82 /** @var int */ 83 public const M_VERSION_DARK = 0b100010000000; 84 /** @var int */ 85 public const M_FINDER_DOT = 0b110000000000; 86 87 /* 88 * values used for reversed reflectance 89 */ 90 91 /** @var int */ 92 public const M_DARKMODULE_LIGHT = 0b000000000001; 93 /** @var int */ 94 public const M_FINDER_DOT_LIGHT = 0b010000000000; 95 /** @var int */ 96 public const M_SEPARATOR_DARK = 0b100000001000; 97 /** @var int */ 98 public const M_QUIETZONE_DARK = 0b100100000000; 99 100 /** 101 * Map of flag => coord 102 * 103 * @see \chillerlan\QRCode\Data\QRMatrix::checkNeighbours() 59 104 * 60 105 * @var int[][] 61 106 */ 62 protected const alignmentPattern = [ 63 1 => [], 64 2 => [6, 18], 65 3 => [6, 22], 66 4 => [6, 26], 67 5 => [6, 30], 68 6 => [6, 34], 69 7 => [6, 22, 38], 70 8 => [6, 24, 42], 71 9 => [6, 26, 46], 72 10 => [6, 28, 50], 73 11 => [6, 30, 54], 74 12 => [6, 32, 58], 75 13 => [6, 34, 62], 76 14 => [6, 26, 46, 66], 77 15 => [6, 26, 48, 70], 78 16 => [6, 26, 50, 74], 79 17 => [6, 30, 54, 78], 80 18 => [6, 30, 56, 82], 81 19 => [6, 30, 58, 86], 82 20 => [6, 34, 62, 90], 83 21 => [6, 28, 50, 72, 94], 84 22 => [6, 26, 50, 74, 98], 85 23 => [6, 30, 54, 78, 102], 86 24 => [6, 28, 54, 80, 106], 87 25 => [6, 32, 58, 84, 110], 88 26 => [6, 30, 58, 86, 114], 89 27 => [6, 34, 62, 90, 118], 90 28 => [6, 26, 50, 74, 98, 122], 91 29 => [6, 30, 54, 78, 102, 126], 92 30 => [6, 26, 52, 78, 104, 130], 93 31 => [6, 30, 56, 82, 108, 134], 94 32 => [6, 34, 60, 86, 112, 138], 95 33 => [6, 30, 58, 86, 114, 142], 96 34 => [6, 34, 62, 90, 118, 146], 97 35 => [6, 30, 54, 78, 102, 126, 150], 98 36 => [6, 24, 50, 76, 102, 128, 154], 99 37 => [6, 28, 54, 80, 106, 132, 158], 100 38 => [6, 32, 58, 84, 110, 136, 162], 101 39 => [6, 26, 54, 82, 110, 138, 166], 102 40 => [6, 30, 58, 86, 114, 142, 170], 107 protected const neighbours = [ 108 0b00000001 => [-1, -1], 109 0b00000010 => [ 0, -1], 110 0b00000100 => [ 1, -1], 111 0b00001000 => [ 1, 0], 112 0b00010000 => [ 1, 1], 113 0b00100000 => [ 0, 1], 114 0b01000000 => [-1, 1], 115 0b10000000 => [-1, 0], 103 116 ]; 104 117 105 118 /** 106 * ISO/IEC 18004:2000 Annex D, Table D.1 - Version information bit stream for each version 107 * 108 * no version pattern for QR Codes < 7 109 * 110 * @var int[] 111 */ 112 protected const versionPattern = [ 113 7 => 0b000111110010010100, 114 8 => 0b001000010110111100, 115 9 => 0b001001101010011001, 116 10 => 0b001010010011010011, 117 11 => 0b001011101111110110, 118 12 => 0b001100011101100010, 119 13 => 0b001101100001000111, 120 14 => 0b001110011000001101, 121 15 => 0b001111100100101000, 122 16 => 0b010000101101111000, 123 17 => 0b010001010001011101, 124 18 => 0b010010101000010111, 125 19 => 0b010011010100110010, 126 20 => 0b010100100110100110, 127 21 => 0b010101011010000011, 128 22 => 0b010110100011001001, 129 23 => 0b010111011111101100, 130 24 => 0b011000111011000100, 131 25 => 0b011001000111100001, 132 26 => 0b011010111110101011, 133 27 => 0b011011000010001110, 134 28 => 0b011100110000011010, 135 29 => 0b011101001100111111, 136 30 => 0b011110110101110101, 137 31 => 0b011111001001010000, 138 32 => 0b100000100111010101, 139 33 => 0b100001011011110000, 140 34 => 0b100010100010111010, 141 35 => 0b100011011110011111, 142 36 => 0b100100101100001011, 143 37 => 0b100101010000101110, 144 38 => 0b100110101001100100, 145 39 => 0b100111010101000001, 146 40 => 0b101000110001101001, 147 ]; 148 149 /** 150 * ISO/IEC 18004:2000 Section 8.9 - Format Information 151 * 152 * ECC level -> mask pattern 119 * the matrix version - always set in QRMatrix, may be null in BitMatrix 120 */ 121 protected Version|null $version = null; 122 123 /** 124 * the current ECC level - always set in QRMatrix, may be null in BitMatrix 125 */ 126 protected EccLevel|null $eccLevel = null; 127 128 /** 129 * the mask pattern that was used in the most recent operation, set via: 130 * 131 * - QRMatrix::setFormatInfo() 132 * - QRMatrix::mask() 133 * - BitMatrix::readFormatInformation() 134 */ 135 protected MaskPattern|null $maskPattern = null; 136 137 /** 138 * the size (side length) of the matrix, including quiet zone (if created) 139 */ 140 protected int $moduleCount; 141 142 /** 143 * the actual matrix data array 153 144 * 154 145 * @var int[][] 155 146 */ 156 protected const formatPattern = [157 [ // L158 0b111011111000100,159 0b111001011110011,160 0b111110110101010,161 0b111100010011101,162 0b110011000101111,163 0b110001100011000,164 0b110110001000001,165 0b110100101110110,166 ],167 [ // M168 0b101010000010010,169 0b101000100100101,170 0b101111001111100,171 0b101101101001011,172 0b100010111111001,173 0b100000011001110,174 0b100111110010111,175 0b100101010100000,176 ],177 [ // Q178 0b011010101011111,179 0b011000001101000,180 0b011111100110001,181 0b011101000000110,182 0b010010010110100,183 0b010000110000011,184 0b010111011011010,185 0b010101111101101,186 ],187 [ // H188 0b001011010001001,189 0b001001110111110,190 0b001110011100111,191 0b001100111010000,192 0b000011101100010,193 0b000001001010101,194 0b000110100001100,195 0b000100000111011,196 ],197 ];198 199 /**200 * the current QR Code version number201 */202 protected int $version;203 204 /**205 * the current ECC level206 */207 protected int $eclevel;208 209 /**210 * the used mask pattern, set via QRMatrix::mapData()211 */212 protected int $maskPattern = QRCode::MASK_PATTERN_AUTO;213 214 /**215 * the size (side length) of the matrix216 */217 protected int $moduleCount;218 219 /**220 * the actual matrix data array221 *222 * @var int[][]223 */224 147 protected array $matrix; 225 148 226 149 /** 227 150 * QRMatrix constructor. 228 * 229 * @throws \chillerlan\QRCode\Data\QRCodeDataException 230 */ 231 public function __construct(int $version, int $eclevel){ 232 233 if(!in_array($version, range(1, 40), true)){ 234 throw new QRCodeDataException('invalid QR Code version'); 235 } 236 237 if(!array_key_exists($eclevel, QRCode::ECC_MODES)){ 238 throw new QRCodeDataException('invalid ecc level'); 239 } 240 151 */ 152 public function __construct(Version $version, EccLevel $eccLevel){ 241 153 $this->version = $version; 242 $this->eclevel = $eclevel; 243 $this->moduleCount = $this->version * 4 + 17; 244 $this->matrix = array_fill(0, $this->moduleCount, array_fill(0, $this->moduleCount, $this::M_NULL)); 245 } 246 247 /** 248 * shortcut to initialize the matrix 249 */ 250 public function init(int $maskPattern, bool $test = null):QRMatrix{ 154 $this->eccLevel = $eccLevel; 155 $this->moduleCount = $this->version->getDimension(); 156 $this->matrix = $this->createMatrix($this->moduleCount, $this::M_NULL); 157 } 158 159 /** 160 * This magic getter serves as an upgrade path for the deprecated property getter methods, 161 * which will be removed in v7 in favor of asymmetric visibility (PHP 8.4+). 162 * 163 * @throws \chillerlan\QRCode\QRCodeException 164 * @codeCoverageIgnore 165 */ 166 public function __get(string $name):mixed{ 167 168 if(in_array($name, ['matrix', 'version', 'eccLevel', 'maskPattern', 'moduleCount'], true)){ 169 return $this->{$name}; 170 } 171 172 throw new QRCodeException('invalid property access'); 173 } 174 175 /** 176 * Creates a 2-dimensional array (square) of the given $size 177 * 178 * @return int[][] 179 */ 180 protected function createMatrix(int $size, int $value):array{ 181 return array_fill(0, $size, array_fill(0, $size, $value)); 182 } 183 184 /** 185 * shortcut to initialize the functional patterns 186 */ 187 public function initFunctionalPatterns():static{ 251 188 return $this 252 189 ->setFinderPattern() … … 254 191 ->setAlignmentPattern() 255 192 ->setTimingPattern() 256 ->setVersionNumber($test)257 ->setFormatInfo($maskPattern, $test)258 193 ->setDarkModule() 194 ->setVersionNumber() 195 ->setFormatInfo() 259 196 ; 260 197 } 261 198 262 199 /** 263 * Returns the data matrix, returns a pure boolean representation if $boolean is set to true 264 * 265 * @return int[][]|bool[][] 266 */ 267 public function matrix(bool $boolean = false):array{ 268 269 if(!$boolean){ 270 return $this->matrix; 271 } 272 273 $matrix = []; 274 275 foreach($this->matrix as $y => $row){ 276 $matrix[$y] = []; 277 278 foreach($row as $x => $val){ 279 $matrix[$y][$x] = ($val >> 8) > 0; 280 } 281 } 282 200 * Returns the data matrix 201 * 202 * @return int[][] 203 * 204 * @deprecated 6.0.1 This method will be removed in v7, use the property "QRMatrix::$matrix" instead. 205 */ 206 public function getMatrix():array{ 207 return $this->matrix; 208 } 209 210 /** 211 * Returns a boolean representation of the data matrix 212 * 213 * @return bool[][] 214 * @phan-suppress PhanTypeMismatchReturn 215 */ 216 public function getBooleanMatrix():array{ 217 $matrix = $this->matrix; 218 219 foreach($matrix as &$row){ 220 $row = array_map($this->isDark(...), $row); 221 } 222 /** @var bool[][] $matrix (phpstan hates this otherwise) */ 283 223 return $matrix; 284 224 } … … 286 226 /** 287 227 * Returns the current version number 288 */ 289 public function version():int{ 228 * 229 * @deprecated 6.0.1 This method will be removed in v7, use the property "QRMatrix::$version" instead. 230 */ 231 public function getVersion():Version|null{ 290 232 return $this->version; 291 233 } … … 293 235 /** 294 236 * Returns the current ECC level 295 */ 296 public function eccLevel():int{ 297 return $this->eclevel; 237 * 238 * @deprecated 6.0.1 This method will be removed in v7, use the property "QRMatrix::$eccLevel" instead. 239 */ 240 public function getEccLevel():EccLevel|null{ 241 return $this->eccLevel; 298 242 } 299 243 300 244 /** 301 245 * Returns the current mask pattern 302 */ 303 public function maskPattern():int{ 246 * 247 * @deprecated 6.0.1 This method will be removed in v7, use the property "QRMatrix::$maskPattern" instead. 248 */ 249 public function getMaskPattern():MaskPattern|null{ 304 250 return $this->maskPattern; 305 251 } … … 309 255 * 310 256 * size = version * 4 + 17 [ + 2 * quietzone size] 311 */ 312 public function size():int{ 257 * 258 * @deprecated 6.0.1 This method will be removed in v7, use the property "QRMatrix::$moduleCount" instead. 259 */ 260 public function getSize():int{ 313 261 return $this->moduleCount; 314 262 } 315 263 316 264 /** 317 * Returns the value of the module at position [$x, $y] 265 * Returns the value of the module at position [$x, $y] or -1 if the coordinate is outside the matrix 318 266 */ 319 267 public function get(int $x, int $y):int{ 268 269 if(!isset($this->matrix[$y][$x])){ 270 return -1; 271 } 272 320 273 return $this->matrix[$y][$x]; 321 274 } … … 324 277 * Sets the $M_TYPE value for the module at position [$x, $y] 325 278 * 326 * true => $M_TYPE << 8279 * true => $M_TYPE | 0x800 327 280 * false => $M_TYPE 328 281 */ 329 public function set(int $x, int $y, bool $value, int $M_TYPE):QRMatrix{ 330 $this->matrix[$y][$x] = $M_TYPE << ($value ? 8 : 0); 331 332 return $this; 333 } 334 335 /** 336 * Checks whether a module is true (dark) or false (light) 337 * 338 * true => $value >> 8 === $M_TYPE 339 * $value >> 8 > 0 340 * 341 * false => $value === $M_TYPE 342 * $value >> 8 === 0 282 public function set(int $x, int $y, bool $value, int $M_TYPE):static{ 283 284 if(isset($this->matrix[$y][$x])){ 285 // we don't know whether the input is dark, so we remove the dark bit 286 $M_TYPE &= ~$this::IS_DARK; 287 288 if($value === true){ 289 $M_TYPE |= $this::IS_DARK; 290 } 291 292 $this->matrix[$y][$x] = $M_TYPE; 293 } 294 295 return $this; 296 } 297 298 /** 299 * Fills an area of $width * $height, from the given starting point [$startX, $startY] (top left) with $value for $M_TYPE. 300 */ 301 public function setArea(int $startX, int $startY, int $width, int $height, bool $value, int $M_TYPE):static{ 302 303 for($y = $startY; $y < ($startY + $height); $y++){ 304 for($x = $startX; $x < ($startX + $width); $x++){ 305 $this->set($x, $y, $value, $M_TYPE); 306 } 307 } 308 309 return $this; 310 } 311 312 /** 313 * Flips the value of the module at ($x, $y) 314 */ 315 public function flip(int $x, int $y):static{ 316 317 if(isset($this->matrix[$y][$x])){ 318 $this->matrix[$y][$x] ^= $this::IS_DARK; 319 } 320 321 return $this; 322 } 323 324 /** 325 * Checks whether the module at ($x, $y) is of the given $M_TYPE 326 * 327 * true => $value & $M_TYPE === $M_TYPE 328 * 329 * Also, returns false if the given coordinates are out of range. 330 */ 331 public function checkType(int $x, int $y, int $M_TYPE):bool{ 332 333 if(isset($this->matrix[$y][$x])){ 334 return ($this->matrix[$y][$x] & $M_TYPE) === $M_TYPE; 335 } 336 337 return false; 338 } 339 340 /** 341 * Checks whether the module at ($x, $y) is in the given array of $M_TYPES, 342 * returns true if a match is found, otherwise false. 343 * 344 * @param int[] $M_TYPES 345 */ 346 public function checkTypeIn(int $x, int $y, array $M_TYPES):bool{ 347 348 foreach($M_TYPES as $type){ 349 if($this->checkType($x, $y, $type)){ 350 return true; 351 } 352 } 353 354 return false; 355 } 356 357 /** 358 * Checks whether the module at ($x, $y) is true (dark) or false (light) 359 * 360 * Also, returns false if the given coordinates are out of range. 343 361 */ 344 362 public function check(int $x, int $y):bool{ 345 return ($this->matrix[$y][$x] >> 8) > 0; 346 } 347 363 364 if(isset($this->matrix[$y][$x])){ 365 return $this->isDark($this->matrix[$y][$x]); 366 } 367 368 return false; 369 } 370 371 /** 372 * Checks whether the given $M_TYPE is a dark value 373 */ 374 public function isDark(int $M_TYPE):bool{ 375 return ($M_TYPE & $this::IS_DARK) === $this::IS_DARK; 376 } 377 378 /** 379 * Checks the status of the neighbouring modules for the module at ($x, $y) and returns a bitmask with the results. 380 * 381 * The 8 flags of the bitmask represent the status of each of the neighbouring fields, 382 * starting with the lowest bit for top left, going clockwise: 383 * 384 * 0 1 2 385 * 7 # 3 386 * 6 5 4 387 */ 388 public function checkNeighbours(int $x, int $y, int|null $M_TYPE = null):int{ 389 $bits = 0; 390 391 foreach($this::neighbours as $bit => [$ix, $iy]){ 392 $ix += $x; 393 $iy += $y; 394 395 // check if the field is the same type 396 if($M_TYPE !== null && !$this->checkType($ix, $iy, $M_TYPE)){ 397 continue; 398 } 399 400 if($this->checkType($ix, $iy, $this::IS_DARK)){ 401 $bits |= $bit; 402 } 403 } 404 405 return $bits; 406 } 348 407 349 408 /** 350 409 * Sets the "dark module", that is always on the same position 1x1px away from the bottom left finder 351 */ 352 public function setDarkModule():QRMatrix{ 353 $this->set(8, 4 * $this->version + 9, true, $this::M_DARKMODULE); 410 * 411 * 4 * version + 9 or moduleCount - 8 412 */ 413 public function setDarkModule():static{ 414 $this->set(8, ($this->moduleCount - 8), true, $this::M_DARKMODULE); 354 415 355 416 return $this; … … 361 422 * ISO/IEC 18004:2000 Section 7.3.2 362 423 */ 363 public function setFinderPattern(): QRMatrix{424 public function setFinderPattern():static{ 364 425 365 426 $pos = [ 366 427 [0, 0], // top left 367 [ $this->moduleCount - 7, 0], // bottom left368 [0, $this->moduleCount - 7], // top right428 [($this->moduleCount - 7), 0], // top right 429 [0, ($this->moduleCount - 7)], // bottom left 369 430 ]; 370 431 371 432 foreach($pos as $c){ 372 for($y = 0; $y < 7; $y++){ 373 for($x = 0; $x < 7; $x++){ 374 // outer (dark) 7*7 square 375 if($x === 0 || $x === 6 || $y === 0 || $y === 6){ 376 $this->set($c[0] + $y, $c[1] + $x, true, $this::M_FINDER); 377 } 378 // inner (light) 5*5 square 379 elseif($x === 1 || $x === 5 || $y === 1 || $y === 5){ 380 $this->set($c[0] + $y, $c[1] + $x, false, $this::M_FINDER); 381 } 382 // 3*3 dot 383 else{ 384 $this->set($c[0] + $y, $c[1] + $x, true, $this::M_FINDER_DOT); 385 } 386 } 387 } 433 $this 434 // phpcs:ignore 435 ->setArea( $c[0] , $c[1] , 7, 7, true, $this::M_FINDER) 436 ->setArea(($c[0] + 1), ($c[1] + 1), 5, 5, false, $this::M_FINDER) 437 ->setArea(($c[0] + 2), ($c[1] + 2), 3, 3, true, $this::M_FINDER_DOT) 438 ; 388 439 } 389 440 … … 396 447 * ISO/IEC 18004:2000 Section 7.3.3 397 448 */ 398 public function setSeparators(): QRMatrix{449 public function setSeparators():static{ 399 450 400 451 $h = [ 401 452 [7, 0], 402 [ $this->moduleCount - 8, 0],403 [7, $this->moduleCount - 8],453 [($this->moduleCount - 8), 0], 454 [7, ($this->moduleCount - 8)], 404 455 ]; 405 456 406 457 $v = [ 407 458 [7, 7], 408 [ $this->moduleCount - 1, 7],409 [7, $this->moduleCount - 8],459 [($this->moduleCount - 1), 7], 460 [7, ($this->moduleCount - 8)], 410 461 ]; 411 462 412 463 for($c = 0; $c < 3; $c++){ 413 464 for($i = 0; $i < 8; $i++){ 414 $this->set($h[$c][0] , $h[$c][1] + $i, false, $this::M_SEPARATOR); 415 $this->set($v[$c][0] - $i, $v[$c][1] , false, $this::M_SEPARATOR); 465 // phpcs:ignore 466 $this->set( $h[$c][0] , ($h[$c][1] + $i), false, $this::M_SEPARATOR); 467 $this->set(($v[$c][0] - $i), $v[$c][1] , false, $this::M_SEPARATOR); 416 468 } 417 469 } … … 426 478 * ISO/IEC 18004:2000 Section 7.3.5 427 479 */ 428 public function setAlignmentPattern():QRMatrix{ 429 430 foreach($this::alignmentPattern[$this->version] as $y){ 431 foreach($this::alignmentPattern[$this->version] as $x){ 480 public function setAlignmentPattern():static{ 481 $alignmentPattern = $this->version->getAlignmentPattern(); 482 483 foreach($alignmentPattern as $y){ 484 foreach($alignmentPattern as $x){ 432 485 433 486 // skip existing patterns … … 436 489 } 437 490 438 for($ry = -2; $ry <= 2; $ry++){ 439 for($rx = -2; $rx <= 2; $rx++){ 440 $v = ($ry === 0 && $rx === 0) || $ry === 2 || $ry === -2 || $rx === 2 || $rx === -2; 441 442 $this->set($x + $rx, $y + $ry, $v, $this::M_ALIGNMENT); 443 } 444 } 491 $this 492 ->setArea(($x - 2), ($y - 2), 5, 5, true, $this::M_ALIGNMENT) 493 ->setArea(($x - 1), ($y - 1), 3, 3, false, $this::M_ALIGNMENT) 494 ->set($x, $y, true, $this::M_ALIGNMENT) 495 ; 445 496 446 497 } … … 456 507 * ISO/IEC 18004:2000 Section 7.3.4 457 508 */ 458 public function setTimingPattern(): QRMatrix{459 460 for each(range(8, $this->moduleCount - 8 - 1) as $i){509 public function setTimingPattern():static{ 510 511 for($i = 8; $i < ($this->moduleCount - 8); $i++){ 461 512 462 513 if($this->matrix[6][$i] !== $this::M_NULL || $this->matrix[$i][6] !== $this::M_NULL){ … … 464 515 } 465 516 466 $v = $i % 2=== 0;517 $v = ($i % 2) === 0; 467 518 468 519 $this->set($i, 6, $v, $this::M_TIMING); // h … … 478 529 * ISO/IEC 18004:2000 Section 8.10 479 530 */ 480 public function setVersionNumber( bool $test = null):QRMatrix{481 $bits = $this ::versionPattern[$this->version] ?? false;482 483 if($bits !== false){531 public function setVersionNumber():static{ 532 $bits = $this->version->getVersionPattern(); 533 534 if($bits !== null){ 484 535 485 536 for($i = 0; $i < 18; $i++){ 486 $a = (int)floor($i /3);487 $b = $i % 3 + $this->moduleCount - 8 - 3;488 $v = !$test &&(($bits >> $i) & 1) === 1;537 $a = intdiv($i, 3); 538 $b = (($i % 3) + ($this->moduleCount - 8 - 3)); 539 $v = (($bits >> $i) & 1) === 1; 489 540 490 541 $this->set($b, $a, $v, $this::M_VERSION); // ne … … 498 549 499 550 /** 500 * Draws the format info along the finder patterns 551 * Draws the format info along the finder patterns. If no $maskPattern, all format info modules will be set to false. 501 552 * 502 553 * ISO/IEC 18004:2000 Section 8.9 503 554 */ 504 public function setFormatInfo(int $maskPattern, bool $test = null):QRMatrix{ 505 $bits = $this::formatPattern[QRCode::ECC_MODES[$this->eclevel]][$maskPattern] ?? 0; 555 public function setFormatInfo(MaskPattern|null $maskPattern = null):static{ 556 $this->maskPattern = $maskPattern; 557 $bits = 0; // sets all format fields to false (test mode) 558 559 if($this->maskPattern instanceof MaskPattern){ 560 $bits = $this->eccLevel->getformatPattern($this->maskPattern); 561 } 506 562 507 563 for($i = 0; $i < 15; $i++){ 508 $v = !$test &&(($bits >> $i) & 1) === 1;564 $v = (($bits >> $i) & 1) === 1; 509 565 510 566 if($i < 6){ … … 512 568 } 513 569 elseif($i < 8){ 514 $this->set(8, $i + 1, $v, $this::M_FORMAT);570 $this->set(8, ($i + 1), $v, $this::M_FORMAT); 515 571 } 516 572 else{ 517 $this->set(8, $this->moduleCount - 15 + $i, $v, $this::M_FORMAT);573 $this->set(8, ($this->moduleCount - 15 + $i), $v, $this::M_FORMAT); 518 574 } 519 575 520 576 if($i < 8){ 521 $this->set( $this->moduleCount - $i - 1, 8, $v, $this::M_FORMAT);577 $this->set(($this->moduleCount - $i - 1), 8, $v, $this::M_FORMAT); 522 578 } 523 579 elseif($i < 9){ 524 $this->set( 15 - $i, 8, $v, $this::M_FORMAT);580 $this->set(((15 - $i)), 8, $v, $this::M_FORMAT); 525 581 } 526 582 else{ 527 $this->set(15 - $i - 1, 8, $v, $this::M_FORMAT); 528 } 529 530 } 531 532 $this->set(8, $this->moduleCount - 8, !$test, $this::M_FORMAT); 583 $this->set((15 - $i - 1), 8, $v, $this::M_FORMAT); 584 } 585 586 } 533 587 534 588 return $this; … … 542 596 * @throws \chillerlan\QRCode\Data\QRCodeDataException 543 597 */ 544 public function setQuietZone(int $size = null):QRMatrix{ 545 546 if($this->matrix[$this->moduleCount - 1][$this->moduleCount - 1] === $this::M_NULL){ 598 public function setQuietZone(int $quietZoneSize):static{ 599 600 // early exit if there's nothing to add 601 if($quietZoneSize < 1){ 602 return $this; 603 } 604 605 if($this->matrix[($this->moduleCount - 1)][($this->moduleCount - 1)] === $this::M_NULL){ 547 606 throw new QRCodeDataException('use only after writing data'); 548 607 } 549 608 550 $size = $size !== null 551 ? max(0, min($size, floor($this->moduleCount / 2))) 552 : 4; 553 554 for($y = 0; $y < $this->moduleCount; $y++){ 555 for($i = 0; $i < $size; $i++){ 556 array_unshift($this->matrix[$y], $this::M_QUIETZONE); 557 array_push($this->matrix[$y], $this::M_QUIETZONE); 558 } 559 } 560 561 $this->moduleCount += ($size * 2); 562 563 $r = array_fill(0, $this->moduleCount, $this::M_QUIETZONE); 564 565 for($i = 0; $i < $size; $i++){ 566 array_unshift($this->matrix, $r); 567 array_push($this->matrix, $r); 609 // create a matrix with the new size 610 $newSize = ($this->moduleCount + ($quietZoneSize * 2)); 611 $newMatrix = $this->createMatrix($newSize, $this::M_QUIETZONE); 612 613 // copy over the current matrix 614 foreach($this->matrix as $y => $row){ 615 foreach($row as $x => $val){ 616 $newMatrix[($y + $quietZoneSize)][($x + $quietZoneSize)] = $val; 617 } 618 } 619 620 // set the new values 621 $this->moduleCount = $newSize; 622 $this->matrix = $newMatrix; 623 624 return $this; 625 } 626 627 /** 628 * Rotates the matrix by 90 degrees clock wise 629 */ 630 public function rotate90():static{ 631 /** @phan-suppress-next-line PhanParamTooFewInternalUnpack */ 632 $this->matrix = array_map((fn(int ...$a):array => array_reverse($a)), ...$this->matrix); 633 634 return $this; 635 } 636 637 /** 638 * Inverts the values of the whole matrix 639 * 640 * ISO/IEC 18004:2015 Section 6.2 - Reflectance reversal 641 */ 642 public function invert():static{ 643 644 foreach($this->matrix as $y => $row){ 645 foreach($row as $x => $val){ 646 647 // skip null fields 648 if($val === $this::M_NULL){ 649 continue; 650 } 651 652 $this->flip($x, $y); 653 } 568 654 } 569 655 … … 573 659 /** 574 660 * Clears a space of $width * $height in order to add a logo or text. 575 * 576 * Additionally, the logo space can be positioned within the QR Code - respecting the main functional patterns - 577 * using $startX and $startY. If either of these are null, the logo space will be centered in that direction. 661 * If no $height is given, the space will be assumed a square of $width. 662 * 663 * Additionally, the logo space can be positioned within the QR Code using $startX and $startY. 664 * If either of these are null, the logo space will be centered in that direction. 578 665 * ECC level "H" (30%) is required. 666 * 667 * The coordinates of $startX and $startY do not include the quiet zone: 668 * [0, 0] is always the top left module of the top left finder pattern, negative values go into the quiet zone top and left. 579 669 * 580 670 * Please note that adding a logo space minimizes the error correction capacity of the QR Code and … … 589 679 * @throws \chillerlan\QRCode\Data\QRCodeDataException 590 680 */ 591 public function setLogoSpace(int $width, int $height, int $startX = null, int $startY = null):QRMatrix{ 592 593 // for logos we operate in ECC H (30%) only 594 if($this->eclevel !== QRCode::ECC_H){ 681 public function setLogoSpace(int $width, int|null $height = null, int|null $startX = null, int|null $startY = null):static{ 682 $height ??= $width; 683 684 // if width and height happen to be negative or 0 (default value), just return - nothing to do 685 if($width <= 0 || $height <= 0){ 686 return $this; // @codeCoverageIgnore 687 } 688 689 // for logos, we operate in ECC H (30%) only 690 if($this->eccLevel->getLevel() !== EccLevel::H){ 595 691 throw new QRCodeDataException('ECC level "H" required to add logo space'); 596 692 } 597 693 598 // we need uneven sizes, adjust if needed 599 if(($width % 2) === 0){ 694 // $this->moduleCount includes the quiet zone (if created), we need the QR size here 695 $dimension = $this->version->getDimension(); 696 697 // throw if the size exceeds the qrcode size 698 if($width > $dimension || $height > $dimension){ 699 throw new QRCodeDataException('logo dimensions exceed matrix size'); 700 } 701 702 // we need uneven sizes to center the logo space, adjust if needed 703 if($startX === null && ($width % 2) === 0){ 600 704 $width++; 601 705 } 602 706 603 if( ($height % 2) === 0){707 if($startY === null && ($height % 2) === 0){ 604 708 $height++; 605 709 } 606 710 607 // $this->moduleCount includes the quiet zone (if created), we need the QR size here608 $length = $this->version * 4 + 17;609 610 711 // throw if the logo space exceeds the maximum error correction capacity 611 if( $width * $height > floor($length * $length * 0.2)){712 if(($width * $height) > (int)($dimension * $dimension * 0.25)){ 612 713 throw new QRCodeDataException('logo space exceeds the maximum error correction capacity'); 613 714 } 614 715 615 // quiet zone size 616 $qz = ($this->moduleCount - $length) / 2; 617 // skip quiet zone and the first 9 rows/columns (finder-, mode-, version- and timing patterns) 618 $start = $qz + 9; 619 // skip quiet zone 620 $end = $this->moduleCount - $qz; 716 $quietzone = (($this->moduleCount - $dimension) / 2); 717 $end = ($this->moduleCount - $quietzone); 621 718 622 719 // determine start coordinates 623 $startX = ($startX !== null ? $startX : ($length - $width) / 2) + $qz; 624 $startY = ($startY !== null ? $startY : ($length - $height) / 2) + $qz; 720 $startX ??= (($dimension - $width) / 2); 721 $startY ??= (($dimension - $height) / 2); 722 $endX = ($quietzone + $startX + $width); 723 $endY = ($quietzone + $startY + $height); 625 724 626 725 // clear the space 726 for($y = ($quietzone + $startY); $y < $endY; $y++){ 727 for($x = ($quietzone + $startX); $x < $endX; $x++){ 728 // out of bounds, skip 729 if($x < $quietzone || $y < $quietzone ||$x >= $end || $y >= $end){ 730 continue; 731 } 732 733 $this->set($x, $y, false, $this::M_LOGO); 734 } 735 } 736 737 return $this; 738 } 739 740 /** 741 * Maps the interleaved binary $data on the matrix 742 */ 743 public function writeCodewords(BitBuffer $bitBuffer):static{ 744 $data = (new ReedSolomonEncoder($this->version, $this->eccLevel))->interleaveEcBytes($bitBuffer); 745 $byteCount = count($data); 746 $iByte = 0; 747 $iBit = 7; 748 $direction = true; 749 750 for($i = ($this->moduleCount - 1); $i > 0; $i -= 2){ 751 752 // skip vertical alignment pattern 753 if($i === 6){ 754 $i--; 755 } 756 757 for($count = 0; $count < $this->moduleCount; $count++){ 758 $y = $count; 759 760 if($direction){ 761 $y = ($this->moduleCount - 1 - $count); 762 } 763 764 for($col = 0; $col < 2; $col++){ 765 $x = ($i - $col); 766 767 // skip functional patterns 768 if($this->matrix[$y][$x] !== $this::M_NULL){ 769 continue; 770 } 771 772 $this->matrix[$y][$x] = $this::M_DATA; 773 774 if($iByte < $byteCount && (($data[$iByte] >> $iBit--) & 1) === 1){ 775 $this->matrix[$y][$x] |= $this::IS_DARK; 776 } 777 778 if($iBit === -1){ 779 $iByte++; 780 $iBit = 7; 781 } 782 } 783 } 784 785 $direction = !$direction; // switch directions 786 } 787 788 return $this; 789 } 790 791 /** 792 * Applies/reverses the mask pattern 793 * 794 * ISO/IEC 18004:2000 Section 8.8.1 795 */ 796 public function mask(MaskPattern $maskPattern):static{ 797 $this->maskPattern = $maskPattern; 798 $mask = $this->maskPattern->getMask(); 799 627 800 foreach($this->matrix as $y => $row){ 628 801 foreach($row as $x => $val){ 629 // out of bounds, skip630 if( $x < $start || $y < $start ||$x >= $end || $y >= $end){631 continue;802 // skip non-data modules 803 if(($val & $this::M_DATA) === $this::M_DATA && $mask($x, $y)){ 804 $this->flip($x, $y); 632 805 } 633 // a match 634 if($x >= $startX && $x < ($startX + $width) && $y >= $startY && $y < ($startY + $height)){ 635 $this->set($x, $y, false, $this::M_LOGO); 636 } 637 } 638 } 639 640 return $this; 641 } 642 643 /** 644 * Maps the binary $data array from QRDataInterface::maskECC() on the matrix, 645 * masking the data using $maskPattern (ISO/IEC 18004:2000 Section 8.8) 646 * 647 * @see \chillerlan\QRCode\Data\QRDataAbstract::maskECC() 648 * 649 * @param int[] $data 650 * @param int $maskPattern 651 * 652 * @return \chillerlan\QRCode\Data\QRMatrix 653 */ 654 public function mapData(array $data, int $maskPattern):QRMatrix{ 655 $this->maskPattern = $maskPattern; 656 $byteCount = count($data); 657 $y = $this->moduleCount - 1; 658 $inc = -1; 659 $byteIndex = 0; 660 $bitIndex = 7; 661 $mask = $this->getMask($this->maskPattern); 662 663 for($i = $y; $i > 0; $i -= 2){ 664 665 if($i === 6){ 666 $i--; 667 } 668 669 while(true){ 670 for($c = 0; $c < 2; $c++){ 671 $x = $i - $c; 672 673 if($this->matrix[$y][$x] === $this::M_NULL){ 674 $v = false; 675 676 if($byteIndex < $byteCount){ 677 $v = (($data[$byteIndex] >> $bitIndex) & 1) === 1; 678 } 679 680 if($mask($x, $y) === 0){ 681 $v = !$v; 682 } 683 684 $this->matrix[$y][$x] = $this::M_DATA << ($v ? 8 : 0); 685 $bitIndex--; 686 687 if($bitIndex === -1){ 688 $byteIndex++; 689 $bitIndex = 7; 690 } 691 692 } 693 } 694 695 $y += $inc; 696 697 if($y < 0 || $this->moduleCount <= $y){ 698 $y -= $inc; 699 $inc = -$inc; 700 701 break; 702 } 703 704 } 705 } 706 707 return $this; 708 } 709 710 /** 711 * ISO/IEC 18004:2000 Section 8.8.1 712 * 713 * Note that some versions of the QR code standard have had errors in the section about mask patterns. 714 * The information below has been corrected. (https://www.thonky.com/qr-code-tutorial/mask-patterns) 715 * 716 * @see \chillerlan\QRCode\QRMatrix::mapData() 717 * 718 * @internal 719 * 720 * @throws \chillerlan\QRCode\Data\QRCodeDataException 721 */ 722 protected function getMask(int $maskPattern):Closure{ 723 724 if((0b111 & $maskPattern) !== $maskPattern){ 725 throw new QRCodeDataException('invalid mask pattern'); // @codeCoverageIgnore 726 } 727 728 return [ 729 0b000 => fn($x, $y):int => ($x + $y) % 2, 730 0b001 => fn($x, $y):int => $y % 2, 731 0b010 => fn($x, $y):int => $x % 3, 732 0b011 => fn($x, $y):int => ($x + $y) % 3, 733 0b100 => fn($x, $y):int => ((int)($y / 2) + (int)($x / 3)) % 2, 734 0b101 => fn($x, $y):int => (($x * $y) % 2) + (($x * $y) % 3), 735 0b110 => fn($x, $y):int => ((($x * $y) % 2) + (($x * $y) % 3)) % 2, 736 0b111 => fn($x, $y):int => ((($x * $y) % 3) + (($x + $y) % 2)) % 2, 737 ][$maskPattern]; 806 } 807 } 808 809 return $this; 738 810 } 739 811 -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Output/QRCodeOutputException.php
r2331970 r3752647 3 3 * Class QRCodeOutputException 4 4 * 5 * @filesource QRCodeOutputException.php6 5 * @created 09.12.2015 7 * @package chillerlan\QRCode\Output8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2015 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode\Output; … … 15 14 use chillerlan\QRCode\QRCodeException; 16 15 17 class QRCodeOutputException extends QRCodeException{} 16 /** 17 * An exception container 18 */ 19 final class QRCodeOutputException extends QRCodeException{ 20 21 } -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Output/QRFpdf.php
r2466054 r3752647 3 3 * Class QRFpdf 4 4 * 5 * https://github.com/chillerlan/php-qrcode/pull/49 5 * @created 03.06.2020 6 * @author Maximilian Kresse 7 * @license MIT 6 8 * 7 * @filesource QRFpdf.php 8 * @created 03.06.2020 9 * @package chillerlan\QRCode\Output 10 * @author Maximilian Kresse 11 * 12 * @license MIT 9 * @see https://github.com/chillerlan/php-qrcode/pull/49 13 10 */ 11 declare(strict_types=1); 14 12 15 13 namespace chillerlan\QRCode\Output; 16 14 15 use chillerlan\QRCode\QROptions; 17 16 use chillerlan\QRCode\Data\QRMatrix; 18 use chillerlan\QRCode\QRCodeException;19 17 use chillerlan\Settings\SettingsContainerInterface; 20 18 use FPDF; 21 19 22 use function array_values, class_exists, count, is_array;20 use function class_exists; 23 21 24 22 /** … … 29 27 */ 30 28 class QRFpdf extends QROutputAbstract{ 29 use RGBArrayModuleValueTrait; 31 30 32 public function __construct(SettingsContainerInterface $options, QRMatrix $matrix){ 31 final public const MIME_TYPE = 'application/pdf'; 32 33 /** @var int[]|null */ 34 protected array|null $prevColor = null; 35 protected FPDF $fpdf; 36 37 /** 38 * QRFpdf constructor. 39 * 40 * @throws \chillerlan\QRCode\Output\QRCodeOutputException 41 */ 42 public function __construct(SettingsContainerInterface|QROptions|iterable $options, QRMatrix $matrix){ 33 43 34 44 if(!class_exists(FPDF::class)){ 35 45 // @codeCoverageIgnoreStart 36 throw new QRCodeException( 37 'The QRFpdf output requires FPDF as dependency but the class "\FPDF" couldn\'t be found.' 46 throw new QRCodeOutputException( 47 'The QRFpdf output requires FPDF (https://github.com/Setasign/FPDF)'. 48 // phpcs:ignore 49 ' as dependency but the class "\\FPDF" could not be found.' 38 50 ); 39 51 // @codeCoverageIgnoreEnd … … 44 56 45 57 /** 46 * @inheritDoc58 * Initializes an FPDF instance 47 59 */ 48 protected function setModuleValues():void{ 60 protected function initFPDF():FPDF{ 61 $fpdf = new FPDF('P', $this->options->fpdfMeasureUnit, $this->getOutputDimensions()); 62 $fpdf->AddPage(); 49 63 50 foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){51 $v = $this->options->moduleValues[$M_TYPE] ?? null;64 return $fpdf; 65 } 52 66 53 if(!is_array($v) || count($v) < 3){ 54 $this->moduleValues[$M_TYPE] = $defaultValue 55 ? [0, 0, 0] 56 : [255, 255, 255]; 57 } 58 else{ 59 $this->moduleValues[$M_TYPE] = array_values($v); 60 } 67 public function dump(string|null $file = null, FPDF|null $fpdf = null):string|FPDF{ 68 $this->fpdf = ($fpdf ?? $this->initFPDF()); 61 69 70 if($this::moduleValueIsValid($this->options->bgColor)){ 71 $bgColor = $this->prepareModuleValue($this->options->bgColor); 72 [$width, $height] = $this->getOutputDimensions(); 73 /** @phan-suppress-next-line PhanParamTooFewUnpack */ 74 $this->fpdf->SetFillColor(...$bgColor); 75 $this->fpdf->Rect(0, 0, $width, $height, 'F'); 62 76 } 63 77 64 }78 $this->prevColor = null; 65 79 66 /** 67 * @inheritDoc 68 * 69 * @return string|\FPDF 70 */ 71 public function dump(string $file = null){ 72 $file ??= $this->options->cachefile; 73 74 $fpdf = new FPDF('P', $this->options->fpdfMeasureUnit, [$this->length, $this->length]); 75 $fpdf->AddPage(); 76 77 $prevColor = null; 78 79 foreach($this->matrix->matrix() as $y => $row){ 80 80 foreach($this->matrix->getMatrix() as $y => $row){ 81 81 foreach($row as $x => $M_TYPE){ 82 /** @var int $M_TYPE */ 83 $color = $this->moduleValues[$M_TYPE]; 84 85 if($prevColor === null || $prevColor !== $color){ 86 $fpdf->SetFillColor(...$color); 87 $prevColor = $color; 88 } 89 90 $fpdf->Rect($x * $this->scale, $y * $this->scale, 1 * $this->scale, 1 * $this->scale, 'F'); 82 $this->module($x, $y, $M_TYPE); 91 83 } 92 93 84 } 94 85 95 86 if($this->options->returnResource){ 96 return $ fpdf;87 return $this->fpdf; 97 88 } 98 89 99 $pdfData = $ fpdf->Output('S');90 $pdfData = $this->fpdf->Output('S'); 100 91 101 if($file !== null){ 102 $this->saveToFile($pdfData, $file); 103 } 92 $this->saveToFile($pdfData, $file); 104 93 105 if($this->options-> imageBase64){106 $pdfData = sprintf('data:application/pdf;base64,%s', base64_encode($pdfData));94 if($this->options->outputBase64){ 95 $pdfData = $this->toBase64DataURI($pdfData); 107 96 } 108 97 … … 110 99 } 111 100 101 /** 102 * Renders a single module 103 */ 104 protected function module(int $x, int $y, int $M_TYPE):void{ 105 106 if(!$this->drawLightModules && !$this->matrix->isDark($M_TYPE)){ 107 return; 108 } 109 110 $color = $this->getModuleValue($M_TYPE); 111 112 if($color !== null && $color !== $this->prevColor){ 113 /** @phan-suppress-next-line PhanParamTooFewUnpack */ 114 $this->fpdf->SetFillColor(...$color); 115 $this->prevColor = $color; 116 } 117 118 $this->fpdf->Rect(($x * $this->scale), ($y * $this->scale), $this->scale, $this->scale, 'F'); 119 } 120 112 121 } -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Output/QRImagick.php
r2466054 r3752647 3 3 * Class QRImagick 4 4 * 5 * @filesource QRImagick.php6 5 * @created 04.07.2018 7 * @package chillerlan\QRCode\Output8 6 * @author smiley <smiley@chillerlan.net> 9 7 * @copyright 2018 smiley … … 12 10 * @noinspection PhpComposerExtensionStubsInspection 13 11 */ 12 declare(strict_types=1); 14 13 15 14 namespace chillerlan\QRCode\Output; 16 15 16 use chillerlan\QRCode\QROptions; 17 17 use chillerlan\QRCode\Data\QRMatrix; 18 use chillerlan\QRCode\QRCodeException;19 18 use chillerlan\Settings\SettingsContainerInterface; 20 19 use Imagick, ImagickDraw, ImagickPixel; 21 22 use function extension_loaded, is_string; 20 use function extension_loaded, in_array, is_string, max, min, preg_match, sprintf, strlen; 23 21 24 22 /** 25 23 * ImageMagick output module (requires ext-imagick) 26 24 * 27 * @see http ://php.net/manual/book.imagick.php28 * @see http ://phpimagick.com25 * @see https://php.net/manual/book.imagick.php 26 * @see https://phpimagick.com 29 27 */ 30 28 class QRImagick extends QROutputAbstract{ 31 29 30 /** 31 * The main image instance 32 */ 32 33 protected Imagick $imagick; 33 34 34 35 /** 35 * @inheritDoc 36 */ 37 public function __construct(SettingsContainerInterface $options, QRMatrix $matrix){ 38 39 if(!extension_loaded('imagick')){ 40 throw new QRCodeException('ext-imagick not loaded'); // @codeCoverageIgnore 41 } 42 43 parent::__construct($options, $matrix); 44 } 45 46 /** 47 * @inheritDoc 48 */ 49 protected function setModuleValues():void{ 50 51 foreach($this::DEFAULT_MODULE_VALUES as $type => $defaultValue){ 52 $v = $this->options->moduleValues[$type] ?? null; 53 54 if(!is_string($v)){ 55 $this->moduleValues[$type] = $defaultValue 56 ? new ImagickPixel($this->options->markupDark) 57 : new ImagickPixel($this->options->markupLight); 58 } 59 else{ 60 $this->moduleValues[$type] = new ImagickPixel($v); 61 } 62 } 63 } 36 * The main draw instance 37 */ 38 protected ImagickDraw $imagickDraw; 39 40 /** 41 * The allocated background color 42 */ 43 protected ImagickPixel $backgroundColor; 64 44 65 45 /** 66 46 * @inheritDoc 67 47 * 68 * @return string|\Imagick 69 */ 70 public function dump(string $file = null){ 71 $file ??= $this->options->cachefile; 72 $this->imagick = new Imagick; 73 74 $this->imagick->newImage( 75 $this->length, 76 $this->length, 77 new ImagickPixel($this->options->imagickBG ?? 'transparent'), 78 $this->options->imagickFormat 79 ); 48 * @throws \chillerlan\QRCode\Output\QRCodeOutputException 49 */ 50 public function __construct(SettingsContainerInterface|QROptions|iterable $options, QRMatrix $matrix){ 51 52 foreach(['fileinfo', 'imagick'] as $ext){ 53 if(!extension_loaded($ext)){ 54 throw new QRCodeOutputException(sprintf('ext-%s not loaded', $ext)); // @codeCoverageIgnore 55 } 56 } 57 58 parent::__construct($options, $matrix); 59 } 60 61 /** 62 * note: we're not necessarily validating the several values, just checking the general syntax 63 * 64 * @see https://www.php.net/manual/imagickpixel.construct.php 65 * @inheritDoc 66 */ 67 public static function moduleValueIsValid(mixed $value):bool{ 68 69 if(!is_string($value)){ 70 return false; 71 } 72 73 $value = trim($value); 74 75 // hex notation 76 // #rgb(a) 77 // #rrggbb(aa) 78 // #rrrrggggbbbb(aaaa) 79 // ... 80 if(preg_match('/^#[a-f\d]+$/i', $value) && in_array((strlen($value) - 1), [3, 4, 6, 8, 9, 12, 16, 24, 32], true)){ 81 return true; 82 } 83 84 // css (-like) func(...values) 85 if(preg_match('#^(graya?|hs(b|la?)|rgba?)\([\d .,%]+\)$#i', $value)){ 86 return true; 87 } 88 89 // predefined css color 90 if(preg_match('/^[a-z]+$/i', $value)){ 91 return true; 92 } 93 94 return false; 95 } 96 97 protected function prepareModuleValue(mixed $value):ImagickPixel{ 98 return new ImagickPixel($value); 99 } 100 101 protected function getDefaultModuleValue(bool $isDark):ImagickPixel{ 102 return $this->prepareModuleValue(($isDark) ? '#000' : '#fff'); 103 } 104 105 public function dump(string|null $file = null):string|Imagick{ 106 $this->setBgColor(); 107 108 $this->imagick = $this->createImage(); 80 109 81 110 $this->drawImage(); 111 // set transparency color after all operations 112 $this->setTransparencyColor(); 82 113 83 114 if($this->options->returnResource){ … … 87 118 $imageData = $this->imagick->getImageBlob(); 88 119 89 if($file !== null){ 90 $this->saveToFile($imageData, $file); 120 $this->imagick->destroy(); 121 122 $this->saveToFile($imageData, $file); 123 124 if($this->options->outputBase64){ 125 $imageData = $this->toBase64DataURI($imageData); 91 126 } 92 127 … … 95 130 96 131 /** 132 * Sets the background color 133 */ 134 protected function setBgColor():void{ 135 136 if($this::moduleValueIsValid($this->options->bgColor)){ 137 $this->backgroundColor = $this->prepareModuleValue($this->options->bgColor); 138 139 return; 140 } 141 142 $this->backgroundColor = $this->prepareModuleValue('white'); 143 } 144 145 /** 146 * Creates a new Imagick instance 147 */ 148 protected function createImage():Imagick{ 149 $imagick = new Imagick; 150 [$width, $height] = $this->getOutputDimensions(); 151 152 $imagick->newImage($width, $height, $this->backgroundColor, $this->options->imagickFormat); 153 154 if($this->options->quality > -1){ 155 $imagick->setImageCompressionQuality(max(0, min(100, $this->options->quality))); 156 } 157 158 return $imagick; 159 } 160 161 /** 162 * Sets the transparency color 163 */ 164 protected function setTransparencyColor():void{ 165 166 if(!$this->options->imageTransparent){ 167 return; 168 } 169 170 $transparencyColor = $this->backgroundColor; 171 172 if($this::moduleValueIsValid($this->options->transparencyColor)){ 173 $transparencyColor = $this->prepareModuleValue($this->options->transparencyColor); 174 } 175 176 $this->imagick->transparentPaintImage($transparencyColor, 0.0, 10, false); 177 } 178 179 /** 97 180 * Creates the QR image via ImagickDraw 98 181 */ 99 182 protected function drawImage():void{ 100 $draw = new ImagickDraw; 101 102 foreach($this->matrix->matrix() as $y => $row){ 183 $this->imagickDraw = new ImagickDraw; 184 $this->imagickDraw->setStrokeWidth(0); 185 186 foreach($this->matrix->getMatrix() as $y => $row){ 103 187 foreach($row as $x => $M_TYPE){ 104 $draw->setStrokeColor($this->moduleValues[$M_TYPE]); 105 $draw->setFillColor($this->moduleValues[$M_TYPE]); 106 $draw->rectangle( 107 $x * $this->scale, 108 $y * $this->scale, 109 ($x + 1) * $this->scale, 110 ($y + 1) * $this->scale 111 ); 112 188 $this->module($x, $y, $M_TYPE); 113 189 } 114 190 } 115 191 116 $this->imagick->drawImage($draw); 192 $this->imagick->drawImage($this->imagickDraw); 193 } 194 195 /** 196 * draws a single pixel at the given position 197 */ 198 protected function module(int $x, int $y, int $M_TYPE):void{ 199 200 if(!$this->drawLightModules && !$this->matrix->isDark($M_TYPE)){ 201 return; 202 } 203 204 $this->imagickDraw->setFillColor($this->getModuleValue($M_TYPE)); 205 206 if($this->drawCircularModules && !$this->matrix->checkTypeIn($x, $y, $this->keepAsSquare)){ 207 $this->imagickDraw->circle( 208 (($x + 0.5) * $this->scale), 209 (($y + 0.5) * $this->scale), 210 (($x + 0.5 + $this->circleRadius) * $this->scale), 211 (($y + 0.5) * $this->scale), 212 ); 213 214 return; 215 } 216 217 $this->imagickDraw->rectangle( 218 ($x * $this->scale), 219 ($y * $this->scale), 220 ((($x + 1) * $this->scale) - 1), 221 ((($y + 1) * $this->scale) - 1), 222 ); 117 223 } 118 224 -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Output/QRMarkup.php
r2466054 r3752647 3 3 * Class QRMarkup 4 4 * 5 * @filesource QRMarkup.php6 5 * @created 17.12.2016 7 * @package chillerlan\QRCode\Output8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2016 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode\Output; 14 13 15 use chillerlan\QRCode\QRCode; 14 /** 15 * Abstract for markup types: HTML, SVG, ... XML anyone? 16 */ 17 abstract class QRMarkup extends QROutputAbstract{ 18 use CssColorModuleValueTrait; 16 19 17 use function is_string, sprintf, strip_tags, trim; 20 public function dump(string|null $file = null):string{ 21 $saveToFile = $file !== null; 22 $data = $this->createMarkup($saveToFile); 18 23 19 /** 20 * Converts the matrix into markup types: HTML, SVG, ... 21 */ 22 class QRMarkup extends QROutputAbstract{ 24 $this->saveToFile($data, $file); 23 25 24 protected string $defaultMode = QRCode::OUTPUT_MARKUP_SVG; 25 26 /** 27 * @see \sprintf() 28 */ 29 protected string $svgHeader = '<svg xmlns="http://www.w3.org/2000/svg" class="qr-svg %1$s" '. 30 'style="width: 100%%; height: auto;" viewBox="0 0 %2$d %2$d">'; 31 32 /** 33 * @inheritDoc 34 */ 35 protected function setModuleValues():void{ 36 37 foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){ 38 $v = $this->options->moduleValues[$M_TYPE] ?? null; 39 40 if(!is_string($v)){ 41 $this->moduleValues[$M_TYPE] = $defaultValue 42 ? $this->options->markupDark 43 : $this->options->markupLight; 44 } 45 else{ 46 $this->moduleValues[$M_TYPE] = trim(strip_tags($v), '\'"'); 47 } 48 26 // transform to data URI only when not saving to file 27 if(!$saveToFile && $this->options->outputBase64){ 28 return $this->toBase64DataURI($data); 49 29 } 50 30 31 return $data; 51 32 } 52 33 53 34 /** 54 * HTML output35 * returns a string with all css classes for the current element 55 36 */ 56 protected function html(string $file = null):string{ 57 58 $html = empty($this->options->cssClass) 59 ? '<div>' 60 : '<div class="'.$this->options->cssClass.'">'; 61 62 $html .= $this->options->eol; 63 64 foreach($this->matrix->matrix() as $row){ 65 $html .= '<div>'; 66 67 foreach($row as $M_TYPE){ 68 $html .= '<span style="background: '.$this->moduleValues[$M_TYPE].';"></span>'; 69 } 70 71 $html .= '</div>'.$this->options->eol; 72 } 73 74 $html .= '</div>'.$this->options->eol; 75 76 if($file !== null){ 77 return '<!DOCTYPE html>'. 78 '<head><meta charset="UTF-8"><title>QR Code</title></head>'. 79 '<body>'.$this->options->eol.$html.'</body>'; 80 } 81 82 return $html; 37 protected function getCssClass(int $M_TYPE = 0):string{ 38 return $this->options->cssClass; 83 39 } 84 40 85 41 /** 86 * SVG output 87 * 88 * @see https://github.com/codemasher/php-qrcode/pull/5 42 * returns the fully parsed and rendered markup string for the given input 89 43 */ 90 protected function svg(string $file = null):string{ 91 $matrix = $this->matrix->matrix(); 92 93 $svg = sprintf($this->svgHeader, $this->options->cssClass, $this->options->svgViewBoxSize ?? $this->moduleCount) 94 .$this->options->eol 95 .'<defs>'.$this->options->svgDefs.'</defs>' 96 .$this->options->eol; 97 98 foreach($this->moduleValues as $M_TYPE => $value){ 99 $path = ''; 100 101 foreach($matrix as $y => $row){ 102 //we'll combine active blocks within a single row as a lightweight compression technique 103 $start = null; 104 $count = 0; 105 106 foreach($row as $x => $module){ 107 108 if($module === $M_TYPE){ 109 $count++; 110 111 if($start === null){ 112 $start = $x; 113 } 114 115 if(isset($row[$x + 1])){ 116 continue; 117 } 118 } 119 120 if($count > 0){ 121 $len = $count; 122 $start ??= 0; // avoid type coercion in sprintf() - phan happy 123 124 $path .= sprintf('M%s %s h%s v1 h-%sZ ', $start, $y, $len, $len); 125 126 // reset count 127 $count = 0; 128 $start = null; 129 } 130 131 } 132 133 } 134 135 if(!empty($path)){ 136 $svg .= sprintf( 137 '<path class="qr-%s %s" stroke="transparent" fill="%s" fill-opacity="%s" d="%s" />', 138 $M_TYPE, $this->options->cssClass, $value, $this->options->svgOpacity, $path 139 ); 140 } 141 142 } 143 144 // close svg 145 $svg .= '</svg>'.$this->options->eol; 146 147 // if saving to file, append the correct headers 148 if($file !== null){ 149 return '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'. 150 $this->options->eol.$svg; 151 } 152 153 if($this->options->imageBase64){ 154 $svg = sprintf('data:image/svg+xml;base64,%s', base64_encode($svg)); 155 } 156 157 return $svg; 158 } 44 abstract protected function createMarkup(bool $saveToFile):string; 159 45 160 46 } -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php
r2466054 r3752647 3 3 * Class QROutputAbstract 4 4 * 5 * @filesource QROutputAbstract.php6 5 * @created 09.12.2015 7 * @package chillerlan\QRCode\Output8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2015 Smiley 10 8 * @license MIT 9 * 10 * @noinspection PhpComposerExtensionStubsInspection 11 11 */ 12 declare(strict_types=1); 12 13 13 14 namespace chillerlan\QRCode\Output; 14 15 15 use chillerlan\QRCode\{Data\QRMatrix, QRCode}; 16 use chillerlan\QRCode\QROptions; 17 use chillerlan\QRCode\Data\QRMatrix; 16 18 use chillerlan\Settings\SettingsContainerInterface; 17 18 use function call_user_func_array, dirname, file_put_contents, get_called_class, in_array, is_writable, sprintf; 19 use finfo; 20 use function base64_encode, dirname, extension_loaded, file_put_contents, is_iterable, is_writable, ksort, sprintf; 21 use const FILEINFO_MIME_TYPE; 19 22 20 23 /** … … 26 29 * the current size of the QR matrix 27 30 * 28 * @see \chillerlan\QRCode\Data\QRMatrix:: size()31 * @see \chillerlan\QRCode\Data\QRMatrix::getSize() 29 32 */ 30 33 protected int $moduleCount; 31 34 32 35 /** 33 * the current output mode 34 * 35 * @see \chillerlan\QRCode\QROptions::$outputType 36 */ 37 protected string $outputMode; 38 39 /** 40 * the default output mode of the current output module 41 */ 42 protected string $defaultMode; 43 44 /** 45 * the current scaling for a QR pixel 36 * the side length of the QR image (modules * scale) 37 */ 38 protected int $length; 39 40 /** 41 * The current module scale value (might have been modified) 46 42 * 47 43 * @see \chillerlan\QRCode\QROptions::$scale … … 50 46 51 47 /** 52 * the side length of the QR image (modules * scale)53 */54 protected int $length;55 56 /**57 48 * an (optional) array of color values for the several QR matrix parts 49 * 50 * @phpstan-var array<int, mixed> 58 51 */ 59 52 protected array $moduleValues; … … 65 58 66 59 /** 67 * @var \chillerlan\Settings\SettingsContainerInterface|\chillerlan\QRCode\QROptions 68 */ 69 protected SettingsContainerInterface $options; 60 * the options instance 61 */ 62 protected SettingsContainerInterface|QROptions $options; 63 64 /** 65 * @see \chillerlan\QRCode\QROptions::$excludeFromConnect 66 * @var int[] 67 * @deprecated 6.0.1 This property will be removed in v7, use `$this->options->excludeFromConnect` instead. 68 */ 69 protected array $excludeFromConnect; 70 71 /** 72 * @see \chillerlan\QRCode\QROptions::$keepAsSquare 73 * @var int[] 74 * @deprecated 6.0.1 This property will be removed in v7, use `$this->options->keepAsSquare` instead. 75 */ 76 protected array $keepAsSquare; 77 78 /** 79 * @see \chillerlan\QRCode\QROptions::$connectPaths 80 * @deprecated 6.0.1 This property will be removed in v7, use `$this->options->connectPaths` instead. 81 */ 82 protected bool $connectPaths; 83 84 /** 85 * @see \chillerlan\QRCode\QROptions::$eol 86 * @deprecated 6.0.1 This property will be removed in v7, use `$this->options->eol` instead. 87 */ 88 protected string $eol; 89 90 /** 91 * @see \chillerlan\QRCode\QROptions::$drawLightModules 92 * @deprecated 6.0.1 This property will be removed in v7, use `$this->options->drawLightModules` instead. 93 */ 94 protected bool $drawLightModules; 95 96 /** 97 * @see \chillerlan\QRCode\QROptions::$drawCircularModules 98 * @deprecated 6.0.1 This property will be removed in v7, use `$this->options->drawCircularModules` instead. 99 */ 100 protected bool $drawCircularModules; 101 102 /** 103 * @see \chillerlan\QRCode\QROptions::$circleRadius 104 * @deprecated 6.0.1 This property will be removed in v7, use `$this->options->circleRadius` instead. 105 */ 106 protected float $circleRadius; 107 108 /** 109 * @deprecated 6.0.1 This property will be removed in v7, use `$this->options->circleRadius * 2` instead. 110 */ 111 protected float $circleDiameter; 70 112 71 113 /** 72 114 * QROutputAbstract constructor. 73 115 */ 74 public function __construct(SettingsContainerInterface $options, QRMatrix $matrix){ 75 $this->options = $options; 76 $this->matrix = $matrix; 77 $this->moduleCount = $this->matrix->size(); 116 public function __construct(SettingsContainerInterface|QROptions|iterable $options, QRMatrix $matrix){ 117 118 if(is_iterable($options)){ 119 $options = new QROptions($options); 120 } 121 122 $this->options = $options; 123 $this->matrix = $matrix; 124 125 if($this->options->invertMatrix){ 126 $this->matrix->invert(); 127 } 128 129 $this->copyVars(); 130 $this->setMatrixDimensions(); 131 $this->setModuleValues(); 132 } 133 134 /** 135 * Creates copies of several QROptions values to avoid calling the magic getters/property hooks 136 * in long loops for a significant performance increase. 137 * 138 * These variables are usually used in the "module" methods and are called up to 31329 times (at version 40). 139 * 140 * @deprecated 6.0.1 This method will be removed in v7 without replacement (unnecessary). 141 */ 142 protected function copyVars():void{ 143 144 $vars = [ 145 'connectPaths', 146 'excludeFromConnect', 147 'eol', 148 'drawLightModules', 149 'drawCircularModules', 150 'keepAsSquare', 151 'circleRadius', 152 ]; 153 154 foreach($vars as $property){ 155 $this->{$property} = $this->options->{$property}; 156 } 157 158 $this->circleDiameter = ($this->circleRadius * 2); 159 } 160 161 /** 162 * Sets/updates the matrix dimensions 163 * 164 * Call this method if you modify the matrix from within your custom output class in case the dimensions have been changed 165 */ 166 protected function setMatrixDimensions():void{ 167 $this->moduleCount = $this->matrix->getSize(); 78 168 $this->scale = $this->options->scale; 79 $this->length = $this->moduleCount * $this->scale; 80 81 $class = get_called_class(); 82 83 if(isset(QRCode::OUTPUT_MODES[$class]) && in_array($this->options->outputType, QRCode::OUTPUT_MODES[$class])){ 84 $this->outputMode = $this->options->outputType; 85 } 86 87 $this->setModuleValues(); 88 } 89 90 /** 91 * Sets the initial module values (clean-up & defaults) 92 */ 93 abstract protected function setModuleValues():void; 94 95 /** 96 * saves the qr data to a file 169 $this->length = ($this->moduleCount * $this->scale); 170 } 171 172 /** 173 * Returns a 2 element array with the current output width and height 174 * 175 * The type and units of the values depend on the output class. The default value is the current module count * scale. 176 * 177 * @return int[] 178 */ 179 protected function getOutputDimensions():array{ 180 return [$this->length, $this->length]; 181 } 182 183 /** 184 * Sets the initial module values 185 */ 186 protected function setModuleValues():void{ 187 188 // first fill the map with the default values 189 foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){ 190 $this->moduleValues[$M_TYPE] = $this->getDefaultModuleValue($defaultValue); 191 } 192 193 // now loop over the options values to replace defaults and add extra values 194 /** @var int $M_TYPE */ 195 foreach($this->options->moduleValues as $M_TYPE => $value){ 196 if($this::moduleValueIsValid($value)){ 197 $this->moduleValues[$M_TYPE] = $this->prepareModuleValue($value); 198 } 199 } 200 201 } 202 203 /** 204 * Prepares the value for the given input (return value depends on the output class) 205 */ 206 abstract protected function prepareModuleValue(mixed $value):mixed; 207 208 /** 209 * Returns a default value for either dark or light modules (return value depends on the output class) 210 */ 211 abstract protected function getDefaultModuleValue(bool $isDark):mixed; 212 213 /** 214 * Returns the prepared value for the given $M_TYPE 215 * 216 * @throws \chillerlan\QRCode\Output\QRCodeOutputException if $moduleValues[$M_TYPE] doesn't exist 217 */ 218 protected function getModuleValue(int $M_TYPE):mixed{ 219 220 if(!isset($this->moduleValues[$M_TYPE])){ 221 throw new QRCodeOutputException(sprintf('$M_TYPE %012b not found in module values map', $M_TYPE)); 222 } 223 224 return $this->moduleValues[$M_TYPE]; 225 } 226 227 /** 228 * Returns the prepared module value at the given coordinate [$x, $y] (convenience) 229 */ 230 protected function getModuleValueAt(int $x, int $y):mixed{ 231 return $this->getModuleValue($this->matrix->get($x, $y)); 232 } 233 234 /** 235 * Returns a base64 data URI for the given string and mime type 236 * 237 * The mime type can be set via class constant MIME_TYPE in child classes, 238 * or given via $mime, otherwise it is guessed from the image $data. 239 */ 240 protected function toBase64DataURI(string $data, string|null $mime = null):string{ 241 $mime ??= static::MIME_TYPE; 242 243 if($mime === ''){ 244 $mime = $this->guessMimeType($data); 245 } 246 247 return sprintf('data:%s;base64,%s', $mime, base64_encode($data)); 248 } 249 250 /** 251 * Guesses the mime type from the given $imageData 252 * 253 * @throws \chillerlan\QRCode\Output\QRCodeOutputException 254 */ 255 protected function guessMimeType(string $imageData):string{ 256 257 if(!extension_loaded('fileinfo')){ 258 throw new QRCodeOutputException('ext-fileinfo not loaded, cannot guess mime type'); 259 } 260 261 $mime = (new finfo(FILEINFO_MIME_TYPE))->buffer($imageData); 262 263 if($mime === false){ 264 throw new QRCodeOutputException('unable to detect mime type'); 265 } 266 267 return $mime; 268 } 269 270 /** 271 * Saves the qr $data to a $file. If $file is null, nothing happens. 97 272 * 98 273 * @see file_put_contents() 99 * @see \chillerlan\QRCode\QROptions:: cachefile274 * @see \chillerlan\QRCode\QROptions::$cachefile 100 275 * 101 276 * @throws \chillerlan\QRCode\Output\QRCodeOutputException 102 277 */ 103 protected function saveToFile(string $data, string $file):bool{ 278 protected function saveToFile(string $data, string|null $file = null):void{ 279 280 if($file === null){ 281 return; 282 } 104 283 105 284 if(!is_writable(dirname($file))){ 106 throw new QRCodeOutputException(sprintf('Could not write data to cache file: %s', $file)); 107 } 108 109 return (bool)file_put_contents($file, $data); 110 } 111 112 /** 113 * @inheritDoc 114 */ 115 public function dump(string $file = null){ 116 $file ??= $this->options->cachefile; 117 118 // call the built-in output method with the optional file path as parameter 119 // to make the called method aware if a cache file was given 120 $data = call_user_func_array([$this, $this->outputMode ?? $this->defaultMode], [$file]); 121 122 if($file !== null){ 123 $this->saveToFile($data, $file); 124 } 125 126 return $data; 285 throw new QRCodeOutputException(sprintf('Cannot write data to cache file: %s', $file)); 286 } 287 288 if(file_put_contents($file, $data) === false){ 289 throw new QRCodeOutputException(sprintf('Cannot write data to cache file: %s (file_put_contents error)', $file)); 290 } 291 } 292 293 /** 294 * collects the modules per QRMatrix::M_* type, runs a transform method on each module and 295 * returns an array with the transformed modules. 296 * 297 * @see \chillerlan\QRCode\Output\QROutputAbstract::moduleTransform() 298 * 299 * @return array<int, mixed> 300 */ 301 protected function collectModules():array{ 302 $paths = []; 303 304 // collect the modules for each type 305 foreach($this->matrix->getMatrix() as $y => $row){ 306 foreach($row as $x => $M_TYPE){ 307 $M_TYPE_LAYER = $M_TYPE; 308 309 if($this->connectPaths && !$this->matrix->checkTypeIn($x, $y, $this->excludeFromConnect)){ 310 // to connect paths we'll redeclare the $M_TYPE_LAYER to data only 311 $M_TYPE_LAYER = QRMatrix::M_DATA; 312 313 if($this->matrix->isDark($M_TYPE)){ 314 $M_TYPE_LAYER = QRMatrix::M_DATA_DARK; 315 } 316 } 317 318 // collect the modules per $M_TYPE 319 $module = $this->moduleTransform($x, $y, $M_TYPE, $M_TYPE_LAYER); 320 321 if($module !== null){ 322 $paths[$M_TYPE_LAYER][] = $module; 323 } 324 } 325 } 326 327 // beautify output 328 ksort($paths); 329 330 return $paths; 331 } 332 333 /** 334 * The transform callback for the module collector 335 * 336 * $x - current column 337 * $y - current row 338 * $M_TYPE - field value 339 * $M_TYPE_LAYER - (possibly modified) field value that acts as layer id ($paths array key) 340 * 341 * This method should return a value suitable for the current output class. 342 * It must return `null` for an empty value. 343 * 344 * @see \chillerlan\QRCode\Output\QROutputAbstract::collectModules() 345 */ 346 protected function moduleTransform(int $x, int $y, int $M_TYPE, int $M_TYPE_LAYER):mixed{ 347 return null; 127 348 } 128 349 -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/Output/QROutputInterface.php
r2466054 r3752647 3 3 * Interface QROutputInterface, 4 4 * 5 * @filesource QROutputInterface.php6 5 * @created 02.12.2015 7 * @package chillerlan\QRCode\Output8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2015 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode\Output; … … 20 19 interface QROutputInterface{ 21 20 22 const DEFAULT_MODULE_VALUES = [ 23 // light 24 QRMatrix::M_NULL => false, // 0 25 QRMatrix::M_DATA => false, // 4 26 QRMatrix::M_FINDER => false, // 6 27 QRMatrix::M_SEPARATOR => false, // 8 28 QRMatrix::M_ALIGNMENT => false, // 10 29 QRMatrix::M_TIMING => false, // 12 30 QRMatrix::M_FORMAT => false, // 14 31 QRMatrix::M_VERSION => false, // 16 32 QRMatrix::M_QUIETZONE => false, // 18 33 QRMatrix::M_LOGO => false, // 20 34 QRMatrix::M_TEST => false, // 255 35 // dark 36 QRMatrix::M_DARKMODULE << 8 => true, // 512 37 QRMatrix::M_DATA << 8 => true, // 1024 38 QRMatrix::M_FINDER << 8 => true, // 1536 39 QRMatrix::M_ALIGNMENT << 8 => true, // 2560 40 QRMatrix::M_TIMING << 8 => true, // 3072 41 QRMatrix::M_FORMAT << 8 => true, // 3584 42 QRMatrix::M_VERSION << 8 => true, // 4096 43 QRMatrix::M_FINDER_DOT << 8 => true, // 5632 44 QRMatrix::M_TEST << 8 => true, // 65280 21 /** 22 * Map of built-in output class FQN 23 * 24 * @var string[] 25 * @see https://github.com/chillerlan/php-qrcode/issues/223 26 */ 27 public const MODES = [ 28 QREps::class, 29 QRFpdf::class, 30 QRGdImageAVIF::class, 31 QRGdImageBMP::class, 32 QRGdImageGIF::class, 33 QRGdImageJPEG::class, 34 QRGdImagePNG::class, 35 QRGdImageWEBP::class, 36 QRImagick::class, 37 QRInterventionImage::class, 38 QRMarkupHTML::class, 39 QRMarkupSVG::class, 40 QRMarkupXML::class, 41 QRStringJSON::class, 42 QRStringText::class, 45 43 ]; 46 44 47 45 /** 48 * generates the output, optionally dumps it to a file, and returns it46 * Map of module type => default value 49 47 * 50 * @ return mixed48 * @var bool[] 51 49 */ 52 public function dump(string $file = null); 50 public const DEFAULT_MODULE_VALUES = [ 51 // light 52 QRMatrix::M_NULL => false, 53 QRMatrix::M_DARKMODULE_LIGHT => false, 54 QRMatrix::M_DATA => false, 55 QRMatrix::M_FINDER => false, 56 QRMatrix::M_SEPARATOR => false, 57 QRMatrix::M_ALIGNMENT => false, 58 QRMatrix::M_TIMING => false, 59 QRMatrix::M_FORMAT => false, 60 QRMatrix::M_VERSION => false, 61 QRMatrix::M_QUIETZONE => false, 62 QRMatrix::M_LOGO => false, 63 QRMatrix::M_FINDER_DOT_LIGHT => false, 64 // dark 65 QRMatrix::M_DARKMODULE => true, 66 QRMatrix::M_DATA_DARK => true, 67 QRMatrix::M_FINDER_DARK => true, 68 QRMatrix::M_SEPARATOR_DARK => true, 69 QRMatrix::M_ALIGNMENT_DARK => true, 70 QRMatrix::M_TIMING_DARK => true, 71 QRMatrix::M_FORMAT_DARK => true, 72 QRMatrix::M_VERSION_DARK => true, 73 QRMatrix::M_QUIETZONE_DARK => true, 74 QRMatrix::M_LOGO_DARK => true, 75 QRMatrix::M_FINDER_DOT => true, 76 ]; 77 78 /** 79 * Map of module type => readable name (for CSS etc.) 80 * 81 * @var string[] 82 */ 83 public const LAYERNAMES = [ 84 // light 85 QRMatrix::M_NULL => 'null', 86 QRMatrix::M_DARKMODULE_LIGHT => 'darkmodule-light', 87 QRMatrix::M_DATA => 'data', 88 QRMatrix::M_FINDER => 'finder', 89 QRMatrix::M_SEPARATOR => 'separator', 90 QRMatrix::M_ALIGNMENT => 'alignment', 91 QRMatrix::M_TIMING => 'timing', 92 QRMatrix::M_FORMAT => 'format', 93 QRMatrix::M_VERSION => 'version', 94 QRMatrix::M_QUIETZONE => 'quietzone', 95 QRMatrix::M_LOGO => 'logo', 96 QRMatrix::M_FINDER_DOT_LIGHT => 'finder-dot-light', 97 // dark 98 QRMatrix::M_DARKMODULE => 'darkmodule', 99 QRMatrix::M_DATA_DARK => 'data-dark', 100 QRMatrix::M_FINDER_DARK => 'finder-dark', 101 QRMatrix::M_SEPARATOR_DARK => 'separator-dark', 102 QRMatrix::M_ALIGNMENT_DARK => 'alignment-dark', 103 QRMatrix::M_TIMING_DARK => 'timing-dark', 104 QRMatrix::M_FORMAT_DARK => 'format-dark', 105 QRMatrix::M_VERSION_DARK => 'version-dark', 106 QRMatrix::M_QUIETZONE_DARK => 'quietzone-dark', 107 QRMatrix::M_LOGO_DARK => 'logo-dark', 108 QRMatrix::M_FINDER_DOT => 'finder-dot', 109 ]; 110 111 /** 112 * Note: do not call this constant from the interface, but rather from one of the child classes 113 * 114 * @var string 115 * @see \chillerlan\QRCode\Output\QROutputAbstract::toBase64DataURI() 116 */ 117 public const MIME_TYPE = ''; 118 119 /** 120 * Determines whether the given value is valid 121 */ 122 public static function moduleValueIsValid(mixed $value):bool; 123 124 /** 125 * Generates the output, optionally dumps it to a file, and returns it 126 * 127 * please note that the value of QROptions::$cachefile is already evaluated at this point. 128 * if the output module is invoked manually, it has no effect at all. 129 * you need to supply the $file parameter here in that case (or handle the option value in your custom output module). 130 * 131 * @see \chillerlan\QRCode\QRCode::renderMatrix() 132 */ 133 public function dump(string|null $file = null):mixed; 53 134 54 135 } -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/QRCode.php
r2466054 r3752647 3 3 * Class QRCode 4 4 * 5 * @filesource QRCode.php6 5 * @created 26.11.2015 7 * @package chillerlan\QRCode8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2015 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode; 14 13 15 use chillerlan\QRCode\ Data\{16 AlphaNum, Byte, Kanji, MaskPatternTester, Number, QRCodeDataException, QRDataInterface, QRMatrix14 use chillerlan\QRCode\Common\{ 15 ECICharset, GDLuminanceSource, IMagickLuminanceSource, LuminanceSourceInterface, MaskPattern, Mode 17 16 }; 18 use chillerlan\QRCode\ Output\{19 QRCodeOutputException, QRFpdf, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString 20 };17 use chillerlan\QRCode\Data\{AlphaNum, Byte, ECI, Hanzi, Kanji, Number, QRData, QRDataModeInterface, QRMatrix}; 18 use chillerlan\QRCode\Decoder\{Decoder, DecoderResult}; 19 use chillerlan\QRCode\Output\{QRCodeOutputException, QROutputInterface}; 21 20 use chillerlan\Settings\SettingsContainerInterface; 22 23 use function call_user_func_array, class_exists, in_array, ord, strlen, strtolower, str_split; 21 use function class_exists, class_implements, in_array, is_iterable, mb_convert_encoding, mb_internal_encoding; 24 22 25 23 /** … … 27 25 * 28 26 * @see https://github.com/kazuhikoarase/qrcode-generator/tree/master/php 29 * @see http ://www.qrcode.com/en/codes/model12.html27 * @see https://www.qrcode.com/en/codes/model12.html 30 28 * @see https://www.swisseduc.ch/informatik/theoretische_informatik/qr_codes/docs/qr_standard.pdf 31 29 * @see https://en.wikipedia.org/wiki/QR_code 32 * @see http ://www.thonky.com/qr-code-tutorial/30 * @see https://www.thonky.com/qr-code-tutorial/ 33 31 */ 34 32 class QRCode{ 35 33 36 /** @var int */37 public const VERSION_AUTO = -1;38 /** @var int */39 public const MASK_PATTERN_AUTO = -1;40 41 // ISO/IEC 18004:2000 Table 242 43 /** @var int */44 public const DATA_NUMBER = 0b0001;45 /** @var int */46 public const DATA_ALPHANUM = 0b0010;47 /** @var int */48 public const DATA_BYTE = 0b0100;49 /** @var int */50 public const DATA_KANJI = 0b1000;51 52 /**53 * References to the keys of the following tables:54 *55 * @see \chillerlan\QRCode\Data\QRDataInterface::MAX_LENGTH56 *57 * @var int[]58 */59 public const DATA_MODES = [60 self::DATA_NUMBER => 0,61 self::DATA_ALPHANUM => 1,62 self::DATA_BYTE => 2,63 self::DATA_KANJI => 3,64 ];65 66 // ISO/IEC 18004:2000 Tables 12, 2567 68 /** @var int */69 public const ECC_L = 0b01; // 7%.70 /** @var int */71 public const ECC_M = 0b00; // 15%.72 /** @var int */73 public const ECC_Q = 0b11; // 25%.74 /** @var int */75 public const ECC_H = 0b10; // 30%.76 77 /**78 * References to the keys of the following tables:79 *80 * @see \chillerlan\QRCode\Data\QRDataInterface::MAX_BITS81 * @see \chillerlan\QRCode\Data\QRDataInterface::RSBLOCKS82 * @see \chillerlan\QRCode\Data\QRMatrix::formatPattern83 *84 * @var int[]85 */86 public const ECC_MODES = [87 self::ECC_L => 0,88 self::ECC_M => 1,89 self::ECC_Q => 2,90 self::ECC_H => 3,91 ];92 93 /** @var string */94 public const OUTPUT_MARKUP_HTML = 'html';95 /** @var string */96 public const OUTPUT_MARKUP_SVG = 'svg';97 /** @var string */98 public const OUTPUT_IMAGE_PNG = 'png';99 /** @var string */100 public const OUTPUT_IMAGE_JPG = 'jpg';101 /** @var string */102 public const OUTPUT_IMAGE_GIF = 'gif';103 /** @var string */104 public const OUTPUT_STRING_JSON = 'json';105 /** @var string */106 public const OUTPUT_STRING_TEXT = 'text';107 /** @var string */108 public const OUTPUT_IMAGICK = 'imagick';109 /** @var string */110 public const OUTPUT_FPDF = 'fpdf';111 /** @var string */112 public const OUTPUT_CUSTOM = 'custom';113 114 /**115 * Map of built-in output modules => capabilities116 *117 * @var string[][]118 */119 public const OUTPUT_MODES = [120 QRMarkup::class => [121 self::OUTPUT_MARKUP_SVG,122 self::OUTPUT_MARKUP_HTML,123 ],124 QRImage::class => [125 self::OUTPUT_IMAGE_PNG,126 self::OUTPUT_IMAGE_GIF,127 self::OUTPUT_IMAGE_JPG,128 ],129 QRString::class => [130 self::OUTPUT_STRING_JSON,131 self::OUTPUT_STRING_TEXT,132 ],133 QRImagick::class => [134 self::OUTPUT_IMAGICK,135 ],136 QRFpdf::class => [137 self::OUTPUT_FPDF138 ]139 ];140 141 /**142 * Map of data mode => interface143 *144 * @var string[]145 */146 protected const DATA_INTERFACES = [147 'number' => Number::class,148 'alphanum' => AlphaNum::class,149 'kanji' => Kanji::class,150 'byte' => Byte::class,151 ];152 153 34 /** 154 35 * The settings container 155 * 156 * @var \chillerlan\QRCode\QROptions|\chillerlan\Settings\SettingsContainerInterface 157 */ 158 protected SettingsContainerInterface $options; 159 160 /** 161 * The selected data interface (Number, AlphaNum, Kanji, Byte) 162 */ 163 protected QRDataInterface $dataInterface; 36 */ 37 protected SettingsContainerInterface|QROptions $options; 38 39 /** 40 * A collection of one or more data segments of QRDataModeInterface instances to write 41 * 42 * @var \chillerlan\QRCode\Data\QRDataModeInterface[] 43 */ 44 protected array $dataSegments = []; 45 46 /** 47 * The luminance source for the reader 48 */ 49 protected string $luminanceSourceFQN = GDLuminanceSource::class; 164 50 165 51 /** 166 52 * QRCode constructor. 167 53 * 168 * Sets the options instance, determines the current mb-encoding and sets it to UTF-8 169 */ 170 public function __construct(SettingsContainerInterface $options = null){ 171 $this->options = $options ?? new QROptions; 172 } 173 174 /** 175 * Renders a QR Code for the given $data and QROptions 176 * 177 * @return mixed 178 */ 179 public function render(string $data, string $file = null){ 180 return $this->initOutputInterface($data)->dump($file); 54 * @phpstan-param array<string, mixed> $options 55 */ 56 public function __construct(SettingsContainerInterface|QROptions|iterable $options = new QROptions){ 57 $this->setOptions($options); 58 } 59 60 /** 61 * Sets an options instance 62 * 63 * @phpstan-param array<string, mixed> $options 64 */ 65 public function setOptions(SettingsContainerInterface|QROptions|iterable $options):static{ 66 67 if(is_iterable($options)){ 68 $options = new QROptions($options); 69 } 70 71 $this->options = $options; 72 73 if($this->options->readerUseImagickIfAvailable){ 74 $this->luminanceSourceFQN = IMagickLuminanceSource::class; 75 } 76 77 return $this; 78 } 79 80 /** 81 * Renders a QR Code for the given $data and QROptions, saves $file optionally 82 */ 83 public function render(string|null $data = null, string|null $file = null):mixed{ 84 85 if($data !== null){ 86 /** @var \chillerlan\QRCode\Data\QRDataModeInterface $dataInterface */ 87 foreach(Mode::INTERFACES as $dataInterface){ 88 89 if($dataInterface::validateString($data)){ 90 $this->addSegment(new $dataInterface($data)); 91 92 break; 93 } 94 } 95 } 96 97 return $this->renderMatrix($this->getQRMatrix(), $file); 98 } 99 100 /** 101 * Renders a QR Code for the given QRMatrix and QROptions, saves $file optionally 102 */ 103 public function renderMatrix(QRMatrix $matrix, string|null $file = null):mixed{ 104 return $this->initOutputInterface($matrix)->dump($file ?? $this->options->cachefile); 181 105 } 182 106 183 107 /** 184 108 * Returns a QRMatrix object for the given $data and current QROptions 185 * 186 * @throws \chillerlan\QRCode\Data\QRCodeDataException 187 */ 188 public function getMatrix(string $data):QRMatrix{ 189 190 if(empty($data)){ 191 throw new QRCodeDataException('QRCode::getMatrix() No data given.'); 192 } 193 194 $this->dataInterface = $this->initDataInterface($data); 195 196 $maskPattern = $this->options->maskPattern === $this::MASK_PATTERN_AUTO 197 ? (new MaskPatternTester($this->dataInterface))->getBestMaskPattern() 198 : $this->options->maskPattern; 199 200 $matrix = $this->dataInterface->initMatrix($maskPattern); 201 202 if((bool)$this->options->addQuietzone){ 109 */ 110 public function getQRMatrix():QRMatrix{ 111 $matrix = (new QRData($this->options, $this->dataSegments))->writeMatrix(); 112 113 $maskPattern = $this->options->maskPattern === MaskPattern::AUTO 114 ? MaskPattern::getBestPattern($matrix) 115 : new MaskPattern($this->options->maskPattern); 116 117 $matrix->setFormatInfo($maskPattern)->mask($maskPattern); 118 119 return $this->addMatrixModifications($matrix); 120 } 121 122 /** 123 * add matrix modifications after mask pattern evaluation and before handing over to output 124 */ 125 protected function addMatrixModifications(QRMatrix $matrix):QRMatrix{ 126 127 if($this->options->addLogoSpace){ 128 // check whether one of the dimensions was omitted 129 $logoSpaceWidth = ($this->options->logoSpaceWidth ?? $this->options->logoSpaceHeight ?? 0); 130 $logoSpaceHeight = ($this->options->logoSpaceHeight ?? $logoSpaceWidth); 131 132 $matrix->setLogoSpace( 133 $logoSpaceWidth, 134 $logoSpaceHeight, 135 $this->options->logoSpaceStartX, 136 $this->options->logoSpaceStartY, 137 ); 138 } 139 140 if($this->options->addQuietzone){ 203 141 $matrix->setQuietZone($this->options->quietzoneSize); 204 142 } … … 208 146 209 147 /** 210 * returns a fresh QRDataInterface for the given $data 211 * 212 * @throws \chillerlan\QRCode\Data\QRCodeDataException 213 */ 214 public function initDataInterface(string $data):QRDataInterface{ 215 216 // allow forcing the data mode 217 // see https://github.com/chillerlan/php-qrcode/issues/39 218 $interface = $this::DATA_INTERFACES[strtolower($this->options->dataModeOverride)] ?? null; 219 220 if($interface !== null){ 221 return new $interface($this->options, $data); 222 } 223 224 foreach($this::DATA_INTERFACES as $mode => $dataInterface){ 225 226 if(call_user_func_array([$this, 'is'.$mode], [$data])){ 227 return new $dataInterface($this->options, $data); 228 } 229 230 } 231 232 throw new QRCodeDataException('invalid data type'); // @codeCoverageIgnore 233 } 234 235 /** 236 * returns a fresh (built-in) QROutputInterface 148 * initializes a fresh built-in or custom QROutputInterface 237 149 * 238 150 * @throws \chillerlan\QRCode\Output\QRCodeOutputException 239 151 */ 240 protected function initOutputInterface(string $data):QROutputInterface{ 241 242 if($this->options->outputType === $this::OUTPUT_CUSTOM && class_exists($this->options->outputInterface)){ 243 return new $this->options->outputInterface($this->options, $this->getMatrix($data)); 244 } 245 246 foreach($this::OUTPUT_MODES as $outputInterface => $modes){ 247 248 if(in_array($this->options->outputType, $modes, true) && class_exists($outputInterface)){ 249 return new $outputInterface($this->options, $this->getMatrix($data)); 250 } 251 252 } 253 254 throw new QRCodeOutputException('invalid output type'); 255 } 256 257 /** 258 * checks if a string qualifies as numeric 259 */ 260 public function isNumber(string $string):bool{ 261 return $this->checkString($string, QRDataInterface::CHAR_MAP_NUMBER); 262 } 263 264 /** 265 * checks if a string qualifies as alphanumeric 266 */ 267 public function isAlphaNum(string $string):bool{ 268 return $this->checkString($string, QRDataInterface::CHAR_MAP_ALPHANUM); 269 } 270 271 /** 272 * checks is a given $string matches the characters of a given $charmap, returns false on the first invalid occurence. 273 */ 274 protected function checkString(string $string, array $charmap):bool{ 275 276 foreach(str_split($string) as $chr){ 277 if(!isset($charmap[$chr])){ 278 return false; 279 } 280 } 281 282 return true; 283 } 284 285 /** 286 * checks if a string qualifies as Kanji 287 */ 288 public function isKanji(string $string):bool{ 289 $i = 0; 290 $len = strlen($string); 291 292 while($i + 1 < $len){ 293 $c = ((0xff & ord($string[$i])) << 8) | (0xff & ord($string[$i + 1])); 294 295 if(!($c >= 0x8140 && $c <= 0x9FFC) && !($c >= 0xE040 && $c <= 0xEBBF)){ 296 return false; 297 } 298 299 $i += 2; 300 } 301 302 return $i >= $len; 303 } 304 305 /** 306 * a dummy 307 */ 308 public function isByte(string $data):bool{ 309 return !empty($data); 152 protected function initOutputInterface(QRMatrix $matrix):QROutputInterface{ 153 $outputInterface = $this->options->outputInterface; 154 155 if(!class_exists($outputInterface)){ 156 throw new QRCodeOutputException('invalid output class'); 157 } 158 159 if(!in_array(QROutputInterface::class, class_implements($outputInterface), true)){ 160 throw new QRCodeOutputException('output class does not implement QROutputInterface'); 161 } 162 163 /** @var \chillerlan\QRCode\Output\QROutputInterface $instance */ 164 $instance = new $outputInterface($this->options, $matrix); 165 166 return $instance; 167 } 168 169 /** 170 * Adds a data segment 171 * 172 * ISO/IEC 18004:2000 8.3.6 - Mixing modes 173 * ISO/IEC 18004:2000 Annex H - Optimisation of bit stream length 174 */ 175 public function addSegment(QRDataModeInterface $segment):static{ 176 $this->dataSegments[] = $segment; 177 178 return $this; 179 } 180 181 /** 182 * Clears the data segments array 183 * 184 * @codeCoverageIgnore 185 */ 186 public function clearSegments():static{ 187 $this->dataSegments = []; 188 189 return $this; 190 } 191 192 /** 193 * Adds a numeric data segment 194 * 195 * ISO/IEC 18004:2000 8.3.2 - Numeric Mode 196 */ 197 public function addNumericSegment(string $data):static{ 198 return $this->addSegment(new Number($data)); 199 } 200 201 /** 202 * Adds an alphanumeric data segment 203 * 204 * ISO/IEC 18004:2000 8.3.3 - Alphanumeric Mode 205 */ 206 public function addAlphaNumSegment(string $data):static{ 207 return $this->addSegment(new AlphaNum($data)); 208 } 209 210 /** 211 * Adds a Kanji data segment (Japanese 13-bit double-byte characters, Shift-JIS) 212 * 213 * ISO/IEC 18004:2000 8.3.5 - Kanji Mode 214 */ 215 public function addKanjiSegment(string $data):static{ 216 return $this->addSegment(new Kanji($data)); 217 } 218 219 /** 220 * Adds a Hanzi data segment (simplified Chinese 13-bit double-byte characters, GB2312/GB18030) 221 * 222 * GBT18284-2000 Hanzi Mode 223 */ 224 public function addHanziSegment(string $data):static{ 225 return $this->addSegment(new Hanzi($data)); 226 } 227 228 /** 229 * Adds an 8-bit byte data segment 230 * 231 * ISO/IEC 18004:2000 8.3.4 - 8-bit Byte Mode 232 */ 233 public function addByteSegment(string $data):static{ 234 return $this->addSegment(new Byte($data)); 235 } 236 237 /** 238 * Adds a standalone ECI designator 239 * 240 * The ECI designator must be followed by a Byte segment that contains the string encoded according to the given ECI charset 241 * 242 * ISO/IEC 18004:2000 8.3.1 - Extended Channel Interpretation (ECI) Mode 243 */ 244 public function addEciDesignator(int $encoding):static{ 245 return $this->addSegment(new ECI($encoding)); 246 } 247 248 /** 249 * Adds an ECI data segment (including designator) 250 * 251 * The given string will be encoded from mb_internal_encoding() to the given ECI character set 252 * 253 * I hate this somehow, but I'll leave it for now 254 * 255 * @throws \chillerlan\QRCode\QRCodeException 256 */ 257 public function addEciSegment(int $encoding, string $data):static{ 258 // validate the encoding id 259 $eciCharset = new ECICharset($encoding); 260 // get charset name 261 $eciCharsetName = $eciCharset->getName(); 262 263 if($eciCharsetName === null){ 264 throw new QRCodeException('unable to add ECI segment'); 265 } 266 267 // convert the string to the given charset 268 $data = mb_convert_encoding($data, $eciCharsetName, mb_internal_encoding()); 269 270 if($data === false){ 271 throw new QRCodeException('mb_convert_encoding() error'); // @codeCoverageIgnore 272 } 273 274 return $this 275 ->addEciDesignator($eciCharset->getID()) 276 ->addByteSegment($data) 277 ; 278 } 279 280 /** 281 * Reads a QR Code from a given file 282 * 283 * @codeCoverageIgnore 284 */ 285 public function readFromFile(string $path):DecoderResult{ 286 return $this->readFromSource($this->luminanceSourceFQN::fromFile($path, $this->options)); 287 } 288 289 /** 290 * Reads a QR Code from the given data blob 291 */ 292 public function readFromBlob(string $blob):DecoderResult{ 293 return $this->readFromSource($this->luminanceSourceFQN::fromBlob($blob, $this->options)); 294 } 295 296 /** 297 * Reads a QR Code from the given luminance source 298 */ 299 public function readFromSource(LuminanceSourceInterface $source):DecoderResult{ 300 return (new Decoder($this->options))->decode($source); 310 301 } 311 302 -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/QRCodeException.php
r2466054 r3752647 3 3 * Class QRCodeException 4 4 * 5 * @filesource QRCodeException.php6 5 * @created 27.11.2015 7 * @package chillerlan\QRCode8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2015 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode; … … 18 17 * An exception container 19 18 */ 20 class QRCodeException extends Exception{} 19 class QRCodeException extends Exception{ 20 21 } -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/QROptions.php
r2466054 r3752647 3 3 * Class QROptions 4 4 * 5 * @filesource QROptions.php6 5 * @created 08.12.2015 7 * @package chillerlan\QRCode8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2015 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\QRCode; … … 17 16 /** 18 17 * The QRCode settings container 19 *20 * @property int $version21 * @property int $versionMin22 * @property int $versionMax23 * @property int $eccLevel24 * @property int $maskPattern25 * @property bool $addQuietzone26 * @property int $quietzoneSize27 * @property string|null $dataModeOverride28 * @property string $outputType29 * @property string|null $outputInterface30 * @property string|null $cachefile31 * @property string $eol32 * @property int $scale33 * @property string $cssClass34 * @property float $svgOpacity35 * @property string $svgDefs36 * @property int $svgViewBoxSize37 * @property string $textDark38 * @property string $textLight39 * @property string $markupDark40 * @property string $markupLight41 * @property bool $returnResource42 * @property bool $imageBase6443 * @property bool $imageTransparent44 * @property array $imageTransparencyBG45 * @property int $pngCompression46 * @property int $jpegQuality47 * @property string $imagickFormat48 * @property string|null $imagickBG49 * @property string $fpdfMeasureUnit50 * @property array|null $moduleValues51 18 */ 52 19 class QROptions extends SettingsContainerAbstract{ 53 use QROptionsTrait ;20 use QROptionsTrait, QRCodeReaderOptionsTrait; 54 21 } -
wp-otp/trunk/vendor/chillerlan/php-qrcode/src/QROptionsTrait.php
r2466054 r3752647 3 3 * Trait QROptionsTrait 4 4 * 5 * @filesource QROptionsTrait.php 5 * Note: the docblocks in this file are optimized for readability in PhpStorm ond on readthedocs.io 6 * 6 7 * @created 10.03.2018 7 * @package chillerlan\QRCode8 8 * @author smiley <smiley@chillerlan.net> 9 9 * @copyright 2018 smiley 10 10 * @license MIT 11 11 * 12 * @noinspection PhpUnused 12 * @noinspection PhpUnused, PhpComposerExtensionStubsInspection 13 13 */ 14 declare(strict_types=1); 14 15 15 16 namespace chillerlan\QRCode; 16 17 17 use function array_values, count, in_array, is_numeric, max, min, sprintf, strtolower; 18 use chillerlan\QRCode\Common\{EccLevel, MaskPattern, Version}; 19 use chillerlan\QRCode\Output\QRMarkupSVG; 20 use function constant, in_array, is_string, max, min, sprintf, strtolower, strtoupper, trim; 21 use const JSON_THROW_ON_ERROR, JSON_UNESCAPED_SLASHES, PHP_EOL; 18 22 19 23 /** 20 24 * The QRCode plug-in settings & setter functionality 25 * 26 * @property int $version 27 * @property int $versionMin 28 * @property int $versionMax 29 * @property int $eccLevel 30 * @property int $maskPattern 31 * @property bool $addQuietzone 32 * @property int $quietzoneSize 33 * @property string $outputInterface 34 * @property bool $returnResource 35 * @property string|null $cachefile 36 * @property bool $outputBase64 37 * @property string $eol 38 * @property mixed $bgColor 39 * @property bool $invertMatrix 40 * @property bool $drawLightModules 41 * @property bool $drawCircularModules 42 * @property float $circleRadius 43 * @property int[] $keepAsSquare 44 * @property bool $connectPaths 45 * @property int[] $excludeFromConnect 46 * @property array<int, mixed> $moduleValues 47 * @property bool $addLogoSpace 48 * @property int|null $logoSpaceWidth 49 * @property int|null $logoSpaceHeight 50 * @property int|null $logoSpaceStartX 51 * @property int|null $logoSpaceStartY 52 * @property int $scale 53 * @property bool $imageTransparent 54 * @property mixed $transparencyColor 55 * @property int $quality 56 * @property bool $gdImageUseUpscale 57 * @property string $imagickFormat 58 * @property string $cssClass 59 * @property bool $svgAddXmlHeader 60 * @property string $svgDefs 61 * @property string $svgPreserveAspectRatio 62 * @property bool $svgUseFillAttributes 63 * @property string $textLineStart 64 * @property int $jsonFlags 65 * @property string $fpdfMeasureUnit 66 * @property string|null $xmlStylesheet 21 67 */ 22 68 trait QROptionsTrait{ 23 69 70 /* 71 * QR Code specific settings 72 */ 73 24 74 /** 25 75 * QR Code version number 26 76 * 27 * [1 ... 40] or QRCode::VERSION_AUTO 28 */ 29 protected int $version = QRCode::VERSION_AUTO; 77 * `1 ... 40` or `Version::AUTO` (default) 78 * 79 * @see \chillerlan\QRCode\Common\Version 80 */ 81 protected int $version = Version::AUTO; 30 82 31 83 /** 32 84 * Minimum QR version 33 85 * 34 * if $version = QRCode::VERSION_AUTO86 * if `QROptions::$version` is set to `Version::AUTO` (default: 1) 35 87 */ 36 88 protected int $versionMin = 1; … … 38 90 /** 39 91 * Maximum QR version 92 * 93 * if `QROptions::$version` is set to `Version::AUTO` (default: 40) 40 94 */ 41 95 protected int $versionMax = 40; … … 44 98 * Error correct level 45 99 * 46 * QRCode::ECC_X where X is: 47 * 48 * - L => 7% 49 * - M => 15% 50 * - Q => 25% 51 * - H => 30% 52 */ 53 protected int $eccLevel = QRCode::ECC_L; 54 55 /** 56 * Mask Pattern to use 57 * 58 * [0...7] or QRCode::MASK_PATTERN_AUTO 59 */ 60 protected int $maskPattern = QRCode::MASK_PATTERN_AUTO; 100 * the constant `EccLevel::X` where `X` is: 101 * 102 * - `L` => 7% (default) 103 * - `M` => 15% 104 * - `Q` => 25% 105 * - `H` => 30% 106 * 107 * alternatively you can just pass the letters L/M/Q/H (case-insensitive) to the magic setter 108 * 109 * @see \chillerlan\QRCode\Common\EccLevel 110 * @see https://github.com/chillerlan/php-qrcode/discussions/160 111 */ 112 protected int $eccLevel = EccLevel::L; 113 114 /** 115 * Mask Pattern to use (no value in using, mostly for unit testing purposes) 116 * 117 * `0 ... 7` or `MaskPattern::PATTERN_AUTO` (default) 118 * 119 * @see \chillerlan\QRCode\Common\MaskPattern 120 */ 121 protected int $maskPattern = MaskPattern::AUTO; 61 122 62 123 /** 63 124 * Add a "quiet zone" (margin) according to the QR code spec 125 * 126 * @see https://www.qrcode.com/en/howto/code.html 64 127 */ 65 128 protected bool $addQuietzone = true; … … 68 131 * Size of the quiet zone 69 132 * 70 * internally clamped to [0 ... $moduleCount / 2], defaults to 4 modules133 * internally clamped to `0 ... $moduleCount / 2` (default: 4) 71 134 */ 72 135 protected int $quietzoneSize = 4; 73 136 74 /** 75 * Use this to circumvent the data mode detection and force the usage of the given mode. 76 * 77 * valid modes are: Number, AlphaNum, Kanji, Byte (case insensitive) 78 * 79 * @see https://github.com/chillerlan/php-qrcode/issues/39 80 */ 81 protected ?string $dataModeOverride = null; 82 83 /** 84 * The output type 85 * 86 * - QRCode::OUTPUT_MARKUP_XXXX where XXXX = HTML, SVG 87 * - QRCode::OUTPUT_IMAGE_XXX where XXX = PNG, GIF, JPG 88 * - QRCode::OUTPUT_STRING_XXXX where XXXX = TEXT, JSON 89 * - QRCode::OUTPUT_CUSTOM 90 */ 91 protected string $outputType = QRCode::OUTPUT_IMAGE_PNG; 92 93 /** 94 * the FQCN of the custom QROutputInterface if $outputType is set to QRCode::OUTPUT_CUSTOM 95 */ 96 protected ?string $outputInterface = null; 97 98 /** 99 * /path/to/cache.file 100 */ 101 protected ?string $cachefile = null; 102 103 /** 104 * newline string [HTML, SVG, TEXT] 137 138 /* 139 * General output settings 140 */ 141 142 /** 143 * The FQCN of the `QROutputInterface` to use 144 */ 145 protected string $outputInterface = QRMarkupSVG::class; 146 147 /** 148 * Return the image resource instead of a render if applicable. 149 * 150 * - `QRGdImage`: `resource` (PHP < 8), `GdImage` 151 * - `QRImagick`: `Imagick` 152 * - `QRFpdf`: `FPDF` 153 * 154 * This option overrides/ignores other output settings, such as `QROptions::$cachefile` 155 * and `QROptions::$outputBase64`. (default: `false`) 156 * 157 * @see \chillerlan\QRCode\Output\QROutputInterface::dump() 158 */ 159 protected bool $returnResource = false; 160 161 /** 162 * Optional cache file path `/path/to/cache.file` 163 * 164 * Please note that the `$file` parameter in `QRCode::render()` and `QRCode::renderMatrix()` 165 * takes precedence over the `QROptions::$cachefile` value. (default: `null`) 166 * 167 * @see \chillerlan\QRCode\QRCode::render() 168 * @see \chillerlan\QRCode\QRCode::renderMatrix() 169 */ 170 protected string|null $cachefile = null; 171 172 /** 173 * Toggle base64 data URI or raw data output (if applicable) 174 * 175 * (default: `true`) 176 * 177 * @see \chillerlan\QRCode\Output\QROutputAbstract::toBase64DataURI() 178 */ 179 protected bool $outputBase64 = true; 180 181 /** 182 * Newline string 183 * 184 * (default: `PHP_EOL`) 105 185 */ 106 186 protected string $eol = PHP_EOL; 107 187 108 /** 109 * size of a QR code pixel [SVG, IMAGE_*], HTML via CSS 188 189 /* 190 * Common visual modifications 191 */ 192 193 /** 194 * Sets the image background color (if applicable) 195 * 196 * - `QRImagick`: defaults to `"white"` 197 * - `QRGdImage`: defaults to `[255, 255, 255]` 198 * - `QRFpdf`: defaults to blank internally (white page) 199 */ 200 protected mixed $bgColor = null; 201 202 /** 203 * Whether to invert the matrix (reflectance reversal) 204 * 205 * (default: `false`) 206 * 207 * @see \chillerlan\QRCode\Data\QRMatrix::invert() 208 */ 209 protected bool $invertMatrix = false; 210 211 /** 212 * Whether to draw the light (false) modules 213 * 214 * (default: `true`) 215 */ 216 protected bool $drawLightModules = true; 217 218 /** 219 * Specify whether to draw the modules as filled circles 220 * 221 * a note for `GdImage` output: 222 * 223 * if `QROptions::$scale` is less than 20, the image will be upscaled internally, then the modules will be drawn 224 * using `imagefilledellipse()` and then scaled back to the expected size 225 * 226 * No effect in: `QREps`, `QRFpdf`, `QRMarkupHTML` 227 * 228 * @see \imagefilledellipse() 229 * @see https://github.com/chillerlan/php-qrcode/issues/23 230 * @see https://github.com/chillerlan/php-qrcode/discussions/122 231 */ 232 protected bool $drawCircularModules = false; 233 234 /** 235 * Specifies the radius of the modules when `QROptions::$drawCircularModules` is set to `true` 236 * 237 * (default: 0.45) 238 */ 239 protected float $circleRadius = 0.45; 240 241 /** 242 * Specifies which module types to exclude when `QROptions::$drawCircularModules` is set to `true` 243 * 244 * (default: `[]`) 245 * 246 * @var int[] 247 */ 248 protected array $keepAsSquare = []; 249 250 /** 251 * Whether to connect the paths for the several module types to avoid weird glitches when using gradients etc. 252 * 253 * This option is exclusive to output classes that use the module collector `QROutputAbstract::collectModules()`, 254 * which converts the `$M_TYPE` of all modules to `QRMatrix::M_DATA` and `QRMatrix::M_DATA_DARK` respectively. 255 * 256 * Module types that should not be added to the connected path can be excluded via `QROptions::$excludeFromConnect`. 257 * 258 * Currentty used in `QREps` and `QRMarkupSVG`. 259 * 260 * @see \chillerlan\QRCode\Output\QROutputAbstract::collectModules() 261 * @see \chillerlan\QRCode\QROptionsTrait::$excludeFromConnect 262 * @see https://github.com/chillerlan/php-qrcode/issues/57 263 */ 264 protected bool $connectPaths = false; 265 266 /** 267 * Specify which paths/patterns to exclude from connecting if `QROptions::$connectPaths` is set to `true` 268 * 269 * @see \chillerlan\QRCode\QROptionsTrait::$connectPaths 270 * 271 * @var int[] 272 */ 273 protected array $excludeFromConnect = []; 274 275 /** 276 * Module values map 277 * 278 * - `QRImagick`, `QRMarkupHTML`, `QRMarkupSVG`: #ABCDEF, cssname, rgb(), rgba()... 279 * - `QREps`, `QRFpdf`, `QRGdImage`: `[R, G, B]` // 0-255 280 * - `QREps`: `[C, M, Y, K]` // 0-255 281 * 282 * @see \chillerlan\QRCode\Output\QROutputAbstract::setModuleValues() 283 * 284 * @var array<int, mixed> 285 */ 286 protected array $moduleValues = []; 287 288 /** 289 * Toggles logo space creation 290 * 291 * @see \chillerlan\QRCode\QRCode::addMatrixModifications() 292 * @see \chillerlan\QRCode\Data\QRMatrix::setLogoSpace() 293 */ 294 protected bool $addLogoSpace = false; 295 296 /** 297 * Width of the logo space 298 * 299 * if only `QROptions::$logoSpaceWidth` is given, the logo space is assumed a square of that size 300 */ 301 protected int|null $logoSpaceWidth = null; 302 303 /** 304 * Height of the logo space 305 * 306 * if only `QROptions::$logoSpaceHeight` is given, the logo space is assumed a square of that size 307 */ 308 protected int|null $logoSpaceHeight = null; 309 310 /** 311 * Optional horizontal start position of the logo space (top left corner) 312 */ 313 protected int|null $logoSpaceStartX = null; 314 315 /** 316 * Optional vertical start position of the logo space (top left corner) 317 */ 318 protected int|null $logoSpaceStartY = null; 319 320 321 /* 322 * Common raster image settings (QRGdImage, QRImagick) 323 */ 324 325 /** 326 * Pixel size of a QR code module 110 327 */ 111 328 protected int $scale = 5; 112 329 113 330 /** 114 * a common css class 115 */ 116 protected string $cssClass = ''; 117 118 /** 119 * SVG opacity 120 */ 121 protected float $svgOpacity = 1.0; 122 123 /** 124 * anything between <defs> 125 * 126 * @see https://developer.mozilla.org/docs/Web/SVG/Element/defs 127 */ 128 protected string $svgDefs = '<style>rect{shape-rendering:crispEdges}</style>'; 129 130 /** 131 * SVG viewBox size. a single integer number which defines width/height of the viewBox attribute. 132 * 133 * viewBox="0 0 x x" 134 * 135 * @see https://css-tricks.com/scale-svg/#article-header-id-3 136 */ 137 protected ?int $svgViewBoxSize = null; 138 139 /** 140 * string substitute for dark 141 */ 142 protected string $textDark = '🔴'; 143 144 /** 145 * string substitute for light 146 */ 147 protected string $textLight = '⭕'; 148 149 /** 150 * markup substitute for dark (CSS value) 151 */ 152 protected string $markupDark = '#000'; 153 154 /** 155 * markup substitute for light (CSS value) 156 */ 157 protected string $markupLight = '#fff'; 158 159 /** 160 * Return the image resource instead of a render if applicable. 161 * This option overrides other output options, such as $cachefile and $imageBase64. 162 * 163 * Supported by the following modules: 164 * 165 * - QRImage: resource (PHP < 8), GdImage 166 * - QRImagick: Imagick 167 * - QRFpdf: FPDF 168 * 169 * @see \chillerlan\QRCode\Output\QROutputInterface::dump() 170 * 171 * @var bool 172 */ 173 protected bool $returnResource = false; 174 175 /** 176 * toggle base64 or raw image data 177 */ 178 protected bool $imageBase64 = true; 179 180 /** 181 * toggle transparency, not supported by jpg 182 */ 183 protected bool $imageTransparent = true; 184 185 /** 186 * @see imagecolortransparent() 187 * 188 * [R, G, B] 189 */ 190 protected array $imageTransparencyBG = [255, 255, 255]; 191 192 /** 193 * @see imagepng() 194 */ 195 protected int $pngCompression = -1; 196 197 /** 198 * @see imagejpeg() 199 */ 200 protected int $jpegQuality = 85; 331 * Toggle transparency 332 * 333 * - `QRGdImage` and `QRImagick`: the given `QROptions::$transparencyColor` is set as transparent 334 * 335 * @see https://github.com/chillerlan/php-qrcode/discussions/121 336 */ 337 protected bool $imageTransparent = false; 338 339 /** 340 * Sets a transparency color for when `QROptions::$imageTransparent` is set to `true`. 341 * 342 * Defaults to `QROptions::$bgColor`. 343 * 344 * - `QRGdImage`: `[R, G, B]`, this color is set as transparent in `imagecolortransparent()` 345 * - `QRImagick`: `"color_str"`, this color is set in `Imagick::transparentPaintImage()` 346 * 347 * @see \imagecolortransparent() 348 * @see \Imagick::transparentPaintImage() 349 */ 350 protected mixed $transparencyColor = null; 351 352 /** 353 * Compression quality 354 * 355 * The given value depends on the used output type: 356 * 357 * - `QRGdImageBMP`: `[0...1]` 358 * - `QRGdImageJPEG`: `[0...100]` 359 * - `QRGdImageWEBP`: `[0...9]` 360 * - `QRGdImagePNG`: `[0...100]` 361 * - `QRImagick`: `[0...100]` 362 * 363 * @see \imagebmp() 364 * @see \imagejpeg() 365 * @see \imagepng() 366 * @see \imagewebp() 367 * @see \Imagick::setImageCompressionQuality() 368 */ 369 protected int $quality = -1; 370 371 372 /* 373 * QRGdImage settings 374 */ 375 376 /** 377 * Toggles the usage of internal upscaling when `QROptions::$drawCircularModules` is set to `true` and 378 * `QROptions::$scale` is less than 20 379 * 380 * @see \chillerlan\QRCode\Output\QRGdImage::createImage() 381 * @see https://github.com/chillerlan/php-qrcode/issues/23 382 */ 383 protected bool $gdImageUseUpscale = true; 384 385 386 /* 387 * QRImagick settings 388 */ 201 389 202 390 /** 203 391 * Imagick output format 204 392 * 205 * @see \Imagick::setType() 206 */ 207 protected string $imagickFormat = 'png'; 208 209 /** 210 * Imagick background color (defaults to "transparent") 211 * 212 * @see \ImagickPixel::__construct() 213 */ 214 protected ?string $imagickBG = null; 215 216 /** 217 * Measurement unit for FPDF output: pt, mm, cm, in (defaults to "pt") 218 * 219 * @see \FPDF::__construct() 393 * @see \Imagick::setImageFormat() 394 * @see https://www.imagemagick.org/script/formats.php 395 */ 396 protected string $imagickFormat = 'png32'; 397 398 399 /* 400 * Common markup output settings (QRMarkupSVG, QRMarkupHTML) 401 */ 402 403 /** 404 * A common css class 405 */ 406 protected string $cssClass = 'qrcode'; 407 408 409 /* 410 * QRMarkupSVG settings 411 */ 412 413 /** 414 * Whether to add an XML header line or not, e.g. to embed the SVG directly in HTML 415 * 416 * `<?xml version="1.0" encoding="UTF-8"?>` 417 */ 418 protected bool $svgAddXmlHeader = true; 419 420 /** 421 * Anything in the SVG `<defs>` tag 422 * 423 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs 424 */ 425 protected string $svgDefs = ''; 426 427 /** 428 * Sets the value for the "preserveAspectRatio" on the `<svg>` element 429 * 430 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio 431 */ 432 protected string $svgPreserveAspectRatio = 'xMidYMid'; 433 434 /** 435 * Whether to use the SVG `fill` attributes 436 * 437 * If set to `true` (default), the `fill` attribute will be set with the module value for the `<path>` element's `$M_TYPE`. 438 * When set to `false`, the module values map will be ignored and the QR Code may be styled via CSS. 439 * 440 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill 441 */ 442 protected bool $svgUseFillAttributes = true; 443 444 445 /* 446 * QRStringText settings 447 */ 448 449 /** 450 * An optional line prefix, e.g. empty space to align the QR Code in a console 451 */ 452 protected string $textLineStart = ''; 453 454 455 /* 456 * QRStringJSON settings 457 */ 458 459 /** 460 * Sets the flags to use for the `json_encode()` call 461 * 462 * @see https://www.php.net/manual/json.constants.php 463 */ 464 protected int $jsonFlags = (JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES); 465 466 467 /* 468 * QRFpdf settings 469 */ 470 471 /** 472 * Measurement unit for `FPDF` output: `pt`, `mm`, `cm`, `in` (default: `pt`) 473 * 474 * @see FPDF::__construct() 220 475 */ 221 476 protected string $fpdfMeasureUnit = 'pt'; 222 477 223 /** 224 * Module values map 225 * 226 * - HTML, IMAGICK: #ABCDEF, cssname, rgb(), rgba()... 227 * - IMAGE: [63, 127, 255] // R, G, B 228 */ 229 protected ?array $moduleValues = null; 478 479 /* 480 * QRMarkupXML settings 481 */ 482 483 /** 484 * Sets an optional XSLT stylesheet in the XML output 485 * 486 * @see https://developer.mozilla.org/en-US/docs/Web/XSLT 487 */ 488 protected string|null $xmlStylesheet = null; 489 230 490 231 491 /** … … 255 515 256 516 /** 257 * sets the error correction level 517 * sets/clamps the version number 518 */ 519 protected function set_version(int $version):void{ 520 $this->version = ($version !== Version::AUTO) ? max(1, min(40, $version)) : Version::AUTO; 521 } 522 523 /** 524 * sets the ECC level 258 525 * 259 526 * @throws \chillerlan\QRCode\QRCodeException 260 527 */ 261 protected function set_eccLevel(int $eccLevel):void{ 262 263 if(!isset(QRCode::ECC_MODES[$eccLevel])){ 264 throw new QRCodeException(sprintf('Invalid error correct level: %s', $eccLevel)); 528 protected function set_eccLevel(int|string $eccLevel):void{ 529 530 if(is_string($eccLevel)){ 531 $ecc = strtoupper(trim($eccLevel)); 532 533 if(!in_array($ecc, ['L', 'M', 'Q', 'H'], true)){ 534 throw new QRCodeException(sprintf('Invalid ECC level: "%s"', $ecc)); 535 } 536 537 // @todo: PHP 8.3+ 538 // $eccLevel = EccLevel::{$ecc}; 539 $eccLevel = constant(EccLevel::class.'::'.$ecc); 265 540 } 266 541 542 /** @var int $eccLevel */ 543 if((0b11 & $eccLevel) !== $eccLevel){ 544 throw new QRCodeException(sprintf('Invalid ECC level: "%s"', $eccLevel)); 545 } 546 267 547 $this->eccLevel = $eccLevel; 268 548 } 269 549 270 550 /** 271 * sets/clamps the mask pattern 272 */ 273 protected function set_maskPattern(int $maskPattern):void{ 274 275 if($maskPattern !== QRCode::MASK_PATTERN_AUTO){ 276 $this->maskPattern = max(0, min(7, $maskPattern)); 277 } 278 279 } 280 281 /** 282 * sets the transparency background color 283 * 284 * @throws \chillerlan\QRCode\QRCodeException 285 */ 286 protected function set_imageTransparencyBG(array $imageTransparencyBG):void{ 287 288 // invalid value - set to white as default 289 if(count($imageTransparencyBG) < 3){ 290 $this->imageTransparencyBG = [255, 255, 255]; 291 292 return; 293 } 294 295 foreach($imageTransparencyBG as $k => $v){ 296 297 // cut off exceeding items 298 if($k > 2){ 299 break; 300 } 301 302 if(!is_numeric($v)){ 303 throw new QRCodeException('Invalid RGB value.'); 304 } 305 306 // clamp the values 307 $this->imageTransparencyBG[$k] = max(0, min(255, (int)$v)); 308 } 309 310 // use the array values to not run into errors with the spread operator (...$arr) 311 $this->imageTransparencyBG = array_values($this->imageTransparencyBG); 312 } 313 314 /** 315 * sets/clamps the version number 316 */ 317 protected function set_version(int $version):void{ 318 319 if($version !== QRCode::VERSION_AUTO){ 320 $this->version = max(1, min(40, $version)); 321 } 322 551 * clamps the module scale at a minimum of 1 and a maximum of 50 552 */ 553 protected function set_scale(int $scale):void{ 554 $this->scale = max(1, min($scale, 50)); 555 } 556 557 /** 558 * sets/clamps the quiet zone size 559 */ 560 protected function set_quietzoneSize(int $quietzoneSize):void{ 561 $this->quietzoneSize = max(0, min($quietzoneSize, 75)); 323 562 } 324 563 … … 338 577 } 339 578 579 /** 580 * clamp the logo space values between 0 and maximum length (177 modules at version 40) 581 */ 582 protected function clampLogoSpaceValue(int|null $value):int|null{ 583 584 if($value === null){ 585 return null; 586 } 587 588 return (int)max(0, min(177, $value)); 589 } 590 591 /** 592 * clamp/set logo space width 593 */ 594 protected function set_logoSpaceWidth(int|null $value):void{ 595 $this->logoSpaceWidth = $this->clampLogoSpaceValue($value); 596 } 597 598 /** 599 * clamp/set logo space height 600 */ 601 protected function set_logoSpaceHeight(int|null $value):void{ 602 $this->logoSpaceHeight = $this->clampLogoSpaceValue($value); 603 } 604 605 /** 606 * clamp/set horizontal logo space start 607 */ 608 protected function set_logoSpaceStartX(int|null $value):void{ 609 $this->logoSpaceStartX = $this->clampLogoSpaceValue($value); 610 } 611 612 /** 613 * clamp/set vertical logo space start 614 */ 615 protected function set_logoSpaceStartY(int|null $value):void{ 616 $this->logoSpaceStartY = $this->clampLogoSpaceValue($value); 617 } 618 619 /** 620 * clamp/set SVG circle radius 621 */ 622 protected function set_circleRadius(float $circleRadius):void{ 623 $this->circleRadius = max(0.1, min(0.75, $circleRadius)); 624 } 625 340 626 } -
wp-otp/trunk/vendor/chillerlan/php-settings-container/README.md
r2466054 r3752647 1 1 # chillerlan/php-settings-container 2 2 3 A container class for immutable settings objects. Not a DI container. PHP 7.4+4 - [`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/main/src/SettingsContainerInterface.php) provides immutable properties with magic getter & setter and some fancy3 A container class for settings objects - decouple configuration logic from your application! Not a DI container. 4 - [`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/main/src/SettingsContainerInterface.php) provides fancy [property hooks](https://wiki.php.net/rfc/property-hooks) for PHP < 8.4. 5 5 6 6 [![PHP Version Support][php-badge]][php] 7 7 [![version][packagist-badge]][packagist] 8 8 [![license][license-badge]][license] 9 [![ Travis][travis-badge]][travis]9 [![Continuous Integration][gh-action-badge]][gh-action] 10 10 [![Coverage][coverage-badge]][coverage] 11 [![Scrunitizer][scrutinizer-badge]][scrutinizer] 12 [![Packagist downloads][downloads-badge]][downloads]<br/> 13 [![Continuous Integration][gh-action-badge]][gh-action] 11 [![Codacy][codacy-badge]][codacy] 12 [![Packagist downloads][downloads-badge]][downloads] 14 13 15 14 [php-badge]: https://img.shields.io/packagist/php-v/chillerlan/php-settings-container?logo=php&color=8892BF 16 15 [php]: https://www.php.net/supported-versions.php 17 [packagist-badge]: https://img.shields.io/packagist/v/chillerlan/php-settings-container.svg 16 [packagist-badge]: https://img.shields.io/packagist/v/chillerlan/php-settings-container.svg?logo=packagist 18 17 [packagist]: https://packagist.org/packages/chillerlan/php-settings-container 19 18 [license-badge]: https://img.shields.io/github/license/chillerlan/php-settings-container.svg 20 19 [license]: https://github.com/chillerlan/php-settings-container/blob/main/LICENSE 21 [travis-badge]: https://img.shields.io/travis/com/chillerlan/php-settings-container/main?logo=travis22 [travis]: https://travis-ci.org/chillerlan/php-settings-container23 20 [coverage-badge]: https://img.shields.io/codecov/c/github/chillerlan/php-settings-container.svg?logo=codecov 24 21 [coverage]: https://codecov.io/github/chillerlan/php-settings-container 25 [ scrutinizer-badge]: https://img.shields.io/scrutinizer/g/chillerlan/php-settings-container.svg?logo=scrutinizer26 [ scrutinizer]: https://scrutinizer-ci.com/g/chillerlan/php-settings-container27 [downloads-badge]: https://img.shields.io/packagist/dt/chillerlan/php-settings-container.svg 22 [codacy-badge]: https://img.shields.io/codacy/grade/bd2467799e2943d2853ce3ebad5af490/main?logo=codacy 23 [codacy]: https://app.codacy.com/gh/chillerlan/php-settings-container/dashboard?branch=main 24 [downloads-badge]: https://img.shields.io/packagist/dt/chillerlan/php-settings-container.svg?logo=packagist 28 25 [downloads]: https://packagist.org/packages/chillerlan/php-settings-container/stats 29 [gh-action-badge]: https:// github.com/chillerlan/php-settings-container/workflows/Continuous%20Integration/badge.svg30 [gh-action]: https://github.com/chillerlan/php-settings-container/actions ?query=workflow%3A%22Continuous+Integration%2226 [gh-action-badge]: https://img.shields.io/github/actions/workflow/status/chillerlan/php-settings-container/ci.yml?branch=main&logo=github 27 [gh-action]: https://github.com/chillerlan/php-settings-container/actions/workflows/ci.yml?query=branch%3Amain 31 28 32 29 ## Documentation … … 35 32 **requires [composer](https://getcomposer.org)** 36 33 37 *composer.json* (note: replace `dev-main` with a [version constraint](https://getcomposer.org/doc/articles/versions.md#writing-version-constraints), e.g. `^ 2.0` - see [releases](https://github.com/chillerlan/php-settings-container/releases) for valid versions)34 *composer.json* (note: replace `dev-main` with a [version constraint](https://getcomposer.org/doc/articles/versions.md#writing-version-constraints), e.g. `^3.0` - see [releases](https://github.com/chillerlan/php-settings-container/releases) for valid versions) 38 35 ```json 39 36 { 40 37 "require": { 41 "php": "^ 7.4",38 "php": "^8.1", 42 39 "chillerlan/php-settings-container": "dev-main" 43 40 } … … 49 46 ## Usage 50 47 51 The `SettingsContainerInterface` (wrapped in`SettingsContainerAbstract` ) provides plug-in functionality for immutable object properties and adds some fancy, like loading/saving JSON, arrays etc.48 The `SettingsContainerInterface` (wrapped in`SettingsContainerAbstract`) provides plug-in functionality for immutable object properties and adds some fancy, like loading/saving JSON, arrays etc. 52 49 It takes an `iterable` as the only constructor argument and calls a method with the trait's name on invocation (`MyTrait::MyTrait()`) for each used trait. 53 50 51 A PHPStan ruleset to exclude errors generated by accessing magic properties on `SettingsContainerInterface` can be found in `rules-magic-access.neon`. 52 53 54 54 ### Simple usage 55 ```php56 class MyContainer extends SettingsContainerAbstract{57 protected $foo;58 protected $bar;59 }60 ```61 Typed properties in PHP 7.4+:62 55 ```php 63 56 class MyContainer extends SettingsContainerAbstract{ … … 68 61 69 62 ```php 70 // use it just like a \stdClass 63 // use it just like a \stdClass (except the properties are fixed) 71 64 $container = new MyContainer; 72 65 $container->foo = 'what'; 73 66 $container->bar = 'foo'; 74 67 75 // which is equivalent to 68 // which is equivalent to 76 69 $container = new MyContainer(['bar' => 'foo', 'foo' => 'what']); 77 70 // ...or try … … 85 78 // JSON via JsonSerializable 86 79 $json = json_encode($container); // -> {"foo": "what", "bar": "foo"} 87 88 //non-existing properties will be ignored: 80 ``` 81 82 By default, non-existing properties will be ignored and return `null`: 83 84 ```php 89 85 $container->nope = 'what'; 90 86 … … 92 88 ``` 93 89 90 You can change this behaviour by adding the attribute `ThrowOnInvalidProperty` to your container class: 91 92 ```php 93 #[ThrowOnInvalidProperty(true)] 94 class MyContainer extends SettingsContainerAbstract{ 95 // ... 96 } 97 98 $container->nope = 'what'; // -> throws: attempt to write invalid property: "$nope" 99 ``` 100 101 94 102 ### Advanced usage 103 104 Suppose the following trait from library 1: 105 95 106 ```php 96 107 trait SomeOptions{ 97 protected $foo;98 protected $what;99 108 protected string $foo; 109 protected string $what; 110 100 111 // this method will be called in SettingsContainerAbstract::construct() 101 112 // after the properties have been set 102 protected function SomeOptions() {113 protected function SomeOptions():void{ 103 114 // just some constructor stuff... 104 115 $this->foo = strtoupper($this->foo); 105 116 } 106 117 118 /* 119 * special prefixed magic setters & getters ("set_"/"get_" + property name) 120 */ 121 107 122 // this method will be called from __set() when property $what is set 108 protected function set_what(string $value) {123 protected function set_what(string $value):void{ 109 124 $this->what = md5($value); 110 125 } 111 } 112 126 127 // this method is called on __get() for the property $what 128 protected function get_what():string{ 129 return 'hash: '.$this->what; 130 } 131 } 132 ``` 133 134 And another trait from library 2: 135 136 ```php 113 137 trait MoreOptions{ 114 protected $bar = 'whatever'; // provide default values 115 } 116 ``` 138 protected string $bar = 'whatever'; // provide default values 139 } 140 ``` 141 142 We can now plug the several library options together to a single class/object: 117 143 118 144 ```php 119 145 $commonOptions = [ 120 146 // SomeOptions 121 'foo' => 'whatever', 147 'foo' => 'whatever', 122 148 // MoreOptions 123 149 'bar' => 'nothing', 124 150 ]; 125 151 126 // now plug the several library options together to a single object127 152 $container = new class ($commonOptions) extends SettingsContainerAbstract{ 128 153 use SomeOptions, MoreOptions; … … 133 158 134 159 $container->what = 'some value'; 135 var_dump($container->what); // -> md5 hash of "some value" 136 ``` 160 var_dump($container->what); // -> hash: 5946210c9e93ae37891dfe96c3e39614 (custom getter added "hash: ") 161 ``` 162 163 ### A note on property hooks (PHP 8.4+) 164 165 Property hooks are called whenever a property is accessed (except from within the hook itself of course), which means that the custom get/set methods this library allows would conflict when a custom method is defined for a property that also has a hook defined. 166 To prevent double method calls, the internal methods `hasSetHook()` and `hasGetHook()` have been introduced, and are called whenever the magic get/set methods are called: when both, a custom method and a property hook exist, only the property hook will be called. 167 <br/>Public properties will never call the magic get/set, however, their hooks *will* be called. (un)serializing a `SettingsContainerInterface` instance will bypass magic get/set and existing property hooks, while JSON de/encode as will call magic get/set or existing hooks explicitly via the `toArray()` and `fromIterable()` methods. 168 169 ```php 170 class PropertyHooksContainer extends SettingsContainerAbstract{ 171 172 protected string $someValue{ 173 set => doStuff($value); 174 } 175 176 // this method will be ignored in magic calls as a "set" hook on the property exists 177 protected function set_someValue(string $value):void{ 178 $this->someValue = doOtherStuff($value); 179 } 180 181 // this custom method will be called as the property has no "get" hook 182 protected function get_someValue():string{ 183 return doWhatever($this->someValue); 184 } 185 186 // this property will never trigger the magic get/set and associated methods 187 public string $otherValue{ 188 set => doStuff($value); 189 get => $this->otherValue; 190 } 191 192 } 193 ``` 194 137 195 138 196 ### API … … 140 198 #### [`SettingsContainerAbstract`](https://github.com/chillerlan/php-settings-container/blob/main/src/SettingsContainerAbstract.php) 141 199 142 method | return | info 143 -------- | ---- | ----------- 144 `__construct(iterable $properties = null)` | - | calls `construct()` internally after the properties have been set 145 (protected) `construct()` | void | calls a method with trait name as replacement constructor for each used trait 146 `__get(string $property)` | mixed | calls `$this->{'get_'.$property}()` if such a method exists 147 `__set(string $property, $value)` | void | calls `$this->{'set_'.$property}($value)` if such a method exists 148 `__isset(string $property)` | bool | 149 `__unset(string $property)` | void | 150 `__toString()` | string | a JSON string 151 `toArray()` | array | 152 `fromIterable(iterable $properties)` | `SettingsContainerInterface` | 153 `toJSON(int $jsonOptions = null)` | string | accepts [JSON options constants](http://php.net/manual/json.constants.php) 154 `fromJSON(string $json)` | `SettingsContainerInterface` | 155 `jsonSerialize()` | mixed | implements the [`JsonSerializable`](https://www.php.net/manual/en/jsonserializable.jsonserialize.php) interface 200 | method | return | info | 201 |--------------------------------------------|------------------------------|---------------------------------------------------------------------------------------------------------------------| 202 | `__construct(iterable $properties = null)` | - | calls `construct()` internally after the properties have been set | 203 | `__get(string $property)` | mixed | calls `$this->{'get_'.$property}()` if such a method exists | 204 | `__set(string $property, $value)` | void | calls `$this->{'set_'.$property}($value)` if such a method exists | 205 | `__isset(string $property)` | bool | | 206 | `__unset(string $property)` | void | | 207 | `__toString()` | string | a JSON string | 208 | `toArray()` | array | | 209 | `fromIterable(iterable $properties)` | `SettingsContainerInterface` | | 210 | `toJSON(int $jsonOptions = null)` | string | accepts [JSON options constants](http://php.net/manual/json.constants.php) | 211 | `fromJSON(string $json)` | `SettingsContainerInterface` | | 212 | `jsonSerialize()` | mixed | implements the [`JsonSerializable`](https://www.php.net/manual/en/jsonserializable.jsonserialize.php) interface | 213 | `serialize()` | string | implements the [`Serializable`](https://www.php.net/manual/en/serializable.serialize.php) interface | 214 | `unserialize(string $data)` | void | implements the [`Serializable`](https://www.php.net/manual/en/serializable.unserialize.php) interface | 215 | `__serialize()` | array | implements the [`Serializable`](https://www.php.net/manual/en/language.oop5.magic.php#object.serialize) interface | 216 | `__unserialize(array $data)` | void | implements the [`Serializable`](https://www.php.net/manual/en/language.oop5.magic.php#object.unserialize) interface | 217 218 219 #### Internal (protected) methods 220 221 | method | return | info | 222 |--------------------------------------|--------|-------------------------------------------------------------------------------| 223 | `construct()` | void | calls a method with trait name as replacement constructor for each used trait | 224 | `isPrivate(string $property)` | bool | private properties are excluded from magic calls | 225 | `hasSetHook(string $property)` | bool | | 226 | `hasGetHook(string $property)` | bool | | 227 156 228 157 229 ## Disclaimer 158 This might be either an utterly genius or completely stupid idea - you decide. However, i like it and it works.159 Also, this is not a dependency injection container. Stop using DI containers FFS.230 This might be either an absolutely brilliant or completely stupid idea - you decide (in hindsight it was a great idea I guess - property hooks made their way into PHP 8.4). 231 <br/>Also, this is not a dependency injection container. Stop using DI containers FFS. -
wp-otp/trunk/vendor/chillerlan/php-settings-container/composer.json
r2466054 r3752647 1 1 { 2 2 "name": "chillerlan/php-settings-container", 3 "description": "A container class for immutable settings objects. Not a DI container. PHP 7.4+",3 "description": "A container class for immutable settings objects. Not a DI container.", 4 4 "homepage": "https://github.com/chillerlan/php-settings-container", 5 5 "license": "MIT", … … 7 7 "minimum-stability": "stable", 8 8 "keywords": [ 9 " php7", "helper", "container", "settings"9 "helper", "container", "settings", "configuration", "property hook" 10 10 ], 11 11 "authors": [ … … 21 21 }, 22 22 "require": { 23 "php": "^ 7.4 || ^8.0",23 "php": "^8.1", 24 24 "ext-json": "*" 25 25 }, 26 26 "require-dev": { 27 "phan/phan": "^4.0", 28 "phpunit/phpunit": "^9.5" 27 "phan/phan": "^5.5.2", 28 "phpmd/phpmd": "^2.15", 29 "phpstan/phpstan": "^2.1.31", 30 "phpstan/phpstan-deprecation-rules": "^2.0.3", 31 "phpunit/phpunit": "^10.5", 32 "slevomat/coding-standard": "^8.22", 33 "squizlabs/php_codesniffer": "^4.0" 29 34 }, 30 35 "autoload": { 31 36 "psr-4": { 32 "chillerlan\\Settings\\": "src /"37 "chillerlan\\Settings\\": "src" 33 38 } 34 39 }, 35 40 "autoload-dev": { 36 41 "psr-4": { 37 "chillerlan\\SettingsTest\\": "tests/", 38 "chillerlan\\SettingsExamples\\": "examples/" 42 "chillerlan\\SettingsTest\\": "tests" 43 } 44 }, 45 "scripts": { 46 "phan": "@php vendor/bin/phan", 47 "phpcs": "@php vendor/bin/phpcs -v", 48 "phpmd": "@php vendor/bin/phpmd src text ./phpmd.xml.dist", 49 "phpstan": "@php vendor/bin/phpstan", 50 "phpstan-baseline": "@php vendor/bin/phpstan --generate-baseline", 51 "phpunit": "@php vendor/bin/phpunit" 52 }, 53 "config": { 54 "lock": false, 55 "sort-packages": true, 56 "platform-check": true, 57 "allow-plugins": { 58 "dealerdirect/phpcodesniffer-composer-installer": true 39 59 } 40 60 } -
wp-otp/trunk/vendor/chillerlan/php-settings-container/src/SettingsContainerAbstract.php
r2466054 r3752647 3 3 * Class SettingsContainerAbstract 4 4 * 5 * @filesource SettingsContainerAbstract.php6 5 * @created 28.08.2018 7 * @package chillerlan\Settings8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2018 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\Settings; 14 13 15 use ReflectionClass, ReflectionProperty; 16 17 use function call_user_func, call_user_func_array, get_object_vars, json_decode, json_encode, method_exists, property_exists; 14 use chillerlan\Settings\Attributes\ThrowOnInvalidProperty; 15 use InvalidArgumentException, JsonException, ReflectionException, ReflectionObject, 16 ReflectionProperty, ReflectionAttribute, RuntimeException; 17 use function is_object, json_decode, json_encode, json_last_error_msg, 18 method_exists, property_exists, serialize, sprintf, unserialize; 19 use const JSON_THROW_ON_ERROR, PHP_VERSION_ID; 18 20 19 21 abstract class SettingsContainerAbstract implements SettingsContainerInterface{ 20 22 23 protected const SET_PREFIX = 'set_'; 24 protected const GET_PREFIX = 'get_'; 25 21 26 /** 22 27 * SettingsContainerAbstract constructor. 23 28 * 24 * @p aram iterable|null$properties25 */ 26 public function __construct(iterable $properties = null){29 * @phpstan-param array<string, mixed> $properties 30 */ 31 public function __construct(iterable|null $properties = null){ 27 32 28 33 if(!empty($properties)){ … … 36 41 * calls a method with trait name as replacement constructor for each used trait 37 42 * (remember pre-php5 classname constructors? yeah, basically this.) 38 *39 * @return void40 43 */ 41 44 protected function construct():void{ 42 $traits = (new Reflection Class($this))->getTraits();45 $traits = (new ReflectionObject($this))->getTraits(); 43 46 44 47 foreach($traits as $trait){ … … 46 49 47 50 if(method_exists($this, $method)){ 48 call_user_func([$this, $method]); 49 } 50 } 51 52 } 53 54 /** 55 * @inheritdoc 56 * 57 * @return mixed|null 58 */ 59 public function __get(string $property){ 60 51 $this->{$method}(); 52 } 53 } 54 55 } 56 57 public function __get(string $property):mixed{ 58 // back out if the property is inaccessible 61 59 if(!property_exists($this, $property) || $this->isPrivate($property)){ 60 61 if($this->throwOnInvalidProperty()){ 62 throw new RuntimeException(sprintf('attempt to read invalid property: "$%s"', $property)); 63 } 64 62 65 return null; 63 66 } 64 65 $method = 'get_'.$property; 66 67 if(method_exists($this, $method)){ 68 return call_user_func([$this, $method]); 69 } 70 67 // call an existing custom method, skip if the property has a hook 68 if(method_exists($this, static::GET_PREFIX.$property) && !$this->hasGetHook($property)){ 69 return $this->{static::GET_PREFIX.$property}(); 70 } 71 // retrieve the value (triggers an existing property hook) 71 72 return $this->{$property}; 72 73 } 73 74 74 /** 75 * @inheritdoc 76 */ 77 public function __set(string $property, $value):void{ 75 public function __set(string $property, mixed $value):void{ 78 76 79 77 if(!property_exists($this, $property) || $this->isPrivate($property)){ 78 79 if($this->throwOnInvalidProperty()){ 80 throw new RuntimeException(sprintf('attempt to write invalid property: "$%s"', $property)); 81 } 82 80 83 return; 81 84 } 82 85 83 $method = 'set_'.$property; 84 85 if(method_exists($this, $method)){ 86 call_user_func_array([$this, $method], [$value]); 86 if(method_exists($this, static::SET_PREFIX.$property) && !$this->hasSetHook($property)){ 87 $this->{static::SET_PREFIX.$property}($value); 87 88 88 89 return; … … 92 93 } 93 94 94 /**95 * @inheritdoc96 */97 95 public function __isset(string $property):bool{ 98 96 return isset($this->{$property}) && !$this->isPrivate($property); 99 97 } 100 98 101 /**102 * @internal Checks if a property is private103 *104 * @param string $property105 *106 * @return bool107 */108 protected function isPrivate(string $property):bool{109 return (new ReflectionProperty($this, $property))->isPrivate();110 }111 112 /**113 * @inheritdoc114 */115 99 public function __unset(string $property):void{ 116 100 … … 121 105 } 122 106 123 /**124 * @inheritdoc125 */126 107 public function __toString():string{ 127 108 return $this->toJSON(); … … 129 110 130 111 /** 131 * @inheritdoc 132 */ 112 * @internal Checks if a property is private 113 */ 114 final protected function isPrivate(string $property):bool{ 115 return (new ReflectionProperty($this, $property))->isPrivate(); 116 } 117 118 /** 119 * @internal Checks if a property has a "set" hook 120 */ 121 final protected function hasSetHook(string $property):bool{ 122 123 if(PHP_VERSION_ID < 80400){ 124 return false; 125 } 126 /** @phan-suppress-next-line PhanUndeclaredMethod, PhanUndeclaredClassConstant */ 127 return (new ReflectionProperty($this, $property))->hasHook(\PropertyHookType::Set); 128 } 129 130 /** 131 * @internal Checks if a property has a "get" hook 132 */ 133 final protected function hasGetHook(string $property):bool{ 134 135 if(PHP_VERSION_ID < 80400){ 136 return false; 137 } 138 /** @phan-suppress-next-line PhanUndeclaredMethod, PhanUndeclaredClassConstant */ 139 return (new ReflectionProperty($this, $property))->hasHook(\PropertyHookType::Get); 140 } 141 142 /** 143 * @internal Checks for the attribute "ThrowOnInvalidProperty", used in the magic get/set 144 * 145 * @see \chillerlan\Settings\Attributes\ThrowOnInvalidProperty 146 */ 147 final protected function throwOnInvalidProperty():bool{ 148 149 $attributes = (new ReflectionObject($this)) 150 ->getAttributes(ThrowOnInvalidProperty::class, ReflectionAttribute::IS_INSTANCEOF) 151 ; 152 153 if($attributes === []){ 154 return false; 155 } 156 /** @var \chillerlan\Settings\Attributes\ThrowOnInvalidProperty $attr */ 157 $attr = $attributes[0]->newInstance(); 158 159 return $attr->throwOnInvalid; 160 } 161 133 162 public function toArray():array{ 134 return get_object_vars($this); 135 } 136 137 /** 138 * @inheritdoc 139 */ 140 public function fromIterable(iterable $properties):SettingsContainerInterface{ 163 164 $properties = (new ReflectionObject($this)) 165 ->getProperties(~(ReflectionProperty::IS_STATIC | ReflectionProperty::IS_READONLY | ReflectionProperty::IS_PRIVATE)) 166 ; 167 168 $data = []; 169 170 foreach($properties as $reflectionProperty){ 171 // the magic getter is called intentionally here, so that any existing hook methods are called on export 172 $data[$reflectionProperty->name] = $this->__get($reflectionProperty->name); 173 } 174 175 return $data; 176 } 177 178 /** 179 * @param iterable<string, mixed> $properties 180 */ 181 public function fromIterable(iterable $properties):static{ 141 182 142 183 foreach($properties as $key => $value){ … … 147 188 } 148 189 149 /** 150 * @inheritdoc 151 */ 152 public function toJSON(int $jsonOptions = null):string{ 153 return json_encode($this, $jsonOptions ?? 0); 154 } 155 156 /** 157 * @inheritdoc 158 */ 159 public function fromJSON(string $json):SettingsContainerInterface{ 190 public function toJSON(int|null $jsonOptions = null):string{ 191 $json = json_encode($this, ($jsonOptions ?? 0)); 192 193 if($json === false){ 194 throw new JsonException(json_last_error_msg()); // @codeCoverageIgnore 195 } 196 197 return $json; 198 } 199 200 public function fromJSON(string $json):static{ 201 /** @phpstan-var array<string, mixed> $data */ 160 202 $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR); 161 203 … … 164 206 165 207 /** 166 * @ inheritdoc208 * @return array<string, mixed> 167 209 */ 168 210 public function jsonSerialize():array{ … … 170 212 } 171 213 214 /** 215 * Returns a serialized string representation of the object in its current state (except static/readonly properties) 216 */ 217 public function serialize():string{ 218 return serialize($this); 219 } 220 221 /** 222 * Restores the data (except static/readonly properties) from the given serialized object to the current instance 223 * 224 * @throws \InvalidArgumentException 225 */ 226 public function unserialize(string $data):void{ 227 $obj = unserialize($data); 228 229 if(!is_object($obj)){ 230 throw new InvalidArgumentException('The given serialized string is invalid'); 231 } 232 233 $reflection = new ReflectionObject($obj); 234 235 if(!$reflection->isInstance($this)){ 236 throw new InvalidArgumentException('The unserialized object does not match the class of this container'); 237 } 238 239 $properties = $reflection->getProperties(~(ReflectionProperty::IS_STATIC | ReflectionProperty::IS_READONLY)); 240 $data = []; 241 242 foreach($properties as $reflectionProperty){ 243 $data[$reflectionProperty->name] = (PHP_VERSION_ID < 80400) 244 ? $reflectionProperty->getValue($obj) 245 /** @phan-suppress-next-line PhanUndeclaredMethod */ 246 : $reflectionProperty->getRawValue($obj); 247 } 248 249 $this->__unserialize($data); 250 } 251 252 /** 253 * Returns a serialized array representation of the object in its current state (except static/readonly properties), 254 * bypassing custom getters and property hooks 255 * 256 * @return array<string, mixed> 257 */ 258 public function __serialize():array{ 259 260 $properties = (new ReflectionObject($this)) 261 ->getProperties(~(ReflectionProperty::IS_STATIC | ReflectionProperty::IS_READONLY)) 262 ; 263 264 $data = []; 265 266 foreach($properties as $reflectionProperty){ 267 // bypass existing property hooks for PHP >= 8.4 268 $data[$reflectionProperty->name] = (PHP_VERSION_ID < 80400) 269 ? $reflectionProperty->getValue($this) 270 /** @phan-suppress-next-line PhanUndeclaredMethod */ 271 : $reflectionProperty->getRawValue($this); 272 } 273 274 return $data; 275 } 276 277 /** 278 * Restores the data from the given array to the current instance, 279 * bypassing custom setters and property hooks 280 * 281 * @param array<string, mixed> $data 282 */ 283 public function __unserialize(array $data):void{ 284 $reflection = new ReflectionObject($this); 285 286 foreach($data as $key => $value){ 287 try{ 288 $reflectionProperty = $reflection->getProperty($key); 289 290 if($reflectionProperty->isStatic() || $reflectionProperty->isReadOnly()){ 291 continue; // @codeCoverageIgnore 292 } 293 294 (PHP_VERSION_ID < 80400) 295 ? $reflectionProperty->setValue($this, $value) 296 /** @phan-suppress-next-line PhanUndeclaredMethod */ 297 : $reflectionProperty->setRawValue($this, $value); 298 299 } 300 // @codeCoverageIgnoreStart 301 catch(ReflectionException){ 302 // attempt to assign a non-existent property, skip 303 continue; 304 } 305 // @codeCoverageIgnoreEnd 306 } 307 308 } 309 172 310 } -
wp-otp/trunk/vendor/chillerlan/php-settings-container/src/SettingsContainerInterface.php
r2331970 r3752647 3 3 * Interface SettingsContainerInterface 4 4 * 5 * @filesource SettingsContainerInterface.php6 5 * @created 28.08.2018 7 * @package chillerlan\Settings8 6 * @author Smiley <smiley@chillerlan.net> 9 7 * @copyright 2018 Smiley 10 8 * @license MIT 11 9 */ 10 declare(strict_types=1); 12 11 13 12 namespace chillerlan\Settings; 14 13 15 use JsonSerializable ;14 use JsonSerializable, Serializable; 16 15 17 16 /** 18 17 * a generic container with magic getter and setter 19 18 */ 20 interface SettingsContainerInterface extends JsonSerializable {19 interface SettingsContainerInterface extends JsonSerializable, Serializable{ 21 20 22 21 /** 23 22 * Retrieve the value of $property 24 23 * 25 * @param string $property 26 * 27 * @return mixed 24 * @return mixed|null 28 25 */ 29 public function __get(string $property) ;26 public function __get(string $property):mixed; 30 27 31 28 /** 32 29 * Set $property to $value while avoiding private and non-existing properties 33 *34 * @param string $property35 * @param mixed $value36 *37 * @return void38 30 */ 39 public function __set(string $property, $value):void;31 public function __set(string $property, mixed $value):void; 40 32 41 33 /** 42 34 * Checks if $property is set (aka. not null), excluding private properties 43 *44 * @param string $property45 *46 * @return bool47 35 */ 48 36 public function __isset(string $property):bool; … … 50 38 /** 51 39 * Unsets $property while avoiding private and non-existing properties 52 *53 * @param string $property54 *55 * @return void56 40 */ 57 41 public function __unset(string $property):void; 58 42 59 43 /** 60 * @see SettingsContainerInterface::toJSON() 61 * 62 * @return string 44 * @see \chillerlan\Settings\SettingsContainerInterface::toJSON() 63 45 */ 64 46 public function __toString():string; … … 67 49 * Returns an array representation of the settings object 68 50 * 69 * @return array 51 * The values will be run through the magic __get(), which may also call custom getters. 52 * 53 * @return array<string, mixed> 70 54 */ 71 55 public function toArray():array; … … 74 58 * Sets properties from a given iterable 75 59 * 76 * @param iterable $properties60 * The values will be run through the magic __set(), which may also call custom setters. 77 61 * 78 * @ return \chillerlan\Settings\SettingsContainerInterface62 * @param iterable<string, mixed> $properties 79 63 */ 80 public function fromIterable(iterable $properties): SettingsContainerInterface;64 public function fromIterable(iterable $properties):static; 81 65 82 66 /** 83 67 * Returns a JSON representation of the settings object 68 * 84 69 * @see \json_encode() 70 * @see \chillerlan\Settings\SettingsContainerInterface::toArray() 85 71 * 86 * @param int|null $jsonOptions 87 * 88 * @return string 72 * @throws \JsonException 89 73 */ 90 public function toJSON(int $jsonOptions = null):string;74 public function toJSON(int|null $jsonOptions = null):string; 91 75 92 76 /** 93 77 * Sets properties from a given JSON string 94 78 * 95 * @param string $json 96 * 97 * @return \chillerlan\Settings\SettingsContainerInterface 79 * @see \chillerlan\Settings\SettingsContainerInterface::fromIterable() 98 80 * 99 81 * @throws \Exception 100 82 * @throws \JsonException 101 83 */ 102 public function fromJSON(string $json): SettingsContainerInterface;84 public function fromJSON(string $json):static; 103 85 104 86 } -
wp-otp/trunk/vendor/composer/ClassLoader.php
r2477335 r3752647 43 43 class ClassLoader 44 44 { 45 /** @var \Closure(string):void */ 46 private static $includeFile; 47 48 /** @var string|null */ 45 49 private $vendorDir; 46 50 47 51 // PSR-4 52 /** 53 * @var array<string, array<string, int>> 54 */ 48 55 private $prefixLengthsPsr4 = array(); 56 /** 57 * @var array<string, list<string>> 58 */ 49 59 private $prefixDirsPsr4 = array(); 60 /** 61 * @var list<string> 62 */ 50 63 private $fallbackDirsPsr4 = array(); 51 64 52 65 // PSR-0 66 /** 67 * List of PSR-0 prefixes 68 * 69 * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) 70 * 71 * @var array<string, array<string, list<string>>> 72 */ 53 73 private $prefixesPsr0 = array(); 74 /** 75 * @var list<string> 76 */ 54 77 private $fallbackDirsPsr0 = array(); 55 78 79 /** @var bool */ 56 80 private $useIncludePath = false; 81 82 /** 83 * @var array<string, string> 84 */ 57 85 private $classMap = array(); 86 87 /** @var bool */ 58 88 private $classMapAuthoritative = false; 89 90 /** 91 * @var array<string, bool> 92 */ 59 93 private $missingClasses = array(); 94 95 /** @var string|null */ 60 96 private $apcuPrefix; 61 97 98 /** 99 * @var array<string, self> 100 */ 62 101 private static $registeredLoaders = array(); 63 102 103 /** 104 * @param string|null $vendorDir 105 */ 64 106 public function __construct($vendorDir = null) 65 107 { 66 108 $this->vendorDir = $vendorDir; 67 } 68 109 self::initializeIncludeClosure(); 110 } 111 112 /** 113 * @return array<string, list<string>> 114 */ 69 115 public function getPrefixes() 70 116 { … … 76 122 } 77 123 124 /** 125 * @return array<string, list<string>> 126 */ 78 127 public function getPrefixesPsr4() 79 128 { … … 81 130 } 82 131 132 /** 133 * @return list<string> 134 */ 83 135 public function getFallbackDirs() 84 136 { … … 86 138 } 87 139 140 /** 141 * @return list<string> 142 */ 88 143 public function getFallbackDirsPsr4() 89 144 { … … 91 146 } 92 147 148 /** 149 * @return array<string, string> Array of classname => path 150 */ 93 151 public function getClassMap() 94 152 { … … 97 155 98 156 /** 99 * @param array $classMap Class to filename map 157 * @param array<string, string> $classMap Class to filename map 158 * 159 * @return void 100 160 */ 101 161 public function addClassMap(array $classMap) … … 112 172 * appending or prepending to the ones previously set for this prefix. 113 173 * 114 * @param string $prefix The prefix 115 * @param array|string $paths The PSR-0 root directories 116 * @param bool $prepend Whether to prepend the directories 174 * @param string $prefix The prefix 175 * @param list<string>|string $paths The PSR-0 root directories 176 * @param bool $prepend Whether to prepend the directories 177 * 178 * @return void 117 179 */ 118 180 public function add($prefix, $paths, $prepend = false) 119 181 { 182 $paths = (array) $paths; 120 183 if (!$prefix) { 121 184 if ($prepend) { 122 185 $this->fallbackDirsPsr0 = array_merge( 123 (array)$paths,186 $paths, 124 187 $this->fallbackDirsPsr0 125 188 ); … … 127 190 $this->fallbackDirsPsr0 = array_merge( 128 191 $this->fallbackDirsPsr0, 129 (array)$paths192 $paths 130 193 ); 131 194 } … … 136 199 $first = $prefix[0]; 137 200 if (!isset($this->prefixesPsr0[$first][$prefix])) { 138 $this->prefixesPsr0[$first][$prefix] = (array)$paths;201 $this->prefixesPsr0[$first][$prefix] = $paths; 139 202 140 203 return; … … 142 205 if ($prepend) { 143 206 $this->prefixesPsr0[$first][$prefix] = array_merge( 144 (array)$paths,207 $paths, 145 208 $this->prefixesPsr0[$first][$prefix] 146 209 ); … … 148 211 $this->prefixesPsr0[$first][$prefix] = array_merge( 149 212 $this->prefixesPsr0[$first][$prefix], 150 (array)$paths213 $paths 151 214 ); 152 215 } … … 157 220 * appending or prepending to the ones previously set for this namespace. 158 221 * 159 * @param string $prefix The prefix/namespace, with trailing '\\'160 * @param array|string $paths The PSR-4 base directories161 * @param bool $prepend Whether to prepend the directories222 * @param string $prefix The prefix/namespace, with trailing '\\' 223 * @param list<string>|string $paths The PSR-4 base directories 224 * @param bool $prepend Whether to prepend the directories 162 225 * 163 226 * @throws \InvalidArgumentException 227 * 228 * @return void 164 229 */ 165 230 public function addPsr4($prefix, $paths, $prepend = false) 166 231 { 232 $paths = (array) $paths; 167 233 if (!$prefix) { 168 234 // Register directories for the root namespace. 169 235 if ($prepend) { 170 236 $this->fallbackDirsPsr4 = array_merge( 171 (array)$paths,237 $paths, 172 238 $this->fallbackDirsPsr4 173 239 ); … … 175 241 $this->fallbackDirsPsr4 = array_merge( 176 242 $this->fallbackDirsPsr4, 177 (array)$paths243 $paths 178 244 ); 179 245 } … … 185 251 } 186 252 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 187 $this->prefixDirsPsr4[$prefix] = (array)$paths;253 $this->prefixDirsPsr4[$prefix] = $paths; 188 254 } elseif ($prepend) { 189 255 // Prepend directories for an already registered namespace. 190 256 $this->prefixDirsPsr4[$prefix] = array_merge( 191 (array)$paths,257 $paths, 192 258 $this->prefixDirsPsr4[$prefix] 193 259 ); … … 196 262 $this->prefixDirsPsr4[$prefix] = array_merge( 197 263 $this->prefixDirsPsr4[$prefix], 198 (array)$paths264 $paths 199 265 ); 200 266 } … … 205 271 * replacing any others previously set for this prefix. 206 272 * 207 * @param string $prefix The prefix 208 * @param array|string $paths The PSR-0 base directories 273 * @param string $prefix The prefix 274 * @param list<string>|string $paths The PSR-0 base directories 275 * 276 * @return void 209 277 */ 210 278 public function set($prefix, $paths) … … 221 289 * replacing any others previously set for this namespace. 222 290 * 223 * @param string $prefix The prefix/namespace, with trailing '\\'224 * @param array|string $paths The PSR-4 base directories291 * @param string $prefix The prefix/namespace, with trailing '\\' 292 * @param list<string>|string $paths The PSR-4 base directories 225 293 * 226 294 * @throws \InvalidArgumentException 295 * 296 * @return void 227 297 */ 228 298 public function setPsr4($prefix, $paths) … … 244 314 * 245 315 * @param bool $useIncludePath 316 * 317 * @return void 246 318 */ 247 319 public function setUseIncludePath($useIncludePath) … … 266 338 * 267 339 * @param bool $classMapAuthoritative 340 * 341 * @return void 268 342 */ 269 343 public function setClassMapAuthoritative($classMapAuthoritative) … … 286 360 * 287 361 * @param string|null $apcuPrefix 362 * 363 * @return void 288 364 */ 289 365 public function setApcuPrefix($apcuPrefix) … … 306 382 * 307 383 * @param bool $prepend Whether to prepend the autoloader or not 384 * 385 * @return void 308 386 */ 309 387 public function register($prepend = false) … … 312 390 313 391 if (null === $this->vendorDir) { 314 //no-op 315 } elseif ($prepend) { 392 return; 393 } 394 395 if ($prepend) { 316 396 self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; 317 397 } else { … … 323 403 /** 324 404 * Unregisters this instance as an autoloader. 405 * 406 * @return void 325 407 */ 326 408 public function unregister() … … 337 419 * 338 420 * @param string $class The name of the class 339 * @return bool|null True if loaded, null otherwise421 * @return true|null True if loaded, null otherwise 340 422 */ 341 423 public function loadClass($class) 342 424 { 343 425 if ($file = $this->findFile($class)) { 344 includeFile($file); 426 $includeFile = self::$includeFile; 427 $includeFile($file); 345 428 346 429 return true; 347 430 } 431 432 return null; 348 433 } 349 434 … … 391 476 392 477 /** 393 * Returns the currently registered loaders indexed by their corresponding vendor directories.394 * 395 * @return self[]478 * Returns the currently registered loaders keyed by their corresponding vendor directories. 479 * 480 * @return array<string, self> 396 481 */ 397 482 public static function getRegisteredLoaders() … … 400 485 } 401 486 487 /** 488 * @param string $class 489 * @param string $ext 490 * @return string|false 491 */ 402 492 private function findFileWithExtension($class, $ext) 403 493 { … … 465 555 return false; 466 556 } 557 558 /** 559 * @return void 560 */ 561 private static function initializeIncludeClosure() 562 { 563 if (self::$includeFile !== null) { 564 return; 565 } 566 567 /** 568 * Scope isolated include. 569 * 570 * Prevents access to $this/self from included files. 571 * 572 * @param string $file 573 * @return void 574 */ 575 self::$includeFile = \Closure::bind(static function($file) { 576 include $file; 577 }, null, null); 578 } 467 579 } 468 469 /**470 * Scope isolated include.471 *472 * Prevents access to $this/self from included files.473 */474 function includeFile($file)475 {476 include $file;477 } -
wp-otp/trunk/vendor/composer/InstalledVersions.php
r2477335 r3752647 1 1 <?php 2 2 3 4 5 6 7 8 9 10 11 3 /* 4 * This file is part of Composer. 5 * 6 * (c) Nils Adermann <naderman@naderman.de> 7 * Jordi Boggiano <j.boggiano@seld.be> 8 * 9 * For the full copyright and license information, please view the LICENSE 10 * file that was distributed with this source code. 11 */ 12 12 13 13 namespace Composer; … … 16 16 use Composer\Semver\VersionParser; 17 17 18 19 20 21 22 18 /** 19 * This class is copied in every Composer installed project and available to all 20 * 21 * See also https://getcomposer.org/doc/07-runtime.md#installed-versions 22 * 23 * To require its presence, you can require `composer-runtime-api ^2.0` 24 * 25 * @final 26 */ 23 27 class InstalledVersions 24 28 { 25 private static $installed = array ( 26 'root' => 27 array ( 28 'pretty_version' => 'trunk', 29 'version' => 'dev-trunk', 30 'aliases' => 31 array ( 32 ), 33 'reference' => NULL, 34 'name' => 'noplanman/wp-otp', 35 ), 36 'versions' => 37 array ( 38 'beberlei/assert' => 39 array ( 40 'pretty_version' => 'v3.3.0', 41 'version' => '3.3.0.0', 42 'aliases' => 43 array ( 44 ), 45 'reference' => '5367e3895976b49704ae671f75bc5f0ba1b986ab', 46 ), 47 'chillerlan/php-qrcode' => 48 array ( 49 'pretty_version' => '4.3.0', 50 'version' => '4.3.0.0', 51 'aliases' => 52 array ( 53 ), 54 'reference' => '4968063fb3baeedb658293f89f9673fbf2499a3e', 55 ), 56 'chillerlan/php-settings-container' => 57 array ( 58 'pretty_version' => '2.1.1', 59 'version' => '2.1.1.0', 60 'aliases' => 61 array ( 62 ), 63 'reference' => '98ccc1b31b31a53bcb563465c4961879b2b93096', 64 ), 65 'noplanman/wp-otp' => 66 array ( 67 'pretty_version' => 'trunk', 68 'version' => 'dev-trunk', 69 'aliases' => 70 array ( 71 ), 72 'reference' => NULL, 73 ), 74 'paragonie/constant_time_encoding' => 75 array ( 76 'pretty_version' => 'v2.4.0', 77 'version' => '2.4.0.0', 78 'aliases' => 79 array ( 80 ), 81 'reference' => 'f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c', 82 ), 83 'spomky-labs/otphp' => 84 array ( 85 'pretty_version' => 'v10.0.1', 86 'version' => '10.0.1.0', 87 'aliases' => 88 array ( 89 ), 90 'reference' => 'f44cce5a9db4b8da410215d992110482c931232f', 91 ), 92 'thecodingmachine/safe' => 93 array ( 94 'pretty_version' => 'v1.3.3', 95 'version' => '1.3.3.0', 96 'aliases' => 97 array ( 98 ), 99 'reference' => 'a8ab0876305a4cdaef31b2350fcb9811b5608dbc', 100 ), 101 ), 102 ); 103 private static $canGetVendors; 104 private static $installedByVendor = array(); 105 106 107 108 109 110 111 112 public static function getInstalledPackages() 113 { 114 $packages = array(); 115 foreach (self::getInstalled() as $installed) { 116 $packages[] = array_keys($installed['versions']); 29 /** 30 * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to 31 * @internal 32 */ 33 private static $selfDir = null; 34 35 /** 36 * @var mixed[]|null 37 * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null 38 */ 39 private static $installed; 40 41 /** 42 * @var bool 43 */ 44 private static $installedIsLocalDir; 45 46 /** 47 * @var bool|null 48 */ 49 private static $canGetVendors; 50 51 /** 52 * @var array[] 53 * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> 54 */ 55 private static $installedByVendor = array(); 56 57 /** 58 * Returns a list of all package names which are present, either by being installed, replaced or provided 59 * 60 * @return string[] 61 * @psalm-return list<string> 62 */ 63 public static function getInstalledPackages() 64 { 65 $packages = array(); 66 foreach (self::getInstalled() as $installed) { 67 $packages[] = array_keys($installed['versions']); 68 } 69 70 if (1 === \count($packages)) { 71 return $packages[0]; 72 } 73 74 return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); 75 } 76 77 /** 78 * Returns a list of all package names with a specific type e.g. 'library' 79 * 80 * @param string $type 81 * @return string[] 82 * @psalm-return list<string> 83 */ 84 public static function getInstalledPackagesByType($type) 85 { 86 $packagesByType = array(); 87 88 foreach (self::getInstalled() as $installed) { 89 foreach ($installed['versions'] as $name => $package) { 90 if (isset($package['type']) && $package['type'] === $type) { 91 $packagesByType[] = $name; 92 } 93 } 94 } 95 96 return $packagesByType; 97 } 98 99 /** 100 * Checks whether the given package is installed 101 * 102 * This also returns true if the package name is provided or replaced by another package 103 * 104 * @param string $packageName 105 * @param bool $includeDevRequirements 106 * @return bool 107 */ 108 public static function isInstalled($packageName, $includeDevRequirements = true) 109 { 110 foreach (self::getInstalled() as $installed) { 111 if (isset($installed['versions'][$packageName])) { 112 return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; 113 } 114 } 115 116 return false; 117 } 118 119 /** 120 * Checks whether the given package satisfies a version constraint 121 * 122 * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: 123 * 124 * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') 125 * 126 * @param VersionParser $parser Install composer/semver to have access to this class and functionality 127 * @param string $packageName 128 * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package 129 * @return bool 130 */ 131 public static function satisfies(VersionParser $parser, $packageName, $constraint) 132 { 133 $constraint = $parser->parseConstraints((string) $constraint); 134 $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); 135 136 return $provided->matches($constraint); 137 } 138 139 /** 140 * Returns a version constraint representing all the range(s) which are installed for a given package 141 * 142 * It is easier to use this via isInstalled() with the $constraint argument if you need to check 143 * whether a given version of a package is installed, and not just whether it exists 144 * 145 * @param string $packageName 146 * @return string Version constraint usable with composer/semver 147 */ 148 public static function getVersionRanges($packageName) 149 { 150 foreach (self::getInstalled() as $installed) { 151 if (!isset($installed['versions'][$packageName])) { 152 continue; 153 } 154 155 $ranges = array(); 156 if (isset($installed['versions'][$packageName]['pretty_version'])) { 157 $ranges[] = $installed['versions'][$packageName]['pretty_version']; 158 } 159 if (array_key_exists('aliases', $installed['versions'][$packageName])) { 160 $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); 161 } 162 if (array_key_exists('replaced', $installed['versions'][$packageName])) { 163 $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); 164 } 165 if (array_key_exists('provided', $installed['versions'][$packageName])) { 166 $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); 167 } 168 169 return implode(' || ', $ranges); 170 } 171 172 throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 173 } 174 175 /** 176 * @param string $packageName 177 * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present 178 */ 179 public static function getVersion($packageName) 180 { 181 foreach (self::getInstalled() as $installed) { 182 if (!isset($installed['versions'][$packageName])) { 183 continue; 184 } 185 186 if (!isset($installed['versions'][$packageName]['version'])) { 187 return null; 188 } 189 190 return $installed['versions'][$packageName]['version']; 191 } 192 193 throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 194 } 195 196 /** 197 * @param string $packageName 198 * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present 199 */ 200 public static function getPrettyVersion($packageName) 201 { 202 foreach (self::getInstalled() as $installed) { 203 if (!isset($installed['versions'][$packageName])) { 204 continue; 205 } 206 207 if (!isset($installed['versions'][$packageName]['pretty_version'])) { 208 return null; 209 } 210 211 return $installed['versions'][$packageName]['pretty_version']; 212 } 213 214 throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 215 } 216 217 /** 218 * @param string $packageName 219 * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference 220 */ 221 public static function getReference($packageName) 222 { 223 foreach (self::getInstalled() as $installed) { 224 if (!isset($installed['versions'][$packageName])) { 225 continue; 226 } 227 228 if (!isset($installed['versions'][$packageName]['reference'])) { 229 return null; 230 } 231 232 return $installed['versions'][$packageName]['reference']; 233 } 234 235 throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 236 } 237 238 /** 239 * @param string $packageName 240 * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. 241 */ 242 public static function getInstallPath($packageName) 243 { 244 foreach (self::getInstalled() as $installed) { 245 if (!isset($installed['versions'][$packageName])) { 246 continue; 247 } 248 249 return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; 250 } 251 252 throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 253 } 254 255 /** 256 * @return array 257 * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} 258 */ 259 public static function getRootPackage() 260 { 261 $installed = self::getInstalled(); 262 263 return $installed[0]['root']; 264 } 265 266 /** 267 * Returns the raw installed.php data for custom implementations 268 * 269 * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. 270 * @return array[] 271 * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} 272 */ 273 public static function getRawData() 274 { 275 @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); 276 277 if (null === self::$installed) { 278 // only require the installed.php file if this file is loaded from its dumped location, 279 // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 280 if (substr(__DIR__, -8, 1) !== 'C') { 281 self::$installed = include __DIR__ . '/installed.php'; 282 } else { 283 self::$installed = array(); 284 } 285 } 286 287 return self::$installed; 288 } 289 290 /** 291 * Returns the raw data of all installed.php which are currently loaded for custom implementations 292 * 293 * @return array[] 294 * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> 295 */ 296 public static function getAllRawData() 297 { 298 return self::getInstalled(); 299 } 300 301 /** 302 * Lets you reload the static array from another file 303 * 304 * This is only useful for complex integrations in which a project needs to use 305 * this class but then also needs to execute another project's autoloader in process, 306 * and wants to ensure both projects have access to their version of installed.php. 307 * 308 * A typical case would be PHPUnit, where it would need to make sure it reads all 309 * the data it needs from this class, then call reload() with 310 * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure 311 * the project in which it runs can then also use this class safely, without 312 * interference between PHPUnit's dependencies and the project's dependencies. 313 * 314 * @param array[] $data A vendor/composer/installed.php data set 315 * @return void 316 * 317 * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data 318 */ 319 public static function reload($data) 320 { 321 self::$installed = $data; 322 self::$installedByVendor = array(); 323 324 // when using reload, we disable the duplicate protection to ensure that self::$installed data is 325 // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, 326 // so we have to assume it does not, and that may result in duplicate data being returned when listing 327 // all installed packages for example 328 self::$installedIsLocalDir = false; 329 } 330 331 /** 332 * @return string 333 */ 334 private static function getSelfDir() 335 { 336 if (self::$selfDir === null) { 337 self::$selfDir = strtr(__DIR__, '\\', '/'); 338 } 339 340 return self::$selfDir; 341 } 342 343 /** 344 * @return array[] 345 * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> 346 */ 347 private static function getInstalled() 348 { 349 if (null === self::$canGetVendors) { 350 self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); 351 } 352 353 $installed = array(); 354 $copiedLocalDir = false; 355 356 if (self::$canGetVendors) { 357 $selfDir = self::getSelfDir(); 358 foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { 359 $vendorDir = strtr($vendorDir, '\\', '/'); 360 if (isset(self::$installedByVendor[$vendorDir])) { 361 $installed[] = self::$installedByVendor[$vendorDir]; 362 } elseif (is_file($vendorDir.'/composer/installed.php')) { 363 /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ 364 $required = require $vendorDir.'/composer/installed.php'; 365 self::$installedByVendor[$vendorDir] = $required; 366 $installed[] = $required; 367 if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { 368 self::$installed = $required; 369 self::$installedIsLocalDir = true; 370 } 371 } 372 if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { 373 $copiedLocalDir = true; 374 } 375 } 376 } 377 378 if (null === self::$installed) { 379 // only require the installed.php file if this file is loaded from its dumped location, 380 // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 381 if (substr(__DIR__, -8, 1) !== 'C') { 382 /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ 383 $required = require __DIR__ . '/installed.php'; 384 self::$installed = $required; 385 } else { 386 self::$installed = array(); 387 } 388 } 389 390 if (self::$installed !== array() && !$copiedLocalDir) { 391 $installed[] = self::$installed; 392 } 393 394 return $installed; 395 } 117 396 } 118 119 120 if (1 === \count($packages)) {121 return $packages[0];122 }123 124 return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));125 }126 127 128 129 130 131 132 133 134 135 public static function isInstalled($packageName)136 {137 foreach (self::getInstalled() as $installed) {138 if (isset($installed['versions'][$packageName])) {139 return true;140 }141 }142 143 return false;144 }145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 public static function satisfies(VersionParser $parser, $packageName, $constraint)160 {161 $constraint = $parser->parseConstraints($constraint);162 $provided = $parser->parseConstraints(self::getVersionRanges($packageName));163 164 return $provided->matches($constraint);165 }166 167 168 169 170 171 172 173 174 175 176 public static function getVersionRanges($packageName)177 {178 foreach (self::getInstalled() as $installed) {179 if (!isset($installed['versions'][$packageName])) {180 continue;181 }182 183 $ranges = array();184 if (isset($installed['versions'][$packageName]['pretty_version'])) {185 $ranges[] = $installed['versions'][$packageName]['pretty_version'];186 }187 if (array_key_exists('aliases', $installed['versions'][$packageName])) {188 $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);189 }190 if (array_key_exists('replaced', $installed['versions'][$packageName])) {191 $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);192 }193 if (array_key_exists('provided', $installed['versions'][$packageName])) {194 $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);195 }196 197 return implode(' || ', $ranges);198 }199 200 throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');201 }202 203 204 205 206 207 public static function getVersion($packageName)208 {209 foreach (self::getInstalled() as $installed) {210 if (!isset($installed['versions'][$packageName])) {211 continue;212 }213 214 if (!isset($installed['versions'][$packageName]['version'])) {215 return null;216 }217 218 return $installed['versions'][$packageName]['version'];219 }220 221 throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');222 }223 224 225 226 227 228 public static function getPrettyVersion($packageName)229 {230 foreach (self::getInstalled() as $installed) {231 if (!isset($installed['versions'][$packageName])) {232 continue;233 }234 235 if (!isset($installed['versions'][$packageName]['pretty_version'])) {236 return null;237 }238 239 return $installed['versions'][$packageName]['pretty_version'];240 }241 242 throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');243 }244 245 246 247 248 249 public static function getReference($packageName)250 {251 foreach (self::getInstalled() as $installed) {252 if (!isset($installed['versions'][$packageName])) {253 continue;254 }255 256 if (!isset($installed['versions'][$packageName]['reference'])) {257 return null;258 }259 260 return $installed['versions'][$packageName]['reference'];261 }262 263 throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');264 }265 266 267 268 269 270 public static function getRootPackage()271 {272 $installed = self::getInstalled();273 274 return $installed[0]['root'];275 }276 277 278 279 280 281 282 283 public static function getRawData()284 {285 return self::$installed;286 }287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 public static function reload($data)307 {308 self::$installed = $data;309 self::$installedByVendor = array();310 }311 312 313 314 315 private static function getInstalled()316 {317 if (null === self::$canGetVendors) {318 self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');319 }320 321 $installed = array();322 323 if (self::$canGetVendors) {324 325 foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {326 if (isset(self::$installedByVendor[$vendorDir])) {327 $installed[] = self::$installedByVendor[$vendorDir];328 } elseif (is_file($vendorDir.'/composer/installed.php')) {329 $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';330 }331 }332 }333 334 $installed[] = self::$installed;335 336 return $installed;337 }338 } -
wp-otp/trunk/vendor/composer/autoload_classmap.php
r2466054 r3752647 3 3 // autoload_classmap.php @generated by Composer 4 4 5 $vendorDir = dirname( dirname(__FILE__));5 $vendorDir = dirname(__DIR__); 6 6 $baseDir = dirname($vendorDir); 7 7 -
wp-otp/trunk/vendor/composer/autoload_files.php
r2466054 r3752647 3 3 // autoload_files.php @generated by Composer 4 4 5 $vendorDir = dirname( dirname(__FILE__));5 $vendorDir = dirname(__DIR__); 6 6 $baseDir = dirname($vendorDir); 7 7 8 8 return array( 9 'a4ecaeafb8cfb009ad0e052c90355e98' => $vendorDir . '/beberlei/assert/lib/Assert/functions.php', 10 '51fcf4e06c07cc00c920b44bcd900e7a' => $vendorDir . '/thecodingmachine/safe/deprecated/apc.php', 11 '47f619d9197b36cf5ab70738d7743fe2' => $vendorDir . '/thecodingmachine/safe/deprecated/libevent.php', 12 'ea6bb8a12ef9b68f6ada99058e530760' => $vendorDir . '/thecodingmachine/safe/deprecated/mssql.php', 13 '9a29089eb3ce41a446744c68a00f118c' => $vendorDir . '/thecodingmachine/safe/deprecated/stats.php', 14 '72243e5536b63e298acb6476f01f1aff' => $vendorDir . '/thecodingmachine/safe/lib/special_cases.php', 15 '3f648889e687f31c52f949ba8a9d0873' => $vendorDir . '/thecodingmachine/safe/generated/apache.php', 16 'eeb4581d958421a4244aaa4167c6a575' => $vendorDir . '/thecodingmachine/safe/generated/apcu.php', 17 '04cb0b3c1dac5b5ddb23c14e3d66dbe9' => $vendorDir . '/thecodingmachine/safe/generated/array.php', 18 '450b332a74a9a21e043c5e953485a791' => $vendorDir . '/thecodingmachine/safe/generated/bzip2.php', 19 '6e9b7954ecfd7cbb9ca239319d1acdb6' => $vendorDir . '/thecodingmachine/safe/generated/calendar.php', 20 '2c6d7e8bd2de9a272a9d4d43b0a4304a' => $vendorDir . '/thecodingmachine/safe/generated/classobj.php', 21 '0b8231c1ad0865447c988a4c16b4001f' => $vendorDir . '/thecodingmachine/safe/generated/com.php', 22 '7643a71fe1c3256058c8fee234cb86e5' => $vendorDir . '/thecodingmachine/safe/generated/cubrid.php', 23 '68e1365710575942efc1d55000032cee' => $vendorDir . '/thecodingmachine/safe/generated/curl.php', 24 '02fd26bca803106c5b942a7197c3ad8b' => $vendorDir . '/thecodingmachine/safe/generated/datetime.php', 25 'f4817dcbd956cd221b1c31f6fbd5749c' => $vendorDir . '/thecodingmachine/safe/generated/dir.php', 26 '51c3f2d10ca61a70dbcea0e38d8e902d' => $vendorDir . '/thecodingmachine/safe/generated/eio.php', 27 '1d34f34327ca3e81535963016e3be2c3' => $vendorDir . '/thecodingmachine/safe/generated/errorfunc.php', 28 '4fd0ba2d3717b0424d474bebfdafa2b4' => $vendorDir . '/thecodingmachine/safe/generated/exec.php', 29 '98f4dae054bc7fb19c13be14935cbdd3' => $vendorDir . '/thecodingmachine/safe/generated/fileinfo.php', 30 '5530ae063ba88323eaf0a07904efdf85' => $vendorDir . '/thecodingmachine/safe/generated/filesystem.php', 31 '633f4f134975d70e97bddad83348e91a' => $vendorDir . '/thecodingmachine/safe/generated/filter.php', 32 'fbd163fc68c5faf73d5ed4002ffd836d' => $vendorDir . '/thecodingmachine/safe/generated/fpm.php', 33 '21b511999d61411fab0692ff8795bbed' => $vendorDir . '/thecodingmachine/safe/generated/ftp.php', 34 '85fbd73fc92365cd90526b0ea03cae3a' => $vendorDir . '/thecodingmachine/safe/generated/funchand.php', 35 '51df9c146e0b7dcbdf358d8abd24dbdc' => $vendorDir . '/thecodingmachine/safe/generated/gmp.php', 36 '93bb7fe678d7dcfb1322f8e3475a48b0' => $vendorDir . '/thecodingmachine/safe/generated/gnupg.php', 37 'c171ba99cf316379ff66468392bf4950' => $vendorDir . '/thecodingmachine/safe/generated/hash.php', 38 '5ab4aad4c28e468209fbfcceb2e5e6a5' => $vendorDir . '/thecodingmachine/safe/generated/ibase.php', 39 '4d57409c5e8e576b0c64c08d9d731cfb' => $vendorDir . '/thecodingmachine/safe/generated/ibmDb2.php', 40 'eeb246d5403972a9d62106e4a4883496' => $vendorDir . '/thecodingmachine/safe/generated/iconv.php', 41 'c28a05f498c01b810a714f7214b7a8da' => $vendorDir . '/thecodingmachine/safe/generated/image.php', 42 '8063cd92acdf00fd978b5599eb7cc142' => $vendorDir . '/thecodingmachine/safe/generated/imap.php', 43 '8bd26dbe768e9c9599edad7b198e5446' => $vendorDir . '/thecodingmachine/safe/generated/info.php', 44 '0c577fe603b029d4b65c84376b15dbd5' => $vendorDir . '/thecodingmachine/safe/generated/ingres-ii.php', 45 'd4362910bde43c0f956b52527effd7d4' => $vendorDir . '/thecodingmachine/safe/generated/inotify.php', 46 '696ba49197d9b55f0428a12bb5a818e1' => $vendorDir . '/thecodingmachine/safe/generated/json.php', 47 '9818aaa99c8647c63f8ef62b7a368160' => $vendorDir . '/thecodingmachine/safe/generated/ldap.php', 48 'bcf523ff2a195eb08e0fbb668ed784d0' => $vendorDir . '/thecodingmachine/safe/generated/libxml.php', 49 '68be68a9a8b95bb56cab6109ff03bc88' => $vendorDir . '/thecodingmachine/safe/generated/lzf.php', 50 'bdca804bb0904ea9f53f328dfc0bb8a5' => $vendorDir . '/thecodingmachine/safe/generated/mailparse.php', 51 'b0a3fcac3eaf55445796d6af26b89366' => $vendorDir . '/thecodingmachine/safe/generated/mbstring.php', 52 '98de16b8db03eb0cb4d318b4402215a6' => $vendorDir . '/thecodingmachine/safe/generated/misc.php', 53 'c112440003b56e243b192c11fa9d836e' => $vendorDir . '/thecodingmachine/safe/generated/msql.php', 54 '7cefd81607cd21b8b3a15656eb6465f5' => $vendorDir . '/thecodingmachine/safe/generated/mysql.php', 55 'aaf438b080089c6d0686679cd34aa72e' => $vendorDir . '/thecodingmachine/safe/generated/mysqli.php', 56 'df0ef890e9afbf95f3924feb1c7a89f3' => $vendorDir . '/thecodingmachine/safe/generated/mysqlndMs.php', 57 'db595fee5972867e45c5327010d78735' => $vendorDir . '/thecodingmachine/safe/generated/mysqlndQc.php', 58 'cbac956836b72483dcff1ac39d5c0a0f' => $vendorDir . '/thecodingmachine/safe/generated/network.php', 59 '6c8f89dfbdc117d7871f572269363f25' => $vendorDir . '/thecodingmachine/safe/generated/oci8.php', 60 '169a669966a45c06bf55ed029122729b' => $vendorDir . '/thecodingmachine/safe/generated/opcache.php', 61 'def61bf4fecd4d4bca7354919cd69302' => $vendorDir . '/thecodingmachine/safe/generated/openssl.php', 62 '26bb010649a6d32d4120181458aa6ef2' => $vendorDir . '/thecodingmachine/safe/generated/outcontrol.php', 63 '1212c201fe43c7492a085b2c71505e0f' => $vendorDir . '/thecodingmachine/safe/generated/password.php', 64 '002ebcb842e2c0d5b7f67fe64cc93158' => $vendorDir . '/thecodingmachine/safe/generated/pcntl.php', 65 '86df38612982dade72c7085ce7eca81f' => $vendorDir . '/thecodingmachine/safe/generated/pcre.php', 66 '1cacc3e65f82a473fbd5507c7ce4385d' => $vendorDir . '/thecodingmachine/safe/generated/pdf.php', 67 '1fc22f445c69ea8706e82fce301c0831' => $vendorDir . '/thecodingmachine/safe/generated/pgsql.php', 68 'c70b42561584f7144bff38cd63c4eef3' => $vendorDir . '/thecodingmachine/safe/generated/posix.php', 69 '9923214639c32ca5173db03a177d3b63' => $vendorDir . '/thecodingmachine/safe/generated/ps.php', 70 '7e9c3f8eae2b5bf42205c4f1295cb7a7' => $vendorDir . '/thecodingmachine/safe/generated/pspell.php', 71 '91aa91f6245c349c2e2e88bd0025f199' => $vendorDir . '/thecodingmachine/safe/generated/readline.php', 72 'd43773cacb9e5e8e897aa255e32007d1' => $vendorDir . '/thecodingmachine/safe/generated/rpminfo.php', 73 'f053a3849e9e8383762b34b91db0320b' => $vendorDir . '/thecodingmachine/safe/generated/rrd.php', 74 '775b964f72f827a1bf87c65ab5b10800' => $vendorDir . '/thecodingmachine/safe/generated/sem.php', 75 '816428bd69c29ab5e1ed622af5dca0cd' => $vendorDir . '/thecodingmachine/safe/generated/session.php', 76 '5093e233bedbefaef0df262bfbab0a5c' => $vendorDir . '/thecodingmachine/safe/generated/shmop.php', 77 '01352920b0151f17e671266e44b52536' => $vendorDir . '/thecodingmachine/safe/generated/simplexml.php', 78 'b080617b1d949683c2e37f8f01dc0e15' => $vendorDir . '/thecodingmachine/safe/generated/sockets.php', 79 '2708aa182ddcfe6ce27c96acaaa40f69' => $vendorDir . '/thecodingmachine/safe/generated/sodium.php', 80 'f1b96cb260a5baeea9a7285cda82a1ec' => $vendorDir . '/thecodingmachine/safe/generated/solr.php', 81 '3fd8853757d0fe3557c179efb807afeb' => $vendorDir . '/thecodingmachine/safe/generated/spl.php', 82 '9312ce96a51c846913fcda5f186d58dd' => $vendorDir . '/thecodingmachine/safe/generated/sqlsrv.php', 83 'd3eb383ad0b8b962b29dc4afd29d6715' => $vendorDir . '/thecodingmachine/safe/generated/ssdeep.php', 84 '42a09bc448f441a0b9f9367ea975c0bf' => $vendorDir . '/thecodingmachine/safe/generated/ssh2.php', 85 'ef711077d356d1b33ca0b10b67b0be8f' => $vendorDir . '/thecodingmachine/safe/generated/stream.php', 86 '764b09f6df081cbb2807b97c6ace3866' => $vendorDir . '/thecodingmachine/safe/generated/strings.php', 87 'ef241678769fee4a44aaa288f3b78aa1' => $vendorDir . '/thecodingmachine/safe/generated/swoole.php', 88 '0efc8f6778cba932b9e2a89e28de2452' => $vendorDir . '/thecodingmachine/safe/generated/uodbc.php', 89 'd383d32907b98af53ee9208c62204fd0' => $vendorDir . '/thecodingmachine/safe/generated/uopz.php', 90 '2fd2e4060f7fe772660f002ce38f0b71' => $vendorDir . '/thecodingmachine/safe/generated/url.php', 91 '782249e03deebeaf57b9991ff5493aa0' => $vendorDir . '/thecodingmachine/safe/generated/var.php', 92 '344440cd1cd7200fdb4f12af0d3c587f' => $vendorDir . '/thecodingmachine/safe/generated/xdiff.php', 93 '3599f369219c658a5fb6c4fe66832f62' => $vendorDir . '/thecodingmachine/safe/generated/xml.php', 94 '7fcd313da9fae337051b091b3492c21b' => $vendorDir . '/thecodingmachine/safe/generated/xmlrpc.php', 95 'd668c74cfa92d893b582356733d9a80e' => $vendorDir . '/thecodingmachine/safe/generated/yaml.php', 96 '4af1dca6db8c527c6eed27bff85ff0e5' => $vendorDir . '/thecodingmachine/safe/generated/yaz.php', 97 'fe43ca06499ac37bc2dedd823af71eb5' => $vendorDir . '/thecodingmachine/safe/generated/zip.php', 98 '356736db98a6834f0a886b8d509b0ecd' => $vendorDir . '/thecodingmachine/safe/generated/zlib.php', 9 '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', 99 10 ); -
wp-otp/trunk/vendor/composer/autoload_namespaces.php
r1685086 r3752647 3 3 // autoload_namespaces.php @generated by Composer 4 4 5 $vendorDir = dirname( dirname(__FILE__));5 $vendorDir = dirname(__DIR__); 6 6 $baseDir = dirname($vendorDir); 7 7 -
wp-otp/trunk/vendor/composer/autoload_psr4.php
r2466054 r3752647 3 3 // autoload_psr4.php @generated by Composer 4 4 5 $vendorDir = dirname( dirname(__FILE__));5 $vendorDir = dirname(__DIR__); 6 6 $baseDir = dirname($vendorDir); 7 7 … … 9 9 'chillerlan\\Settings\\' => array($vendorDir . '/chillerlan/php-settings-container/src'), 10 10 'chillerlan\\QRCode\\' => array($vendorDir . '/chillerlan/php-qrcode/src'), 11 ' Safe\\' => array($vendorDir . '/thecodingmachine/safe/lib', $vendorDir . '/thecodingmachine/safe/deprecated', $vendorDir . '/thecodingmachine/safe/generated'),11 'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'), 12 12 'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'), 13 13 'OTPHP\\' => array($vendorDir . '/spomky-labs/otphp/src'), 14 'Assert\\' => array($vendorDir . '/beberlei/assert/lib/Assert'),15 14 ); -
wp-otp/trunk/vendor/composer/autoload_real.php
r2477335 r3752647 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit c7ff053f14f929092d06e37035c6064c5 class ComposerAutoloaderInit0cde52f04200d0b097061008ff484a30 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit c7ff053f14f929092d06e37035c6064c', 'loadClassLoader'), true, true);28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname( \dirname(__FILE__)));29 spl_autoload_unregister(array('ComposerAutoloaderInit c7ff053f14f929092d06e37035c6064c', 'loadClassLoader'));27 spl_autoload_register(array('ComposerAutoloaderInit0cde52f04200d0b097061008ff484a30', 'loadClassLoader'), true, true); 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit0cde52f04200d0b097061008ff484a30', 'loadClassLoader')); 30 30 31 $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); 32 if ($useStaticLoader) { 33 require __DIR__ . '/autoload_static.php'; 34 35 call_user_func(\Composer\Autoload\ComposerStaticInitc7ff053f14f929092d06e37035c6064c::getInitializer($loader)); 36 } else { 37 $map = require __DIR__ . '/autoload_namespaces.php'; 38 foreach ($map as $namespace => $path) { 39 $loader->set($namespace, $path); 40 } 41 42 $map = require __DIR__ . '/autoload_psr4.php'; 43 foreach ($map as $namespace => $path) { 44 $loader->setPsr4($namespace, $path); 45 } 46 47 $classMap = require __DIR__ . '/autoload_classmap.php'; 48 if ($classMap) { 49 $loader->addClassMap($classMap); 50 } 51 } 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit0cde52f04200d0b097061008ff484a30::getInitializer($loader)); 52 33 53 34 $loader->register(true); 54 35 55 if ($useStaticLoader) { 56 $includeFiles = Composer\Autoload\ComposerStaticInitc7ff053f14f929092d06e37035c6064c::$files; 57 } else { 58 $includeFiles = require __DIR__ . '/autoload_files.php'; 59 } 60 foreach ($includeFiles as $fileIdentifier => $file) { 61 composerRequirec7ff053f14f929092d06e37035c6064c($fileIdentifier, $file); 36 $filesToLoad = \Composer\Autoload\ComposerStaticInit0cde52f04200d0b097061008ff484a30::$files; 37 $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { 38 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { 39 $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; 40 41 require $file; 42 } 43 }, null, null); 44 foreach ($filesToLoad as $fileIdentifier => $file) { 45 $requireFile($fileIdentifier, $file); 62 46 } 63 47 … … 65 49 } 66 50 } 67 68 function composerRequirec7ff053f14f929092d06e37035c6064c($fileIdentifier, $file)69 {70 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {71 require $file;72 73 $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;74 }75 } -
wp-otp/trunk/vendor/composer/autoload_static.php
r2477335 r3752647 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit c7ff053f14f929092d06e37035c6064c7 class ComposerStaticInit0cde52f04200d0b097061008ff484a30 8 8 { 9 9 public static $files = array ( 10 'a4ecaeafb8cfb009ad0e052c90355e98' => __DIR__ . '/..' . '/beberlei/assert/lib/Assert/functions.php', 11 '51fcf4e06c07cc00c920b44bcd900e7a' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/apc.php', 12 '47f619d9197b36cf5ab70738d7743fe2' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/libevent.php', 13 'ea6bb8a12ef9b68f6ada99058e530760' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/mssql.php', 14 '9a29089eb3ce41a446744c68a00f118c' => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated/stats.php', 15 '72243e5536b63e298acb6476f01f1aff' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/special_cases.php', 16 '3f648889e687f31c52f949ba8a9d0873' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/apache.php', 17 'eeb4581d958421a4244aaa4167c6a575' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/apcu.php', 18 '04cb0b3c1dac5b5ddb23c14e3d66dbe9' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/array.php', 19 '450b332a74a9a21e043c5e953485a791' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/bzip2.php', 20 '6e9b7954ecfd7cbb9ca239319d1acdb6' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/calendar.php', 21 '2c6d7e8bd2de9a272a9d4d43b0a4304a' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/classobj.php', 22 '0b8231c1ad0865447c988a4c16b4001f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/com.php', 23 '7643a71fe1c3256058c8fee234cb86e5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/cubrid.php', 24 '68e1365710575942efc1d55000032cee' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/curl.php', 25 '02fd26bca803106c5b942a7197c3ad8b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/datetime.php', 26 'f4817dcbd956cd221b1c31f6fbd5749c' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/dir.php', 27 '51c3f2d10ca61a70dbcea0e38d8e902d' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/eio.php', 28 '1d34f34327ca3e81535963016e3be2c3' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/errorfunc.php', 29 '4fd0ba2d3717b0424d474bebfdafa2b4' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/exec.php', 30 '98f4dae054bc7fb19c13be14935cbdd3' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/fileinfo.php', 31 '5530ae063ba88323eaf0a07904efdf85' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/filesystem.php', 32 '633f4f134975d70e97bddad83348e91a' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/filter.php', 33 'fbd163fc68c5faf73d5ed4002ffd836d' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/fpm.php', 34 '21b511999d61411fab0692ff8795bbed' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ftp.php', 35 '85fbd73fc92365cd90526b0ea03cae3a' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/funchand.php', 36 '51df9c146e0b7dcbdf358d8abd24dbdc' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/gmp.php', 37 '93bb7fe678d7dcfb1322f8e3475a48b0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/gnupg.php', 38 'c171ba99cf316379ff66468392bf4950' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/hash.php', 39 '5ab4aad4c28e468209fbfcceb2e5e6a5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ibase.php', 40 '4d57409c5e8e576b0c64c08d9d731cfb' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ibmDb2.php', 41 'eeb246d5403972a9d62106e4a4883496' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/iconv.php', 42 'c28a05f498c01b810a714f7214b7a8da' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/image.php', 43 '8063cd92acdf00fd978b5599eb7cc142' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/imap.php', 44 '8bd26dbe768e9c9599edad7b198e5446' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/info.php', 45 '0c577fe603b029d4b65c84376b15dbd5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ingres-ii.php', 46 'd4362910bde43c0f956b52527effd7d4' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/inotify.php', 47 '696ba49197d9b55f0428a12bb5a818e1' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/json.php', 48 '9818aaa99c8647c63f8ef62b7a368160' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ldap.php', 49 'bcf523ff2a195eb08e0fbb668ed784d0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/libxml.php', 50 '68be68a9a8b95bb56cab6109ff03bc88' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/lzf.php', 51 'bdca804bb0904ea9f53f328dfc0bb8a5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mailparse.php', 52 'b0a3fcac3eaf55445796d6af26b89366' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mbstring.php', 53 '98de16b8db03eb0cb4d318b4402215a6' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/misc.php', 54 'c112440003b56e243b192c11fa9d836e' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/msql.php', 55 '7cefd81607cd21b8b3a15656eb6465f5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mysql.php', 56 'aaf438b080089c6d0686679cd34aa72e' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mysqli.php', 57 'df0ef890e9afbf95f3924feb1c7a89f3' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mysqlndMs.php', 58 'db595fee5972867e45c5327010d78735' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/mysqlndQc.php', 59 'cbac956836b72483dcff1ac39d5c0a0f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/network.php', 60 '6c8f89dfbdc117d7871f572269363f25' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/oci8.php', 61 '169a669966a45c06bf55ed029122729b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/opcache.php', 62 'def61bf4fecd4d4bca7354919cd69302' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/openssl.php', 63 '26bb010649a6d32d4120181458aa6ef2' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/outcontrol.php', 64 '1212c201fe43c7492a085b2c71505e0f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/password.php', 65 '002ebcb842e2c0d5b7f67fe64cc93158' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pcntl.php', 66 '86df38612982dade72c7085ce7eca81f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pcre.php', 67 '1cacc3e65f82a473fbd5507c7ce4385d' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pdf.php', 68 '1fc22f445c69ea8706e82fce301c0831' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pgsql.php', 69 'c70b42561584f7144bff38cd63c4eef3' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/posix.php', 70 '9923214639c32ca5173db03a177d3b63' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ps.php', 71 '7e9c3f8eae2b5bf42205c4f1295cb7a7' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/pspell.php', 72 '91aa91f6245c349c2e2e88bd0025f199' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/readline.php', 73 'd43773cacb9e5e8e897aa255e32007d1' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/rpminfo.php', 74 'f053a3849e9e8383762b34b91db0320b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/rrd.php', 75 '775b964f72f827a1bf87c65ab5b10800' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sem.php', 76 '816428bd69c29ab5e1ed622af5dca0cd' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/session.php', 77 '5093e233bedbefaef0df262bfbab0a5c' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/shmop.php', 78 '01352920b0151f17e671266e44b52536' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/simplexml.php', 79 'b080617b1d949683c2e37f8f01dc0e15' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sockets.php', 80 '2708aa182ddcfe6ce27c96acaaa40f69' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sodium.php', 81 'f1b96cb260a5baeea9a7285cda82a1ec' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/solr.php', 82 '3fd8853757d0fe3557c179efb807afeb' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/spl.php', 83 '9312ce96a51c846913fcda5f186d58dd' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/sqlsrv.php', 84 'd3eb383ad0b8b962b29dc4afd29d6715' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ssdeep.php', 85 '42a09bc448f441a0b9f9367ea975c0bf' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/ssh2.php', 86 'ef711077d356d1b33ca0b10b67b0be8f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/stream.php', 87 '764b09f6df081cbb2807b97c6ace3866' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/strings.php', 88 'ef241678769fee4a44aaa288f3b78aa1' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/swoole.php', 89 '0efc8f6778cba932b9e2a89e28de2452' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/uodbc.php', 90 'd383d32907b98af53ee9208c62204fd0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/uopz.php', 91 '2fd2e4060f7fe772660f002ce38f0b71' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/url.php', 92 '782249e03deebeaf57b9991ff5493aa0' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/var.php', 93 '344440cd1cd7200fdb4f12af0d3c587f' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/xdiff.php', 94 '3599f369219c658a5fb6c4fe66832f62' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/xml.php', 95 '7fcd313da9fae337051b091b3492c21b' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/xmlrpc.php', 96 'd668c74cfa92d893b582356733d9a80e' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/yaml.php', 97 '4af1dca6db8c527c6eed27bff85ff0e5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/yaz.php', 98 'fe43ca06499ac37bc2dedd823af71eb5' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/zip.php', 99 '356736db98a6834f0a886b8d509b0ecd' => __DIR__ . '/..' . '/thecodingmachine/safe/generated/zlib.php', 10 '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', 100 11 ); 101 12 102 13 public static $prefixLengthsPsr4 = array ( 103 'c' => 14 'c' => 104 15 array ( 105 16 'chillerlan\\Settings\\' => 20, 106 17 'chillerlan\\QRCode\\' => 18, 107 18 ), 108 ' S' =>19 'P' => 109 20 array ( 110 'Safe\\' => 5, 111 ), 112 'P' => 113 array ( 21 'Psr\\Clock\\' => 10, 114 22 'ParagonIE\\ConstantTime\\' => 23, 115 23 ), 116 'O' => 24 'O' => 117 25 array ( 118 26 'OTPHP\\' => 6, 119 ),120 'A' =>121 array (122 'Assert\\' => 7,123 27 ), 124 28 ); 125 29 126 30 public static $prefixDirsPsr4 = array ( 127 'chillerlan\\Settings\\' => 31 'chillerlan\\Settings\\' => 128 32 array ( 129 33 0 => __DIR__ . '/..' . '/chillerlan/php-settings-container/src', 130 34 ), 131 'chillerlan\\QRCode\\' => 35 'chillerlan\\QRCode\\' => 132 36 array ( 133 37 0 => __DIR__ . '/..' . '/chillerlan/php-qrcode/src', 134 38 ), 135 ' Safe\\' =>39 'Psr\\Clock\\' => 136 40 array ( 137 0 => __DIR__ . '/..' . '/thecodingmachine/safe/lib', 138 1 => __DIR__ . '/..' . '/thecodingmachine/safe/deprecated', 139 2 => __DIR__ . '/..' . '/thecodingmachine/safe/generated', 41 0 => __DIR__ . '/..' . '/psr/clock/src', 140 42 ), 141 'ParagonIE\\ConstantTime\\' => 43 'ParagonIE\\ConstantTime\\' => 142 44 array ( 143 45 0 => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src', 144 46 ), 145 'OTPHP\\' => 47 'OTPHP\\' => 146 48 array ( 147 49 0 => __DIR__ . '/..' . '/spomky-labs/otphp/src', 148 ),149 'Assert\\' =>150 array (151 0 => __DIR__ . '/..' . '/beberlei/assert/lib/Assert',152 50 ), 153 51 ); … … 160 58 { 161 59 return \Closure::bind(function () use ($loader) { 162 $loader->prefixLengthsPsr4 = ComposerStaticInit c7ff053f14f929092d06e37035c6064c::$prefixLengthsPsr4;163 $loader->prefixDirsPsr4 = ComposerStaticInit c7ff053f14f929092d06e37035c6064c::$prefixDirsPsr4;164 $loader->classMap = ComposerStaticInit c7ff053f14f929092d06e37035c6064c::$classMap;60 $loader->prefixLengthsPsr4 = ComposerStaticInit0cde52f04200d0b097061008ff484a30::$prefixLengthsPsr4; 61 $loader->prefixDirsPsr4 = ComposerStaticInit0cde52f04200d0b097061008ff484a30::$prefixDirsPsr4; 62 $loader->classMap = ComposerStaticInit0cde52f04200d0b097061008ff484a30::$classMap; 165 63 166 64 }, null, ClassLoader::class); -
wp-otp/trunk/vendor/composer/installed.json
r2466054 r3752647 2 2 "packages": [ 3 3 { 4 "name": "beberlei/assert", 5 "version": "v3.3.0", 6 "version_normalized": "3.3.0.0", 7 "source": { 8 "type": "git", 9 "url": "https://github.com/beberlei/assert.git", 10 "reference": "5367e3895976b49704ae671f75bc5f0ba1b986ab" 11 }, 12 "dist": { 13 "type": "zip", 14 "url": "https://api.github.com/repos/beberlei/assert/zipball/5367e3895976b49704ae671f75bc5f0ba1b986ab", 15 "reference": "5367e3895976b49704ae671f75bc5f0ba1b986ab", 16 "shasum": "" 17 }, 18 "require": { 19 "ext-ctype": "*", 20 "ext-intl": "*", 21 "ext-json": "*", 4 "name": "chillerlan/php-qrcode", 5 "version": "6.0.1", 6 "version_normalized": "6.0.1.0", 7 "source": { 8 "type": "git", 9 "url": "https://github.com/chillerlan/php-qrcode.git", 10 "reference": "49006e34bd5328f163e80329e7312f34dceea59b" 11 }, 12 "dist": { 13 "type": "zip", 14 "url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/49006e34bd5328f163e80329e7312f34dceea59b", 15 "reference": "49006e34bd5328f163e80329e7312f34dceea59b", 16 "shasum": "" 17 }, 18 "require": { 19 "chillerlan/php-settings-container": "^3.2.1", 22 20 "ext-mbstring": "*", 23 "ext-simplexml": "*", 24 "php": "^7.0 || ^8.0" 21 "php": "^8.2" 25 22 }, 26 23 "require-dev": { 27 "friendsofphp/php-cs-fixer": "*", 28 "phpstan/phpstan": "*", 29 "phpunit/phpunit": ">=6.0.0", 30 "yoast/phpunit-polyfills": "^0.1.0" 31 }, 32 "time": "2020-11-13T20:02:54+00:00", 33 "type": "library", 34 "installation-source": "dist", 35 "autoload": { 36 "psr-4": { 37 "Assert\\": "lib/Assert" 38 }, 39 "files": [ 40 "lib/Assert/functions.php" 41 ] 42 }, 43 "notification-url": "https://packagist.org/downloads/", 44 "license": [ 45 "BSD-2-Clause" 46 ], 47 "authors": [ 48 { 49 "name": "Benjamin Eberlei", 50 "email": "kontakt@beberlei.de", 51 "role": "Lead Developer" 52 }, 53 { 54 "name": "Richard Quadling", 55 "email": "rquadling@gmail.com", 56 "role": "Collaborator" 57 } 58 ], 59 "description": "Thin assertion library for input validation in business models.", 60 "keywords": [ 61 "assert", 62 "assertion", 63 "validation" 64 ], 65 "support": { 66 "issues": "https://github.com/beberlei/assert/issues", 67 "source": "https://github.com/beberlei/assert/tree/v3.3.0" 68 }, 69 "install-path": "../beberlei/assert" 70 }, 71 { 72 "name": "chillerlan/php-qrcode", 73 "version": "4.3.0", 74 "version_normalized": "4.3.0.0", 75 "source": { 76 "type": "git", 77 "url": "https://github.com/chillerlan/php-qrcode.git", 78 "reference": "4968063fb3baeedb658293f89f9673fbf2499a3e" 79 }, 80 "dist": { 81 "type": "zip", 82 "url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/4968063fb3baeedb658293f89f9673fbf2499a3e", 83 "reference": "4968063fb3baeedb658293f89f9673fbf2499a3e", 84 "shasum": "" 85 }, 86 "require": { 87 "chillerlan/php-settings-container": "^2.1", 88 "ext-mbstring": "*", 89 "php": "^7.4 || ^8.0" 90 }, 91 "require-dev": { 92 "phan/phan": "^3.2.2", 93 "phpunit/phpunit": "^9.4", 94 "setasign/fpdf": "^1.8.2" 24 "chillerlan/php-authenticator": "^5.3", 25 "ext-fileinfo": "*", 26 "intervention/image": "^3.11", 27 "phan/phan": "^6.0.1", 28 "phpbench/phpbench": "^1.4", 29 "phpmd/phpmd": "^2.15", 30 "phpstan/phpstan": "^2.1.40", 31 "phpstan/phpstan-deprecation-rules": "^2.0.4", 32 "phpunit/phpunit": "^11.5", 33 "setasign/fpdf": "^1.8.6", 34 "slevomat/coding-standard": "^8.28", 35 "squizlabs/php_codesniffer": "^4.0" 95 36 }, 96 37 "suggest": { 97 38 "chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.", 98 "setasign/fpdf": "Required to use the QR FPDF output." 99 }, 100 "time": "2020-11-18T20:49:20+00:00", 39 "intervention/image": "More advanced GD and ImageMagick output.", 40 "setasign/fpdf": "Required to use the QR FPDF output.", 41 "simple-icons/simple-icons": "SVG icons that you can use to embed as logos in the QR Code" 42 }, 43 "time": "2026-03-18T21:21:07+00:00", 101 44 "type": "library", 102 45 "installation-source": "dist", 103 46 "autoload": { 104 47 "psr-4": { 105 "chillerlan\\QRCode\\": "src/" 106 } 107 }, 108 "notification-url": "https://packagist.org/downloads/", 109 "license": [ 110 "MIT" 48 "chillerlan\\QRCode\\": "src" 49 } 50 }, 51 "notification-url": "https://packagist.org/downloads/", 52 "license": [ 53 "MIT", 54 "Apache-2.0" 111 55 ], 112 56 "authors": [ 113 57 { 114 58 "name": "Kazuhiko Arase", 115 "homepage": "https://github.com/kazuhikoarase" 59 "homepage": "https://github.com/kazuhikoarase/qrcode-generator" 60 }, 61 { 62 "name": "ZXing Authors", 63 "homepage": "https://github.com/zxing/zxing" 64 }, 65 { 66 "name": "Ashot Khanamiryan", 67 "homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder" 116 68 }, 117 69 { … … 125 77 } 126 78 ], 127 "description": "A QR code generator. PHP 7.4+",79 "description": "A QR Code generator and reader with a user-friendly API. PHP 8.2+", 128 80 "homepage": "https://github.com/chillerlan/php-qrcode", 129 81 "keywords": [ … … 131 83 "qr", 132 84 "qr code", 85 "qr-reader", 133 86 "qrcode", 134 "qrcode-generator" 135 ], 136 "support": { 87 "qrcode-generator", 88 "qrcode-reader" 89 ], 90 "support": { 91 "docs": "https://php-qrcode.readthedocs.io", 137 92 "issues": "https://github.com/chillerlan/php-qrcode/issues", 138 "source": "https://github.com/chillerlan/php-qrcode /tree/4.3.0"93 "source": "https://github.com/chillerlan/php-qrcode" 139 94 }, 140 95 "funding": [ 141 96 { 142 "url": "https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4",143 "type": "custom"144 },145 {146 97 "url": "https://ko-fi.com/codemasher", 147 "type": " ko_fi"98 "type": "Ko-Fi" 148 99 } 149 100 ], … … 152 103 { 153 104 "name": "chillerlan/php-settings-container", 154 "version": " 2.1.1",155 "version_normalized": " 2.1.1.0",105 "version": "3.3.0", 106 "version_normalized": "3.3.0.0", 156 107 "source": { 157 108 "type": "git", 158 109 "url": "https://github.com/chillerlan/php-settings-container.git", 159 "reference": " 98ccc1b31b31a53bcb563465c4961879b2b93096"160 }, 161 "dist": { 162 "type": "zip", 163 "url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/ 98ccc1b31b31a53bcb563465c4961879b2b93096",164 "reference": " 98ccc1b31b31a53bcb563465c4961879b2b93096",110 "reference": "a0a487cbf5344f721eb504bf0f59bada40c381b7" 111 }, 112 "dist": { 113 "type": "zip", 114 "url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/a0a487cbf5344f721eb504bf0f59bada40c381b7", 115 "reference": "a0a487cbf5344f721eb504bf0f59bada40c381b7", 165 116 "shasum": "" 166 117 }, 167 118 "require": { 168 119 "ext-json": "*", 169 "php": "^ 7.4 || ^8.0"120 "php": "^8.1" 170 121 }, 171 122 "require-dev": { 172 "phan/phan": "^4.0", 173 "phpunit/phpunit": "^9.5" 174 }, 175 "time": "2021-01-06T15:57:03+00:00", 123 "phan/phan": "^5.5.2", 124 "phpmd/phpmd": "^2.15", 125 "phpstan/phpstan": "^2.1.31", 126 "phpstan/phpstan-deprecation-rules": "^2.0.3", 127 "phpunit/phpunit": "^10.5", 128 "slevomat/coding-standard": "^8.22", 129 "squizlabs/php_codesniffer": "^4.0" 130 }, 131 "time": "2026-03-20T21:10:52+00:00", 176 132 "type": "library", 177 133 "installation-source": "dist", 178 134 "autoload": { 179 135 "psr-4": { 180 "chillerlan\\Settings\\": "src /"136 "chillerlan\\Settings\\": "src" 181 137 } 182 138 }, … … 192 148 } 193 149 ], 194 "description": "A container class for immutable settings objects. Not a DI container. PHP 7.4+",150 "description": "A container class for immutable settings objects. Not a DI container.", 195 151 "homepage": "https://github.com/chillerlan/php-settings-container", 196 152 "keywords": [ 197 "PHP7",198 153 "Settings", 154 "configuration", 199 155 "container", 200 "helper" 156 "helper", 157 "property hook" 201 158 ], 202 159 "support": { … … 218 175 { 219 176 "name": "paragonie/constant_time_encoding", 220 "version": "v 2.4.0",221 "version_normalized": " 2.4.0.0",177 "version": "v3.1.3", 178 "version_normalized": "3.1.3.0", 222 179 "source": { 223 180 "type": "git", 224 181 "url": "https://github.com/paragonie/constant_time_encoding.git", 225 "reference": " f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c"226 }, 227 "dist": { 228 "type": "zip", 229 "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/ f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c",230 "reference": " f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c",231 "shasum": "" 232 }, 233 "require": { 234 "php": "^ 7|^8"182 "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77" 183 }, 184 "dist": { 185 "type": "zip", 186 "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", 187 "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", 188 "shasum": "" 189 }, 190 "require": { 191 "php": "^8" 235 192 }, 236 193 "require-dev": { 237 "phpunit/phpunit": "^6|^7|^8|^9", 238 "vimeo/psalm": "^1|^2|^3|^4" 239 }, 240 "time": "2020-12-06T15:14:20+00:00", 194 "infection/infection": "^0", 195 "nikic/php-fuzzer": "^0", 196 "phpunit/phpunit": "^9|^10|^11", 197 "vimeo/psalm": "^4|^5|^6" 198 }, 199 "time": "2025-09-24T15:06:41+00:00", 241 200 "type": "library", 242 201 "installation-source": "dist", … … 287 246 }, 288 247 { 248 "name": "psr/clock", 249 "version": "1.0.0", 250 "version_normalized": "1.0.0.0", 251 "source": { 252 "type": "git", 253 "url": "https://github.com/php-fig/clock.git", 254 "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" 255 }, 256 "dist": { 257 "type": "zip", 258 "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", 259 "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", 260 "shasum": "" 261 }, 262 "require": { 263 "php": "^7.0 || ^8.0" 264 }, 265 "time": "2022-11-25T14:36:26+00:00", 266 "type": "library", 267 "installation-source": "dist", 268 "autoload": { 269 "psr-4": { 270 "Psr\\Clock\\": "src/" 271 } 272 }, 273 "notification-url": "https://packagist.org/downloads/", 274 "license": [ 275 "MIT" 276 ], 277 "authors": [ 278 { 279 "name": "PHP-FIG", 280 "homepage": "https://www.php-fig.org/" 281 } 282 ], 283 "description": "Common interface for reading the clock.", 284 "homepage": "https://github.com/php-fig/clock", 285 "keywords": [ 286 "clock", 287 "now", 288 "psr", 289 "psr-20", 290 "time" 291 ], 292 "support": { 293 "issues": "https://github.com/php-fig/clock/issues", 294 "source": "https://github.com/php-fig/clock/tree/1.0.0" 295 }, 296 "install-path": "../psr/clock" 297 }, 298 { 289 299 "name": "spomky-labs/otphp", 290 "version": " v10.0.1",291 "version_normalized": "1 0.0.1.0",300 "version": "11.5.0", 301 "version_normalized": "11.5.0.0", 292 302 "source": { 293 303 "type": "git", 294 304 "url": "https://github.com/Spomky-Labs/otphp.git", 295 "reference": "f44cce5a9db4b8da410215d992110482c931232f" 296 }, 297 "dist": { 298 "type": "zip", 299 "url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/f44cce5a9db4b8da410215d992110482c931232f", 300 "reference": "f44cce5a9db4b8da410215d992110482c931232f", 301 "shasum": "" 302 }, 303 "require": { 304 "beberlei/assert": "^3.0", 305 "ext-mbstring": "*", 306 "paragonie/constant_time_encoding": "^2.0", 307 "php": "^7.2|^8.0", 308 "thecodingmachine/safe": "^0.1.14|^1.0" 305 "reference": "877683d6352b80cdc7020fd43a725629c2524435" 306 }, 307 "dist": { 308 "type": "zip", 309 "url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/877683d6352b80cdc7020fd43a725629c2524435", 310 "reference": "877683d6352b80cdc7020fd43a725629c2524435", 311 "shasum": "" 312 }, 313 "require": { 314 "paragonie/constant_time_encoding": "^2.0 || ^3.0", 315 "php": ">=8.1", 316 "psr/clock": "^1.0", 317 "symfony/deprecation-contracts": "^3.2" 309 318 }, 310 319 "require-dev": { 311 "php-coveralls/php-coveralls": "^2.0", 312 "phpstan/phpstan": "^0.12", 313 "phpstan/phpstan-beberlei-assert": "^0.12", 314 "phpstan/phpstan-deprecation-rules": "^0.12", 315 "phpstan/phpstan-phpunit": "^0.12", 316 "phpstan/phpstan-strict-rules": "^0.12", 317 "phpunit/phpunit": "^8.0", 318 "thecodingmachine/phpstan-safe-rule": "^1.0" 319 }, 320 "time": "2020-01-28T09:24:19+00:00", 321 "type": "library", 322 "extra": { 323 "branch-alias": { 324 "v10.0": "10.0.x-dev", 325 "v9.0": "9.0.x-dev", 326 "v8.3": "8.3.x-dev" 327 } 328 }, 320 "symfony/error-handler": "^6.4|^7.0|^8.0" 321 }, 322 "time": "2026-06-06T23:41:24+00:00", 323 "type": "library", 329 324 "installation-source": "dist", 330 325 "autoload": { … … 360 355 "support": { 361 356 "issues": "https://github.com/Spomky-Labs/otphp/issues", 362 "source": "https://github.com/Spomky-Labs/otphp/tree/v10.0.1" 363 }, 357 "source": "https://github.com/Spomky-Labs/otphp/tree/11.5.0" 358 }, 359 "funding": [ 360 { 361 "url": "https://github.com/Spomky", 362 "type": "github" 363 }, 364 { 365 "url": "https://www.patreon.com/FlorentMorselli", 366 "type": "patreon" 367 } 368 ], 364 369 "install-path": "../spomky-labs/otphp" 365 370 }, 366 371 { 367 "name": "thecodingmachine/safe", 368 "version": "v1.3.3", 369 "version_normalized": "1.3.3.0", 370 "source": { 371 "type": "git", 372 "url": "https://github.com/thecodingmachine/safe.git", 373 "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc" 374 }, 375 "dist": { 376 "type": "zip", 377 "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/a8ab0876305a4cdaef31b2350fcb9811b5608dbc", 378 "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc", 379 "shasum": "" 380 }, 381 "require": { 382 "php": ">=7.2" 383 }, 384 "require-dev": { 385 "phpstan/phpstan": "^0.12", 386 "squizlabs/php_codesniffer": "^3.2", 387 "thecodingmachine/phpstan-strict-rules": "^0.12" 388 }, 389 "time": "2020-10-28T17:51:34+00:00", 372 "name": "symfony/deprecation-contracts", 373 "version": "v3.7.1", 374 "version_normalized": "3.7.1.0", 375 "source": { 376 "type": "git", 377 "url": "https://github.com/symfony/deprecation-contracts.git", 378 "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" 379 }, 380 "dist": { 381 "type": "zip", 382 "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", 383 "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", 384 "shasum": "" 385 }, 386 "require": { 387 "php": ">=8.1" 388 }, 389 "time": "2026-06-05T06:23:12+00:00", 390 390 "type": "library", 391 391 "extra": { 392 "thanks": { 393 "url": "https://github.com/symfony/contracts", 394 "name": "symfony/contracts" 395 }, 392 396 "branch-alias": { 393 "dev-master": "0.1-dev" 394 } 395 }, 396 "installation-source": "dist", 397 "autoload": { 398 "psr-4": { 399 "Safe\\": [ 400 "lib/", 401 "deprecated/", 402 "generated/" 403 ] 404 }, 397 "dev-main": "3.7-dev" 398 } 399 }, 400 "installation-source": "dist", 401 "autoload": { 405 402 "files": [ 406 "deprecated/apc.php", 407 "deprecated/libevent.php", 408 "deprecated/mssql.php", 409 "deprecated/stats.php", 410 "lib/special_cases.php", 411 "generated/apache.php", 412 "generated/apcu.php", 413 "generated/array.php", 414 "generated/bzip2.php", 415 "generated/calendar.php", 416 "generated/classobj.php", 417 "generated/com.php", 418 "generated/cubrid.php", 419 "generated/curl.php", 420 "generated/datetime.php", 421 "generated/dir.php", 422 "generated/eio.php", 423 "generated/errorfunc.php", 424 "generated/exec.php", 425 "generated/fileinfo.php", 426 "generated/filesystem.php", 427 "generated/filter.php", 428 "generated/fpm.php", 429 "generated/ftp.php", 430 "generated/funchand.php", 431 "generated/gmp.php", 432 "generated/gnupg.php", 433 "generated/hash.php", 434 "generated/ibase.php", 435 "generated/ibmDb2.php", 436 "generated/iconv.php", 437 "generated/image.php", 438 "generated/imap.php", 439 "generated/info.php", 440 "generated/ingres-ii.php", 441 "generated/inotify.php", 442 "generated/json.php", 443 "generated/ldap.php", 444 "generated/libxml.php", 445 "generated/lzf.php", 446 "generated/mailparse.php", 447 "generated/mbstring.php", 448 "generated/misc.php", 449 "generated/msql.php", 450 "generated/mysql.php", 451 "generated/mysqli.php", 452 "generated/mysqlndMs.php", 453 "generated/mysqlndQc.php", 454 "generated/network.php", 455 "generated/oci8.php", 456 "generated/opcache.php", 457 "generated/openssl.php", 458 "generated/outcontrol.php", 459 "generated/password.php", 460 "generated/pcntl.php", 461 "generated/pcre.php", 462 "generated/pdf.php", 463 "generated/pgsql.php", 464 "generated/posix.php", 465 "generated/ps.php", 466 "generated/pspell.php", 467 "generated/readline.php", 468 "generated/rpminfo.php", 469 "generated/rrd.php", 470 "generated/sem.php", 471 "generated/session.php", 472 "generated/shmop.php", 473 "generated/simplexml.php", 474 "generated/sockets.php", 475 "generated/sodium.php", 476 "generated/solr.php", 477 "generated/spl.php", 478 "generated/sqlsrv.php", 479 "generated/ssdeep.php", 480 "generated/ssh2.php", 481 "generated/stream.php", 482 "generated/strings.php", 483 "generated/swoole.php", 484 "generated/uodbc.php", 485 "generated/uopz.php", 486 "generated/url.php", 487 "generated/var.php", 488 "generated/xdiff.php", 489 "generated/xml.php", 490 "generated/xmlrpc.php", 491 "generated/yaml.php", 492 "generated/yaz.php", 493 "generated/zip.php", 494 "generated/zlib.php" 403 "function.php" 495 404 ] 496 405 }, … … 499 408 "MIT" 500 409 ], 501 "description": "PHP core functions that throw exceptions instead of returning FALSE on error", 502 "support": { 503 "issues": "https://github.com/thecodingmachine/safe/issues", 504 "source": "https://github.com/thecodingmachine/safe/tree/v1.3.3" 505 }, 506 "install-path": "../thecodingmachine/safe" 410 "authors": [ 411 { 412 "name": "Nicolas Grekas", 413 "email": "p@tchwork.com" 414 }, 415 { 416 "name": "Symfony Community", 417 "homepage": "https://symfony.com/contributors" 418 } 419 ], 420 "description": "A generic function and convention to trigger deprecation notices", 421 "homepage": "https://symfony.com", 422 "support": { 423 "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" 424 }, 425 "funding": [ 426 { 427 "url": "https://symfony.com/sponsor", 428 "type": "custom" 429 }, 430 { 431 "url": "https://github.com/fabpot", 432 "type": "github" 433 }, 434 { 435 "url": "https://github.com/nicolas-grekas", 436 "type": "github" 437 }, 438 { 439 "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 440 "type": "tidelift" 441 } 442 ], 443 "install-path": "../symfony/deprecation-contracts" 507 444 } 508 445 ], -
wp-otp/trunk/vendor/composer/installed.php
r2466054 r3752647 1 <?php return array ( 2 'root' => 3 array ( 4 'pretty_version' => 'trunk', 5 'version' => 'dev-trunk', 6 'aliases' => 7 array ( 1 <?php return array( 2 'root' => array( 3 'name' => 'noplanman/wp-otp', 4 'pretty_version' => 'trunk', 5 'version' => 'dev-trunk', 6 'reference' => null, 7 'type' => 'wordpress-plugin', 8 'install_path' => __DIR__ . '/../../', 9 'aliases' => array(), 10 'dev' => false, 8 11 ), 9 'reference' => NULL, 10 'name' => 'noplanman/wp-otp', 11 ), 12 'versions' => 13 array ( 14 'beberlei/assert' => 15 array ( 16 'pretty_version' => 'v3.3.0', 17 'version' => '3.3.0.0', 18 'aliases' => 19 array ( 20 ), 21 'reference' => '5367e3895976b49704ae671f75bc5f0ba1b986ab', 12 'versions' => array( 13 'chillerlan/php-qrcode' => array( 14 'pretty_version' => '6.0.1', 15 'version' => '6.0.1.0', 16 'reference' => '49006e34bd5328f163e80329e7312f34dceea59b', 17 'type' => 'library', 18 'install_path' => __DIR__ . '/../chillerlan/php-qrcode', 19 'aliases' => array(), 20 'dev_requirement' => false, 21 ), 22 'chillerlan/php-settings-container' => array( 23 'pretty_version' => '3.3.0', 24 'version' => '3.3.0.0', 25 'reference' => 'a0a487cbf5344f721eb504bf0f59bada40c381b7', 26 'type' => 'library', 27 'install_path' => __DIR__ . '/../chillerlan/php-settings-container', 28 'aliases' => array(), 29 'dev_requirement' => false, 30 ), 31 'noplanman/wp-otp' => array( 32 'pretty_version' => 'trunk', 33 'version' => 'dev-trunk', 34 'reference' => null, 35 'type' => 'wordpress-plugin', 36 'install_path' => __DIR__ . '/../../', 37 'aliases' => array(), 38 'dev_requirement' => false, 39 ), 40 'paragonie/constant_time_encoding' => array( 41 'pretty_version' => 'v3.1.3', 42 'version' => '3.1.3.0', 43 'reference' => 'd5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77', 44 'type' => 'library', 45 'install_path' => __DIR__ . '/../paragonie/constant_time_encoding', 46 'aliases' => array(), 47 'dev_requirement' => false, 48 ), 49 'psr/clock' => array( 50 'pretty_version' => '1.0.0', 51 'version' => '1.0.0.0', 52 'reference' => 'e41a24703d4560fd0acb709162f73b8adfc3aa0d', 53 'type' => 'library', 54 'install_path' => __DIR__ . '/../psr/clock', 55 'aliases' => array(), 56 'dev_requirement' => false, 57 ), 58 'spomky-labs/otphp' => array( 59 'pretty_version' => '11.5.0', 60 'version' => '11.5.0.0', 61 'reference' => '877683d6352b80cdc7020fd43a725629c2524435', 62 'type' => 'library', 63 'install_path' => __DIR__ . '/../spomky-labs/otphp', 64 'aliases' => array(), 65 'dev_requirement' => false, 66 ), 67 'symfony/deprecation-contracts' => array( 68 'pretty_version' => 'v3.7.1', 69 'version' => '3.7.1.0', 70 'reference' => 'f3202fa1b5097b0af062dc978b32ecf63404e31d', 71 'type' => 'library', 72 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 73 'aliases' => array(), 74 'dev_requirement' => false, 75 ), 22 76 ), 23 'chillerlan/php-qrcode' =>24 array (25 'pretty_version' => '4.3.0',26 'version' => '4.3.0.0',27 'aliases' =>28 array (29 ),30 'reference' => '4968063fb3baeedb658293f89f9673fbf2499a3e',31 ),32 'chillerlan/php-settings-container' =>33 array (34 'pretty_version' => '2.1.1',35 'version' => '2.1.1.0',36 'aliases' =>37 array (38 ),39 'reference' => '98ccc1b31b31a53bcb563465c4961879b2b93096',40 ),41 'noplanman/wp-otp' =>42 array (43 'pretty_version' => 'trunk',44 'version' => 'dev-trunk',45 'aliases' =>46 array (47 ),48 'reference' => NULL,49 ),50 'paragonie/constant_time_encoding' =>51 array (52 'pretty_version' => 'v2.4.0',53 'version' => '2.4.0.0',54 'aliases' =>55 array (56 ),57 'reference' => 'f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c',58 ),59 'spomky-labs/otphp' =>60 array (61 'pretty_version' => 'v10.0.1',62 'version' => '10.0.1.0',63 'aliases' =>64 array (65 ),66 'reference' => 'f44cce5a9db4b8da410215d992110482c931232f',67 ),68 'thecodingmachine/safe' =>69 array (70 'pretty_version' => 'v1.3.3',71 'version' => '1.3.3.0',72 'aliases' =>73 array (74 ),75 'reference' => 'a8ab0876305a4cdaef31b2350fcb9811b5608dbc',76 ),77 ),78 77 ); -
wp-otp/trunk/vendor/composer/platform_check.php
r2466054 r3752647 5 5 $issues = array(); 6 6 7 if (!(PHP_VERSION_ID >= 70400)) {8 $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.';7 if (!(PHP_VERSION_ID >= 80200)) { 8 $issues[] = 'Your Composer dependencies require a PHP version ">= 8.2.0". You are running ' . PHP_VERSION . '.'; 9 9 } 10 10 … … 20 20 } 21 21 } 22 trigger_error( 23 'Composer detected issues in your platform: ' . implode(' ', $issues), 24 E_USER_ERROR 22 throw new \RuntimeException( 23 'Composer detected issues in your platform: ' . implode(' ', $issues) 25 24 ); 26 25 } -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/LICENSE.txt
r2466054 r3752647 1 1 The MIT License (MIT) 2 2 3 Copyright (c) 2016 - 202 0Paragon Initiative Enterprises3 Copyright (c) 2016 - 2022 Paragon Initiative Enterprises 4 4 5 5 Permission is hereby granted, free of charge, to any person obtaining a copy -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/README.md
r2192307 r3752647 1 1 # Constant-Time Encoding 2 2 3 [](https://travis-ci.org/paragonie/constant_time_encoding) 3 [](https://github.com/paragonie/constant_time_encoding/actions) 4 [](https://github.com/paragonie/constant_time_encoding/actions) 4 5 [](https://packagist.org/packages/paragonie/constant_time_encoding) 5 6 [](https://packagist.org/packages/paragonie/constant_time_encoding) … … 12 13 misses. Further reading on [cache-timing attacks](http://blog.ircmaxell.com/2014/11/its-all-about-time.html). 13 14 14 Our fork offers the following en chancements:15 Our fork offers the following enhancements: 15 16 16 17 * `mbstring.func_overload` resistance … … 23 24 ## PHP Version Requirements 24 25 25 Version 2 of this library should work on **PHP 7** or newer. For PHP 5 26 support, see [the v1.x branch](https://github.com/paragonie/constant_time_encoding/tree/v1.x). 26 Version 3 of this library should work on **PHP 8** or newer. 27 27 28 If you are adding this as a dependency to a project intended to work on both PHP 5 and PHP 7, please set the required version to `^1|^2` instead of just `^1` or `^2`. 28 Version 2 of this library should work on **PHP 7** or newer. See [the v2.x branch](https://github.com/paragonie/constant_time_encoding/tree/v2.x). 29 30 For PHP 5 support, see [the v1.x branch](https://github.com/paragonie/constant_time_encoding/tree/v1.x). 31 32 If you are adding this as a dependency to a project intended to work on PHP 5 through 8.4, please set the required version to `^1|^2|^3`. 29 33 30 34 ## How to Install … … 37 41 38 42 ```php 39 use \ParagonIE\ConstantTime\Encoding;43 use ParagonIE\ConstantTime\Encoding; 40 44 41 45 // possibly (if applicable): … … 64 68 65 69 ```php 66 use \ParagonIE\ConstantTime\Base64;67 use \ParagonIE\ConstantTime\Base32;70 use ParagonIE\ConstantTime\Base64; 71 use ParagonIE\ConstantTime\Base32; 68 72 69 73 $data = random_bytes(32); -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/composer.json
r2466054 r3752647 38 38 }, 39 39 "require": { 40 "php": "^ 7|^8"40 "php": "^8" 41 41 }, 42 42 "require-dev": { 43 "phpunit/phpunit": "^6|^7|^8|^9", 44 "vimeo/psalm": "^1|^2|^3|^4" 43 "infection/infection": "^0", 44 "nikic/php-fuzzer": "^0", 45 "phpunit/phpunit": "^9|^10|^11", 46 "vimeo/psalm": "^4|^5|^6" 45 47 }, 46 48 "autoload": { … … 48 50 "ParagonIE\\ConstantTime\\": "src/" 49 51 } 52 }, 53 "autoload-dev": { 54 "psr-4": { 55 "ParagonIE\\ConstantTime\\Tests\\": "tests/" 56 } 57 }, 58 "scripts": { 59 "mutation-test": "infection" 60 }, 61 "config": { 62 "process-timeout": 0, 63 "allow-plugins": { 64 "infection/extension-installer": true 65 } 50 66 } 51 67 } -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/src/Base32.php
r2466054 r3752647 3 3 namespace ParagonIE\ConstantTime; 4 4 5 use InvalidArgumentException; 6 use Override; 7 use RangeException; 8 use SensitiveParameter; 9 use TypeError; 10 use function pack; 11 use function rtrim; 12 use function strlen; 13 use function substr; 14 use function unpack; 15 5 16 /** 6 * Copyright (c) 2016 - 20 18Paragon Initiative Enterprises.17 * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises. 7 18 * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) 8 19 * … … 41 52 * @return string 42 53 */ 43 public static function decode(string $encodedString, bool $strictPadding = false): string 44 { 54 #[Override] 55 public static function decode( 56 #[SensitiveParameter] 57 string $encodedString, 58 bool $strictPadding = false 59 ): string { 45 60 return static::doDecode($encodedString, false, $strictPadding); 46 61 } … … 53 68 * @return string 54 69 */ 55 public static function decodeUpper(string $src, bool $strictPadding = false): string 56 { 70 public static function decodeUpper( 71 #[SensitiveParameter] 72 string $src, 73 bool $strictPadding = false 74 ): string { 57 75 return static::doDecode($src, true, $strictPadding); 58 76 } … … 61 79 * Encode into Base32 (RFC 4648) 62 80 * 81 * @param string $binString 82 * @return string 83 * @throws TypeError 84 */ 85 #[Override] 86 public static function encode( 87 #[SensitiveParameter] 88 string $binString 89 ): string { 90 return static::doEncode($binString, false, true); 91 } 92 93 /** 94 * Encode into Base32 (RFC 4648) 95 * 63 96 * @param string $src 64 97 * @return string 65 * @throws \TypeError 66 */ 67 public static function encode(string $src): string 68 { 69 return static::doEncode($src, false, true); 70 } 71 /** 72 * Encode into Base32 (RFC 4648) 98 * @throws TypeError 99 * @api 100 */ 101 public static function encodeUnpadded( 102 #[SensitiveParameter] 103 string $src 104 ): string { 105 return static::doEncode($src, false, false); 106 } 107 108 /** 109 * Encode into uppercase Base32 (RFC 4648) 73 110 * 74 111 * @param string $src 75 112 * @return string 76 * @throws \TypeError 77 */ 78 public static function encodeUnpadded(string $src): string 79 { 80 return static::doEncode($src, false, false); 113 * @throws TypeError 114 * @api 115 */ 116 public static function encodeUpper( 117 #[SensitiveParameter] 118 string $src 119 ): string { 120 return static::doEncode($src, true, true); 81 121 } 82 122 … … 86 126 * @param string $src 87 127 * @return string 88 * @throws \TypeError 89 */ 90 public static function encodeUpper(string $src): string 91 { 92 return static::doEncode($src, true, true); 93 } 94 95 /** 96 * Encode into uppercase Base32 (RFC 4648) 97 * 98 * @param string $src 99 * @return string 100 * @throws \TypeError 101 */ 102 public static function encodeUpperUnpadded(string $src): string 103 { 128 * @throws TypeError 129 * @api 130 */ 131 public static function encodeUpperUnpadded( 132 #[SensitiveParameter] 133 string $src 134 ): string { 104 135 return static::doEncode($src, true, false); 105 136 } … … 111 142 * @param int $src 112 143 * @return int 144 * @api 113 145 */ 114 146 protected static function decode5Bits(int $src): int … … 133 165 * @param int $src 134 166 * @return int 167 * @api 135 168 */ 136 169 protected static function decode5BitsUpper(int $src): int … … 153 186 * @param int $src 154 187 * @return string 188 * @api 155 189 */ 156 190 protected static function encode5Bits(int $src): string … … 161 195 $diff -= ((25 - $src) >> 8) & 73; 162 196 163 return \pack('C', $src + $diff);197 return pack('C', $src + $diff); 164 198 } 165 199 … … 172 206 * @param int $src 173 207 * @return string 208 * @api 174 209 */ 175 210 protected static function encode5BitsUpper(int $src): string … … 180 215 $diff -= ((25 - $src) >> 8) & 41; 181 216 182 return \pack('C', $src + $diff); 183 } 184 217 return pack('C', $src + $diff); 218 } 219 220 /** 221 * @param string $encodedString 222 * @param bool $upper 223 * @return string 224 * @api 225 */ 226 public static function decodeNoPadding( 227 #[SensitiveParameter] 228 string $encodedString, 229 bool $upper = false 230 ): string { 231 $srcLen = strlen($encodedString); 232 if ($srcLen === 0) { 233 return ''; 234 } 235 if (($srcLen & 7) === 0) { 236 for ($j = 0; $j < 7 && $j < $srcLen; ++$j) { 237 if ($encodedString[$srcLen - $j - 1] === '=') { 238 throw new InvalidArgumentException( 239 "decodeNoPadding() doesn't tolerate padding" 240 ); 241 } 242 } 243 } 244 return static::doDecode( 245 $encodedString, 246 $upper, 247 true 248 ); 249 } 185 250 186 251 /** … … 191 256 * @param bool $strictPadding 192 257 * @return string 193 * @throws \TypeError 194 * @psalm-suppress RedundantCondition 195 */ 196 protected static function doDecode(string $src, bool $upper = false, bool $strictPadding = false): string 197 { 258 * 259 * @throws TypeError 260 */ 261 protected static function doDecode( 262 #[SensitiveParameter] 263 string $src, 264 bool $upper = false, 265 bool $strictPadding = false 266 ): string { 198 267 // We do this to reduce code duplication: 199 268 $method = $upper … … 202 271 203 272 // Remove padding 204 $srcLen = Binary::safeStrlen($src);273 $srcLen = strlen($src); 205 274 if ($srcLen === 0) { 206 275 return ''; … … 217 286 } 218 287 if (($srcLen & 7) === 1) { 219 throw new \RangeException(288 throw new RangeException( 220 289 'Incorrect padding' 221 290 ); 222 291 } 223 292 } else { 224 $src = \rtrim($src, '=');225 $srcLen = Binary::safeStrlen($src);293 $src = rtrim($src, '='); 294 $srcLen = strlen($src); 226 295 } 227 296 … … 231 300 for ($i = 0; $i + 8 <= $srcLen; $i += 8) { 232 301 /** @var array<int, int> $chunk */ 233 $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 8));302 $chunk = unpack('C*', substr($src, $i, 8)); 234 303 /** @var int $c0 */ 235 304 $c0 = static::$method($chunk[1]); … … 249 318 $c7 = static::$method($chunk[8]); 250 319 251 $dest .= \pack(320 $dest .= pack( 252 321 'CCCCC', 253 322 (($c0 << 3) | ($c1 >> 2) ) & 0xff, … … 262 331 if ($i < $srcLen) { 263 332 /** @var array<int, int> $chunk */ 264 $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));333 $chunk = unpack('C*', substr($src, $i, $srcLen - $i)); 265 334 /** @var int $c0 */ 266 335 $c0 = static::$method($chunk[1]); … … 280 349 $c6 = static::$method($chunk[7]); 281 350 282 $dest .= \pack(351 $dest .= pack( 283 352 'CCCC', 284 353 (($c0 << 3) | ($c1 >> 2) ) & 0xff, … … 288 357 ); 289 358 $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6) >> 8; 359 if ($strictPadding) { 360 $err |= ($c6 << 5) & 0xff; 361 } 290 362 } elseif ($i + 5 < $srcLen) { 291 363 /** @var int $c1 */ … … 300 372 $c5 = static::$method($chunk[6]); 301 373 302 $dest .= \pack(374 $dest .= pack( 303 375 'CCCC', 304 376 (($c0 << 3) | ($c1 >> 2) ) & 0xff, … … 318 390 $c4 = static::$method($chunk[5]); 319 391 320 $dest .= \pack(392 $dest .= pack( 321 393 'CCC', 322 394 (($c0 << 3) | ($c1 >> 2) ) & 0xff, … … 325 397 ); 326 398 $err |= ($c0 | $c1 | $c2 | $c3 | $c4) >> 8; 399 if ($strictPadding) { 400 $err |= ($c4 << 7) & 0xff; 401 } 327 402 } elseif ($i + 3 < $srcLen) { 328 403 /** @var int $c1 */ … … 333 408 $c3 = static::$method($chunk[4]); 334 409 335 $dest .= \pack(410 $dest .= pack( 336 411 'CC', 337 412 (($c0 << 3) | ($c1 >> 2) ) & 0xff, … … 339 414 ); 340 415 $err |= ($c0 | $c1 | $c2 | $c3) >> 8; 416 if ($strictPadding) { 417 $err |= ($c3 << 4) & 0xff; 418 } 341 419 } elseif ($i + 2 < $srcLen) { 342 420 /** @var int $c1 */ … … 345 423 $c2 = static::$method($chunk[3]); 346 424 347 $dest .= \pack(425 $dest .= pack( 348 426 'CC', 349 427 (($c0 << 3) | ($c1 >> 2) ) & 0xff, … … 351 429 ); 352 430 $err |= ($c0 | $c1 | $c2) >> 8; 431 if ($strictPadding) { 432 $err |= ($c2 << 6) & 0xff; 433 } 353 434 } elseif ($i + 1 < $srcLen) { 354 435 /** @var int $c1 */ 355 436 $c1 = static::$method($chunk[2]); 356 437 357 $dest .= \pack(438 $dest .= pack( 358 439 'C', 359 440 (($c0 << 3) | ($c1 >> 2) ) & 0xff 360 441 ); 361 442 $err |= ($c0 | $c1) >> 8; 443 if ($strictPadding) { 444 $err |= ($c1 << 6) & 0xff; 445 } 362 446 } else { 363 $dest .= \pack(447 $dest .= pack( 364 448 'C', 365 449 (($c0 << 3) ) & 0xff … … 368 452 } 369 453 } 370 /** @var bool $check */371 454 $check = ($err === 0); 372 455 if (!$check) { 373 throw new \RangeException(456 throw new RangeException( 374 457 'Base32::doDecode() only expects characters in the correct base32 alphabet' 375 458 ); … … 385 468 * @param bool $pad 386 469 * @return string 387 * @throws \TypeError 388 */ 389 protected static function doEncode(string $src, bool $upper = false, $pad = true): string 390 { 470 * @throws TypeError 471 */ 472 protected static function doEncode( 473 #[SensitiveParameter] 474 string $src, 475 bool $upper = false, 476 bool $pad = true 477 ): string { 391 478 // We do this to reduce code duplication: 392 479 $method = $upper … … 395 482 396 483 $dest = ''; 397 $srcLen = Binary::safeStrlen($src);484 $srcLen = strlen($src); 398 485 399 486 // Main loop (no padding): 400 487 for ($i = 0; $i + 5 <= $srcLen; $i += 5) { 401 488 /** @var array<int, int> $chunk */ 402 $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 5));489 $chunk = unpack('C*', substr($src, $i, 5)); 403 490 $b0 = $chunk[1]; 404 491 $b1 = $chunk[2]; … … 419 506 if ($i < $srcLen) { 420 507 /** @var array<int, int> $chunk */ 421 $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));508 $chunk = unpack('C*', substr($src, $i, $srcLen - $i)); 422 509 $b0 = $chunk[1]; 423 510 if ($i + 3 < $srcLen) { -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/src/Base32Hex.php
r2192307 r3752647 3 3 namespace ParagonIE\ConstantTime; 4 4 5 use Override; 6 use function pack; 7 5 8 /** 6 * Copyright (c) 2016 - 20 18Paragon Initiative Enterprises.9 * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises. 7 10 * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) 8 11 * … … 41 44 * @return int 42 45 */ 46 #[Override] 43 47 protected static function decode5Bits(int $src): int 44 48 { … … 61 65 * @return int 62 66 */ 67 #[Override] 63 68 protected static function decode5BitsUpper(int $src): int 64 69 { … … 81 86 * @return string 82 87 */ 88 #[Override] 83 89 protected static function encode5Bits(int $src): string 84 90 { … … 88 94 $src += ((0x39 - $src) >> 8) & 39; 89 95 90 return \pack('C', $src);96 return pack('C', $src); 91 97 } 92 98 … … 100 106 * @return string 101 107 */ 108 #[Override] 102 109 protected static function encode5BitsUpper(int $src): string 103 110 { … … 107 114 $src += ((0x39 - $src) >> 8) & 7; 108 115 109 return \pack('C', $src);116 return pack('C', $src); 110 117 } 111 118 } -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/src/Base64.php
r2466054 r3752647 3 3 namespace ParagonIE\ConstantTime; 4 4 5 use InvalidArgumentException; 6 use Override; 7 use RangeException; 8 use SensitiveParameter; 9 use SodiumException; 10 use TypeError; 11 use function extension_loaded; 12 use function pack; 13 use function rtrim; 14 use function sodium_base642bin; 15 use function sodium_bin2base64; 16 use function strlen; 17 use function substr; 18 use function unpack; 19 use const SODIUM_BASE64_VARIANT_ORIGINAL; 20 use const SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING; 21 use const SODIUM_BASE64_VARIANT_URLSAFE; 22 use const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING; 23 5 24 /** 6 * Copyright (c) 2016 - 20 18Paragon Initiative Enterprises.25 * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises. 7 26 * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) 8 27 * … … 39 58 * Base64 character set "[A-Z][a-z][0-9]+/" 40 59 * 60 * @param string $binString 61 * @return string 62 * 63 * @throws TypeError 64 */ 65 #[Override] 66 public static function encode( 67 #[SensitiveParameter] 68 string $binString 69 ): string { 70 if (extension_loaded('sodium')) { 71 $variant = match(static::class) { 72 Base64::class => SODIUM_BASE64_VARIANT_ORIGINAL, 73 Base64UrlSafe::class => SODIUM_BASE64_VARIANT_URLSAFE, 74 default => 0, 75 }; 76 if ($variant > 0) { 77 try { 78 return sodium_bin2base64($binString, $variant); 79 } catch (SodiumException $ex) { 80 throw new RangeException($ex->getMessage(), $ex->getCode(), $ex); 81 } 82 } 83 } 84 return static::doEncode($binString, true); 85 } 86 87 /** 88 * Encode into Base64, no = padding 89 * 90 * Base64 character set "[A-Z][a-z][0-9]+/" 91 * 41 92 * @param string $src 42 93 * @return string 43 * @throws \TypeError 44 */ 45 public static function encode(string $src): string 46 { 47 return static::doEncode($src, true); 48 } 49 50 /** 51 * Encode into Base64, no = padding 52 * 53 * Base64 character set "[A-Z][a-z][0-9]+/" 54 * 55 * @param string $src 56 * @return string 57 * @throws \TypeError 58 */ 59 public static function encodeUnpadded(string $src): string 60 { 94 * 95 * @throws TypeError 96 * @api 97 */ 98 public static function encodeUnpadded( 99 #[SensitiveParameter] 100 string $src 101 ): string { 102 if (extension_loaded('sodium')) { 103 $variant = match(static::class) { 104 Base64::class => SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING, 105 Base64UrlSafe::class => SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING, 106 default => 0, 107 }; 108 if ($variant > 0) { 109 try { 110 return sodium_bin2base64($src, $variant); 111 } catch (SodiumException $ex) { 112 throw new RangeException($ex->getMessage(), $ex->getCode(), $ex); 113 } 114 } 115 } 61 116 return static::doEncode($src, false); 62 117 } … … 66 121 * @param bool $pad Include = padding? 67 122 * @return string 68 * @throws \TypeError 69 */ 70 protected static function doEncode(string $src, bool $pad = true): string 71 { 123 * 124 * @throws TypeError 125 */ 126 protected static function doEncode( 127 #[SensitiveParameter] 128 string $src, 129 bool $pad = true 130 ): string { 72 131 $dest = ''; 73 $srcLen = Binary::safeStrlen($src);132 $srcLen = strlen($src); 74 133 // Main loop (no padding): 75 134 for ($i = 0; $i + 3 <= $srcLen; $i += 3) { 76 135 /** @var array<int, int> $chunk */ 77 $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 3));136 $chunk = unpack('C*', substr($src, $i, 3)); 78 137 $b0 = $chunk[1]; 79 138 $b1 = $chunk[2]; … … 89 148 if ($i < $srcLen) { 90 149 /** @var array<int, int> $chunk */ 91 $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));150 $chunk = unpack('C*', substr($src, $i, $srcLen - $i)); 92 151 $b0 = $chunk[1]; 93 152 if ($i + 1 < $srcLen) { … … 120 179 * @param bool $strictPadding 121 180 * @return string 122 * @throws \RangeException 123 * @throws \TypeError 124 * @psalm-suppress RedundantCondition 125 */ 126 public static function decode(string $encodedString, bool $strictPadding = false): string 127 { 181 * 182 * @throws RangeException 183 * @throws TypeError 184 */ 185 #[Override] 186 public static function decode( 187 #[SensitiveParameter] 188 string $encodedString, 189 bool $strictPadding = false 190 ): string { 128 191 // Remove padding 129 $srcLen = Binary::safeStrlen($encodedString);192 $srcLen = strlen($encodedString); 130 193 if ($srcLen === 0) { 131 194 return ''; … … 142 205 } 143 206 if (($srcLen & 3) === 1) { 144 throw new \RangeException(207 throw new RangeException( 145 208 'Incorrect padding' 146 209 ); 147 210 } 148 211 if ($encodedString[$srcLen - 1] === '=') { 149 throw new \RangeException(212 throw new RangeException( 150 213 'Incorrect padding' 151 214 ); 152 215 } 216 if (extension_loaded('sodium')) { 217 $variant = match(static::class) { 218 Base64::class => SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING, 219 Base64UrlSafe::class => SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING, 220 default => 0, 221 }; 222 if ($variant > 0) { 223 try { 224 return sodium_base642bin(substr($encodedString, 0, $srcLen), $variant); 225 } catch (SodiumException $ex) { 226 throw new RangeException($ex->getMessage(), $ex->getCode(), $ex); 227 } 228 } 229 } 153 230 } else { 154 $encodedString = \rtrim($encodedString, '='); 155 $srcLen = Binary::safeStrlen($encodedString); 231 // Just remove all padding. 232 $encodedString = rtrim($encodedString, '='); 233 $srcLen = strlen($encodedString); 156 234 } 157 235 … … 161 239 for ($i = 0; $i + 4 <= $srcLen; $i += 4) { 162 240 /** @var array<int, int> $chunk */ 163 $chunk = \unpack('C*', Binary::safeSubstr($encodedString, $i, 4));241 $chunk = unpack('C*', substr($encodedString, $i, 4)); 164 242 $c0 = static::decode6Bits($chunk[1]); 165 243 $c1 = static::decode6Bits($chunk[2]); … … 167 245 $c3 = static::decode6Bits($chunk[4]); 168 246 169 $dest .= \pack(247 $dest .= pack( 170 248 'CCC', 171 249 ((($c0 << 2) | ($c1 >> 4)) & 0xff), … … 178 256 if ($i < $srcLen) { 179 257 /** @var array<int, int> $chunk */ 180 $chunk = \unpack('C*', Binary::safeSubstr($encodedString, $i, $srcLen - $i));258 $chunk = unpack('C*', substr($encodedString, $i, $srcLen - $i)); 181 259 $c0 = static::decode6Bits($chunk[1]); 182 260 … … 184 262 $c1 = static::decode6Bits($chunk[2]); 185 263 $c2 = static::decode6Bits($chunk[3]); 186 $dest .= \pack(264 $dest .= pack( 187 265 'CC', 188 266 ((($c0 << 2) | ($c1 >> 4)) & 0xff), … … 190 268 ); 191 269 $err |= ($c0 | $c1 | $c2) >> 8; 270 if ($strictPadding) { 271 $err |= ($c2 << 6) & 0xff; 272 } 192 273 } elseif ($i + 1 < $srcLen) { 193 274 $c1 = static::decode6Bits($chunk[2]); 194 $dest .= \pack(275 $dest .= pack( 195 276 'C', 196 277 ((($c0 << 2) | ($c1 >> 4)) & 0xff) 197 278 ); 198 279 $err |= ($c0 | $c1) >> 8; 199 } elseif ($i < $srcLen && $strictPadding) { 280 if ($strictPadding) { 281 $err |= ($c1 << 4) & 0xff; 282 } 283 } elseif ($strictPadding) { 200 284 $err |= 1; 201 285 } 202 286 } 203 /** @var bool $check */204 287 $check = ($err === 0); 205 288 if (!$check) { 206 throw new \RangeException(289 throw new RangeException( 207 290 'Base64::decode() only expects characters in the correct base64 alphabet' 208 291 ); 209 292 } 210 293 return $dest; 294 } 295 296 /** 297 * @param string $encodedString 298 * @return string 299 * @api 300 */ 301 public static function decodeNoPadding( 302 #[SensitiveParameter] 303 string $encodedString 304 ): string { 305 $srcLen = strlen($encodedString); 306 if ($srcLen === 0) { 307 return ''; 308 } 309 if (($srcLen & 3) === 0) { 310 // If $strLen is not zero, and it is divisible by 4, then it's at least 4. 311 if ($encodedString[$srcLen - 1] === '=' || $encodedString[$srcLen - 2] === '=') { 312 throw new InvalidArgumentException( 313 "decodeNoPadding() doesn't tolerate padding" 314 ); 315 } 316 } 317 return static::decode( 318 $encodedString, 319 true 320 ); 211 321 } 212 322 … … 267 377 $diff += ((62 - $src) >> 8) & 3; 268 378 269 return \pack('C', $src + $diff);379 return pack('C', $src + $diff); 270 380 } 271 381 } -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/src/Base64DotSlash.php
r2192307 r3752647 3 3 namespace ParagonIE\ConstantTime; 4 4 5 use Override; 6 5 7 /** 6 * Copyright (c) 2016 - 20 18Paragon Initiative Enterprises.8 * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises. 7 9 * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) 8 10 * … … 45 47 * @return int 46 48 */ 49 #[Override] 47 50 protected static function decode6Bits(int $src): int 48 51 { … … 71 74 * @return string 72 75 */ 76 #[Override] 73 77 protected static function encode6Bits(int $src): string 74 78 { -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php
r2192307 r3752647 3 3 namespace ParagonIE\ConstantTime; 4 4 5 use Override; 6 5 7 /** 6 * Copyright (c) 2016 - 20 18Paragon Initiative Enterprises.8 * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises. 7 9 * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) 8 10 * … … 45 47 * @return int 46 48 */ 49 #[Override] 47 50 protected static function decode6Bits(int $src): int 48 51 { … … 68 71 * @return string 69 72 */ 73 #[Override] 70 74 protected static function encode6Bits(int $src): string 71 75 { -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/src/Base64UrlSafe.php
r2192307 r3752647 3 3 namespace ParagonIE\ConstantTime; 4 4 5 use Override; 6 5 7 /** 6 * Copyright (c) 2016 - 20 18Paragon Initiative Enterprises.8 * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises. 7 9 * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) 8 10 * … … 46 48 * @return int 47 49 */ 50 #[Override] 48 51 protected static function decode6Bits(int $src): int 49 52 { … … 75 78 * @return string 76 79 */ 80 #[Override] 77 81 protected static function encode6Bits(int $src): string 78 82 { -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/src/Binary.php
r2466054 r3752647 3 3 namespace ParagonIE\ConstantTime; 4 4 5 use SensitiveParameter; 6 use TypeError; 7 use function strlen; 8 use function substr; 9 5 10 /** 6 * Copyright (c) 2016 - 20 18Paragon Initiative Enterprises.11 * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises. 7 12 * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) 8 13 * … … 44 49 * @return int 45 50 */ 46 public static function safeStrlen(string $str): int 47 { 48 if (\function_exists('mb_strlen')) { 49 return (int) \mb_strlen($str, '8bit'); 50 } else { 51 return \strlen($str); 52 } 51 public static function safeStrlen( 52 #[SensitiveParameter] 53 string $str 54 ): int { 55 return strlen($str); 53 56 } 54 57 … … 61 64 * @param string $str 62 65 * @param int $start 63 * @param int $length66 * @param ?int $length 64 67 * @return string 65 * @throws \TypeError 68 * 69 * @throws TypeError 66 70 */ 67 71 public static function safeSubstr( 72 #[SensitiveParameter] 68 73 string $str, 69 74 int $start = 0, 70 $length = null75 ?int $length = null 71 76 ): string { 72 77 if ($length === 0) { 73 78 return ''; 74 79 } 75 if (\function_exists('mb_substr')) {76 return \mb_substr($str, $start, $length, '8bit');77 }78 80 // Unlike mb_substr(), substr() doesn't accept NULL for length 79 81 if ($length !== null) { 80 return \substr($str, $start, $length);82 return substr($str, $start, $length); 81 83 } else { 82 return \substr($str, $start);84 return substr($str, $start); 83 85 } 84 86 } -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/src/EncoderInterface.php
r2192307 r3752647 3 3 namespace ParagonIE\ConstantTime; 4 4 5 use SensitiveParameter; 6 5 7 /** 6 * Copyright (c) 2016 - 20 18Paragon Initiative Enterprises.8 * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises. 7 9 * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) 8 10 * … … 39 41 * @return string 40 42 */ 41 public static function encode(string $binString): string; 43 public static function encode( 44 #[SensitiveParameter] 45 string $binString 46 ): string; 42 47 43 48 /** … … 49 54 * @return string (raw binary) 50 55 */ 51 public static function decode(string $encodedString, bool $strictPadding = false): string; 56 public static function decode( 57 #[SensitiveParameter] 58 string $encodedString, 59 bool $strictPadding = false 60 ): string; 52 61 } -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/src/Encoding.php
r2192307 r3752647 3 3 namespace ParagonIE\ConstantTime; 4 4 5 use RangeException; 6 use SensitiveParameter; 7 use TypeError; 8 5 9 /** 6 * Copyright (c) 2016 - 20 18Paragon Initiative Enterprises.10 * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises. 7 11 * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) 8 12 * … … 29 33 * Class Encoding 30 34 * @package ParagonIE\ConstantTime 35 * @api 31 36 */ 32 37 abstract class Encoding … … 37 42 * @param string $str 38 43 * @return string 39 * @throws \TypeError 40 */ 41 public static function base32Encode(string $str): string 42 { 44 * @throws TypeError 45 */ 46 public static function base32Encode( 47 #[SensitiveParameter] 48 string $str 49 ): string { 43 50 return Base32::encode($str); 44 51 } … … 49 56 * @param string $str 50 57 * @return string 51 * @throws \TypeError 52 */ 53 public static function base32EncodeUpper(string $str): string 54 { 58 * @throws TypeError 59 */ 60 public static function base32EncodeUpper( 61 #[SensitiveParameter] 62 string $str 63 ): string { 55 64 return Base32::encodeUpper($str); 56 65 } … … 61 70 * @param string $str 62 71 * @return string 63 * @throws \TypeError 64 */ 65 public static function base32Decode(string $str): string 66 { 72 * @throws TypeError 73 */ 74 public static function base32Decode( 75 #[SensitiveParameter] 76 string $str 77 ): string { 67 78 return Base32::decode($str); 68 79 } … … 73 84 * @param string $str 74 85 * @return string 75 * @throws \TypeError 76 */ 77 public static function base32DecodeUpper(string $str): string 78 { 86 * @throws TypeError 87 */ 88 public static function base32DecodeUpper( 89 #[SensitiveParameter] 90 string $str 91 ): string { 79 92 return Base32::decodeUpper($str); 80 93 } … … 85 98 * @param string $str 86 99 * @return string 87 * @throws \TypeError 88 */ 89 public static function base32HexEncode(string $str): string 90 { 100 * @throws TypeError 101 */ 102 public static function base32HexEncode( 103 #[SensitiveParameter] 104 string $str 105 ): string { 91 106 return Base32Hex::encode($str); 92 107 } … … 97 112 * @param string $str 98 113 * @return string 99 * @throws \TypeError 100 */ 101 public static function base32HexEncodeUpper(string $str): string 102 { 114 * @throws TypeError 115 */ 116 public static function base32HexEncodeUpper( 117 #[SensitiveParameter] 118 string $str 119 ): string { 103 120 return Base32Hex::encodeUpper($str); 104 121 } … … 109 126 * @param string $str 110 127 * @return string 111 * @throws \TypeError 112 */ 113 public static function base32HexDecode(string $str): string 114 { 128 * @throws TypeError 129 */ 130 public static function base32HexDecode( 131 #[SensitiveParameter] 132 string $str 133 ): string { 115 134 return Base32Hex::decode($str); 116 135 } … … 121 140 * @param string $str 122 141 * @return string 123 * @throws \TypeError 124 */ 125 public static function base32HexDecodeUpper(string $str): string 126 { 142 * @throws TypeError 143 */ 144 public static function base32HexDecodeUpper( 145 #[SensitiveParameter] 146 string $str 147 ): string { 127 148 return Base32Hex::decodeUpper($str); 128 149 } … … 133 154 * @param string $str 134 155 * @return string 135 * @throws \TypeError 136 */ 137 public static function base64Encode(string $str): string 138 { 156 * @throws TypeError 157 */ 158 public static function base64Encode( 159 #[SensitiveParameter] 160 string $str 161 ): string { 139 162 return Base64::encode($str); 140 163 } … … 145 168 * @param string $str 146 169 * @return string 147 * @throws \TypeError 148 */ 149 public static function base64Decode(string $str): string 150 { 170 * @throws TypeError 171 */ 172 public static function base64Decode( 173 #[SensitiveParameter] 174 string $str 175 ): string { 151 176 return Base64::decode($str); 152 177 } … … 158 183 * @param string $str 159 184 * @return string 160 * @throws \TypeError 161 */ 162 public static function base64EncodeDotSlash(string $str): string 163 { 185 * @throws TypeError 186 */ 187 public static function base64EncodeDotSlash( 188 #[SensitiveParameter] 189 string $str 190 ): string { 164 191 return Base64DotSlash::encode($str); 165 192 } … … 172 199 * @param string $str 173 200 * @return string 174 * @throws \RangeException 175 * @throws \TypeError 176 */ 177 public static function base64DecodeDotSlash(string $str): string 178 { 201 * @throws RangeException 202 * @throws TypeError 203 */ 204 public static function base64DecodeDotSlash( 205 #[SensitiveParameter] 206 string $str 207 ): string { 179 208 return Base64DotSlash::decode($str); 180 209 } … … 186 215 * @param string $str 187 216 * @return string 188 * @throws \TypeError 189 */ 190 public static function base64EncodeDotSlashOrdered(string $str): string 191 { 217 * @throws TypeError 218 */ 219 public static function base64EncodeDotSlashOrdered( 220 #[SensitiveParameter] 221 string $str 222 ): string { 192 223 return Base64DotSlashOrdered::encode($str); 193 224 } … … 200 231 * @param string $str 201 232 * @return string 202 * @throws \RangeException 203 * @throws \TypeError 204 */ 205 public static function base64DecodeDotSlashOrdered(string $str): string 206 { 233 * @throws RangeException 234 * @throws TypeError 235 */ 236 public static function base64DecodeDotSlashOrdered( 237 #[SensitiveParameter] 238 string $str 239 ): string { 207 240 return Base64DotSlashOrdered::decode($str); 208 241 } … … 214 247 * @param string $bin_string (raw binary) 215 248 * @return string 216 * @throws \TypeError 217 */ 218 public static function hexEncode(string $bin_string): string 219 { 249 * @throws TypeError 250 */ 251 public static function hexEncode( 252 #[SensitiveParameter] 253 string $bin_string 254 ): string { 220 255 return Hex::encode($bin_string); 221 256 } … … 227 262 * @param string $hex_string 228 263 * @return string (raw binary) 229 * @throws \RangeException 230 */ 231 public static function hexDecode(string $hex_string): string 232 { 264 * @throws RangeException 265 */ 266 public static function hexDecode( 267 #[SensitiveParameter] 268 string $hex_string 269 ): string { 233 270 return Hex::decode($hex_string); 234 271 } … … 240 277 * @param string $bin_string (raw binary) 241 278 * @return string 242 * @throws \TypeError 243 */ 244 public static function hexEncodeUpper(string $bin_string): string 245 { 279 * @throws TypeError 280 */ 281 public static function hexEncodeUpper( 282 #[SensitiveParameter] 283 string $bin_string 284 ): string { 246 285 return Hex::encodeUpper($bin_string); 247 286 } … … 254 293 * @return string 255 294 */ 256 public static function hexDecodeUpper(string $bin_string): string 257 { 295 public static function hexDecodeUpper( 296 #[SensitiveParameter] 297 string $bin_string 298 ): string { 258 299 return Hex::decode($bin_string); 259 300 } -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/src/Hex.php
r2466054 r3752647 3 3 namespace ParagonIE\ConstantTime; 4 4 5 use Override; 6 use RangeException; 7 use SensitiveParameter; 8 use SodiumException; 9 use TypeError; 10 use function extension_loaded; 11 use function pack; 12 use function sodium_bin2hex; 13 use function sodium_hex2bin; 14 use function strlen; 15 use function unpack; 16 5 17 /** 6 * Copyright (c) 2016 - 20 18Paragon Initiative Enterprises.18 * Copyright (c) 2016 - 2025 Paragon Initiative Enterprises. 7 19 * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) 8 20 * … … 38 50 * @param string $binString (raw binary) 39 51 * @return string 40 * @throws \TypeError52 * @throws TypeError 41 53 */ 42 public static function encode(string $binString): string 43 { 44 /** @var string $hex */ 54 #[Override] 55 public static function encode( 56 #[SensitiveParameter] 57 string $binString 58 ): string { 59 if (extension_loaded('sodium')) { 60 try { 61 return sodium_bin2hex($binString); 62 } catch (SodiumException $ex) { 63 throw new RangeException($ex->getMessage(), $ex->getCode(), $ex); 64 } 65 } 45 66 $hex = ''; 46 $len = Binary::safeStrlen($binString);67 $len = strlen($binString); 47 68 for ($i = 0; $i < $len; ++$i) { 48 69 /** @var array<int, int> $chunk */ 49 $chunk = \unpack('C', Binary::safeSubstr($binString, $i, 1)); 50 /** @var int $c */ 70 $chunk = unpack('C', $binString[$i]); 51 71 $c = $chunk[1] & 0xf; 52 /** @var int $b */53 72 $b = $chunk[1] >> 4; 54 73 … … 68 87 * @param string $binString (raw binary) 69 88 * @return string 70 * @throws \TypeError89 * @throws TypeError 71 90 */ 72 public static function encodeUpper(string $binString): string 73 { 74 /** @var string $hex */ 91 public static function encodeUpper( 92 #[SensitiveParameter] 93 string $binString 94 ): string { 75 95 $hex = ''; 76 /** @var int $len */ 77 $len = Binary::safeStrlen($binString); 96 $len = strlen($binString); 78 97 79 98 for ($i = 0; $i < $len; ++$i) { 80 99 /** @var array<int, int> $chunk */ 81 $chunk = \unpack('C', Binary::safeSubstr($binString, $i, 2)); 82 /** @var int $c */ 100 $chunk = unpack('C', $binString[$i]); 83 101 $c = $chunk[1] & 0xf; 84 /** @var int $b */85 102 $b = $chunk[1] >> 4; 86 103 … … 101 118 * @param bool $strictPadding 102 119 * @return string (raw binary) 103 * @throws \RangeException120 * @throws RangeException 104 121 */ 105 public static function decode(string $encodedString, bool $strictPadding = false): string 106 { 107 /** @var int $hex_pos */ 122 #[Override] 123 public static function decode( 124 #[SensitiveParameter] 125 string $encodedString, 126 bool $strictPadding = false 127 ): string { 128 if (extension_loaded('sodium') && $strictPadding) { 129 try { 130 return sodium_hex2bin($encodedString); 131 } catch (SodiumException $ex) { 132 throw new RangeException($ex->getMessage(), $ex->getCode(), $ex); 133 } 134 } 108 135 $hex_pos = 0; 109 /** @var string $bin */110 136 $bin = ''; 111 /** @var int $c_acc */112 137 $c_acc = 0; 113 /** @var int $hex_len */ 114 $hex_len = Binary::safeStrlen($encodedString); 115 /** @var int $state */ 138 $hex_len = strlen($encodedString); 116 139 $state = 0; 117 140 if (($hex_len & 1) !== 0) { 118 141 if ($strictPadding) { 119 throw new \RangeException(142 throw new RangeException( 120 143 'Expected an even number of hexadecimal characters' 121 144 ); … … 127 150 128 151 /** @var array<int, int> $chunk */ 129 $chunk = \unpack('C*', $encodedString);152 $chunk = unpack('C*', $encodedString); 130 153 while ($hex_pos < $hex_len) { 131 154 ++$hex_pos; 132 /** @var int $c */133 155 $c = $chunk[$hex_pos]; 134 /** @var int $c_num */135 156 $c_num = $c ^ 48; 136 /** @var int $c_num0 */137 157 $c_num0 = ($c_num - 10) >> 8; 138 /** @var int $c_alpha */139 158 $c_alpha = ($c & ~32) - 55; 140 /** @var int $c_alpha0 */141 159 $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8; 142 160 143 161 if (($c_num0 | $c_alpha0) === 0) { 144 throw new \RangeException(162 throw new RangeException( 145 163 'Expected hexadecimal character' 146 164 ); 147 165 } 148 /** @var int $c_val */149 166 $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0); 150 167 if ($state === 0) { 151 168 $c_acc = $c_val * 16; 152 169 } else { 153 $bin .= \pack('C', $c_acc | $c_val);170 $bin .= pack('C', $c_acc | $c_val); 154 171 } 155 172 $state ^= 1; -
wp-otp/trunk/vendor/paragonie/constant_time_encoding/src/RFC4648.php
r2192307 r3752647 3 3 namespace ParagonIE\ConstantTime; 4 4 5 use SensitiveParameter; 6 use TypeError; 7 5 8 /** 6 * Copyright (c) 2016 - 20 18Paragon Initiative Enterprises.9 * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises. 7 10 * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) 8 11 * … … 32 35 * 33 36 * @package ParagonIE\ConstantTime 37 * @api 34 38 */ 35 39 abstract class RFC4648 … … 42 46 * @param string $str 43 47 * @return string 44 * @throws \TypeError 45 */ 46 public static function base64Encode(string $str): string 47 { 48 * 49 * @throws TypeError 50 */ 51 public static function base64Encode( 52 #[SensitiveParameter] 53 string $str 54 ): string { 48 55 return Base64::encode($str); 49 56 } … … 56 63 * @param string $str 57 64 * @return string 58 * @throws \TypeError 59 */ 60 public static function base64Decode(string $str): string 61 { 65 * 66 * @throws TypeError 67 */ 68 public static function base64Decode( 69 #[SensitiveParameter] 70 string $str 71 ): string { 62 72 return Base64::decode($str, true); 63 73 } … … 70 80 * @param string $str 71 81 * @return string 72 * @throws \TypeError 73 */ 74 public static function base64UrlSafeEncode(string $str): string 75 { 82 * 83 * @throws TypeError 84 */ 85 public static function base64UrlSafeEncode( 86 #[SensitiveParameter] 87 string $str 88 ): string { 76 89 return Base64UrlSafe::encode($str); 77 90 } … … 84 97 * @param string $str 85 98 * @return string 86 * @throws \TypeError 87 */ 88 public static function base64UrlSafeDecode(string $str): string 89 { 99 * 100 * @throws TypeError 101 */ 102 public static function base64UrlSafeDecode( 103 #[SensitiveParameter] 104 string $str 105 ): string { 90 106 return Base64UrlSafe::decode($str, true); 91 107 } … … 98 114 * @param string $str 99 115 * @return string 100 * @throws \TypeError 101 */ 102 public static function base32Encode(string $str): string 103 { 116 * 117 * @throws TypeError 118 */ 119 public static function base32Encode( 120 #[SensitiveParameter] 121 string $str 122 ): string { 104 123 return Base32::encodeUpper($str); 105 124 } … … 112 131 * @param string $str 113 132 * @return string 114 * @throws \TypeError 115 */ 116 public static function base32Decode(string $str): string 117 { 133 * 134 * @throws TypeError 135 */ 136 public static function base32Decode( 137 #[SensitiveParameter] 138 string $str 139 ): string { 118 140 return Base32::decodeUpper($str, true); 119 141 } … … 126 148 * @param string $str 127 149 * @return string 128 * @throws \TypeError 129 */ 130 public static function base32HexEncode(string $str): string 131 { 150 * 151 * @throws TypeError 152 */ 153 public static function base32HexEncode( 154 #[SensitiveParameter] 155 string $str 156 ): string { 132 157 return Base32::encodeUpper($str); 133 158 } … … 140 165 * @param string $str 141 166 * @return string 142 * @throws \TypeError 143 */ 144 public static function base32HexDecode(string $str): string 145 { 167 * 168 * @throws TypeError 169 */ 170 public static function base32HexDecode( 171 #[SensitiveParameter] 172 string $str 173 ): string { 146 174 return Base32::decodeUpper($str, true); 147 175 } … … 154 182 * @param string $str 155 183 * @return string 156 * @throws \TypeError 157 */ 158 public static function base16Encode(string $str): string 159 { 184 * 185 * @throws TypeError 186 */ 187 public static function base16Encode( 188 #[SensitiveParameter] 189 string $str 190 ): string { 160 191 return Hex::encodeUpper($str); 161 192 } … … 169 200 * @return string 170 201 */ 171 public static function base16Decode(string $str): string 172 { 202 public static function base16Decode( 203 #[SensitiveParameter] 204 string $str 205 ): string { 173 206 return Hex::decode($str, true); 174 207 } -
wp-otp/trunk/vendor/spomky-labs/otphp/composer.json
r2331970 r3752647 17 17 ], 18 18 "require": { 19 "php": "^7.2|^8.0", 20 "ext-mbstring": "*", 21 "paragonie/constant_time_encoding": "^2.0", 22 "beberlei/assert": "^3.0", 23 "thecodingmachine/safe": "^0.1.14|^1.0" 19 "php": ">=8.1", 20 "paragonie/constant_time_encoding": "^2.0 || ^3.0", 21 "psr/clock": "^1.0", 22 "symfony/deprecation-contracts": "^3.2" 24 23 }, 25 24 "require-dev": { 26 "phpunit/phpunit": "^8.0", 27 "php-coveralls/php-coveralls": "^2.0", 28 "phpstan/phpstan": "^0.12", 29 "phpstan/phpstan-beberlei-assert": "^0.12", 30 "phpstan/phpstan-deprecation-rules": "^0.12", 31 "phpstan/phpstan-phpunit": "^0.12", 32 "phpstan/phpstan-strict-rules": "^0.12", 33 "thecodingmachine/phpstan-safe-rule": "^1.0" 34 }, 35 "suggest": { 25 "symfony/error-handler": "^6.4|^7.0|^8.0" 36 26 }, 37 27 "autoload": { … … 41 31 "psr-4": { "OTPHP\\Test\\": "tests/" } 42 32 }, 43 "extra": { 44 "branch-alias": { 45 "v10.0": "10.0.x-dev", 46 "v9.0": "9.0.x-dev", 47 "v8.3": "8.3.x-dev" 48 } 33 "config": { 34 "allow-plugins": { 35 "phpstan/extension-installer": true, 36 "infection/extension-installer": true, 37 "composer/package-versions-deprecated": true, 38 "symfony/flex": true, 39 "symfony/runtime": true 40 }, 41 "optimize-autoloader": true, 42 "preferred-install": { 43 "*": "dist" 44 }, 45 "sort-packages": true 49 46 } 50 47 } -
wp-otp/trunk/vendor/spomky-labs/otphp/src/Factory.php
r2331970 r3752647 3 3 declare(strict_types=1); 4 4 5 /*6 * The MIT License (MIT)7 *8 * Copyright (c) 2014-2019 Spomky-Labs9 *10 * This software may be modified and distributed under the terms11 * of the MIT license. See the LICENSE file for details.12 */13 14 5 namespace OTPHP; 15 6 16 use Assert\Assertion;17 use InvalidArgumentException;18 use function Safe\parse_url;19 use function Safe\sprintf;7 use function count; 8 use OTPHP\Exception\InvalidProvisioningUriException; 9 use Psr\Clock\ClockInterface; 10 use function sprintf; 20 11 use Throwable; 21 12 22 13 /** 23 14 * This class is used to load OTP object from a provisioning Uri. 15 * 16 * @readonly 17 * 18 * @see \OTPHP\Test\FactoryTest 24 19 */ 25 20 final class Factory implements FactoryInterface 26 21 { 27 public static function loadFromProvisioningUri(string $uri ): OTPInterface22 public static function loadFromProvisioningUri(string $uri, ?ClockInterface $clock = null): OTPInterface 28 23 { 29 24 try { 30 $parsed_url = parse_url($uri); 25 $parsed_url = Url::fromString($uri); 26 $parsed_url->getScheme() === 'otpauth' || throw new InvalidProvisioningUriException('Invalid scheme.'); 31 27 } catch (Throwable $throwable) { 32 throw new InvalidArgumentException('Not a valid OTP provisioning URI', $throwable->getCode(), $throwable); 28 throw new InvalidProvisioningUriException( 29 'Not a valid OTP provisioning URI', 30 $throwable->getCode(), 31 $throwable 32 ); 33 33 } 34 Assertion::isArray($parsed_url, 'Not a valid OTP provisioning URI'); 35 self::checkData($parsed_url); 34 if ($clock === null) { 35 trigger_deprecation( 36 'spomky-labs/otphp', 37 '11.3.0', 38 'The parameter "$clock" will become mandatory in 12.0.0. Please set a valid PSR Clock implementation instead of "null".' 39 ); 40 $clock = new InternalClock(); 41 } 36 42 37 $otp = self::createOTP($parsed_url); 43 try { 44 $otp = self::createOTP($parsed_url, $clock); 38 45 39 self::populateOTP($otp, $parsed_url); 46 self::populateOTP($otp, $parsed_url); 47 } catch (InvalidProvisioningUriException $exception) { 48 throw $exception; 49 } catch (Throwable $throwable) { 50 throw new InvalidProvisioningUriException( 51 'Not a valid OTP provisioning URI', 52 $throwable->getCode(), 53 $throwable 54 ); 55 } 40 56 41 57 return $otp; 42 58 } 43 59 44 /** 45 * @param array<string, mixed> $data 46 */ 47 private static function populateParameters(OTPInterface &$otp, array $data): void 60 private static function populateParameters(OTPInterface $otp, Url $data): void 48 61 { 49 foreach ($data ['query']as $key => $value) {62 foreach ($data->getQuery() as $key => $value) { 50 63 $otp->setParameter($key, $value); 51 64 } 52 65 } 53 66 54 /** 55 * @param array<string, mixed> $data 56 */ 57 private static function populateOTP(OTPInterface &$otp, array $data): void 67 private static function populateOTP(OTPInterface $otp, Url $data): void 58 68 { 59 69 self::populateParameters($otp, $data); 60 $result = explode(':', rawurldecode( mb_substr($data['path'], 1)));70 $result = explode(':', rawurldecode(substr($data->getPath(), 1))); 61 71 62 if ( 2 > \count($result)) {72 if (count($result) < 2) { 63 73 $otp->setIssuerIncludedAsParameter(false); 64 74 … … 66 76 } 67 77 68 if (null !== $otp->getIssuer()) { 69 Assertion::eq($result[0], $otp->getIssuer(), 'Invalid OTP: invalid issuer in parameter'); 78 $issuerFromLabel = $result[0]; 79 $issuerFromParameter = $otp->getIssuer(); 80 81 if ($issuerFromParameter !== null) { 82 // Issuer parameter takes precedence over issuer in label 83 // According to Google Authenticator spec: "they should be equal" but not required to be 70 84 $otp->setIssuerIncludedAsParameter(true); 85 } else { 86 // No issuer parameter, use the issuer from label 87 $issuerFromLabel !== '' || throw new InvalidProvisioningUriException( 88 'Issuer from label must not be empty.' 89 ); 90 $otp->setIssuer($issuerFromLabel); 71 91 } 72 $otp->setIssuer($result[0]); 92 } 93 94 private static function createOTP(Url $parsed_url, ClockInterface $clock): OTPInterface 95 { 96 switch ($parsed_url->getHost()) { 97 case 'totp': 98 $totp = TOTP::createFromSecret($parsed_url->getSecret(), $clock); 99 $totp->setLabel(self::getLabel($parsed_url->getPath())); 100 101 return $totp; 102 case 'hotp': 103 $hotp = HOTP::createFromSecret($parsed_url->getSecret()); 104 $hotp->setLabel(self::getLabel($parsed_url->getPath())); 105 106 return $hotp; 107 default: 108 throw new InvalidProvisioningUriException(sprintf('Unsupported "%s" OTP type', $parsed_url->getHost())); 109 } 73 110 } 74 111 75 112 /** 76 * @param array<string, mixed> $data 113 * @param non-empty-string $data 114 * @return non-empty-string 77 115 */ 78 private static function checkData(array &$data): void79 {80 foreach (['scheme', 'host', 'path', 'query'] as $key) {81 Assertion::keyExists($data, $key, 'Not a valid OTP provisioning URI');82 }83 Assertion::eq('otpauth', $data['scheme'], 'Not a valid OTP provisioning URI');84 parse_str($data['query'], $data['query']);85 Assertion::keyExists($data['query'], 'secret', 'Not a valid OTP provisioning URI');86 }87 88 /**89 * @param array<string, mixed> $parsed_url90 */91 private static function createOTP(array $parsed_url): OTPInterface92 {93 switch ($parsed_url['host']) {94 case 'totp':95 $totp = TOTP::create($parsed_url['query']['secret']);96 $totp->setLabel(self::getLabel($parsed_url['path']));97 98 return $totp;99 case 'hotp':100 $hotp = HOTP::create($parsed_url['query']['secret']);101 $hotp->setLabel(self::getLabel($parsed_url['path']));102 103 return $hotp;104 default:105 throw new InvalidArgumentException(sprintf('Unsupported "%s" OTP type', $parsed_url['host']));106 }107 }108 109 116 private static function getLabel(string $data): string 110 117 { 111 $result = explode(':', rawurldecode(mb_substr($data, 1))); 118 $result = explode(':', rawurldecode(substr($data, 1))); 119 $label = count($result) === 2 ? $result[1] : $result[0]; 120 $label !== '' || throw new InvalidProvisioningUriException('Label must not be empty.'); 112 121 113 return 2 === \count($result) ? $result[1] : $result[0];122 return $label; 114 123 } 115 124 } -
wp-otp/trunk/vendor/spomky-labs/otphp/src/FactoryInterface.php
r2331970 r3752647 3 3 declare(strict_types=1); 4 4 5 /* 6 * The MIT License (MIT) 7 * 8 * Copyright (c) 2014-2019 Spomky-Labs 9 * 10 * This software may be modified and distributed under the terms 11 * of the MIT license. See the LICENSE file for details. 12 */ 5 namespace OTPHP; 13 6 14 namespace OTPHP;7 use Psr\Clock\ClockInterface; 15 8 16 9 interface FactoryInterface 17 10 { 18 11 /** 19 * This method is the unique public method of the class. 20 * It can load a provisioning Uri and convert it into an OTP object. 12 * This method is the unique public method of the class. It can load a provisioning Uri and convert it into an OTP 13 * object. 14 * 15 * @param non-empty-string $uri 21 16 */ 22 public static function loadFromProvisioningUri(string $uri ): OTPInterface;17 public static function loadFromProvisioningUri(string $uri, ?ClockInterface $clock = null): OTPInterface; 23 18 } -
wp-otp/trunk/vendor/spomky-labs/otphp/src/HOTP.php
r2331970 r3752647 3 3 declare(strict_types=1); 4 4 5 /*6 * The MIT License (MIT)7 *8 * Copyright (c) 2014-2019 Spomky-Labs9 *10 * This software may be modified and distributed under the terms11 * of the MIT license. See the LICENSE file for details.12 */13 14 5 namespace OTPHP; 15 6 16 use Assert\Assertion; 7 use function is_int; 8 use OTPHP\Exception\InvalidParameterException; 17 9 10 /** 11 * Note: This class is not marked as readonly because the verify() method 12 * updates the counter state on successful verification, which is an intentional 13 * side-effect to prevent OTP reuse. 14 * 15 * @see \OTPHP\Test\HOTPTest 16 */ 18 17 final class HOTP extends OTP implements HOTPInterface 19 18 { 20 protected function __construct(?string $secret, int $counter, string $digest, int $digits) 21 { 22 parent::__construct($secret, $digest, $digits); 23 $this->setCounter($counter); 19 private const DEFAULT_WINDOW = 0; 20 21 public static function create( 22 null|string $secret = null, 23 int $counter = self::DEFAULT_COUNTER, 24 string $digest = self::DEFAULT_DIGEST, 25 int $digits = self::DEFAULT_DIGITS, 26 ?int $secretSize = null 27 ): self { 28 $htop = $secret !== null 29 ? self::createFromSecret($secret) 30 : self::generate($secretSize) 31 ; 32 $htop->setCounter($counter); 33 $htop->setDigest($digest); 34 $htop->setDigits($digits); 35 36 return $htop; 24 37 } 25 38 26 public static function create (?string $secret = null, int $counter = 0, string $digest = 'sha1', int $digits = 6): HOTPInterface39 public static function createFromSecret(string $secret): self 27 40 { 28 return new self($secret, $counter, $digest, $digits); 41 $htop = new self($secret); 42 $htop->setCounter(self::DEFAULT_COUNTER); 43 $htop->setDigest(self::DEFAULT_DIGEST); 44 $htop->setDigits(self::DEFAULT_DIGITS); 45 46 return $htop; 29 47 } 30 48 31 protected function setCounter(int $counter): void 49 /** 50 * @param positive-int|null $secretSize 51 */ 52 public static function generate(?int $secretSize = null): self 32 53 { 33 $this->setParameter('counter', $counter);54 return self::createFromSecret(self::generateSecret($secretSize)); 34 55 } 35 56 57 /** 58 * @return 0|positive-int 59 */ 36 60 public function getCounter(): int 37 61 { 38 return $this->getParameter('counter'); 39 } 62 $value = $this->getParameter('counter'); 63 (is_int($value) && $value >= 0) || throw new InvalidParameterException( 64 'Invalid "counter" parameter.', 65 'counter', 66 $value 67 ); 40 68 41 private function updateCounter(int $counter): void 42 { 43 $this->setCounter($counter); 69 return $value; 44 70 } 45 71 46 72 public function getProvisioningUri(): string 47 73 { 48 return $this->generateURI('hotp', ['counter' => $this->getCounter()]); 74 return $this->generateURI('hotp', [ 75 'counter' => $this->getCounter(), 76 ]); 49 77 } 50 78 51 79 /** 52 80 * If the counter is not provided, the OTP is verified at the actual counter. 81 * 82 * @param null|0|positive-int $counter 53 83 */ 54 public function verify(string $otp, ?int $counter = null, ?int $window = null): bool84 public function verify(string $otp, null|int $counter = null, null|int $window = null): bool 55 85 { 56 Assertion::greaterOrEqualThan($counter, 0, 'The counter must be at least 0.'); 86 $counter >= 0 || throw new InvalidParameterException( 87 'The counter must be at least 0.', 88 'counter', 89 $counter 90 ); 57 91 58 if ( null === $counter) {92 if ($counter === null) { 59 93 $counter = $this->getCounter(); 60 94 } elseif ($counter < $this->getCounter()) { … … 65 99 } 66 100 67 p rivate function getWindow(?int $window): int101 public function setCounter(int $counter): void 68 102 { 69 return abs($window ?? 0);103 $this->setParameter('counter', $counter); 70 104 } 71 105 72 private function verifyOtpWithWindow(string $otp, int $counter, ?int $window): bool 106 public function withCounter(int $counter): self 107 { 108 $otp = clone $this; 109 $otp->setParameter('counter', $counter); 110 111 return $otp; 112 } 113 114 /** 115 * @return array<non-empty-string, callable> 116 */ 117 protected function getParameterMap(): array 118 { 119 return [...parent::getParameterMap(), ...[ 120 'counter' => static function (mixed $value): int { 121 $value = (int) $value; 122 $value >= 0 || throw new InvalidParameterException( 123 'Counter must be at least 0.', 124 'counter', 125 $value 126 ); 127 128 return $value; 129 }, 130 ]]; 131 } 132 133 private function updateCounter(int $counter): void 134 { 135 $this->setCounter($counter); 136 } 137 138 /** 139 * @param null|0|positive-int $window 140 */ 141 private function getWindow(null|int $window): int 142 { 143 return abs($window ?? self::DEFAULT_WINDOW); 144 } 145 146 /** 147 * @param non-empty-string $otp 148 * @param 0|positive-int $counter 149 * @param null|0|positive-int $window 150 */ 151 private function verifyOtpWithWindow(string $otp, int $counter, null|int $window): bool 73 152 { 74 153 $window = $this->getWindow($window); … … 84 163 return false; 85 164 } 86 87 /**88 * @return array<string, mixed>89 */90 protected function getParameterMap(): array91 {92 $v = array_merge(93 parent::getParameterMap(),94 ['counter' => function ($value): int {95 Assertion::greaterOrEqualThan((int) $value, 0, 'Counter must be at least 0.');96 97 return (int) $value;98 }]99 );100 101 return $v;102 }103 165 } -
wp-otp/trunk/vendor/spomky-labs/otphp/src/HOTPInterface.php
r2331970 r3752647 2 2 3 3 declare(strict_types=1); 4 5 /*6 * The MIT License (MIT)7 *8 * Copyright (c) 2014-2019 Spomky-Labs9 *10 * This software may be modified and distributed under the terms11 * of the MIT license. See the LICENSE file for details.12 */13 4 14 5 namespace OTPHP; … … 16 7 interface HOTPInterface extends OTPInterface 17 8 { 9 public const DEFAULT_COUNTER = 0; 10 18 11 /** 19 12 * The initial counter (a positive integer). … … 22 15 23 16 /** 24 * Create a new TOTP object.17 * Create a new HOTP object. 25 18 * 26 19 * If the secret is null, a random 64 bytes secret will be generated. 20 * 21 * @param null|non-empty-string $secret 22 * @param 0|positive-int $counter 23 * @param non-empty-string $digest 24 * @param positive-int $digits 25 * 26 * @deprecated Deprecated since v11.1, use ::createFromSecret or ::generate instead 27 27 */ 28 public static function create(?string $secret = null, int $counter = 0, string $digest = 'sha1', int $digits = 6): self; 28 public static function create( 29 null|string $secret = null, 30 int $counter = 0, 31 string $digest = 'sha1', 32 int $digits = 6 33 ): self; 34 35 /** 36 * @deprecated Deprecated since v11.4, use {@see self::withCounter()} instead 37 */ 38 public function setCounter(int $counter): void; 39 40 public function withCounter(int $counter): self; 29 41 } -
wp-otp/trunk/vendor/spomky-labs/otphp/src/OTP.php
r2331970 r3752647 3 3 declare(strict_types=1); 4 4 5 /* 6 * The MIT License (MIT) 7 * 8 * Copyright (c) 2014-2019 Spomky-Labs 9 * 10 * This software may be modified and distributed under the terms 11 * of the MIT license. See the LICENSE file for details. 5 namespace OTPHP; 6 7 use function array_key_exists; 8 use function chr; 9 use function count; 10 use Exception; 11 use function in_array; 12 use function is_int; 13 use function is_string; 14 use OTPHP\Exception\InvalidLabelException; 15 use OTPHP\Exception\InvalidParameterException; 16 use OTPHP\Exception\ParameterNotFoundException; 17 use OTPHP\Exception\SecretDecodingException; 18 use ParagonIE\ConstantTime\Base32; 19 use function sprintf; 20 use const STR_PAD_LEFT; 21 use function strlen; 22 23 /** 24 * @readonly 12 25 */ 13 14 namespace OTPHP;15 16 use Assert\Assertion;17 use ParagonIE\ConstantTime\Base32;18 use RuntimeException;19 use function Safe\ksort;20 use function Safe\sprintf;21 22 26 abstract class OTP implements OTPInterface 23 27 { 24 use ParameterTrait; 25 26 protected function __construct(?string $secret, string $digest, int $digits) 28 private const DEFAULT_SECRET_SIZE = 64; 29 30 /** 31 * Minimum digest size, in bytes, required by the RFC 4226 dynamic truncation. 32 * 33 * The truncation reads four bytes starting at an offset taken from the low 34 * nibble of the last digest byte, i.e. an offset in the range [0, 15]. It 35 * therefore reads up to index "offset + 3" = 18 and needs at least 19 bytes. 36 * A shorter digest (e.g. MD5, 16 bytes) makes the truncation read past the 37 * end of the hash, collapsing the output to a small, secret-independent set 38 * of values. Such algorithms are also outside RFC 4226/6238 and are not 39 * interoperable with authenticator apps. See {@see self::generateOTP()}. 40 */ 41 private const MINIMUM_DIGEST_SIZE = 19; 42 43 /** 44 * @var array<non-empty-string, mixed> 45 */ 46 private array $parameters = []; 47 48 /** 49 * @var non-empty-string|null 50 */ 51 private null|string $issuer = null; 52 53 /** 54 * @var non-empty-string|null 55 */ 56 private null|string $label = null; 57 58 private bool $issuer_included_as_parameter = true; 59 60 /** 61 * @param non-empty-string $secret 62 */ 63 protected function __construct(string $secret) 27 64 { 28 65 $this->setSecret($secret); 29 $this->setDigest($digest);30 $this->setDigits($digits);31 66 } 32 67 … … 39 74 40 75 /** 76 * @param 0|positive-int $input 77 */ 78 public function at(int $input): string 79 { 80 return $this->generateOTP($input); 81 } 82 83 /** 84 * @return array<non-empty-string, mixed> 85 */ 86 public function getParameters(): array 87 { 88 $parameters = $this->parameters; 89 90 if ($this->getIssuer() !== null && $this->isIssuerIncludedAsParameter() === true) { 91 $parameters['issuer'] = $this->getIssuer(); 92 } 93 94 return $parameters; 95 } 96 97 public function getSecret(): string 98 { 99 $value = $this->getParameter('secret'); 100 (is_string($value) && $value !== '') || throw new InvalidParameterException( 101 'Invalid "secret" parameter.', 102 'secret', 103 $value 104 ); 105 106 return $value; 107 } 108 109 public function getLabel(): null|string 110 { 111 return $this->label; 112 } 113 114 public function setLabel(string $label): void 115 { 116 $this->setParameter('label', $label); 117 } 118 119 public function withLabel(string $label): static 120 { 121 $otp = clone $this; 122 $otp->setParameter('label', $label); 123 124 return $otp; 125 } 126 127 public function getIssuer(): null|string 128 { 129 return $this->issuer; 130 } 131 132 public function setIssuer(string $issuer): void 133 { 134 $this->setParameter('issuer', $issuer); 135 } 136 137 public function withIssuer(string $issuer): static 138 { 139 $otp = clone $this; 140 $otp->setParameter('issuer', $issuer); 141 142 return $otp; 143 } 144 145 public function isIssuerIncludedAsParameter(): bool 146 { 147 return $this->issuer_included_as_parameter; 148 } 149 150 public function setIssuerIncludedAsParameter(bool $issuer_included_as_parameter): void 151 { 152 $this->issuer_included_as_parameter = $issuer_included_as_parameter; 153 } 154 155 public function withIssuerIncludedAsParameter(bool $issuer_included_as_parameter): static 156 { 157 $otp = clone $this; 158 $otp->issuer_included_as_parameter = $issuer_included_as_parameter; 159 160 return $otp; 161 } 162 163 public function getDigits(): int 164 { 165 $value = $this->getParameter('digits'); 166 (is_int($value) && $value >= 1 && $value <= self::MAX_DIGITS) || throw new InvalidParameterException( 167 'Invalid "digits" parameter.', 168 'digits', 169 $value 170 ); 171 172 return $value; 173 } 174 175 public function getDigest(): string 176 { 177 $value = $this->getParameter('algorithm'); 178 (is_string($value) && $value !== '') || throw new InvalidParameterException( 179 'Invalid "algorithm" parameter.', 180 'algorithm', 181 $value 182 ); 183 184 return $value; 185 } 186 187 public function hasParameter(string $parameter): bool 188 { 189 return array_key_exists($parameter, $this->parameters); 190 } 191 192 public function getParameter(string $parameter): mixed 193 { 194 if ($this->hasParameter($parameter)) { 195 return $this->getParameters()[$parameter]; 196 } 197 198 throw new ParameterNotFoundException(sprintf('Parameter "%s" does not exist', $parameter), $parameter); 199 } 200 201 public function setParameter(string $parameter, mixed $value): void 202 { 203 $map = $this->getParameterMap(); 204 205 if (array_key_exists($parameter, $map) === true) { 206 $callback = $map[$parameter]; 207 $value = $callback($value); 208 } 209 210 if (in_array($parameter, ['label', 'issuer'], true)) { 211 $this->{$parameter} = $value; 212 } else { 213 $this->parameters[$parameter] = $value; 214 } 215 } 216 217 public function withParameter(string $parameter, mixed $value): static 218 { 219 $otp = clone $this; 220 $otp->setParameter($parameter, $value); 221 222 return $otp; 223 } 224 225 public function setSecret(string $secret): void 226 { 227 $this->setParameter('secret', $secret); 228 } 229 230 public function withSecret(string $secret): static 231 { 232 $otp = clone $this; 233 $otp->setParameter('secret', $secret); 234 235 return $otp; 236 } 237 238 public function setDigits(int $digits): void 239 { 240 $this->setParameter('digits', $digits); 241 } 242 243 public function withDigits(int $digits): static 244 { 245 $otp = clone $this; 246 $otp->setParameter('digits', $digits); 247 248 return $otp; 249 } 250 251 public function setDigest(string $digest): void 252 { 253 $this->setParameter('algorithm', $digest); 254 } 255 256 public function withDigest(string $digest): static 257 { 258 $otp = clone $this; 259 $otp->setParameter('algorithm', $digest); 260 261 return $otp; 262 } 263 264 /** 265 * @param positive-int|null $secretSize 266 * 267 * @return non-empty-string 268 */ 269 final protected static function generateSecret(?int $secretSize = null): string 270 { 271 $secretSize ??= self::DEFAULT_SECRET_SIZE; 272 $secretSize > 0 || throw new InvalidParameterException( 273 'Secret size must be at least 1.', 274 'secretSize', 275 $secretSize 276 ); 277 278 return Base32::encodeUpper(random_bytes($secretSize)); 279 } 280 281 /** 41 282 * The OTP at the specified input. 283 * 284 * @param 0|positive-int $input 285 * 286 * @return non-empty-string 42 287 */ 43 288 protected function generateOTP(int $input): string 44 289 { 45 290 $hash = hash_hmac($this->getDigest(), $this->intToByteString($input), $this->getDecodedSecret(), true); 46 47 $hmac = array_values(unpack('C*', $hash)); 48 49 $offset = ($hmac[\count($hmac) - 1] & 0xF); 50 $code = ($hmac[$offset + 0] & 0x7F) << 24 | ($hmac[$offset + 1] & 0xFF) << 16 | ($hmac[$offset + 2] & 0xFF) << 8 | ($hmac[$offset + 3] & 0xFF); 291 $unpacked = unpack('C*', $hash); 292 $unpacked !== false || throw new InvalidParameterException('Invalid data.', 'hash', $hash); 293 /** @var list<int> $hmac */ 294 $hmac = array_values($unpacked); 295 296 $offset = ($hmac[count($hmac) - 1] & 0xF); 297 $code = ($hmac[$offset] & 0x7F) << 24 | ($hmac[$offset + 1] & 0xFF) << 16 | ($hmac[$offset + 2] & 0xFF) << 8 | ($hmac[$offset + 3] & 0xFF); 51 298 $otp = $code % (10 ** $this->getDigits()); 52 299 … … 54 301 } 55 302 56 public function at(int $timestamp): string 57 { 58 return $this->generateOTP($timestamp); 59 } 60 61 /** 62 * @param array<string, mixed> $options 303 /** 304 * @param array<non-empty-string, mixed> $options 63 305 */ 64 306 protected function filterOptions(array &$options): void 65 307 { 66 foreach (['algorithm' => 'sha1', 'period' => 30, 'digits' => 6] as $key => $default) { 308 foreach ([ 309 'algorithm' => 'sha1', 310 'period' => 30, 311 'digits' => 6, 312 ] as $key => $default) { 67 313 if (isset($options[$key]) && $default === $options[$key]) { 68 314 unset($options[$key]); … … 74 320 75 321 /** 76 * @param array<string, mixed> $options 322 * @param non-empty-string $type 323 * @param array<non-empty-string, mixed> $options 324 * 325 * @return non-empty-string 77 326 */ 78 327 protected function generateURI(string $type, array $options): string 79 328 { 329 $options = [...$options, ...$this->getParameters()]; 330 $this->filterOptions($options); 331 $params = str_replace(['+', '%7E'], ['%20', '~'], http_build_query($options, '', '&')); 332 333 return sprintf('otpauth://%s/%s?%s', $type, rawurlencode($this->buildProvisioningUriLabel()), $params); 334 } 335 336 /** 337 * @param non-empty-string $safe 338 * @param non-empty-string $user 339 */ 340 protected function compareOTP(string $safe, string $user): bool 341 { 342 return hash_equals($safe, $user); 343 } 344 345 /** 346 * @return array<non-empty-string, callable> 347 */ 348 protected function getParameterMap(): array 349 { 350 return [ 351 'label' => function (string $value): string { 352 $value !== '' || throw new InvalidLabelException('Label must not be empty.', 'label', $value); 353 $this->validateLabel($value); 354 355 return $value; 356 }, 357 'secret' => static fn (string $value): string => strtoupper(trim($value, '=')), 358 'algorithm' => static function (string $value): string { 359 $value = strtolower($value); 360 in_array($value, hash_hmac_algos(), true) || throw new InvalidParameterException( 361 sprintf('The "%s" digest is not supported.', $value), 362 'algorithm', 363 $value 364 ); 365 $size = strlen(hash($value, '', true)); 366 $size >= self::MINIMUM_DIGEST_SIZE || throw new InvalidParameterException( 367 sprintf( 368 'The "%s" digest produces a %d-byte hash which is too short for the RFC 4226 dynamic truncation; at least %d bytes are required.', 369 $value, 370 $size, 371 self::MINIMUM_DIGEST_SIZE 372 ), 373 'algorithm', 374 $value 375 ); 376 377 return $value; 378 }, 379 'digits' => static function ($value): int { 380 $value = (int) $value; 381 ($value >= 1 && $value <= self::MAX_DIGITS) || throw new InvalidParameterException( 382 sprintf('Digits must be between 1 and %d.', self::MAX_DIGITS), 383 'digits', 384 $value 385 ); 386 387 return $value; 388 }, 389 'issuer' => function (string $value): string { 390 $value !== '' || throw new InvalidLabelException('Issuer must not be empty.', 'issuer', $value); 391 $this->hasColon($value) === false || throw new InvalidLabelException( 392 'Issuer must not contain a colon.', 393 'issuer', 394 $value 395 ); 396 397 return $value; 398 }, 399 ]; 400 } 401 402 /** 403 * @return non-empty-string 404 */ 405 private function getDecodedSecret(): string 406 { 407 try { 408 $decoded = Base32::decodeUpper($this->getSecret()); 409 } catch (Exception) { 410 throw new SecretDecodingException('Unable to decode the secret. Is it correctly base32 encoded?'); 411 } 412 $decoded !== '' || throw new SecretDecodingException('The decoded secret must not be empty.'); 413 414 return $decoded; 415 } 416 417 private function intToByteString(int $int): string 418 { 419 $result = []; 420 while ($int !== 0) { 421 $result[] = chr($int & 0xFF); 422 $int >>= 8; 423 } 424 425 return str_pad(implode('', array_reverse($result)), 8, "\000", STR_PAD_LEFT); 426 } 427 428 /** 429 * @return non-empty-string 430 */ 431 private function buildProvisioningUriLabel(): string 432 { 433 $issuer = $this->getIssuer(); 80 434 $label = $this->getLabel(); 81 Assertion::string($label, 'The label is not set.'); 82 Assertion::false($this->hasColon($label), 'Label must not contain a colon.'); 83 $options = array_merge($options, $this->getParameters()); 84 $this->filterOptions($options); 85 $params = str_replace(['+', '%7E'], ['%20', '~'], http_build_query($options)); 86 87 return sprintf('otpauth://%s/%s?%s', $type, rawurlencode((null !== $this->getIssuer() ? $this->getIssuer().':' : '').$label), $params); 88 } 89 90 private function getDecodedSecret(): string 91 { 92 try { 93 return Base32::decodeUpper($this->getSecret()); 94 } catch (\Exception $e) { 95 throw new RuntimeException('Unable to decode the secret. Is it correctly base32 encoded?'); 96 } 97 } 98 99 private function intToByteString(int $int): string 100 { 101 $result = []; 102 while (0 !== $int) { 103 $result[] = \chr($int & 0xFF); 104 $int >>= 8; 105 } 106 107 return str_pad(implode(array_reverse($result)), 8, "\000", STR_PAD_LEFT); 108 } 109 110 protected function compareOTP(string $safe, string $user): bool 111 { 112 return hash_equals($safe, $user); 435 436 return match (true) { 437 $issuer === null && $label === null => throw new InvalidLabelException( 438 'The label is not set. Either label or issuer must be set.', 439 'label' 440 ), 441 $label !== null && $this->hasColon($label) => throw new InvalidLabelException( 442 'Label must not contain a colon.', 443 'label', 444 $label 445 ), 446 $issuer !== null && $label !== null => $issuer . ':' . $label, 447 $issuer !== null => $issuer, 448 default => $label, 449 }; 450 } 451 452 /** 453 * Validates a label according to Google Authenticator spec: 454 * label = accountname / issuer (":" / "%3A") *"%20" accountname 455 * Neither issuer nor account name may themselves contain a colon. 456 * 457 * Valid examples: 458 * - alice@gmail.com 459 * - Provider1:Alice%20Smith 460 * - Big%20Corporation%3A%20alice%40bigco.com 461 * 462 * @param non-empty-string $value 463 */ 464 private function validateLabel(string $value): void 465 { 466 // Check for colon separators (literal or URL-encoded) 467 $hasLiteralColon = str_contains($value, ':'); 468 $hasEncodedColon = str_contains($value, '%3A') || str_contains($value, '%3a'); 469 470 if (! $hasLiteralColon && ! $hasEncodedColon) { 471 // Simple label (account name only) - no colons allowed anywhere 472 return; 473 } 474 475 // Label contains a separator - validate issuer:account format 476 // Split by literal or encoded colon 477 $parts = match (true) { 478 $hasLiteralColon => explode(':', $value, 2), 479 default => preg_split('/%3[Aa]/', $value, 2), 480 }; 481 482 if ($parts === false || count($parts) !== 2) { 483 throw new InvalidLabelException('Label must not contain a colon.', 'label', $value); 484 } 485 486 [$issuerPart, $accountPart] = $parts; 487 488 // Remove leading %20 (spaces) from account part per spec: *"%20" accountname 489 $accountPart = ltrim($accountPart, '%20'); 490 491 // Validate that neither part contains additional colons 492 if ($this->hasColon($issuerPart) || $this->hasColon($accountPart)) { 493 throw new InvalidLabelException( 494 'Neither issuer nor account name in label may contain a colon.', 495 'label', 496 $value 497 ); 498 } 499 } 500 501 /** 502 * @param non-empty-string $value 503 */ 504 private function hasColon(string $value): bool 505 { 506 $colons = [':', '%3A', '%3a']; 507 foreach ($colons as $colon) { 508 if (str_contains($value, $colon)) { 509 return true; 510 } 511 } 512 513 return false; 113 514 } 114 515 } -
wp-otp/trunk/vendor/spomky-labs/otphp/src/OTPInterface.php
r2331970 r3752647 2 2 3 3 declare(strict_types=1); 4 5 /*6 * The MIT License (MIT)7 *8 * Copyright (c) 2014-2019 Spomky-Labs9 *10 * This software may be modified and distributed under the terms11 * of the MIT license. See the LICENSE file for details.12 */13 4 14 5 namespace OTPHP; … … 16 7 interface OTPInterface 17 8 { 18 /** 19 * @return string Return the OTP at the specified timestamp 20 */ 21 public function at(int $timestamp): string; 9 public const DEFAULT_DIGITS = 6; 22 10 23 11 /** 24 * Verify that the OTP is valid with the specified input. 25 * If no input is provided, the input is set to a default value or false is returned. 12 * Upper bound for the "digits" parameter. The RFC 4226 dynamic truncation 13 * yields a 31-bit value (max 2 147 483 647, i.e. 10 digits); above this 14 * bound the extra digits carry no entropy and "10 ** digits" overflows 15 * PHP's integer range, leading to a DivisionByZeroError during generation. 26 16 */ 27 public function verify(string $otp, ?int $input = null, ?int $window = null): bool; 17 public const MAX_DIGITS = 10; 18 19 public const DEFAULT_DIGEST = 'sha1'; 28 20 29 21 /** 30 * @return string The secret of the OTP 22 * Create a OTP object from an existing secret. 23 * 24 * @param non-empty-string $secret 25 */ 26 public static function createFromSecret(string $secret): self; 27 28 /** 29 * Create a new OTP object. A random 64 bytes secret will be generated. 30 */ 31 public static function generate(): self; 32 33 /** 34 * @param non-empty-string $secret 35 * 36 * @deprecated Deprecated since v11.4, use {@see self::withSecret()} instead 37 */ 38 public function setSecret(string $secret): void; 39 40 /** 41 * @param non-empty-string $secret 42 */ 43 public function withSecret(string $secret): self; 44 45 /** 46 * @deprecated Deprecated since v11.4, use {@see self::withDigits()} instead 47 */ 48 public function setDigits(int $digits): void; 49 50 public function withDigits(int $digits): self; 51 52 /** 53 * @param non-empty-string $digest 54 * 55 * @deprecated Deprecated since v11.4, use {@see self::withDigest()} instead 56 */ 57 public function setDigest(string $digest): void; 58 59 /** 60 * @param non-empty-string $digest 61 */ 62 public function withDigest(string $digest): self; 63 64 /** 65 * Generate the OTP at the specified input. 66 * 67 * @param 0|positive-int $input 68 * 69 * @return non-empty-string Return the OTP at the specified timestamp 70 */ 71 public function at(int $input): string; 72 73 /** 74 * Verify that the OTP is valid with the specified input. If no input is provided, the input is set to a default 75 * value or false is returned. 76 * 77 * @param non-empty-string $otp 78 * @param null|0|positive-int $input 79 * @param null|0|positive-int $window 80 */ 81 public function verify(string $otp, null|int $input = null, null|int $window = null): bool; 82 83 /** 84 * @return non-empty-string The secret of the OTP 31 85 */ 32 86 public function getSecret(): string; 33 87 34 88 /** 35 * @param string $label The label of the OTP 89 * @param non-empty-string $label The label of the OTP 90 * 91 * @deprecated Deprecated since v11.4, use {@see self::withLabel()} instead 36 92 */ 37 93 public function setLabel(string $label): void; 38 94 39 95 /** 40 * @ return string|null The label of the OTP96 * @param non-empty-string $label The label of the OTP 41 97 */ 42 public function getLabel(): ?string;98 public function withLabel(string $label): self; 43 99 44 100 /** 45 * @return string|null The issuer 101 * @return non-empty-string|null The label of the OTP 102 */ 103 public function getLabel(): null|string; 104 105 /** 106 * @return non-empty-string|null The issuer 46 107 */ 47 108 public function getIssuer(): ?string; 48 109 110 /** 111 * @param non-empty-string $issuer 112 * 113 * @deprecated Deprecated since v11.4, use {@see self::withIssuer()} instead 114 */ 49 115 public function setIssuer(string $issuer): void; 116 117 /** 118 * @param non-empty-string $issuer 119 */ 120 public function withIssuer(string $issuer): self; 50 121 51 122 /** … … 54 125 public function isIssuerIncludedAsParameter(): bool; 55 126 127 /** 128 * @deprecated Deprecated since v11.4, use {@see self::withIssuerIncludedAsParameter()} instead 129 */ 56 130 public function setIssuerIncludedAsParameter(bool $issuer_included_as_parameter): void; 57 131 132 public function withIssuerIncludedAsParameter(bool $issuer_included_as_parameter): self; 133 58 134 /** 59 * @return int Number of digits in the OTP135 * @return positive-int Number of digits in the OTP 60 136 */ 61 137 public function getDigits(): int; 62 138 63 139 /** 64 * @return string Digest algorithm used to calculate the OTP. Possible values are 'md5', 'sha1', 'sha256' and 'sha512'140 * @return non-empty-string Digest algorithm used to calculate the OTP. Spec-compliant, interoperable values are 'sha1', 'sha256' and 'sha512'. Any digest shorter than 19 bytes (e.g. 'md5') is rejected as it cannot satisfy the RFC 4226 dynamic truncation. 65 141 */ 66 142 public function getDigest(): string; 67 143 68 144 /** 69 * @ return mixed|null145 * @param non-empty-string $parameter 70 146 */ 71 public function getParameter(string $parameter) ;147 public function getParameter(string $parameter): mixed; 72 148 149 /** 150 * @param non-empty-string $parameter 151 */ 73 152 public function hasParameter(string $parameter): bool; 74 153 75 154 /** 76 * @return array< string, mixed>155 * @return array<non-empty-string, mixed> 77 156 */ 78 157 public function getParameters(): array; 79 158 80 159 /** 81 * @param mixed|null $value 160 * @param non-empty-string $parameter 161 * 162 * @deprecated Deprecated since v11.4, use {@see self::withParameter()} instead 82 163 */ 83 public function setParameter(string $parameter, $value): void; 164 public function setParameter(string $parameter, mixed $value): void; 165 166 /** 167 * @param non-empty-string $parameter 168 */ 169 public function withParameter(string $parameter, mixed $value): self; 84 170 85 171 /** 86 172 * Get the provisioning URI. 173 * 174 * @return non-empty-string 87 175 */ 88 176 public function getProvisioningUri(): string; … … 91 179 * Get the provisioning URI. 92 180 * 93 * @param string $uri The Uri of the QRCode generator with all parameters. This Uri MUST contain a placeholder that will be replaced by the method.94 * @param string $placeholder the placeholder to be replaced in the QR Code generator URI181 * @param non-empty-string $uri The Uri of the QRCode generator with all parameters. This Uri MUST contain a placeholder that will be replaced by the method. 182 * @param non-empty-string $placeholder the placeholder to be replaced in the QR Code generator URI 95 183 */ 96 184 public function getQrCodeUri(string $uri, string $placeholder): string; -
wp-otp/trunk/vendor/spomky-labs/otphp/src/TOTP.php
r2331970 r3752647 3 3 declare(strict_types=1); 4 4 5 /* 6 * The MIT License (MIT) 5 namespace OTPHP; 6 7 use function is_int; 8 use OTPHP\Exception\InvalidParameterException; 9 use Psr\Clock\ClockInterface; 10 11 /** 12 * @readonly 7 13 * 8 * Copyright (c) 2014-2019 Spomky-Labs 9 * 10 * This software may be modified and distributed under the terms 11 * of the MIT license. See the LICENSE file for details. 14 * @see \OTPHP\Test\TOTPTest 12 15 */ 13 14 namespace OTPHP;15 16 use Assert\Assertion;17 use function Safe\ksort;18 19 16 final class TOTP extends OTP implements TOTPInterface 20 17 { 21 protected function __construct(?string $secret, int $period, string $digest, int $digits, int $epoch = 0) 22 { 23 parent::__construct($secret, $digest, $digits); 24 $this->setPeriod($period); 25 $this->setEpoch($epoch); 26 } 27 28 public static function create(?string $secret = null, int $period = 30, string $digest = 'sha1', int $digits = 6, int $epoch = 0): TOTPInterface 29 { 30 return new self($secret, $period, $digest, $digits, $epoch); 31 } 32 33 protected function setPeriod(int $period): void 18 private readonly ClockInterface $clock; 19 20 public function __construct(string $secret, ?ClockInterface $clock = null) 21 { 22 parent::__construct($secret); 23 if ($clock === null) { 24 trigger_deprecation( 25 'spomky-labs/otphp', 26 '11.3.0', 27 'The parameter "$clock" will become mandatory in 12.0.0. Please set a valid PSR Clock implementation instead of "null".' 28 ); 29 $clock = new InternalClock(); 30 } 31 32 $this->clock = $clock; 33 } 34 35 public static function create( 36 null|string $secret = null, 37 int $period = self::DEFAULT_PERIOD, 38 string $digest = self::DEFAULT_DIGEST, 39 int $digits = self::DEFAULT_DIGITS, 40 int $epoch = self::DEFAULT_EPOCH, 41 ?ClockInterface $clock = null, 42 ?int $secretSize = null 43 ): self { 44 $totp = $secret !== null 45 ? self::createFromSecret($secret, $clock) 46 : self::generate($clock, $secretSize) 47 ; 48 $totp->setPeriod($period); 49 $totp->setDigest($digest); 50 $totp->setDigits($digits); 51 $totp->setEpoch($epoch); 52 53 return $totp; 54 } 55 56 public static function createFromSecret(string $secret, ?ClockInterface $clock = null): self 57 { 58 $totp = new self($secret, $clock); 59 $totp->setPeriod(self::DEFAULT_PERIOD); 60 $totp->setDigest(self::DEFAULT_DIGEST); 61 $totp->setDigits(self::DEFAULT_DIGITS); 62 $totp->setEpoch(self::DEFAULT_EPOCH); 63 64 return $totp; 65 } 66 67 /** 68 * @param positive-int|null $secretSize 69 */ 70 public static function generate(?ClockInterface $clock = null, ?int $secretSize = null): self 71 { 72 return self::createFromSecret(self::generateSecret($secretSize), $clock); 73 } 74 75 public function getPeriod(): int 76 { 77 $value = $this->getParameter('period'); 78 (is_int($value) && $value > 0) || throw new InvalidParameterException( 79 'Invalid "period" parameter.', 80 'period', 81 $value 82 ); 83 84 return $value; 85 } 86 87 public function getEpoch(): int 88 { 89 $value = $this->getParameter('epoch'); 90 (is_int($value) && $value >= 0) || throw new InvalidParameterException( 91 'Invalid "epoch" parameter.', 92 'epoch', 93 $value 94 ); 95 96 return $value; 97 } 98 99 public function expiresIn(): int 100 { 101 $period = $this->getPeriod(); 102 103 return $period - (($this->clock->now()->getTimestamp() - $this->getEpoch()) % $period); 104 } 105 106 /** 107 * The OTP at the specified input. 108 * 109 * @param 0|positive-int $input 110 */ 111 public function at(int $input): string 112 { 113 return $this->generateOTP($this->timecode($input)); 114 } 115 116 public function now(): string 117 { 118 $timestamp = $this->clock->now() 119 ->getTimestamp(); 120 $timestamp >= 0 || throw new InvalidParameterException( 121 'The timestamp must return a positive integer.', 122 'timestamp', 123 $timestamp 124 ); 125 126 return $this->at($timestamp); 127 } 128 129 /** 130 * If no timestamp is provided, the OTP is verified at the actual timestamp. When used, the leeway parameter will 131 * allow time drift. The passed value is in seconds. 132 * 133 * @param 0|positive-int $timestamp 134 * @param null|0|positive-int $leeway 135 */ 136 public function verify(string $otp, null|int $timestamp = null, null|int $leeway = null): bool 137 { 138 $timestamp ??= $this->clock->now() 139 ->getTimestamp(); 140 $timestamp >= 0 || throw new InvalidParameterException( 141 'Timestamp must be at least 0.', 142 'timestamp', 143 $timestamp 144 ); 145 146 if ($leeway === null) { 147 return $this->compareOTP($this->at($timestamp), $otp); 148 } 149 150 $leeway = abs($leeway); 151 $leeway < $this->getPeriod() || throw new InvalidParameterException( 152 'The leeway must be lower than the TOTP period', 153 'leeway', 154 $leeway 155 ); 156 $timestampMinusLeeway = $timestamp - $leeway; 157 $timestampMinusLeeway >= 0 || throw new InvalidParameterException( 158 'The timestamp must be greater than or equal to the leeway.', 159 'timestamp', 160 $timestamp 161 ); 162 163 return $this->compareOTP($this->at($timestampMinusLeeway), $otp) 164 || $this->compareOTP($this->at($timestamp), $otp) 165 || $this->compareOTP($this->at($timestamp + $leeway), $otp); 166 } 167 168 public function getProvisioningUri(): string 169 { 170 $params = []; 171 if ($this->getPeriod() !== 30) { 172 $params['period'] = $this->getPeriod(); 173 } 174 175 if ($this->getEpoch() !== 0) { 176 $params['epoch'] = $this->getEpoch(); 177 } 178 179 return $this->generateURI('totp', $params); 180 } 181 182 public function setPeriod(int $period): void 34 183 { 35 184 $this->setParameter('period', $period); 36 185 } 37 186 38 public function getPeriod(): int 39 { 40 return $this->getParameter('period'); 41 } 42 43 private function setEpoch(int $epoch): void 187 public function withPeriod(int $period): self 188 { 189 $otp = clone $this; 190 $otp->setParameter('period', $period); 191 192 return $otp; 193 } 194 195 public function setEpoch(int $epoch): void 44 196 { 45 197 $this->setParameter('epoch', $epoch); 46 198 } 47 199 48 public function getEpoch(): int 49 { 50 return $this->getParameter('epoch'); 51 } 52 53 public function at(int $timestamp): string 54 { 55 return $this->generateOTP($this->timecode($timestamp)); 56 } 57 58 public function now(): string 59 { 60 return $this->at(time()); 61 } 62 63 /** 64 * If no timestamp is provided, the OTP is verified at the actual timestamp. 65 */ 66 public function verify(string $otp, ?int $timestamp = null, ?int $window = null): bool 67 { 68 $timestamp = $this->getTimestamp($timestamp); 69 70 if (null === $window) { 71 return $this->compareOTP($this->at($timestamp), $otp); 72 } 73 74 return $this->verifyOtpWithWindow($otp, $timestamp, $window); 75 } 76 77 private function verifyOtpWithWindow(string $otp, int $timestamp, int $window): bool 78 { 79 $window = abs($window); 80 81 for ($i = 0; $i <= $window; ++$i) { 82 $next = $i * $this->getPeriod() + $timestamp; 83 $previous = -$i * $this->getPeriod() + $timestamp; 84 $valid = $this->compareOTP($this->at($next), $otp) || 85 $this->compareOTP($this->at($previous), $otp); 86 87 if ($valid) { 88 return true; 89 } 90 } 91 92 return false; 93 } 94 95 private function getTimestamp(?int $timestamp): int 96 { 97 $timestamp = $timestamp ?? time(); 98 Assertion::greaterOrEqualThan($timestamp, 0, 'Timestamp must be at least 0.'); 99 100 return $timestamp; 101 } 102 103 public function getProvisioningUri(): string 104 { 105 $params = []; 106 if (30 !== $this->getPeriod()) { 107 $params['period'] = $this->getPeriod(); 108 } 109 110 if (0 !== $this->getEpoch()) { 111 $params['epoch'] = $this->getEpoch(); 112 } 113 114 return $this->generateURI('totp', $params); 115 } 116 200 public function withEpoch(int $epoch): self 201 { 202 $otp = clone $this; 203 $otp->setParameter('epoch', $epoch); 204 205 return $otp; 206 } 207 208 /** 209 * @return array<non-empty-string, callable> 210 */ 211 protected function getParameterMap(): array 212 { 213 return [ 214 ...parent::getParameterMap(), 215 'period' => static function ($value): int { 216 (int) $value > 0 || throw new InvalidParameterException('Period must be at least 1.', 'period', $value); 217 218 return (int) $value; 219 }, 220 'epoch' => static function ($value): int { 221 (int) $value >= 0 || throw new InvalidParameterException( 222 'Epoch must be greater than or equal to 0.', 223 'epoch', 224 $value 225 ); 226 227 return (int) $value; 228 }, 229 ]; 230 } 231 232 /** 233 * @param array<non-empty-string, mixed> $options 234 */ 235 protected function filterOptions(array &$options): void 236 { 237 parent::filterOptions($options); 238 239 if (isset($options['epoch']) && $options['epoch'] === 0) { 240 unset($options['epoch']); 241 } 242 243 ksort($options); 244 } 245 246 /** 247 * @param 0|positive-int $timestamp 248 * 249 * @return 0|positive-int 250 */ 117 251 private function timecode(int $timestamp): int 118 252 { 119 return (int) floor(($timestamp - $this->getEpoch()) / $this->getPeriod()); 120 } 121 122 /** 123 * @return array<string, mixed> 124 */ 125 protected function getParameterMap(): array 126 { 127 $v = array_merge( 128 parent::getParameterMap(), 129 [ 130 'period' => function ($value): int { 131 Assertion::greaterThan((int) $value, 0, 'Period must be at least 1.'); 132 133 return (int) $value; 134 }, 135 'epoch' => function ($value): int { 136 Assertion::greaterOrEqualThan((int) $value, 0, 'Epoch must be greater than or equal to 0.'); 137 138 return (int) $value; 139 }, 140 ] 141 ); 142 143 return $v; 144 } 145 146 /** 147 * @param array<string, mixed> $options 148 */ 149 protected function filterOptions(array &$options): void 150 { 151 parent::filterOptions($options); 152 153 if (isset($options['epoch']) && 0 === $options['epoch']) { 154 unset($options['epoch']); 155 } 156 157 ksort($options); 253 $timecode = (int) floor(($timestamp - $this->getEpoch()) / $this->getPeriod()); 254 $timecode >= 0 || throw new InvalidParameterException( 255 'Timecode must be at least 0. The timestamp must be greater than or equal to the epoch.', 256 'timecode', 257 $timecode 258 ); 259 260 return $timecode; 158 261 } 159 262 } -
wp-otp/trunk/vendor/spomky-labs/otphp/src/TOTPInterface.php
r2331970 r3752647 2 2 3 3 declare(strict_types=1); 4 5 /*6 * The MIT License (MIT)7 *8 * Copyright (c) 2014-2019 Spomky-Labs9 *10 * This software may be modified and distributed under the terms11 * of the MIT license. See the LICENSE file for details.12 */13 4 14 5 namespace OTPHP; … … 16 7 interface TOTPInterface extends OTPInterface 17 8 { 9 public const DEFAULT_PERIOD = 30; 10 11 public const DEFAULT_EPOCH = 0; 12 18 13 /** 19 14 * Create a new TOTP object. 20 15 * 21 16 * If the secret is null, a random 64 bytes secret will be generated. 17 * 18 * @param null|non-empty-string $secret 19 * @param positive-int $period 20 * @param non-empty-string $digest 21 * @param positive-int $digits 22 * 23 * @deprecated Deprecated since v11.1, use ::createFromSecret or ::generate instead 22 24 */ 23 public static function create(?string $secret = null, int $period = 30, string $digest = 'sha1', int $digits = 6): self; 25 public static function create( 26 null|string $secret = null, 27 int $period = self::DEFAULT_PERIOD, 28 string $digest = self::DEFAULT_DIGEST, 29 int $digits = self::DEFAULT_DIGITS 30 ): self; 31 32 /** 33 * @deprecated Deprecated since v11.4, use {@see self::withPeriod()} instead 34 */ 35 public function setPeriod(int $period): void; 36 37 public function withPeriod(int $period): self; 38 39 /** 40 * @deprecated Deprecated since v11.4, use {@see self::withEpoch()} instead 41 */ 42 public function setEpoch(int $epoch): void; 43 44 public function withEpoch(int $epoch): self; 24 45 25 46 /** 26 47 * Return the TOTP at the current time. 48 * 49 * @return non-empty-string 27 50 */ 28 51 public function now(): string; … … 33 56 public function getPeriod(): int; 34 57 58 public function expiresIn(): int; 59 35 60 public function getEpoch(): int; 36 61 } -
wp-otp/trunk/wp-otp.php
r2477335 r3752647 3 3 * Plugin Name: WP-OTP 4 4 * Plugin URI: https://wordpress.org/plugins/wp-otp/ 5 * Description: WP-OTP adds 2 Factor Authentication using TOTP. (Based on "WP Secure Login" by Brijesh Kothari) 6 * Version: 0.6.1 5 * Description: WP-OTP adds 2 Factor Authentication using TOTP. 6 * Version: 0.7.0 7 * Requires PHP: 8.2 7 8 * Author: Armando Lüscher 8 9 * Author URI: https://noplanman.ch 9 10 * License: GPLv2 or later 10 11 * License URI: https://www.gnu.org/licenses/gpl-2.0.html 11 * GitLab Plugin URI: https://git.feneas.org/noplanman/wp-otp12 * GitLab Branch: master13 12 * 14 13 * @package Wp_Otp … … 22 21 // Define constants. 23 22 define( 'WP_OTP_SLUG', 'wp-otp' ); 24 define( 'WP_OTP_VERSION', '0. 6.1' );23 define( 'WP_OTP_VERSION', '0.7.0' ); 25 24 26 25 require_once __DIR__ . '/vendor/autoload.php';
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)