aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/chillerlan/php-qrcode/src/QRCode.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/chillerlan/php-qrcode/src/QRCode.php')
-rwxr-xr-xvendor/chillerlan/php-qrcode/src/QRCode.php313
1 files changed, 313 insertions, 0 deletions
diff --git a/vendor/chillerlan/php-qrcode/src/QRCode.php b/vendor/chillerlan/php-qrcode/src/QRCode.php
new file mode 100755
index 000000000..908030feb
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/QRCode.php
@@ -0,0 +1,313 @@
+<?php
+/**
+ * Class QRCode
+ *
+ * @filesource QRCode.php
+ * @created 26.11.2015
+ * @package chillerlan\QRCode
+ * @author Smiley <smiley@chillerlan.net>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode;
+
+use chillerlan\QRCode\Data\{
+ AlphaNum, Byte, Kanji, MaskPatternTester, Number, QRCodeDataException, QRDataInterface, QRMatrix
+};
+use chillerlan\QRCode\Output\{
+ QRCodeOutputException, QRFpdf, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString
+};
+use chillerlan\Settings\SettingsContainerInterface;
+
+use function call_user_func_array, class_exists, in_array, ord, strlen, strtolower, str_split;
+
+/**
+ * Turns a text string into a Model 2 QR Code
+ *
+ * @see https://github.com/kazuhikoarase/qrcode-generator/tree/master/php
+ * @see http://www.qrcode.com/en/codes/model12.html
+ * @see https://www.swisseduc.ch/informatik/theoretische_informatik/qr_codes/docs/qr_standard.pdf
+ * @see https://en.wikipedia.org/wiki/QR_code
+ * @see http://www.thonky.com/qr-code-tutorial/
+ */
+class QRCode{
+
+ /** @var int */
+ public const VERSION_AUTO = -1;
+ /** @var int */
+ public const MASK_PATTERN_AUTO = -1;
+
+ // ISO/IEC 18004:2000 Table 2
+
+ /** @var int */
+ public const DATA_NUMBER = 0b0001;
+ /** @var int */
+ public const DATA_ALPHANUM = 0b0010;
+ /** @var int */
+ public const DATA_BYTE = 0b0100;
+ /** @var int */
+ public const DATA_KANJI = 0b1000;
+
+ /**
+ * References to the keys of the following tables:
+ *
+ * @see \chillerlan\QRCode\Data\QRDataInterface::MAX_LENGTH
+ *
+ * @var int[]
+ */
+ public const DATA_MODES = [
+ self::DATA_NUMBER => 0,
+ self::DATA_ALPHANUM => 1,
+ self::DATA_BYTE => 2,
+ self::DATA_KANJI => 3,
+ ];
+
+ // ISO/IEC 18004:2000 Tables 12, 25
+
+ /** @var int */
+ public const ECC_L = 0b01; // 7%.
+ /** @var int */
+ public const ECC_M = 0b00; // 15%.
+ /** @var int */
+ public const ECC_Q = 0b11; // 25%.
+ /** @var int */
+ public const ECC_H = 0b10; // 30%.
+
+ /**
+ * References to the keys of the following tables:
+ *
+ * @see \chillerlan\QRCode\Data\QRDataInterface::MAX_BITS
+ * @see \chillerlan\QRCode\Data\QRDataInterface::RSBLOCKS
+ * @see \chillerlan\QRCode\Data\QRMatrix::formatPattern
+ *
+ * @var int[]
+ */
+ public const ECC_MODES = [
+ self::ECC_L => 0,
+ self::ECC_M => 1,
+ self::ECC_Q => 2,
+ self::ECC_H => 3,
+ ];
+
+ /** @var string */
+ public const OUTPUT_MARKUP_HTML = 'html';
+ /** @var string */
+ public const OUTPUT_MARKUP_SVG = 'svg';
+ /** @var string */
+ public const OUTPUT_IMAGE_PNG = 'png';
+ /** @var string */
+ public const OUTPUT_IMAGE_JPG = 'jpg';
+ /** @var string */
+ public const OUTPUT_IMAGE_GIF = 'gif';
+ /** @var string */
+ public const OUTPUT_STRING_JSON = 'json';
+ /** @var string */
+ public const OUTPUT_STRING_TEXT = 'text';
+ /** @var string */
+ public const OUTPUT_IMAGICK = 'imagick';
+ /** @var string */
+ public const OUTPUT_FPDF = 'fpdf';
+ /** @var string */
+ public const OUTPUT_CUSTOM = 'custom';
+
+ /**
+ * Map of built-in output modules => capabilities
+ *
+ * @var string[][]
+ */
+ public const OUTPUT_MODES = [
+ QRMarkup::class => [
+ self::OUTPUT_MARKUP_SVG,
+ self::OUTPUT_MARKUP_HTML,
+ ],
+ QRImage::class => [
+ self::OUTPUT_IMAGE_PNG,
+ self::OUTPUT_IMAGE_GIF,
+ self::OUTPUT_IMAGE_JPG,
+ ],
+ QRString::class => [
+ self::OUTPUT_STRING_JSON,
+ self::OUTPUT_STRING_TEXT,
+ ],
+ QRImagick::class => [
+ self::OUTPUT_IMAGICK,
+ ],
+ QRFpdf::class => [
+ self::OUTPUT_FPDF
+ ]
+ ];
+
+ /**
+ * Map of data mode => interface
+ *
+ * @var string[]
+ */
+ protected const DATA_INTERFACES = [
+ 'number' => Number::class,
+ 'alphanum' => AlphaNum::class,
+ 'kanji' => Kanji::class,
+ 'byte' => Byte::class,
+ ];
+
+ /**
+ * The settings container
+ *
+ * @var \chillerlan\QRCode\QROptions|\chillerlan\Settings\SettingsContainerInterface
+ */
+ protected SettingsContainerInterface $options;
+
+ /**
+ * The selected data interface (Number, AlphaNum, Kanji, Byte)
+ */
+ protected QRDataInterface $dataInterface;
+
+ /**
+ * QRCode constructor.
+ *
+ * Sets the options instance, determines the current mb-encoding and sets it to UTF-8
+ */
+ public function __construct(SettingsContainerInterface $options = null){
+ $this->options = $options ?? new QROptions;
+ }
+
+ /**
+ * Renders a QR Code for the given $data and QROptions
+ *
+ * @return mixed
+ */
+ public function render(string $data, string $file = null){
+ return $this->initOutputInterface($data)->dump($file);
+ }
+
+ /**
+ * Returns a QRMatrix object for the given $data and current QROptions
+ *
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ */
+ public function getMatrix(string $data):QRMatrix{
+
+ if(empty($data)){
+ throw new QRCodeDataException('QRCode::getMatrix() No data given.');
+ }
+
+ $this->dataInterface = $this->initDataInterface($data);
+
+ $maskPattern = $this->options->maskPattern === $this::MASK_PATTERN_AUTO
+ ? (new MaskPatternTester($this->dataInterface))->getBestMaskPattern()
+ : $this->options->maskPattern;
+
+ $matrix = $this->dataInterface->initMatrix($maskPattern);
+
+ if((bool)$this->options->addQuietzone){
+ $matrix->setQuietZone($this->options->quietzoneSize);
+ }
+
+ return $matrix;
+ }
+
+ /**
+ * returns a fresh QRDataInterface for the given $data
+ *
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ */
+ public function initDataInterface(string $data):QRDataInterface{
+
+ // allow forcing the data mode
+ // see https://github.com/chillerlan/php-qrcode/issues/39
+ $interface = $this::DATA_INTERFACES[strtolower($this->options->dataModeOverride)] ?? null;
+
+ if($interface !== null){
+ return new $interface($this->options, $data);
+ }
+
+ foreach($this::DATA_INTERFACES as $mode => $dataInterface){
+
+ if(call_user_func_array([$this, 'is'.$mode], [$data])){
+ return new $dataInterface($this->options, $data);
+ }
+
+ }
+
+ throw new QRCodeDataException('invalid data type'); // @codeCoverageIgnore
+ }
+
+ /**
+ * returns a fresh (built-in) QROutputInterface
+ *
+ * @throws \chillerlan\QRCode\Output\QRCodeOutputException
+ */
+ protected function initOutputInterface(string $data):QROutputInterface{
+
+ if($this->options->outputType === $this::OUTPUT_CUSTOM && class_exists($this->options->outputInterface)){
+ /** @phan-suppress-next-line PhanTypeExpectedObjectOrClassName */
+ return new $this->options->outputInterface($this->options, $this->getMatrix($data));
+ }
+
+ foreach($this::OUTPUT_MODES as $outputInterface => $modes){
+
+ if(in_array($this->options->outputType, $modes, true) && class_exists($outputInterface)){
+ return new $outputInterface($this->options, $this->getMatrix($data));
+ }
+
+ }
+
+ throw new QRCodeOutputException('invalid output type');
+ }
+
+ /**
+ * checks if a string qualifies as numeric
+ */
+ public function isNumber(string $string):bool{
+ return $this->checkString($string, QRDataInterface::CHAR_MAP_NUMBER);
+ }
+
+ /**
+ * checks if a string qualifies as alphanumeric
+ */
+ public function isAlphaNum(string $string):bool{
+ return $this->checkString($string, QRDataInterface::CHAR_MAP_ALPHANUM);
+ }
+
+ /**
+ * checks is a given $string matches the characters of a given $charmap, returns false on the first invalid occurence.
+ */
+ protected function checkString(string $string, array $charmap):bool{
+
+ foreach(str_split($string) as $chr){
+ if(!isset($charmap[$chr])){
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * checks if a string qualifies as Kanji
+ */
+ public function isKanji(string $string):bool{
+ $i = 0;
+ $len = strlen($string);
+
+ while($i + 1 < $len){
+ $c = ((0xff & ord($string[$i])) << 8) | (0xff & ord($string[$i + 1]));
+
+ if(!($c >= 0x8140 && $c <= 0x9FFC) && !($c >= 0xE040 && $c <= 0xEBBF)){
+ return false;
+ }
+
+ $i += 2;
+ }
+
+ return $i >= $len;
+ }
+
+ /**
+ * a dummy
+ */
+ public function isByte(string $data):bool{
+ return $data !== '';
+ }
+
+}