国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

312 lines
11KB

  1. <?php
  2. if (!defined('DEDEINC')) exit('dedebiz');
  3. /*
  4. * PHP QR Code encoder
  5. *
  6. * Input splitting classes
  7. *
  8. * Based on libqrencode C library distributed under LGPL 2.1
  9. * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
  10. *
  11. * PHP QR Code is distributed under LGPL 3
  12. * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
  13. *
  14. * The following data / specifications are taken from
  15. * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
  16. * or
  17. * "Automatic identification and data capture techniques --
  18. * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
  19. *
  20. * This library is free software; you can redistribute it and/or
  21. * modify it under the terms of the GNU Lesser General Public
  22. * License as published by the Free Software Foundation; either
  23. * version 3 of the License, or any later version.
  24. *
  25. * This library is distributed in the hope that it will be useful,
  26. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  28. * Lesser General Public License for more details.
  29. *
  30. * You should have received a copy of the GNU Lesser General Public
  31. * License along with this library; if not, write to the Free Software
  32. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  33. */
  34. class QRsplit {
  35. public $dataStr = '';
  36. public $input;
  37. public $modeHint;
  38. //----------------------------------------------------------------------
  39. public function __construct($dataStr, $input, $modeHint)
  40. {
  41. $this->dataStr = $dataStr;
  42. $this->input = $input;
  43. $this->modeHint = $modeHint;
  44. }
  45. //----------------------------------------------------------------------
  46. public static function isdigitat($str, $pos)
  47. {
  48. if ($pos >= strlen($str))
  49. return false;
  50. return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
  51. }
  52. //----------------------------------------------------------------------
  53. public static function isalnumat($str, $pos)
  54. {
  55. if ($pos >= strlen($str))
  56. return false;
  57. return (QRinput::lookAnTable(ord($str[$pos])) >= 0);
  58. }
  59. //----------------------------------------------------------------------
  60. public function identifyMode($pos)
  61. {
  62. if ($pos >= strlen($this->dataStr))
  63. return QR_MODE_NUL;
  64. $c = $this->dataStr[$pos];
  65. if (self::isdigitat($this->dataStr, $pos)) {
  66. return QR_MODE_NUM;
  67. } else if (self::isalnumat($this->dataStr, $pos)) {
  68. return QR_MODE_AN;
  69. } else if ($this->modeHint == QR_MODE_KANJI) {
  70. if ($pos+1 < strlen($this->dataStr))
  71. {
  72. $d = $this->dataStr[$pos+1];
  73. $word = (ord($c) << 8) | ord($d);
  74. if (($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) {
  75. return QR_MODE_KANJI;
  76. }
  77. }
  78. }
  79. return QR_MODE_8;
  80. }
  81. //----------------------------------------------------------------------
  82. public function eatNum()
  83. {
  84. $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
  85. $p = 0;
  86. while(self::isdigitat($this->dataStr, $p)) {
  87. $p++;
  88. }
  89. $run = $p;
  90. $mode = $this->identifyMode($p);
  91. if ($mode == QR_MODE_8) {
  92. $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
  93. + QRinput::estimateBitsMode8(1) //+ 4 + l8
  94. - QRinput::estimateBitsMode8($run + 1); //- 4 - l8
  95. if ($dif > 0) {
  96. return $this->eat8();
  97. }
  98. }
  99. if ($mode == QR_MODE_AN) {
  100. $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln
  101. + QRinput::estimateBitsModeAn(1) //+ 4 + la
  102. - QRinput::estimateBitsModeAn($run + 1);//- 4 - la
  103. if ($dif > 0) {
  104. return $this->eatAn();
  105. }
  106. }
  107. $ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr));
  108. if ($ret < 0)
  109. return -1;
  110. return $run;
  111. }
  112. //----------------------------------------------------------------------
  113. public function eatAn()
  114. {
  115. $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
  116. $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
  117. $p = 0;
  118. while(self::isalnumat($this->dataStr, $p)) {
  119. if (self::isdigitat($this->dataStr, $p)) {
  120. $q = $p;
  121. while(self::isdigitat($this->dataStr, $q)) {
  122. $q++;
  123. }
  124. $dif = QRinput::estimateBitsModeAn($p) //+ 4 + la
  125. + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
  126. - QRinput::estimateBitsModeAn($q); //- 4 - la
  127. if ($dif < 0) {
  128. break;
  129. } else {
  130. $p = $q;
  131. }
  132. } else {
  133. $p++;
  134. }
  135. }
  136. $run = $p;
  137. if (!self::isalnumat($this->dataStr, $p)) {
  138. $dif = QRinput::estimateBitsModeAn($run) + 4 + $la
  139. + QRinput::estimateBitsMode8(1) //+ 4 + l8
  140. - QRinput::estimateBitsMode8($run + 1); //- 4 - l8
  141. if ($dif > 0) {
  142. return $this->eat8();
  143. }
  144. }
  145. $ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr));
  146. if ($ret < 0)
  147. return -1;
  148. return $run;
  149. }
  150. //----------------------------------------------------------------------
  151. public function eatKanji()
  152. {
  153. $p = 0;
  154. while($this->identifyMode($p) == QR_MODE_KANJI) {
  155. $p += 2;
  156. }
  157. $ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr));
  158. if ($ret < 0)
  159. return -1;
  160. return $run;
  161. }
  162. //----------------------------------------------------------------------
  163. public function eat8()
  164. {
  165. $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
  166. $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
  167. $p = 1;
  168. $dataStrLen = strlen($this->dataStr);
  169. while($p < $dataStrLen) {
  170. $mode = $this->identifyMode($p);
  171. if ($mode == QR_MODE_KANJI) {
  172. break;
  173. }
  174. if ($mode == QR_MODE_NUM) {
  175. $q = $p;
  176. while(self::isdigitat($this->dataStr, $q)) {
  177. $q++;
  178. }
  179. $dif = QRinput::estimateBitsMode8($p) //+ 4 + l8
  180. + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln
  181. - QRinput::estimateBitsMode8($q); //- 4 - l8
  182. if ($dif < 0) {
  183. break;
  184. } else {
  185. $p = $q;
  186. }
  187. } else if ($mode == QR_MODE_AN) {
  188. $q = $p;
  189. while(self::isalnumat($this->dataStr, $q)) {
  190. $q++;
  191. }
  192. $dif = QRinput::estimateBitsMode8($p) //+ 4 + l8
  193. + QRinput::estimateBitsModeAn($q - $p) + 4 + $la
  194. - QRinput::estimateBitsMode8($q); //- 4 - l8
  195. if ($dif < 0) {
  196. break;
  197. } else {
  198. $p = $q;
  199. }
  200. } else {
  201. $p++;
  202. }
  203. }
  204. $run = $p;
  205. $ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr));
  206. if ($ret < 0)
  207. return -1;
  208. return $run;
  209. }
  210. //----------------------------------------------------------------------
  211. public function splitString()
  212. {
  213. while (strlen($this->dataStr) > 0)
  214. {
  215. if ($this->dataStr == '')
  216. return 0;
  217. $mode = $this->identifyMode(0);
  218. switch ($mode) {
  219. case QR_MODE_NUM: $length = $this->eatNum(); break;
  220. case QR_MODE_AN: $length = $this->eatAn(); break;
  221. case QR_MODE_KANJI:
  222. if ($hint == QR_MODE_KANJI)
  223. $length = $this->eatKanji();
  224. else $length = $this->eat8();
  225. break;
  226. default: $length = $this->eat8(); break;
  227. }
  228. if ($length == 0) return 0;
  229. if ($length < 0) return -1;
  230. $this->dataStr = substr($this->dataStr, $length);
  231. }
  232. }
  233. //----------------------------------------------------------------------
  234. public function toUpper()
  235. {
  236. $stringLen = strlen($this->dataStr);
  237. $p = 0;
  238. while ($p<$stringLen) {
  239. $mode = self::identifyMode(substr($this->dataStr, $p), $this->modeHint);
  240. if ($mode == QR_MODE_KANJI) {
  241. $p += 2;
  242. } else {
  243. if (ord($this->dataStr[$p]) >= ord('a') && ord($this->dataStr[$p]) <= ord('z')) {
  244. $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
  245. }
  246. $p++;
  247. }
  248. }
  249. return $this->dataStr;
  250. }
  251. //----------------------------------------------------------------------
  252. public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true)
  253. {
  254. if (is_null($string) || $string == '\0' || $string == '') {
  255. throw new Exception('empty string!!!');
  256. }
  257. $split = new QRsplit($string, $input, $modeHint);
  258. if (!$casesensitive)
  259. $split->toUpper();
  260. return $split->splitString();
  261. }
  262. }