1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Defr\QRPlatba;
13:
14: use Endroid\QrCode\QrCode;
15:
16: 17: 18: 19: 20:
21: class QRPlatba
22: {
23: 24: 25:
26: const VERSION = '1.0';
27:
28: 29: 30:
31: private static $currencies = [
32: 'AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN',
33: 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL',
34: 'BSD', 'BTN', 'BWP', 'BYN', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY',
35: 'COP', 'CRC', 'CUC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD',
36: 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GGP', 'GHS',
37: 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF',
38: 'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD', 'JOD',
39: 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD', 'KZT',
40: 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD',
41: 'MMK', 'MNT', 'MOP', 'MRO', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN',
42: 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK',
43: 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR',
44: 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLL', 'SOS', 'SPL', 'SRD',
45: 'STD', 'SVC', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY',
46: 'TTD', 'TVD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VEF',
47: 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XDR', 'XOF', 'XPF', 'YER', 'ZAR',
48: 'ZMW', 'ZWD',
49: ];
50:
51: 52: 53:
54: private $keys = [
55: 'ACC' => null,
56:
57: 'ALT-ACC' => null,
58:
59: 'AM' => null,
60:
61: 'CC' => 'CZK',
62:
63: 'DT' => null,
64:
65: 'MSG' => null,
66:
67: 'X-VS' => null,
68:
69: 'X-SS' => null,
70:
71: 'X-KS' => null,
72:
73: 'RF' => null,
74:
75: 'RN' => null,
76:
77: 'PT' => null,
78:
79: 'CRC32' => null,
80:
81: 'NT' => null,
82:
83: 'NTA' => null,
84:
85: 'X-PER' => null,
86:
87: 'X-ID' => null,
88:
89: 'X-URL' => null,
90:
91: ];
92:
93: 94: 95: 96: 97: 98: 99: 100: 101:
102: public function __construct($account = null, $amount = null, $variable = null, $currency = null)
103: {
104: if ($account) {
105: $this->setAccount($account);
106: }
107: if ($amount) {
108: $this->setAmount($amount);
109: }
110: if ($variable) {
111: $this->setVariableSymbol($variable);
112: }
113: if ($currency) {
114: $this->setCurrency($currency);
115: }
116: }
117:
118: 119: 120: 121: 122: 123: 124: 125: 126: 127:
128: public static function create($account = null, $amount = null, $variable = null)
129: {
130: return new self($account, $amount, $variable);
131: }
132:
133: 134: 135: 136: 137: 138: 139:
140: public function setAccount($account)
141: {
142: $this->keys['ACC'] = self::accountToIban($account);
143:
144: return $this;
145: }
146:
147: 148: 149: 150: 151: 152: 153:
154: public function setAmount($amount)
155: {
156: $this->keys['AM'] = sprintf('%.2f', $amount);
157:
158: return $this;
159: }
160:
161: 162: 163: 164: 165: 166: 167:
168: public function setVariableSymbol($vs)
169: {
170: $this->keys['X-VS'] = $vs;
171:
172: return $this;
173: }
174:
175: 176: 177: 178: 179: 180: 181:
182: public function setConstantSymbol($cs)
183: {
184: $this->keys['X-CS'] = $cs;
185:
186: return $this;
187: }
188:
189: 190: 191: 192: 193: 194: 195: 196: 197:
198: public function setSpecificSymbol($ss)
199: {
200: if (mb_strlen($ss) > 10) {
201: throw new QRPlatbaException('Specific symbol is higher than 10 chars');
202: }
203: $this->keys['X-SS'] = $ss;
204:
205: return $this;
206: }
207:
208: 209: 210: 211: 212: 213: 214:
215: public function setMessage($msg)
216: {
217: $this->keys['MSG'] = mb_substr($this->stripDiacritics($msg), 0, 60);
218:
219: return $this;
220: }
221:
222: 223: 224: 225: 226: 227: 228:
229: public function setRecipientName($name)
230: {
231: $this->keys['RN'] = mb_substr($this->stripDiacritics($name), 0, 35);
232:
233: return $this;
234: }
235:
236: 237: 238: 239: 240: 241: 242:
243: public function setDueDate(\DateTime $date)
244: {
245: $this->keys['DT'] = $date->format('Ymd');
246:
247: return $this;
248: }
249:
250: 251: 252: 253: 254: 255:
256: public function setCurrency($cc)
257: {
258: if (!in_array($cc, self::$currencies, true)) {
259: throw new \InvalidArgumentException(sprintf('Currency %s is not supported.', $cc));
260: }
261:
262: $this->keys['CC'] = $cc;
263:
264: return $this;
265: }
266:
267: 268: 269: 270: 271:
272: public function __toString()
273: {
274: $chunks = ['SPD', self::VERSION];
275: foreach ($this->keys as $key => $value) {
276: if (null === $value) {
277: continue;
278: }
279: $chunks[] = $key.':'.$value;
280: }
281:
282: return implode('*', $chunks);
283: }
284:
285: 286: 287: 288: 289: 290: 291: 292:
293: public function getQRCodeImage($htmlTag = true, $size = 300)
294: {
295: $qrCode = $this->getQRCodeInstance($size);
296: $data = $qrCode->writeDataUri();
297:
298: return $htmlTag
299: ? sprintf('<img src="%s" alt="QR Platba">', $data)
300: : $data;
301: }
302:
303: 304: 305: 306: 307: 308: 309: 310: 311: 312:
313: public function saveQRCodeImage($filename = null, $format = 'png', $size = 300)
314: {
315: $qrCode = $this->getQRCodeInstance($size);
316: $qrCode->setWriterByExtension($format);
317: $qrCode->writeFile($filename);
318:
319: return $this;
320: }
321:
322: 323: 324: 325: 326: 327: 328:
329: public function getQRCodeInstance($size = 300)
330: {
331: $qrCode = new QrCode();
332: $qrCode
333: ->setText((string) $this)
334: ->setSize($size)
335: ->setForegroundColor(['r' => 0, 'g' => 0, 'b' => 0, 'a' => 0])
336: ->setBackgroundColor(['r' => 255, 'g' => 255, 'b' => 255, 'a' => 0]);
337:
338: return $qrCode;
339: }
340:
341: 342: 343: 344: 345: 346: 347:
348: public static function accountToIban($accountNumber)
349: {
350: $accountNumber = explode('/', $accountNumber);
351: $bank = $accountNumber[1];
352: $pre = 0;
353: $acc = 0;
354: if (false === mb_strpos($accountNumber[0], '-')) {
355: $acc = $accountNumber[0];
356: } else {
357: list($pre, $acc) = explode('-', $accountNumber[0]);
358: }
359:
360: $accountPart = sprintf('%06d%010s', $pre, $acc);
361: $iban = 'CZ00'.$bank.$accountPart;
362:
363: $alfa = 'A B C D E F G H I J K L M N O P Q R S T U V W X Y Z';
364: $alfa = explode(' ', $alfa);
365: $alfa_replace = [];
366: for ($i = 1; $i < 27; ++$i) {
367: $alfa_replace[] = $i + 9;
368: }
369: $controlegetal = str_replace(
370: $alfa,
371: $alfa_replace,
372: mb_substr($iban, 4, mb_strlen($iban) - 4).mb_substr($iban, 0, 2).'00'
373: );
374: $controlegetal = 98 - (int) bcmod($controlegetal, 97);
375: $iban = sprintf('CZ%02d%04d%06d%010s', $controlegetal, $bank, $pre, $acc);
376:
377: return $iban;
378: }
379:
380: 381: 382: 383: 384: 385: 386:
387: private function stripDiacritics($string)
388: {
389: $string = str_replace(
390: [
391: 'ě', 'š', 'č', 'ř', 'ž', 'ý', 'á', 'í', 'é', 'ú', 'ů',
392: 'ó', 'ť', 'ď', 'ľ', 'ň', 'ŕ', 'â', 'ă', 'ä', 'ĺ', 'ć',
393: 'ç', 'ę', 'ë', 'î', 'ń', 'ô', 'ő', 'ö', 'ů', 'ű', 'ü',
394: 'Ě', 'Š', 'Č', 'Ř', 'Ž', 'Ý', 'Á', 'Í', 'É', 'Ú', 'Ů',
395: 'Ó', 'Ť', 'Ď', 'Ľ', 'Ň', 'Ä', 'Ć', 'Ë', 'Ö', 'Ü'
396: ],
397: [
398: 'e', 's', 'c', 'r', 'z', 'y', 'a', 'i', 'e', 'u', 'u',
399: 'o', 't', 'd', 'l', 'n', 'a', 'a', 'a', 'a', 'a', 'a',
400: 'c', 'e', 'e', 'i', 'n', 'o', 'o', 'o', 'u', 'u', 'u',
401: 'E', 'S', 'C', 'R', 'Z', 'Y', 'A', 'I', 'E', 'U', 'U',
402: 'O', 'T', 'D', 'L', 'N', 'A', 'C', 'E', 'O', 'U'
403: ],
404: $string
405: );
406:
407: return $string;
408: }
409: }
410: