$fields */ public static function encode( array $fields ): string { $lines = []; foreach ( $fields as $key => $value ) { $lines[] = $key . '=' . $value; } return base64_encode( implode( "\n", $lines ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- ePay.bg wire format, not obfuscation. } public static function checksum( string $encoded, string $secret ): string { return '' === $secret ? '' : hash_hmac( 'sha1', $encoded, $secret ); } public static function verify( string $encoded, string $checksum, string $secret ): bool { $checksum = strtolower( trim( $checksum ) ); if ( '' === $secret || 1 !== preg_match( '/^[0-9a-f]{40}$/', $checksum ) ) { return false; } return hash_equals( self::checksum( $encoded, $secret ), $checksum ); } /** * @return list> */ public static function parse_notification( string $encoded ): array { $decoded = base64_decode( $encoded, true ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- ePay.bg wire format, not obfuscation. if ( false === $decoded ) { return []; } $entries = []; foreach ( preg_split( '/\r\n|\n|\r/', $decoded ) as $line ) { $entry = []; foreach ( explode( ':', $line ) as $part ) { $pair = explode( '=', $part, 2 ); if ( 2 !== count( $pair ) ) { continue; } $key = strtolower( trim( $pair[0] ) ); if ( in_array( $key, self::NOTIFICATION_KEYS, true ) ) { $entry[ $key ] = trim( $pair[1] ); } } if ( 1 === preg_match( '/^\d{1,20}$/', $entry['invoice'] ?? '' ) ) { $entry['status'] ??= ''; $entries[] = $entry; } } return $entries; } public static function request_field( string $encoded, string $key ): string { $decoded = base64_decode( $encoded, true ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- ePay.bg wire format, not obfuscation. if ( false === $decoded ) { return ''; } foreach ( preg_split( '/\r\n|\n|\r/', $decoded ) as $line ) { $pair = explode( '=', $line, 2 ); if ( 2 === count( $pair ) && $pair[0] === $key ) { return $pair[1]; } } return ''; } /** * @param array $statuses Invoice => OK|ERR|NO. */ public static function reply( array $statuses ): string { $out = ''; foreach ( $statuses as $invoice => $status ) { $out .= 'INVOICE=' . self::clean( (string) $invoice ) . ':STATUS=' . self::clean( $status ) . "\n"; } return $out; } public static function error_reply( string $code ): string { return 'ERR=' . self::clean( $code ) . "\n"; } private static function clean( string $value ): string { return (string) preg_replace( '/[\x00-\x1f:]/', '', $value ); } }