qrsplit.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. <?php
  2. class QRsplit
  3. {
  4. public $dataStr = '';
  5. public $input;
  6. public $modeHint;
  7. public function __construct($dataStr, $input, $modeHint)
  8. {
  9. $this->dataStr = $dataStr;
  10. $this->input = $input;
  11. $this->modeHint = $modeHint;
  12. }
  13. static public function isdigitat($str, $pos)
  14. {
  15. if (strlen($str) <= $pos) {
  16. return false;
  17. }
  18. return ord('0') <= ord($str[$pos]) && ord($str[$pos]) <= ord('9');
  19. }
  20. static public function isalnumat($str, $pos)
  21. {
  22. if (strlen($str) <= $pos) {
  23. return false;
  24. }
  25. return 0 <= QRinput::lookAnTable(ord($str[$pos]));
  26. }
  27. public function identifyMode($pos)
  28. {
  29. if (strlen($this->dataStr) <= $pos) {
  30. return QR_MODE_NUL;
  31. }
  32. $c = $this->dataStr[$pos];
  33. if (self::isdigitat($this->dataStr, $pos)) {
  34. return QR_MODE_NUM;
  35. }
  36. else if (self::isalnumat($this->dataStr, $pos)) {
  37. return QR_MODE_AN;
  38. }
  39. else if ($this->modeHint == QR_MODE_KANJI) {
  40. if ($pos + 1 < strlen($this->dataStr)) {
  41. $d = $this->dataStr[$pos + 1];
  42. $word = ord($c) << 8 | ord($d);
  43. if (33088 <= $word && $word <= 40956 || 57408 <= $word && $word <= 60351) {
  44. return QR_MODE_KANJI;
  45. }
  46. }
  47. }
  48. return QR_MODE_8;
  49. }
  50. public function eatNum()
  51. {
  52. $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
  53. $p = 0;
  54. while (self::isdigitat($this->dataStr, $p)) {
  55. $p++;
  56. }
  57. $run = $p;
  58. $mode = $this->identifyMode($p);
  59. if ($mode == QR_MODE_8) {
  60. $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln + QRinput::estimateBitsMode8(1) - QRinput::estimateBitsMode8($run + 1);
  61. if (0 < $dif) {
  62. return $this->eat8();
  63. }
  64. }
  65. if ($mode == QR_MODE_AN) {
  66. $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln + QRinput::estimateBitsModeAn(1) - QRinput::estimateBitsModeAn($run + 1);
  67. if (0 < $dif) {
  68. return $this->eatAn();
  69. }
  70. }
  71. $ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr));
  72. if ($ret < 0) {
  73. return -1;
  74. }
  75. return $run;
  76. }
  77. public function eatAn()
  78. {
  79. $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
  80. $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
  81. $p = 0;
  82. while (self::isalnumat($this->dataStr, $p)) {
  83. if (self::isdigitat($this->dataStr, $p)) {
  84. $q = $p;
  85. while (self::isdigitat($this->dataStr, $q)) {
  86. $q++;
  87. }
  88. $dif = QRinput::estimateBitsModeAn($p) + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln - QRinput::estimateBitsModeAn($q);
  89. if ($dif < 0) {
  90. break;
  91. }
  92. else {
  93. $p = $q;
  94. }
  95. }
  96. else {
  97. $p++;
  98. }
  99. }
  100. $run = $p;
  101. if (!self::isalnumat($this->dataStr, $p)) {
  102. $dif = QRinput::estimateBitsModeAn($run) + 4 + $la + QRinput::estimateBitsMode8(1) - QRinput::estimateBitsMode8($run + 1);
  103. if (0 < $dif) {
  104. return $this->eat8();
  105. }
  106. }
  107. $ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr));
  108. if ($ret < 0) {
  109. return -1;
  110. }
  111. return $run;
  112. }
  113. public function eatKanji()
  114. {
  115. $p = 0;
  116. while ($this->identifyMode($p) == QR_MODE_KANJI) {
  117. $p += 2;
  118. }
  119. $ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr));
  120. if ($ret < 0) {
  121. return -1;
  122. }
  123. return $run;
  124. }
  125. public function eat8()
  126. {
  127. $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());
  128. $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());
  129. $p = 1;
  130. $dataStrLen = strlen($this->dataStr);
  131. while ($p < $dataStrLen) {
  132. $mode = $this->identifyMode($p);
  133. if ($mode == QR_MODE_KANJI) {
  134. break;
  135. }
  136. if ($mode == QR_MODE_NUM) {
  137. $q = $p;
  138. while (self::isdigitat($this->dataStr, $q)) {
  139. $q++;
  140. }
  141. $dif = QRinput::estimateBitsMode8($p) + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln - QRinput::estimateBitsMode8($q);
  142. if ($dif < 0) {
  143. break;
  144. }
  145. else {
  146. $p = $q;
  147. }
  148. }
  149. else if ($mode == QR_MODE_AN) {
  150. $q = $p;
  151. while (self::isalnumat($this->dataStr, $q)) {
  152. $q++;
  153. }
  154. $dif = QRinput::estimateBitsMode8($p) + QRinput::estimateBitsModeAn($q - $p) + 4 + $la - QRinput::estimateBitsMode8($q);
  155. if ($dif < 0) {
  156. break;
  157. }
  158. else {
  159. $p = $q;
  160. }
  161. }
  162. else {
  163. $p++;
  164. }
  165. }
  166. $run = $p;
  167. $ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr));
  168. if ($ret < 0) {
  169. return -1;
  170. }
  171. return $run;
  172. }
  173. public function splitString()
  174. {
  175. while (0 < strlen($this->dataStr)) {
  176. if ($this->dataStr == '') {
  177. return 0;
  178. }
  179. $mode = $this->identifyMode(0);
  180. switch ($mode) {
  181. case QR_MODE_NUM:
  182. $length = $this->eatNum();
  183. break;
  184. case QR_MODE_AN:
  185. $length = $this->eatAn();
  186. break;
  187. case QR_MODE_KANJI:
  188. if ($hint == QR_MODE_KANJI) {
  189. $length = $this->eatKanji();
  190. }
  191. else {
  192. $length = $this->eat8();
  193. }
  194. break;
  195. default:
  196. $length = $this->eat8();
  197. break;
  198. }
  199. if ($length == 0) {
  200. return 0;
  201. }
  202. if ($length < 0) {
  203. return -1;
  204. }
  205. $this->dataStr = substr($this->dataStr, $length);
  206. }
  207. }
  208. public function toUpper()
  209. {
  210. $stringLen = strlen($this->dataStr);
  211. $p = 0;
  212. while ($p < $stringLen) {
  213. $mode = self::identifyMode(substr($this->dataStr, $p), $this->modeHint);
  214. if ($mode == QR_MODE_KANJI) {
  215. $p += 2;
  216. }
  217. else {
  218. if (ord('a') <= ord($this->dataStr[$p]) && ord($this->dataStr[$p]) <= ord('z')) {
  219. $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
  220. }
  221. $p++;
  222. }
  223. }
  224. return $this->dataStr;
  225. }
  226. static public function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true)
  227. {
  228. if (is_null($string) || $string == '\\0' || $string == '') {
  229. throw new Exception('empty string!!!');
  230. }
  231. $split = new QRsplit($string, $input, $modeHint);
  232. if (!$casesensitive) {
  233. $split->toUpper();
  234. }
  235. return $split->splitString();
  236. }
  237. }
  238. ?>