qrcode.class.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. <?php
  2. define ("QRCODE_DATA_PATH","./Data/qrcode_data");
  3. /*
  4. #
  5. # QRcode class library for PHP4/5 version 0.50beta12 (C)2002-2009,Y.Swetake
  6. #
  7. # This version supports QRcode model2 version 1-40.
  8. # Several functions are not supported.
  9. #
  10. */
  11. class Qrcode{
  12. var $qrcode_error_correct;
  13. var $qrcode_version;
  14. var $qrcode_structureappend_n;
  15. var $qrcode_structureappend_m;
  16. var $qrcode_structureappend_parity;
  17. var $qrcode_structureappend_originaldata;
  18. public function __construct(){
  19. $this->qrcode_error_correct="M";
  20. $this->qrcode_version=0;
  21. $this->qrcode_structureappend_n=0;
  22. $this->qrcode_structureappend_m=0;
  23. $this->qrcode_structureappend_parity="";
  24. $this->qrcode_structureappend_originaldata="";
  25. }
  26. public function set_qrcode_version($z){
  27. if ($z>=0 && $z<=40){
  28. $this->qrcode_version=$z;
  29. }
  30. }
  31. public function set_qrcode_error_correct($z){
  32. $this->qrcode_error_correct=$z;
  33. }
  34. public function get_qrcode_version(){
  35. return($this->qrcode_version);
  36. }
  37. public function set_structureappend($m,$n,$p){
  38. if ($n>1 && $n<=16 && $m>0 && $m<=16 && $p>=0 && $p<=255){
  39. $this->qrcode_structureappend_m=$m;
  40. $this->qrcode_structureappend_n=$n;
  41. $this->qrcode_structureappend_parity=$p;
  42. }
  43. }
  44. public function cal_structureappend_parity($originaldata){
  45. $originaldata_length=strlen($originaldata);
  46. if ($originaldata_length>1){
  47. $structureappend_parity=0;
  48. $i=0;
  49. while ($i<$originaldata_length){
  50. $structureappend_parity=($structureappend_parity ^ ord(substr($originaldata,$i,1)));
  51. $i++;
  52. }
  53. return($structureappend_parity);
  54. }
  55. }
  56. public function cal_qrcode($qrcode_data_string){
  57. $data_length=strlen($qrcode_data_string);
  58. if ($data_length<=0) {
  59. trigger_error("Data do not exist.",E_USER_ERROR);
  60. exit;
  61. }
  62. $data_counter=0;
  63. if ($this->qrcode_structureappend_n>1){
  64. $data_value[0]=3;
  65. $data_bits[0]=4;
  66. $data_value[1]=$this->qrcode_structureappend_m-1;
  67. $data_bits[1]=4;
  68. $data_value[2]=$this->qrcode_structureappend_n-1;
  69. $data_bits[2]=4;
  70. $data_value[3]=$this->qrcode_structureappend_parity;
  71. $data_bits[3]=8;
  72. $data_counter=4;
  73. }
  74. $data_bits[$data_counter]=4;
  75. /* --- determine encode mode */
  76. if (preg_match("/[^0-9]/",$qrcode_data_string)!=0){
  77. if (preg_match("/[^0-9A-Z \$\*\%\+\.\/\:\-]/",$qrcode_data_string)!=0) {
  78. /* --- 8bit byte mode */
  79. $codeword_num_plus=array(0,0,0,0,0,0,0,0,0,0,
  80. 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
  81. 8,8,8,8,8,8,8,8,8,8,8,8,8,8);
  82. $data_value[$data_counter]=4;
  83. $data_counter++;
  84. $data_value[$data_counter]=$data_length;
  85. $data_bits[$data_counter]=8; /* #version 1-9 */
  86. $codeword_num_counter_value=$data_counter;
  87. $data_counter++;
  88. $i=0;
  89. while ($i<$data_length){
  90. $data_value[$data_counter]=ord(substr($qrcode_data_string,$i,1));
  91. $data_bits[$data_counter]=8;
  92. $data_counter++;
  93. $i++;
  94. }
  95. } else {
  96. /* ---- alphanumeric mode */
  97. $codeword_num_plus=array(0,0,0,0,0,0,0,0,0,0,
  98. 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  99. 4,4,4,4,4,4,4,4,4,4,4,4,4,4);
  100. $data_value[$data_counter]=2;
  101. $data_counter++;
  102. $data_value[$data_counter]=$data_length;
  103. $data_bits[$data_counter]=9; /* #version 1-9 */
  104. $codeword_num_counter_value=$data_counter;
  105. $alphanumeric_character_hash=array("0"=>0,"1"=>1,"2"=>2,"3"=>3,
  106. "4"=>4,"5"=>5,"6"=>6,"7"=>7,"8"=>8,"9"=>9,"A"=>10,"B"=>11,"C"=>12,"D"=>13,
  107. "E"=>14,"F"=>15,"G"=>16,"H"=>17,"I"=>18,"J"=>19,"K"=>20,"L"=>21,"M"=>22,
  108. "N"=>23,"O"=>24,"P"=>25,"Q"=>26,"R"=>27,"S"=>28,"T"=>29,"U"=>30,"V"=>31,
  109. "W"=>32,"X"=>33,"Y"=>34,"Z"=>35," "=>36,"$"=>37,"%"=>38,"*"=>39,
  110. "+"=>40,"-"=>41,"."=>42,"/"=>43,":"=>44);
  111. $i=0;
  112. $data_counter++;
  113. while ($i<$data_length){
  114. if (($i %2)==0){
  115. $data_value[$data_counter]=$alphanumeric_character_hash[substr($qrcode_data_string,$i,1)];
  116. $data_bits[$data_counter]=6;
  117. } else {
  118. $data_value[$data_counter]=$data_value[$data_counter]*45+$alphanumeric_character_hash[substr($qrcode_data_string,$i,1)];
  119. $data_bits[$data_counter]=11;
  120. $data_counter++;
  121. }
  122. $i++;
  123. }
  124. }
  125. } else {
  126. /* ---- numeric mode */
  127. $codeword_num_plus=array(0,0,0,0,0,0,0,0,0,0,
  128. 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  129. 4,4,4,4,4,4,4,4,4,4,4,4,4,4);
  130. $data_value[$data_counter]=1;
  131. $data_counter++;
  132. $data_value[$data_counter]=$data_length;
  133. $data_bits[$data_counter]=10; /* #version 1-9 */
  134. $codeword_num_counter_value=$data_counter;
  135. $i=0;
  136. $data_counter++;
  137. while ($i<$data_length){
  138. if (($i % 3)==0){
  139. $data_value[$data_counter]=substr($qrcode_data_string,$i,1);
  140. $data_bits[$data_counter]=4;
  141. } else {
  142. $data_value[$data_counter]=$data_value[$data_counter]*10+substr($qrcode_data_string,$i,1);
  143. if (($i % 3)==1){
  144. $data_bits[$data_counter]=7;
  145. } else {
  146. $data_bits[$data_counter]=10;
  147. $data_counter++;
  148. }
  149. }
  150. $i++;
  151. }
  152. }
  153. if (@$data_bits[$data_counter]>0) {
  154. $data_counter++;
  155. }
  156. $i=0;
  157. $total_data_bits=0;
  158. while($i<$data_counter){
  159. $total_data_bits+=$data_bits[$i];
  160. $i++;
  161. }
  162. $ecc_character_hash=array("L"=>"1",
  163. "l"=>"1",
  164. "M"=>"0",
  165. "m"=>"0",
  166. "Q"=>"3",
  167. "q"=>"3",
  168. "H"=>"2",
  169. "h"=>"2");
  170. $ec=@$ecc_character_hash[$this->qrcode_error_correct];
  171. if (!$ec){$ec=0;}
  172. $max_data_bits_array=array(
  173. 0,128,224,352,512,688,864,992,1232,1456,1728,
  174. 2032,2320,2672,2920,3320,3624,4056,4504,5016,5352,
  175. 5712,6256,6880,7312,8000,8496,9024,9544,10136,10984,
  176. 11640,12328,13048,13800,14496,15312,15936,16816,17728,18672,
  177. 152,272,440,640,864,1088,1248,1552,1856,2192,
  178. 2592,2960,3424,3688,4184,4712,5176,5768,6360,6888,
  179. 7456,8048,8752,9392,10208,10960,11744,12248,13048,13880,
  180. 14744,15640,16568,17528,18448,19472,20528,21616,22496,23648,
  181. 72,128,208,288,368,480,528,688,800,976,
  182. 1120,1264,1440,1576,1784,2024,2264,2504,2728,3080,
  183. 3248,3536,3712,4112,4304,4768,5024,5288,5608,5960,
  184. 6344,6760,7208,7688,7888,8432,8768,9136,9776,10208,
  185. 104,176,272,384,496,608,704,880,1056,1232,
  186. 1440,1648,1952,2088,2360,2600,2936,3176,3560,3880,
  187. 4096,4544,4912,5312,5744,6032,6464,6968,7288,7880,
  188. 8264,8920,9368,9848,10288,10832,11408,12016,12656,13328
  189. );
  190. if (!$this->qrcode_version){
  191. /* #--- auto version select */
  192. $i=1+40*$ec;
  193. $j=$i+39;
  194. $this->qrcode_version=1;
  195. while ($i<=$j){
  196. if (($max_data_bits_array[$i])>=$total_data_bits+$codeword_num_plus[$this->qrcode_version] ){
  197. $max_data_bits=$max_data_bits_array[$i];
  198. break;
  199. }
  200. $i++;
  201. $this->qrcode_version++;
  202. }
  203. } else {
  204. $max_data_bits=$max_data_bits_array[$this->qrcode_version+40*$ec];
  205. }
  206. $total_data_bits+=$codeword_num_plus[$this->qrcode_version];
  207. $data_bits[$codeword_num_counter_value]+=$codeword_num_plus[$this->qrcode_version];
  208. $max_codewords_array=array(0,26,44,70,100,134,172,196,242,
  209. 292,346,404,466,532,581,655,733,815,901,991,1085,1156,
  210. 1258,1364,1474,1588,1706,1828,1921,2051,2185,2323,2465,
  211. 2611,2761,2876,3034,3196,3362,3532,3706);
  212. $max_codewords=$max_codewords_array[$this->qrcode_version];
  213. $max_modules_1side=17+($this->qrcode_version <<2);
  214. $matrix_remain_bit=array(0,0,7,7,7,7,7,0,0,0,0,0,0,0,3,3,3,3,3,3,3,
  215. 4,4,4,4,4,4,4,3,3,3,3,3,3,3,0,0,0,0,0,0);
  216. /* ---- read version ECC data file */
  217. $byte_num=$matrix_remain_bit[$this->qrcode_version]+($max_codewords << 3);
  218. $filename=QRCODE_DATA_PATH."/qrv".$this->qrcode_version."_".$ec.".dat";
  219. $fp1 = fopen ($filename, "rb");
  220. $matx=fread($fp1,$byte_num);
  221. $maty=fread($fp1,$byte_num);
  222. $masks=fread($fp1,$byte_num);
  223. $fi_x=fread($fp1,15);
  224. $fi_y=fread($fp1,15);
  225. $rs_ecc_codewords=ord(fread($fp1,1));
  226. $rso=fread($fp1,128);
  227. fclose($fp1);
  228. $matrix_x_array=unpack("C*",$matx);
  229. $matrix_y_array=unpack("C*",$maty);
  230. $mask_array=unpack("C*",$masks);
  231. $rs_block_order=unpack("C*",$rso);
  232. $format_information_x2=unpack("C*",$fi_x);
  233. $format_information_y2=unpack("C*",$fi_y);
  234. $format_information_x1=array(0,1,2,3,4,5,7,8,8,8,8,8,8,8,8);
  235. $format_information_y1=array(8,8,8,8,8,8,8,8,7,5,4,3,2,1,0);
  236. $max_data_codewords=($max_data_bits >>3);
  237. $filename = QRCODE_DATA_PATH."/rsc".$rs_ecc_codewords.".dat";
  238. $fp0 = fopen ($filename, "rb");
  239. $i=0;
  240. while ($i<256) {
  241. $rs_cal_table_array[$i]=fread ($fp0,$rs_ecc_codewords);
  242. $i++;
  243. }
  244. fclose ($fp0);
  245. /* -- read frame data -- */
  246. $filename = QRCODE_DATA_PATH."/qrvfr".$this->qrcode_version.".dat";
  247. $fp0 = fopen ($filename, "rb");
  248. $frame_data = fread ($fp0, filesize ($filename));
  249. fclose ($fp0);
  250. /* --- set terminator */
  251. if ($total_data_bits<=$max_data_bits-4){
  252. $data_value[$data_counter]=0;
  253. $data_bits[$data_counter]=4;
  254. } else {
  255. if ($total_data_bits<$max_data_bits){
  256. $data_value[$data_counter]=0;
  257. $data_bits[$data_counter]=$max_data_bits-$total_data_bits;
  258. } else {
  259. if ($total_data_bits>$max_data_bits){
  260. trigger_error("Overflow error",E_USER_ERROR);
  261. exit;
  262. }
  263. }
  264. }
  265. /* ----divide data by 8bit */
  266. $i=0;
  267. $codewords_counter=0;
  268. $codewords[0]=0;
  269. $remaining_bits=8;
  270. while ($i<=$data_counter) {
  271. $buffer=@$data_value[$i];
  272. $buffer_bits=@$data_bits[$i];
  273. $flag=1;
  274. while ($flag) {
  275. if ($remaining_bits>$buffer_bits){
  276. $codewords[$codewords_counter]=((@$codewords[$codewords_counter]<<$buffer_bits) | $buffer);
  277. $remaining_bits-=$buffer_bits;
  278. $flag=0;
  279. } else {
  280. $buffer_bits-=$remaining_bits;
  281. $codewords[$codewords_counter]=(($codewords[$codewords_counter] << $remaining_bits) | ($buffer >> $buffer_bits));
  282. if ($buffer_bits==0) {
  283. $flag=0;
  284. } else {
  285. $buffer= ($buffer & ((1 << $buffer_bits)-1) );
  286. $flag=1;
  287. }
  288. $codewords_counter++;
  289. if ($codewords_counter<$max_data_codewords-1){
  290. $codewords[$codewords_counter]=0;
  291. }
  292. $remaining_bits=8;
  293. }
  294. }
  295. $i++;
  296. }
  297. if ($remaining_bits!=8) {
  298. $codewords[$codewords_counter]=$codewords[$codewords_counter] << $remaining_bits;
  299. } else {
  300. $codewords_counter--;
  301. }
  302. /* ---- set padding character */
  303. if ($codewords_counter<$max_data_codewords-1){
  304. $flag=1;
  305. while ($codewords_counter<$max_data_codewords-1){
  306. $codewords_counter++;
  307. if ($flag==1) {
  308. $codewords[$codewords_counter]=236;
  309. } else {
  310. $codewords[$codewords_counter]=17;
  311. }
  312. $flag=$flag*(-1);
  313. }
  314. }
  315. /* ---- RS-ECC prepare */
  316. $i=0;
  317. $j=0;
  318. $rs_block_number=0;
  319. $rs_temp[0]="";
  320. while($i<$max_data_codewords){
  321. $rs_temp[$rs_block_number].=chr($codewords[$i]);
  322. $j++;
  323. if ($j>=$rs_block_order[$rs_block_number+1]-$rs_ecc_codewords){
  324. $j=0;
  325. $rs_block_number++;
  326. $rs_temp[$rs_block_number]="";
  327. }
  328. $i++;
  329. }
  330. /*
  331. #
  332. # RS-ECC main
  333. #
  334. */
  335. $rs_block_number=0;
  336. $rs_block_order_num=count($rs_block_order);
  337. while ($rs_block_number<$rs_block_order_num){
  338. $rs_codewords=$rs_block_order[$rs_block_number+1];
  339. $rs_data_codewords=$rs_codewords-$rs_ecc_codewords;
  340. $rstemp=$rs_temp[$rs_block_number].str_repeat(chr(0),$rs_ecc_codewords);
  341. $padding_data=str_repeat(chr(0),$rs_data_codewords);
  342. $j=$rs_data_codewords;
  343. while($j>0){
  344. $first=ord(substr($rstemp,0,1));
  345. if ($first){
  346. $left_chr=substr($rstemp,1);
  347. $cal=$rs_cal_table_array[$first].$padding_data;
  348. $rstemp=$left_chr ^ $cal;
  349. } else {
  350. $rstemp=substr($rstemp,1);
  351. }
  352. $j--;
  353. }
  354. $codewords=array_merge($codewords,unpack("C*",$rstemp));
  355. $rs_block_number++;
  356. }
  357. /* ---- flash matrix */
  358. $i=0;
  359. while ($i<$max_modules_1side){
  360. $j=0;
  361. while ($j<$max_modules_1side){
  362. $matrix_content[$j][$i]=0;
  363. $j++;
  364. }
  365. $i++;
  366. }
  367. /* --- attach data */
  368. $i=0;
  369. while ($i<$max_codewords){
  370. $codeword_i=$codewords[$i];
  371. $j=8;
  372. while ($j>=1){
  373. $codeword_bits_number=($i << 3) + $j;
  374. $matrix_content[ $matrix_x_array[$codeword_bits_number] ][ $matrix_y_array[$codeword_bits_number] ]=((255*($codeword_i & 1)) ^ $mask_array[$codeword_bits_number] );
  375. $codeword_i= $codeword_i >> 1;
  376. $j--;
  377. }
  378. $i++;
  379. }
  380. $matrix_remain=$matrix_remain_bit[$this->qrcode_version];
  381. while ($matrix_remain){
  382. $remain_bit_temp = $matrix_remain + ( $max_codewords <<3);
  383. $matrix_content[ $matrix_x_array[$remain_bit_temp] ][ $matrix_y_array[$remain_bit_temp] ] = ( 255 ^ $mask_array[$remain_bit_temp] );
  384. $matrix_remain--;
  385. }
  386. #--- mask select
  387. $min_demerit_score=0;
  388. $hor_master="";
  389. $ver_master="";
  390. $k=0;
  391. while($k<$max_modules_1side){
  392. $l=0;
  393. while($l<$max_modules_1side){
  394. $hor_master=$hor_master.chr($matrix_content[$l][$k]);
  395. $ver_master=$ver_master.chr($matrix_content[$k][$l]);
  396. $l++;
  397. }
  398. $k++;
  399. }
  400. $i=0;
  401. $all_matrix=$max_modules_1side*$max_modules_1side;
  402. while ($i<8){
  403. $demerit_n1=0;
  404. $ptn_temp=array();
  405. $bit= 1<< $i;
  406. $bit_r=(~$bit)&255;
  407. $bit_mask=str_repeat(chr($bit),$all_matrix);
  408. $hor = $hor_master & $bit_mask;
  409. $ver = $ver_master & $bit_mask;
  410. $ver_shift1=$ver.str_repeat(chr(170),$max_modules_1side);
  411. $ver_shift2=str_repeat(chr(170),$max_modules_1side).$ver;
  412. $ver_or=chunk_split(~($ver_shift1 | $ver_shift2),$max_modules_1side,chr(170));
  413. $ver_and=chunk_split(~($ver_shift1 & $ver_shift2),$max_modules_1side,chr(170));
  414. $hor=chunk_split(~$hor,$max_modules_1side,chr(170));
  415. $ver=chunk_split(~$ver,$max_modules_1side,chr(170));
  416. $hor=$hor.chr(170).$ver;
  417. $n1_search="/".str_repeat(chr(255),5)."+|".str_repeat(chr($bit_r),5)."+/";
  418. $n3_search=chr($bit_r).chr(255).chr($bit_r).chr($bit_r).chr($bit_r).chr(255).chr($bit_r);
  419. $demerit_n3=substr_count($hor,$n3_search)*40;
  420. $demerit_n4=floor(abs(( (100* (substr_count($ver,chr($bit_r))/($byte_num)) )-50)/5))*10;
  421. $n2_search1="/".chr($bit_r).chr($bit_r)."+/";
  422. $n2_search2="/".chr(255).chr(255)."+/";
  423. $demerit_n2=0;
  424. preg_match_all($n2_search1,$ver_and,$ptn_temp);
  425. foreach($ptn_temp[0] as $str_temp){
  426. $demerit_n2+=(strlen($str_temp)-1);
  427. }
  428. $ptn_temp=array();
  429. preg_match_all($n2_search2,$ver_or,$ptn_temp);
  430. foreach($ptn_temp[0] as $str_temp){
  431. $demerit_n2+=(strlen($str_temp)-1);
  432. }
  433. $demerit_n2*=3;
  434. $ptn_temp=array();
  435. preg_match_all($n1_search,$hor,$ptn_temp);
  436. foreach($ptn_temp[0] as $str_temp){
  437. $demerit_n1+=(strlen($str_temp)-2);
  438. }
  439. $demerit_score=$demerit_n1+$demerit_n2+$demerit_n3+$demerit_n4;
  440. if ($demerit_score<=$min_demerit_score || $i==0){
  441. $mask_number=$i;
  442. $min_demerit_score=$demerit_score;
  443. }
  444. $i++;
  445. }
  446. $mask_content=1 << $mask_number;
  447. # --- format information
  448. $format_information_value=(($ec << 3) | $mask_number);
  449. $format_information_array=array("101010000010010","101000100100101",
  450. "101111001111100","101101101001011","100010111111001","100000011001110",
  451. "100111110010111","100101010100000","111011111000100","111001011110011",
  452. "111110110101010","111100010011101","110011000101111","110001100011000",
  453. "110110001000001","110100101110110","001011010001001","001001110111110",
  454. "001110011100111","001100111010000","000011101100010","000001001010101",
  455. "000110100001100","000100000111011","011010101011111","011000001101000",
  456. "011111100110001","011101000000110","010010010110100","010000110000011",
  457. "010111011011010","010101111101101");
  458. $i=0;
  459. while ($i<15){
  460. $content=substr($format_information_array[$format_information_value],$i,1);
  461. $matrix_content[$format_information_x1[$i]][$format_information_y1[$i]]=$content * 255;
  462. $matrix_content[$format_information_x2[$i+1]][$format_information_y2[$i+1]]=$content * 255;
  463. $i++;
  464. }
  465. $out="";
  466. $mxe=$max_modules_1side;
  467. $i=0;
  468. while ($i<$mxe){
  469. $j=0;
  470. while ($j<$mxe){
  471. if ($matrix_content[$j][$i] & $mask_content){
  472. $out.="1";
  473. } else {
  474. $out.="0";
  475. }
  476. $j++;
  477. }
  478. $out.="\n";
  479. $i++;
  480. }
  481. $out = $out | $frame_data;
  482. return ($out);
  483. }
  484. }
  485. ?>