PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.4
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.4
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / vendor_prefixed / chillerlan / php-qrcode / src / Data / QRDataAbstract.php

QRDataAbstract.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 18.4, at vendor_prefixed/chillerlan/php-qrcode/src/Data/QRDataAbstract.php

291 lines 9.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class QRDataAbstract
5 *
6 * @filesource QRDataAbstract.php
7 * @created 25.11.2015
8 * @package chillerlan\QRCode\Data
9 * @author Smiley <smiley@chillerlan.net>
10 * @copyright 2015 Smiley
11 * @license MIT
12 */
13 namespace YoastSEO_Vendor\chillerlan\QRCode\Data;
14
15 use YoastSEO_Vendor\chillerlan\QRCode\QRCode;
16 use YoastSEO_Vendor\chillerlan\QRCode\QRCodeException;
17 use YoastSEO_Vendor\chillerlan\QRCode\QROptions;
18 use YoastSEO_Vendor\chillerlan\QRCode\Helpers\BitBuffer;
19 use YoastSEO_Vendor\chillerlan\QRCode\Helpers\Polynomial;
20 use YoastSEO_Vendor\chillerlan\QRCode\Traits\ClassLoader;
21 /**
22 * Processes the binary data and maps it on a matrix which is then being returned
23 */
24 abstract class QRDataAbstract implements \YoastSEO_Vendor\chillerlan\QRCode\Data\QRDataInterface
25 {
26 use ClassLoader;
27 /**
28 * the string byte count
29 *
30 * @var int
31 */
32 protected $strlen;
33 /**
34 * the current data mode: Num, Alphanum, Kanji, Byte
35 *
36 * @var int
37 */
38 protected $datamode;
39 /**
40 * mode length bits for the version breakpoints 1-9, 10-26 and 27-40
41 *
42 * @var array
43 */
44 protected $lengthBits = [0, 0, 0];
45 /**
46 * current QR Code version
47 *
48 * @var int
49 */
50 protected $version;
51 /**
52 * the raw data that's being passed to QRMatrix::mapData()
53 *
54 * @var array
55 */
56 protected $matrixdata;
57 /**
58 * ECC temp data
59 *
60 * @var array
61 */
62 protected $ecdata;
63 /**
64 * ECC temp data
65 *
66 * @var array
67 */
68 protected $dcdata;
69 /**
70 * @var \chillerlan\QRCode\QROptions
71 */
72 protected $options;
73 /**
74 * @var \chillerlan\QRCode\Helpers\BitBuffer
75 */
76 protected $bitBuffer;
77 /**
78 * QRDataInterface constructor.
79 *
80 * @param \chillerlan\QRCode\QROptions $options
81 * @param string|null $data
82 */
83 public function __construct(\YoastSEO_Vendor\chillerlan\QRCode\QROptions $options, $data = null)
84 {
85 $this->options = $options;
86 if ($data !== null) {
87 $this->setData($data);
88 }
89 }
90 /**
91 * Sets the data string (internally called by the constructor)
92 *
93 * @param string $data
94 *
95 * @return \chillerlan\QRCode\Data\QRDataInterface
96 */
97 public function setData($data)
98 {
99 if ($this->datamode === \YoastSEO_Vendor\chillerlan\QRCode\QRCode::DATA_KANJI) {
100 $data = \mb_convert_encoding($data, 'SJIS', \mb_detect_encoding($data));
101 }
102 $this->strlen = $this->getLength($data);
103 $this->version = $this->options->version === \YoastSEO_Vendor\chillerlan\QRCode\QRCode::VERSION_AUTO ? $this->getMinimumVersion() : $this->options->version;
104 $this->matrixdata = $this->writeBitBuffer($data)->maskECC();
105 return $this;
106 }
107 /**
108 * returns a fresh matrix object with the data written for the given $maskPattern
109 *
110 * @param int $maskPattern
111 * @param bool|null $test
112 *
113 * @return \chillerlan\QRCode\Data\QRMatrix
114 */
115 public function initMatrix($maskPattern, $test = null)
116 {
117 /** @var \chillerlan\QRCode\Data\QRMatrix $matrix */
118 $matrix = $this->loadClass(\YoastSEO_Vendor\chillerlan\QRCode\Data\QRMatrix::class, null, $this->version, $this->options->eccLevel);
119 return $matrix->setFinderPattern()->setSeparators()->setAlignmentPattern()->setTimingPattern()->setVersionNumber($test)->setFormatInfo($maskPattern, $test)->setDarkModule()->mapData($this->matrixdata, $maskPattern);
120 }
121 /**
122 * returns the length bits for the version breakpoints 1-9, 10-26 and 27-40
123 *
124 * @return int
125 * @throws \chillerlan\QRCode\Data\QRCodeDataException
126 * @codeCoverageIgnore
127 */
128 protected function getLengthBits()
129 {
130 foreach ([9, 26, 40] as $key => $breakpoint) {
131 if ($this->version <= $breakpoint) {
132 return $this->lengthBits[$key];
133 }
134 }
135 throw new \YoastSEO_Vendor\chillerlan\QRCode\Data\QRCodeDataException('invalid version number: ' . $this->version);
136 }
137 /**
138 * returns the byte count of the $data string
139 *
140 * @param string $data
141 *
142 * @return int
143 */
144 protected function getLength($data)
145 {
146 return \strlen($data);
147 }
148 /**
149 * returns the minimum version number for the given string
150 *
151 * @return int
152 * @throws \chillerlan\QRCode\Data\QRCodeDataException
153 */
154 protected function getMinimumVersion()
155 {
156 // guess the version number within the given range
157 foreach (\range(\max(1, $this->options->versionMin), \min($this->options->versionMax, 40)) as $version) {
158 $maxlength = self::MAX_LENGTH[$version][\YoastSEO_Vendor\chillerlan\QRCode\QRCode::DATA_MODES[$this->datamode]][\YoastSEO_Vendor\chillerlan\QRCode\QRCode::ECC_MODES[$this->options->eccLevel]];
159 if ($this->strlen <= $maxlength) {
160 return $version;
161 }
162 }
163 throw new \YoastSEO_Vendor\chillerlan\QRCode\Data\QRCodeDataException('data exceeds ' . $maxlength . ' characters');
164 }
165 /**
166 * @see \chillerlan\QRCode\Data\QRDataAbstract::writeBitBuffer()
167 *
168 * @param string $data
169 *
170 * @return void
171 */
172 protected abstract function write($data);
173 /**
174 * writes the string data to the BitBuffer
175 *
176 * @param string $data
177 *
178 * @return \chillerlan\QRCode\Data\QRDataAbstract
179 * @throws \chillerlan\QRCode\QRCodeException
180 */
181 protected function writeBitBuffer($data)
182 {
183 $this->bitBuffer = new \YoastSEO_Vendor\chillerlan\QRCode\Helpers\BitBuffer();
184 // @todo: fixme, get real length
185 $MAX_BITS = self::MAX_BITS[$this->version][\YoastSEO_Vendor\chillerlan\QRCode\QRCode::ECC_MODES[$this->options->eccLevel]];
186 $this->bitBuffer->clear()->put($this->datamode, 4)->put($this->strlen, $this->getLengthBits());
187 $this->write($data);
188 // there was an error writing the BitBuffer data, which is... unlikely.
189 if ($this->bitBuffer->length > $MAX_BITS) {
190 throw new \YoastSEO_Vendor\chillerlan\QRCode\QRCodeException('code length overflow. (' . $this->bitBuffer->length . ' > ' . $MAX_BITS . 'bit)');
191 // @codeCoverageIgnore
192 }
193 // end code.
194 if ($this->bitBuffer->length + 4 <= $MAX_BITS) {
195 $this->bitBuffer->put(0, 4);
196 }
197 // padding
198 while ($this->bitBuffer->length % 8 !== 0) {
199 $this->bitBuffer->putBit(\false);
200 }
201 // padding
202 while (\true) {
203 if ($this->bitBuffer->length >= $MAX_BITS) {
204 break;
205 }
206 $this->bitBuffer->put(0xec, 8);
207 if ($this->bitBuffer->length >= $MAX_BITS) {
208 break;
209 }
210 $this->bitBuffer->put(0x11, 8);
211 }
212 return $this;
213 }
214 /**
215 * ECC masking
216 *
217 * @see \chillerlan\QRCode\Data\QRDataAbstract::writeBitBuffer()
218 *
219 * @link http://www.thonky.com/qr-code-tutorial/error-correction-coding
220 *
221 * @return array
222 */
223 protected function maskECC()
224 {
225 list($l1, $l2, $b1, $b2) = self::RSBLOCKS[$this->version][\YoastSEO_Vendor\chillerlan\QRCode\QRCode::ECC_MODES[$this->options->eccLevel]];
226 $rsBlocks = \array_fill(0, $l1, [$b1, $b2]);
227 $rsCount = $l1 + $l2;
228 $this->ecdata = \array_fill(0, $rsCount, null);
229 $this->dcdata = $this->ecdata;
230 if ($l2 > 0) {
231 $rsBlocks = \array_merge($rsBlocks, \array_fill(0, $l2, [$b1 + 1, $b2 + 1]));
232 }
233 $totalCodeCount = 0;
234 $maxDcCount = 0;
235 $maxEcCount = 0;
236 $offset = 0;
237 foreach ($rsBlocks as $key => $block) {
238 list($rsBlockTotal, $dcCount) = $block;
239 $ecCount = $rsBlockTotal - $dcCount;
240 $maxDcCount = \max($maxDcCount, $dcCount);
241 $maxEcCount = \max($maxEcCount, $ecCount);
242 $this->dcdata[$key] = \array_fill(0, $dcCount, null);
243 foreach ($this->dcdata[$key] as $a => $_z) {
244 $this->dcdata[$key][$a] = 0xff & $this->bitBuffer->buffer[$a + $offset];
245 }
246 list($num, $add) = $this->poly($key, $ecCount);
247 foreach ($this->ecdata[$key] as $c => $_z) {
248 $modIndex = $c + $add;
249 $this->ecdata[$key][$c] = $modIndex >= 0 ? $num[$modIndex] : 0;
250 }
251 $offset += $dcCount;
252 $totalCodeCount += $rsBlockTotal;
253 }
254 $data = \array_fill(0, $totalCodeCount, null);
255 $index = 0;
256 $mask = function ($arr, $count) use(&$data, &$index, $rsCount) {
257 for ($x = 0; $x < $count; $x++) {
258 for ($y = 0; $y < $rsCount; $y++) {
259 if ($x < \count($arr[$y])) {
260 $data[$index] = $arr[$y][$x];
261 $index++;
262 }
263 }
264 }
265 };
266 $mask($this->dcdata, $maxDcCount);
267 $mask($this->ecdata, $maxEcCount);
268 return $data;
269 }
270 /**
271 * @param int $key
272 * @param int $count
273 *
274 * @return int[]
275 */
276 protected function poly($key, $count)
277 {
278 $rsPoly = new \YoastSEO_Vendor\chillerlan\QRCode\Helpers\Polynomial();
279 $modPoly = new \YoastSEO_Vendor\chillerlan\QRCode\Helpers\Polynomial();
280 for ($i = 0; $i < $count; $i++) {
281 $modPoly->setNum([1, $modPoly->gexp($i)]);
282 $rsPoly->multiply($modPoly->getNum());
283 }
284 $rsPolyCount = \count($rsPoly->getNum());
285 $modPoly->setNum($this->dcdata[$key], $rsPolyCount - 1)->mod($rsPoly->getNum());
286 $this->ecdata[$key] = \array_fill(0, $rsPolyCount - 1, null);
287 $num = $modPoly->getNum();
288 return [$num, \count($num) - \count($this->ecdata[$key])];
289 }
290 }
291