Skip to content

Commit 48b1703

Browse files
committed
Optimized memory usage.
1 parent 7f7445c commit 48b1703

23 files changed

+491
-99
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.4
2+
3+
* Optimized memory usage.
4+
15
## 2.3
26

37
* Support specify custom keyring details for Electronic Signature.

src/Contracts/BufferInterface.php

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
namespace EbicsApi\Ebics\Contracts;
4+
5+
/**
6+
* Buffer class interface.
7+
*
8+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
9+
* @author Andrew Svirin
10+
*/
11+
interface BufferInterface
12+
{
13+
const DEFAULT_READ_LENGTH = 1024;
14+
15+
/**
16+
* Open buffer.
17+
*
18+
* @param string $mode
19+
*
20+
* @return void
21+
*/
22+
public function open(string $mode): void;
23+
24+
/**
25+
* Close buffer.
26+
*
27+
* @return void
28+
*/
29+
public function close(): void;
30+
31+
/**
32+
* Reset pointer.
33+
*
34+
* @return void
35+
*/
36+
public function rewind(): void;
37+
38+
/**
39+
* Write to buffer.
40+
*
41+
* @param string $string
42+
*
43+
* @return void
44+
*/
45+
public function write(string $string): void;
46+
47+
/**
48+
* Read from buffer.
49+
*
50+
* @param int|null $length
51+
*
52+
* @return string
53+
*/
54+
public function read(?int $length = null): string;
55+
56+
/**
57+
* Read from buffer full content.
58+
*
59+
* @return string
60+
*/
61+
public function readContent(): string;
62+
63+
/**
64+
* Is end of file.
65+
*
66+
* @return bool
67+
*/
68+
public function eof(): bool;
69+
70+
/**
71+
* Move to pointer.
72+
*
73+
* @param int $offset
74+
*
75+
* @return int
76+
*/
77+
public function fseek(int $offset): int;
78+
79+
/**
80+
* Apply filter.
81+
*
82+
* @param string $filterName
83+
* @param int $mode
84+
*
85+
* @return void
86+
*/
87+
public function filterAppend(string $filterName, int $mode): void;
88+
89+
/**
90+
* Length of content.
91+
*
92+
* @return int
93+
*/
94+
public function length(): int;
95+
}

src/Contracts/Crypt/AESInterface.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace EbicsApi\Ebics\Contracts\Crypt;
44

5+
use EbicsApi\Ebics\Contracts\BufferInterface;
6+
57
/**
68
* Crypt AES representation.
79
*
@@ -67,6 +69,19 @@ public function setIV(string $iv);
6769
*/
6870
public function encrypt(string $plaintext);
6971

72+
/**
73+
* Decrypts a message.
74+
*
75+
* If strlen($ciphertext) is not a multiple of the block size, null bytes will be added
76+
* to the end of the string until it is.
77+
*
78+
* @param BufferInterface $ciphertext
79+
* @param BufferInterface $plaintext
80+
*
81+
* @return void
82+
*/
83+
public function decryptBuffer(BufferInterface $ciphertext, BufferInterface $plaintext);
84+
7085
/**
7186
* Decrypts a message.
7287
*

src/Contracts/EbicsClientInterface.php

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -518,13 +518,6 @@ public function getBank(): Bank;
518518
*/
519519
public function getUser(): User;
520520

521-
/**
522-
* Set http client to subset later in the project.
523-
*
524-
* @param HttpClientInterface $httpClient
525-
*/
526-
public function setHttpClient(HttpClientInterface $httpClient): void;
527-
528521
/**
529522
* Get response handler for manual process response.
530523
*

src/EbicsBankLetter.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use EbicsApi\Ebics\Contracts\BankLetter\FormatterInterface;
66
use EbicsApi\Ebics\Factories\BankLetterFactory;
7+
use EbicsApi\Ebics\Factories\CertificateX509Factory;
8+
use EbicsApi\Ebics\Factories\SignatureBankLetterFactory;
79
use EbicsApi\Ebics\Models\Bank;
810
use EbicsApi\Ebics\Models\BankLetter;
911
use EbicsApi\Ebics\Models\Keyring;
@@ -12,6 +14,7 @@
1214
use EbicsApi\Ebics\Services\BankLetter\Formatter\PdfBankLetterFormatter;
1315
use EbicsApi\Ebics\Services\BankLetter\Formatter\TxtBankLetterFormatter;
1416
use EbicsApi\Ebics\Services\BankLetterService;
17+
use EbicsApi\Ebics\Services\CryptService;
1518
use EbicsApi\Ebics\Services\DigestResolverV2;
1619
use EbicsApi\Ebics\Services\DigestResolverV3;
1720
use LogicException;
@@ -27,10 +30,16 @@ final class EbicsBankLetter
2730
{
2831
private BankLetterService $bankLetterService;
2932
private BankLetterFactory $bankLetterFactory;
33+
private CryptService $cryptService;
3034

3135
public function __construct()
3236
{
33-
$this->bankLetterService = new BankLetterService();
37+
$this->cryptService = new CryptService();
38+
$this->bankLetterService = new BankLetterService(
39+
$this->cryptService,
40+
new SignatureBankLetterFactory(),
41+
new CertificateX509Factory()
42+
);
3443
$this->bankLetterFactory = new BankLetterFactory();
3544
}
3645

@@ -47,9 +56,9 @@ public function __construct()
4756
public function prepareBankLetter(Bank $bank, User $user, Keyring $keyring): BankLetter
4857
{
4958
if (Keyring::VERSION_25 === $keyring->getVersion() || Keyring::VERSION_24 === $keyring->getVersion()) {
50-
$digestResolver = new DigestResolverV2();
59+
$digestResolver = new DigestResolverV2($this->cryptService);
5160
} elseif (Keyring::VERSION_30 === $keyring->getVersion()) {
52-
$digestResolver = new DigestResolverV3();
61+
$digestResolver = new DigestResolverV3($this->cryptService);
5362
} else {
5463
throw new LogicException(sprintf('Version "%s" is not implemented', $keyring->getVersion()));
5564
}

src/EbicsClient.php

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace EbicsApi\Ebics;
44

5+
use DateTimeInterface;
56
use EbicsApi\Ebics\Contexts\BTDContext;
67
use EbicsApi\Ebics\Contexts\BTUContext;
78
use EbicsApi\Ebics\Contexts\FDLContext;
@@ -51,11 +52,11 @@
5152
use EbicsApi\Ebics\Models\UploadTransaction;
5253
use EbicsApi\Ebics\Models\User;
5354
use EbicsApi\Ebics\Models\X509\ContentX509Generator;
55+
use EbicsApi\Ebics\Services\BufferFactory;
5456
use EbicsApi\Ebics\Services\CryptService;
5557
use EbicsApi\Ebics\Services\CurlHttpClient;
5658
use EbicsApi\Ebics\Services\XmlService;
5759
use EbicsApi\Ebics\Services\ZipService;
58-
use DateTimeInterface;
5960
use LogicException;
6061

6162
/**
@@ -81,45 +82,64 @@ final class EbicsClient implements EbicsClientInterface
8182
private HttpClientInterface $httpClient;
8283
private TransactionFactory $transactionFactory;
8384
private SegmentFactory $segmentFactory;
85+
private BufferFactory $bufferFactory;
8486

8587
/**
8688
* Constructor.
8789
*
8890
* @param Bank $bank
8991
* @param User $user
9092
* @param Keyring $keyring
93+
* @param array $options
9194
*/
92-
public function __construct(Bank $bank, User $user, Keyring $keyring)
95+
public function __construct(Bank $bank, User $user, Keyring $keyring, array $options = [])
9396
{
9497
$this->bank = $bank;
9598
$this->user = $user;
9699
$this->keyring = $keyring;
97100

101+
$this->segmentFactory = new SegmentFactory();
102+
$this->cryptService = new CryptService();
103+
$this->zipService = new ZipService();
104+
$this->bufferFactory = new BufferFactory($options['buffer_filename'] ?? 'php://memory');
105+
98106
if (Keyring::VERSION_24 === $keyring->getVersion()) {
99107
$this->requestFactory = new RequestFactoryV24($bank, $user, $keyring);
100108
$this->orderDataHandler = new OrderDataHandlerV24($user, $keyring);
101-
$this->responseHandler = new ResponseHandlerV24();
109+
$this->responseHandler = new ResponseHandlerV24(
110+
$this->segmentFactory,
111+
$this->cryptService,
112+
$this->zipService,
113+
$this->bufferFactory
114+
);
102115
} elseif (Keyring::VERSION_25 === $keyring->getVersion()) {
103116
$this->requestFactory = new RequestFactoryV25($bank, $user, $keyring);
104117
$this->orderDataHandler = new OrderDataHandlerV25($user, $keyring);
105-
$this->responseHandler = new ResponseHandlerV25();
118+
$this->responseHandler = new ResponseHandlerV25(
119+
$this->segmentFactory,
120+
$this->cryptService,
121+
$this->zipService,
122+
$this->bufferFactory
123+
);
106124
} elseif (Keyring::VERSION_30 === $keyring->getVersion()) {
107125
$this->requestFactory = new RequestFactoryV3($bank, $user, $keyring);
108126
$this->orderDataHandler = new OrderDataHandlerV3($user, $keyring);
109-
$this->responseHandler = new ResponseHandlerV3();
127+
$this->responseHandler = new ResponseHandlerV3(
128+
$this->segmentFactory,
129+
$this->cryptService,
130+
$this->zipService,
131+
$this->bufferFactory
132+
);
110133
} else {
111134
throw new LogicException(sprintf('Version "%s" is not implemented', $keyring->getVersion()));
112135
}
113136

114-
$this->cryptService = new CryptService();
115137
$this->xmlService = new XmlService();
116-
$this->zipService = new ZipService();
117138
$this->signatureFactory = new SignatureFactory();
118139
$this->documentFactory = new DocumentFactory();
119140
$this->orderResultFactory = new OrderResultFactory();
120141
$this->transactionFactory = new TransactionFactory();
121-
$this->segmentFactory = new SegmentFactory();
122-
$this->httpClient = new CurlHttpClient();
142+
$this->httpClient = $options['http_client'] ?? new CurlHttpClient();
123143
}
124144

125145
/**
@@ -1065,19 +1085,35 @@ private function downloadTransaction(callable $requestClosure, callable $ackClos
10651085

10661086
$this->transferReceipt($transaction, $acknowledged);
10671087

1068-
$orderDataEncrypted = '';
1088+
$orderDataEncoded = $this->bufferFactory->create();
10691089
foreach ($transaction->getSegments() as $segment) {
1070-
$orderDataEncrypted .= $segment->getOrderData();
1090+
$orderDataEncoded->write($segment->getOrderData());
1091+
$segment->setOrderData('');
1092+
}
1093+
$orderDataEncoded->rewind();
1094+
1095+
$orderDataDecoded = $this->bufferFactory->create();
1096+
while (!$orderDataEncoded->eof()) {
1097+
$orderDataDecoded->write(base64_decode($orderDataEncoded->read()));
10711098
}
1099+
$orderDataDecoded->rewind();
1100+
unset($orderDataEncoded);
10721101

1073-
$orderDataCompressed = $this->cryptService->decryptOrderDataCompressed(
1102+
$orderDataCompressed = $this->bufferFactory->create();
1103+
$this->cryptService->decryptOrderDataCompressed(
10741104
$this->keyring,
1075-
$orderDataEncrypted,
1105+
$orderDataDecoded,
1106+
$orderDataCompressed,
10761107
$lastSegment->getTransactionKey()
10771108
);
1078-
$orderData = $this->zipService->uncompress($orderDataCompressed);
1109+
unset($orderDataDecoded);
10791110

1080-
$transaction->setOrderData($orderData);
1111+
$orderData = $this->bufferFactory->create();
1112+
$this->zipService->uncompress($orderDataCompressed, $orderData);
1113+
unset($orderDataCompressed);
1114+
1115+
$transaction->setOrderData($orderData->readContent());
1116+
unset($orderData);
10811117

10821118
return $transaction;
10831119
}
@@ -1271,14 +1307,6 @@ public function getUser(): User
12711307
return $this->user;
12721308
}
12731309

1274-
/**
1275-
* @inheritDoc
1276-
*/
1277-
public function setHttpClient(HttpClientInterface $httpClient): void
1278-
{
1279-
$this->httpClient = $httpClient;
1280-
}
1281-
12821310
/**
12831311
* Get user signature.
12841312
*

src/Factories/RequestFactoryV24.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use EbicsApi\Ebics\Models\Keyring;
1515
use EbicsApi\Ebics\Models\UploadTransaction;
1616
use EbicsApi\Ebics\Models\User;
17+
use EbicsApi\Ebics\Services\CryptService;
1718
use EbicsApi\Ebics\Services\DigestResolverV2;
1819
use LogicException;
1920

@@ -30,7 +31,7 @@ public function __construct(Bank $bank, User $user, Keyring $keyring)
3031
$this->authSignatureHandler = new AuthSignatureHandlerV24($keyring);
3132
$this->userSignatureHandler = new UserSignatureHandlerV2($user, $keyring);
3233
$this->orderDataHandler = new OrderDataHandlerV24($user, $keyring);
33-
$this->digestResolver = new DigestResolverV2();
34+
$this->digestResolver = new DigestResolverV2(new CryptService());
3435
parent::__construct($bank, $user, $keyring);
3536
}
3637

src/Factories/RequestFactoryV25.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use EbicsApi\Ebics\Models\UploadTransaction;
2424
use EbicsApi\Ebics\Models\User;
2525
use EbicsApi\Ebics\Models\UserSignature;
26+
use EbicsApi\Ebics\Services\CryptService;
2627
use EbicsApi\Ebics\Services\DigestResolverV2;
2728
use LogicException;
2829

@@ -39,7 +40,7 @@ public function __construct(Bank $bank, User $user, Keyring $keyring)
3940
$this->authSignatureHandler = new AuthSignatureHandlerV25($keyring);
4041
$this->userSignatureHandler = new UserSignatureHandlerV2($user, $keyring);
4142
$this->orderDataHandler = new OrderDataHandlerV25($user, $keyring);
42-
$this->digestResolver = new DigestResolverV2();
43+
$this->digestResolver = new DigestResolverV2(new CryptService());
4344
parent::__construct($bank, $user, $keyring);
4445
}
4546

src/Factories/RequestFactoryV3.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use EbicsApi\Ebics\Models\UploadTransaction;
2626
use EbicsApi\Ebics\Models\User;
2727
use EbicsApi\Ebics\Models\UserSignature;
28+
use EbicsApi\Ebics\Services\CryptService;
2829
use EbicsApi\Ebics\Services\DigestResolverV3;
2930

3031
/**
@@ -40,7 +41,7 @@ public function __construct(Bank $bank, User $user, Keyring $keyring)
4041
$this->authSignatureHandler = new AuthSignatureHandlerV3($keyring);
4142
$this->userSignatureHandler = new UserSignatureHandlerV3($user, $keyring);
4243
$this->orderDataHandler = new OrderDataHandlerV3($user, $keyring);
43-
$this->digestResolver = new DigestResolverV3();
44+
$this->digestResolver = new DigestResolverV3(new CryptService());
4445
parent::__construct($bank, $user, $keyring);
4546
}
4647

0 commit comments

Comments
 (0)