PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.18
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.18
1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 All 163 releases
woocommerce-pos / vendor_prefixed / chillerlan / php-qrcode / src / QRCode.php

QRCode.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.18, at vendor_prefixed/chillerlan/php-qrcode/src/QRCode.php

447 lines 15.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class QRCode
5 *
6 * @created 26.11.2015
7 * @author Smiley <smiley@chillerlan.net>
8 * @copyright 2015 Smiley
9 * @license MIT
10 *
11 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
12 */
13 namespace WCPOS\Vendor\chillerlan\QRCode;
14
15 use WCPOS\Vendor\chillerlan\QRCode\Common\EccLevel;
16 use WCPOS\Vendor\chillerlan\QRCode\Common\ECICharset;
17 use WCPOS\Vendor\chillerlan\QRCode\Common\GDLuminanceSource;
18 use WCPOS\Vendor\chillerlan\QRCode\Common\IMagickLuminanceSource;
19 use WCPOS\Vendor\chillerlan\QRCode\Common\LuminanceSourceInterface;
20 use WCPOS\Vendor\chillerlan\QRCode\Common\MaskPattern;
21 use WCPOS\Vendor\chillerlan\QRCode\Common\Mode;
22 use WCPOS\Vendor\chillerlan\QRCode\Common\Version;
23 use WCPOS\Vendor\chillerlan\QRCode\Data\AlphaNum;
24 use WCPOS\Vendor\chillerlan\QRCode\Data\Byte;
25 use WCPOS\Vendor\chillerlan\QRCode\Data\ECI;
26 use WCPOS\Vendor\chillerlan\QRCode\Data\Hanzi;
27 use WCPOS\Vendor\chillerlan\QRCode\Data\Kanji;
28 use WCPOS\Vendor\chillerlan\QRCode\Data\Number;
29 use WCPOS\Vendor\chillerlan\QRCode\Data\QRData;
30 use WCPOS\Vendor\chillerlan\QRCode\Data\QRDataModeInterface;
31 use WCPOS\Vendor\chillerlan\QRCode\Data\QRMatrix;
32 use WCPOS\Vendor\chillerlan\QRCode\Decoder\Decoder;
33 use WCPOS\Vendor\chillerlan\QRCode\Decoder\DecoderResult;
34 use WCPOS\Vendor\chillerlan\QRCode\Output\QRCodeOutputException;
35 use WCPOS\Vendor\chillerlan\QRCode\Output\QROutputInterface;
36 use WCPOS\Vendor\chillerlan\Settings\SettingsContainerInterface;
37 use function class_exists, class_implements, in_array, mb_convert_encoding, mb_internal_encoding;
38 /**
39 * Turns a text string into a Model 2 QR Code
40 *
41 * @see https://github.com/kazuhikoarase/qrcode-generator/tree/master/php
42 * @see https://www.qrcode.com/en/codes/model12.html
43 * @see https://www.swisseduc.ch/informatik/theoretische_informatik/qr_codes/docs/qr_standard.pdf
44 * @see https://en.wikipedia.org/wiki/QR_code
45 * @see https://www.thonky.com/qr-code-tutorial/
46 */
47 class QRCode
48 {
49 /**
50 * @deprecated 5.0.0 use Version::AUTO instead
51 * @see \chillerlan\QRCode\Common\Version::AUTO
52 * @var int
53 */
54 public const VERSION_AUTO = Version::AUTO;
55 /**
56 * @deprecated 5.0.0 use MaskPattern::AUTO instead
57 * @see \chillerlan\QRCode\Common\MaskPattern::AUTO
58 * @var int
59 */
60 public const MASK_PATTERN_AUTO = MaskPattern::AUTO;
61 /**
62 * @deprecated 5.0.0 use EccLevel::L instead
63 * @see \chillerlan\QRCode\Common\EccLevel::L
64 * @var int
65 */
66 public const ECC_L = EccLevel::L;
67 /**
68 * @deprecated 5.0.0 use EccLevel::M instead
69 * @see \chillerlan\QRCode\Common\EccLevel::M
70 * @var int
71 */
72 public const ECC_M = EccLevel::M;
73 /**
74 * @deprecated 5.0.0 use EccLevel::Q instead
75 * @see \chillerlan\QRCode\Common\EccLevel::Q
76 * @var int
77 */
78 public const ECC_Q = EccLevel::Q;
79 /**
80 * @deprecated 5.0.0 use EccLevel::H instead
81 * @see \chillerlan\QRCode\Common\EccLevel::H
82 * @var int
83 */
84 public const ECC_H = EccLevel::H;
85 /**
86 * @deprecated 5.0.0 use QROutputInterface::MARKUP_HTML instead
87 * @see \chillerlan\QRCode\Output\QROutputInterface::MARKUP_HTML
88 * @var string
89 */
90 public const OUTPUT_MARKUP_HTML = QROutputInterface::MARKUP_HTML;
91 /**
92 * @deprecated 5.0.0 use QROutputInterface::MARKUP_SVG instead
93 * @see \chillerlan\QRCode\Output\QROutputInterface::MARKUP_SVG
94 * @var string
95 */
96 public const OUTPUT_MARKUP_SVG = QROutputInterface::MARKUP_SVG;
97 /**
98 * @deprecated 5.0.0 use QROutputInterface::GDIMAGE_PNG instead
99 * @see \chillerlan\QRCode\Output\QROutputInterface::GDIMAGE_PNG
100 * @var string
101 */
102 public const OUTPUT_IMAGE_PNG = QROutputInterface::GDIMAGE_PNG;
103 /**
104 * @deprecated 5.0.0 use QROutputInterface::GDIMAGE_JPG instead
105 * @see \chillerlan\QRCode\Output\QROutputInterface::GDIMAGE_JPG
106 * @var string
107 */
108 public const OUTPUT_IMAGE_JPG = QROutputInterface::GDIMAGE_JPG;
109 /**
110 * @deprecated 5.0.0 use QROutputInterface::GDIMAGE_GIF instead
111 * @see \chillerlan\QRCode\Output\QROutputInterface::GDIMAGE_GIF
112 * @var string
113 */
114 public const OUTPUT_IMAGE_GIF = QROutputInterface::GDIMAGE_GIF;
115 /**
116 * @deprecated 5.0.0 use QROutputInterface::STRING_JSON instead
117 * @see \chillerlan\QRCode\Output\QROutputInterface::STRING_JSON
118 * @var string
119 */
120 public const OUTPUT_STRING_JSON = QROutputInterface::STRING_JSON;
121 /**
122 * @deprecated 5.0.0 use QROutputInterface::STRING_TEXT instead
123 * @see \chillerlan\QRCode\Output\QROutputInterface::STRING_TEXT
124 * @var string
125 */
126 public const OUTPUT_STRING_TEXT = QROutputInterface::STRING_TEXT;
127 /**
128 * @deprecated 5.0.0 use QROutputInterface::IMAGICK instead
129 * @see \chillerlan\QRCode\Output\QROutputInterface::IMAGICK
130 * @var string
131 */
132 public const OUTPUT_IMAGICK = QROutputInterface::IMAGICK;
133 /**
134 * @deprecated 5.0.0 use QROutputInterface::FPDF instead
135 * @see \chillerlan\QRCode\Output\QROutputInterface::FPDF
136 * @var string
137 */
138 public const OUTPUT_FPDF = QROutputInterface::FPDF;
139 /**
140 * @deprecated 5.0.0 use QROutputInterface::EPS instead
141 * @see \chillerlan\QRCode\Output\QROutputInterface::EPS
142 * @var string
143 */
144 public const OUTPUT_EPS = QROutputInterface::EPS;
145 /**
146 * @deprecated 5.0.0 use QROutputInterface::CUSTOM instead
147 * @see \chillerlan\QRCode\Output\QROutputInterface::CUSTOM
148 * @var string
149 */
150 public const OUTPUT_CUSTOM = QROutputInterface::CUSTOM;
151 /**
152 * @deprecated 5.0.0 use QROutputInterface::MODES instead
153 * @see \chillerlan\QRCode\Output\QROutputInterface::MODES
154 * @var string[]
155 */
156 public const OUTPUT_MODES = QROutputInterface::MODES;
157 /**
158 * The settings container
159 *
160 * @var \chillerlan\QRCode\QROptions|\chillerlan\Settings\SettingsContainerInterface
161 */
162 protected SettingsContainerInterface $options;
163 /**
164 * A collection of one or more data segments of QRDataModeInterface instances to write
165 *
166 * @var \chillerlan\QRCode\Data\QRDataModeInterface[]
167 */
168 protected array $dataSegments = [];
169 /**
170 * The luminance source for the reader
171 */
172 protected string $luminanceSourceFQN = GDLuminanceSource::class;
173 /**
174 * QRCode constructor.
175 *
176 * PHP8: accept iterable
177 */
178 public function __construct(?SettingsContainerInterface $options = null)
179 {
180 $this->setOptions($options ?? new QROptions());
181 }
182 /**
183 * Sets an options instance
184 */
185 public function setOptions(SettingsContainerInterface $options) : self
186 {
187 $this->options = $options;
188 if ($this->options->readerUseImagickIfAvailable) {
189 $this->luminanceSourceFQN = IMagickLuminanceSource::class;
190 }
191 return $this;
192 }
193 /**
194 * Renders a QR Code for the given $data and QROptions, saves $file optionally
195 *
196 * Note: it is possible to add several data segments before calling this method with a valid $data string
197 * which will result in a mixed-mode QR Code with the given parameter as last element.
198 *
199 * @see https://github.com/chillerlan/php-qrcode/issues/246
200 *
201 * @return mixed
202 */
203 public function render(?string $data = null, ?string $file = null)
204 {
205 if ($data !== null) {
206 /** @var \chillerlan\QRCode\Data\QRDataModeInterface $dataInterface */
207 foreach (Mode::INTERFACES as $dataInterface) {
208 if ($dataInterface::validateString($data)) {
209 $this->addSegment(new $dataInterface($data));
210 break;
211 }
212 }
213 }
214 return $this->renderMatrix($this->getQRMatrix(), $file);
215 }
216 /**
217 * Renders a QR Code for the given QRMatrix and QROptions, saves $file optionally
218 *
219 * @return mixed
220 */
221 public function renderMatrix(QRMatrix $matrix, ?string $file = null)
222 {
223 return $this->initOutputInterface($matrix)->dump($file ?? $this->options->cachefile);
224 }
225 /**
226 * Returns a QRMatrix object for the given $data and current QROptions
227 *
228 * @throws \chillerlan\QRCode\Data\QRCodeDataException
229 */
230 public function getQRMatrix() : QRMatrix
231 {
232 $matrix = (new QRData($this->options, $this->dataSegments))->writeMatrix();
233 $maskPattern = $this->options->maskPattern === MaskPattern::AUTO ? MaskPattern::getBestPattern($matrix) : new MaskPattern($this->options->maskPattern);
234 $matrix->setFormatInfo($maskPattern)->mask($maskPattern);
235 return $this->addMatrixModifications($matrix);
236 }
237 /**
238 * add matrix modifications after mask pattern evaluation and before handing over to output
239 */
240 protected function addMatrixModifications(QRMatrix $matrix) : QRMatrix
241 {
242 if ($this->options->addLogoSpace) {
243 // check whether one of the dimensions was omitted
244 $logoSpaceWidth = $this->options->logoSpaceWidth ?? $this->options->logoSpaceHeight ?? 0;
245 $logoSpaceHeight = $this->options->logoSpaceHeight ?? $logoSpaceWidth;
246 $matrix->setLogoSpace($logoSpaceWidth, $logoSpaceHeight, $this->options->logoSpaceStartX, $this->options->logoSpaceStartY);
247 }
248 if ($this->options->addQuietzone) {
249 $matrix->setQuietZone($this->options->quietzoneSize);
250 }
251 return $matrix;
252 }
253 /**
254 * @deprecated 5.0.0 use QRCode::getQRMatrix() instead
255 * @see \chillerlan\QRCode\QRCode::getQRMatrix()
256 * @codeCoverageIgnore
257 */
258 public function getMatrix() : QRMatrix
259 {
260 return $this->getQRMatrix();
261 }
262 /**
263 * initializes a fresh built-in or custom QROutputInterface
264 *
265 * @throws \chillerlan\QRCode\Output\QRCodeOutputException
266 */
267 protected function initOutputInterface(QRMatrix $matrix) : QROutputInterface
268 {
269 // @todo: remove custom invocation in v6
270 $outputInterface = QROutputInterface::MODES[$this->options->outputType] ?? null;
271 if ($this->options->outputType === QROutputInterface::CUSTOM) {
272 $outputInterface = $this->options->outputInterface;
273 }
274 if (!$outputInterface || !class_exists($outputInterface)) {
275 throw new QRCodeOutputException('invalid output module');
276 }
277 if (!in_array(QROutputInterface::class, class_implements($outputInterface), \true)) {
278 throw new QRCodeOutputException('output module does not implement QROutputInterface');
279 }
280 return new $outputInterface($this->options, $matrix);
281 }
282 /**
283 * checks if a string qualifies as numeric (convenience method)
284 *
285 * @deprecated 5.0.0 use Number::validateString() instead
286 * @see \chillerlan\QRCode\Data\Number::validateString()
287 * @codeCoverageIgnore
288 */
289 public function isNumber(string $string) : bool
290 {
291 return Number::validateString($string);
292 }
293 /**
294 * checks if a string qualifies as alphanumeric (convenience method)
295 *
296 * @deprecated 5.0.0 use AlphaNum::validateString() instead
297 * @see \chillerlan\QRCode\Data\AlphaNum::validateString()
298 * @codeCoverageIgnore
299 */
300 public function isAlphaNum(string $string) : bool
301 {
302 return AlphaNum::validateString($string);
303 }
304 /**
305 * checks if a string qualifies as Kanji (convenience method)
306 *
307 * @deprecated 5.0.0 use Kanji::validateString() instead
308 * @see \chillerlan\QRCode\Data\Kanji::validateString()
309 * @codeCoverageIgnore
310 */
311 public function isKanji(string $string) : bool
312 {
313 return Kanji::validateString($string);
314 }
315 /**
316 * a dummy (convenience method)
317 *
318 * @deprecated 5.0.0 use Byte::validateString() instead
319 * @see \chillerlan\QRCode\Data\Byte::validateString()
320 * @codeCoverageIgnore
321 */
322 public function isByte(string $string) : bool
323 {
324 return Byte::validateString($string);
325 }
326 /**
327 * Adds a data segment
328 *
329 * ISO/IEC 18004:2000 8.3.6 - Mixing modes
330 * ISO/IEC 18004:2000 Annex H - Optimisation of bit stream length
331 */
332 public function addSegment(QRDataModeInterface $segment) : self
333 {
334 $this->dataSegments[] = $segment;
335 return $this;
336 }
337 /**
338 * Clears the data segments array
339 *
340 * @codeCoverageIgnore
341 */
342 public function clearSegments() : self
343 {
344 $this->dataSegments = [];
345 return $this;
346 }
347 /**
348 * Adds a numeric data segment
349 *
350 * ISO/IEC 18004:2000 8.3.2 - Numeric Mode
351 */
352 public function addNumericSegment(string $data) : self
353 {
354 return $this->addSegment(new Number($data));
355 }
356 /**
357 * Adds an alphanumeric data segment
358 *
359 * ISO/IEC 18004:2000 8.3.3 - Alphanumeric Mode
360 */
361 public function addAlphaNumSegment(string $data) : self
362 {
363 return $this->addSegment(new AlphaNum($data));
364 }
365 /**
366 * Adds a Kanji data segment (Japanese 13-bit double-byte characters, Shift-JIS)
367 *
368 * ISO/IEC 18004:2000 8.3.5 - Kanji Mode
369 */
370 public function addKanjiSegment(string $data) : self
371 {
372 return $this->addSegment(new Kanji($data));
373 }
374 /**
375 * Adds a Hanzi data segment (simplified Chinese 13-bit double-byte characters, GB2312/GB18030)
376 *
377 * GBT18284-2000 Hanzi Mode
378 */
379 public function addHanziSegment(string $data) : self
380 {
381 return $this->addSegment(new Hanzi($data));
382 }
383 /**
384 * Adds an 8-bit byte data segment
385 *
386 * ISO/IEC 18004:2000 8.3.4 - 8-bit Byte Mode
387 */
388 public function addByteSegment(string $data) : self
389 {
390 return $this->addSegment(new Byte($data));
391 }
392 /**
393 * Adds a standalone ECI designator
394 *
395 * The ECI designator must be followed by a Byte segment that contains the string encoded according to the given ECI charset
396 *
397 * ISO/IEC 18004:2000 8.3.1 - Extended Channel Interpretation (ECI) Mode
398 */
399 public function addEciDesignator(int $encoding) : self
400 {
401 return $this->addSegment(new ECI($encoding));
402 }
403 /**
404 * Adds an ECI data segment (including designator)
405 *
406 * The given string will be encoded from mb_internal_encoding() to the given ECI character set
407 *
408 * I hate this somehow, but I'll leave it for now
409 *
410 * @throws \chillerlan\QRCode\QRCodeException
411 */
412 public function addEciSegment(int $encoding, string $data) : self
413 {
414 // validate the encoding id
415 $eciCharset = new ECICharset($encoding);
416 // get charset name
417 $eciCharsetName = $eciCharset->getName();
418 // convert the string to the given charset
419 if ($eciCharsetName !== null) {
420 $data = mb_convert_encoding($data, $eciCharsetName, mb_internal_encoding());
421 return $this->addEciDesignator($eciCharset->getID())->addByteSegment($data);
422 }
423 throw new QRCodeException('unable to add ECI segment');
424 }
425 /**
426 * Reads a QR Code from a given file
427 */
428 public function readFromFile(string $path) : DecoderResult
429 {
430 return $this->readFromSource($this->luminanceSourceFQN::fromFile($path, $this->options));
431 }
432 /**
433 * Reads a QR Code from the given data blob
434 */
435 public function readFromBlob(string $blob) : DecoderResult
436 {
437 return $this->readFromSource($this->luminanceSourceFQN::fromBlob($blob, $this->options));
438 }
439 /**
440 * Reads a QR Code from the given luminance source
441 */
442 public function readFromSource(LuminanceSourceInterface $source) : DecoderResult
443 {
444 return (new Decoder())->decode($source);
445 }
446 }
447