I received a job today. I recognized a simple verification code. This verification code is straightforward. It has very little interference information. So just get the information for comparison. It is easy to identify.

But everything won’t be so smooth. Maybe it’s for me. I think what I do is very tortuous…

This captcha image is generated using ASP. It is, of course, a BMP format.

But for PHP, this is a soft injury because PHP’s GD library does not include BMP at all. Although there is wbmp, it is still different.

So I googled it. The result made me feel a bit of joy. There is a ready-made class that recognizes 256-color BMP. It is very exciting. It is not a matter of white money!!

The result is disappointing. The 256-color BMP and 24-bit color are two concepts. This means that I have to rewrite it..

It seems that there are no ready-made libraries and functions. You can only write it yourself. Analyze the BMP header with the most primitive open. A byte read.

All went to google BMP 24-bit color head analysis.. so long article… immediately disappointed..

So boring to go through the manual.. Look at the imagecreatefromgif imagecreatefromjpeg, imagecreatefrompng, imagecreatefromwbmp and so on. There is no imagecreatefrombmp

So suddenly whimsy. Go to google about imagecreatefrombmp what will be the result. Sure enough, I did not expect. There have been people who wrote this function..

  1. function imagecreatefrombmp($file)
  2. {
  3.     global  $CurrentBit$echoMode;
  4.     $f=fopen($file,“r”);
  5.     $Header=fread($f,2);
  6.     if($Header==“BM”)
  7.     {
  8.         $Size=freaddword($f);
  9.         $Reserved1=freadword($f);
  10.         $Reserved2=freadword($f);
  11.         $FirstByteOfImage=freaddword($f);
  12.         $SizeBITMAPINFOHEADER=freaddword($f);
  13.         $Width=freaddword($f);
  14.         $Height=freaddword($f);
  15.         $biPlanes=freadword($f);
  16.         $biBitCount=freadword($f);
  17.         $RLECompression=freaddword($f);
  18.         $WidthxHeight=freaddword($f);
  19.         $biXPelsPerMeter=freaddword($f);
  20.         $biYPelsPerMeter=freaddword($f);
  21.         $NumberOfPalettesUsed=freaddword($f);
  22.         $NumberOfImportantColors=freaddword($f);
  23.         if($biBitCount<24)
  24.         {
  25.             $img=imagecreate($Width,$Height);
  26.             $Colors=pow(2,$biBitCount);
  27.             for($p=0;$p<$Colors;$p++)
  28.             {
  29.                 $B=freadbyte($f);
  30.                 $G=freadbyte($f);
  31.                 $R=freadbyte($f);
  32.                 $Reserved=freadbyte($f);
  33.                 $Palette[]=imagecolorallocate($img,$R,$G,$B);
  34.             };
  35.             if($RLECompression==0)
  36.             {
  37.                 $Zbytek=(4-ceil(($Width/(8/$biBitCount)))%4)%4;
  38.                 for($y=$Height-1;$y>=0;$y–)
  39.                 {
  40.                     $CurrentBit=0;
  41.                     for($x=0;$x<$Width;$x++)
  42.                     {
  43.                         $C=freadbits($f,$biBitCount);
  44.                         imagesetpixel($img,$x,$y,$Palette[$C]);
  45.                     };
  46.                     if($CurrentBit!=0) {freadbyte($f);};
  47.                     for($g=0;$g<$Zbytek;$g++)
  48.                     freadbyte($f);
  49.                 };
  50.             };
  51.         };
  52.         if($RLECompression==1) //$BI_RLE8
  53.         {
  54.             $y=$Height;
  55.             $pocetb=0;
  56.             while(true)
  57.             {
  58.                 $ and -;
  59.                 $prefix=freadbyte($f);
  60.                 $suffix=freadbyte($f);
  61.                 $pocetb+=2;
  62.                 $echoit=false;
  63.                 if($echoit)echo “Prefix: $prefix Suffix: $suffix<BR>”;
  64.                 if(($prefix==0)and($suffix==1)) break;
  65.                 if(feof($f)) break;
  66.                 while(!(($prefix==0)and($suffix==0)))
  67.                 {
  68.                     if($prefix==0)
  69.                     {
  70.                         $pocet=$suffix;
  71.                         $Data.=fread($f,$pocet);
  72.                         $ pocetb + = $ number ;
  73.                         if($pocetb%2==1) {freadbyte($f); $pocetb++;};
  74.                     };
  75.                     if($prefix>0)
  76.                     {
  77.                         $ count = $ prefix ;
  78.                         for($r=0;$r<$pocet;$r++)
  79.                         $Data.=chr($suffix);
  80.                     };
  81.                     $prefix=freadbyte($f);
  82.                     $suffix=freadbyte($f);
  83.                     $pocetb+=2;
  84.                     if($echoitecho “Prefix: $prefix Suffix: $suffix<BR>”;
  85.                 };
  86.                 for($x=0;$x<strlen($Data);$x++)
  87.                 {
  88.                     imagesetpixel($img,$x,$y,$Palette[ord($Data[$x])]);
  89.                 };
  90.                 $Data=“”;
  91.             };
  92.         };
  93.         if($RLECompression==2) //$BI_RLE4
  94.         {
  95.             $y=$Height;
  96.             $pocetb=0;
  97.             /*while(!feof($f))
  98.             echo freadbyte($f).”_”.freadbyte($f).”<BR>”;*/
  99.             while(true)
  100.             {
  101.                 //break;
  102.                 $ and -;
  103.                 $prefix=freadbyte($f);
  104.                 $suffix=freadbyte($f);
  105.                 $pocetb+=2;
  106.                 $echoit=false;
  107.                 if($echoit)echo “Prefix: $prefix Suffix: $suffix<BR>”;
  108.                 if(($prefix==0)and($suffix==1)) break;
  109.                 if(feof($f)) break;
  110.                 while(!(($prefix==0)and($suffix==0)))
  111.                 {
  112.                     if($prefix==0)
  113.                     {
  114.                         $pocet=$suffix;
  115.                         $CurrentBit=0;
  116.                         for($h=0;$h<$pocet;$h++)
  117.                         $Data.=chr(freadbits($f,4));
  118.                         if($CurrentBit!=0) freadbits($f,4);
  119.                         $ pocetb + = ceil (( $ number / 2));
  120.                         if($pocetb%2==1) {freadbyte($f); $pocetb++;};
  121.                     };
  122.                     if($prefix>0)
  123.                     {
  124.                         $ count = $ prefix ;
  125.                         $i=0;
  126.                         for($r=0;$r<$pocet;$r++)
  127.                         {
  128.                             if($i%2==0)
  129.                             {
  130.                                 $Data.=chr($suffix%16);
  131.                             }
  132.                             else
  133.                             {
  134.                                 $Data.=chr(floor($suffix/16));
  135.                             };
  136.                             $i++;
  137.                         };
  138.                     };
  139.                     $prefix=freadbyte($f);
  140.                     $suffix=freadbyte($f);
  141.                     $pocetb+=2;
  142.                     if($echoitecho “Prefix: $prefix Suffix: $suffix<BR>”;
  143.                 };
  144.                 for($x=0;$x<strlen($Data);$x++)
  145.                 {
  146.                     imagesetpixel($img,$x,$y,$Palette[ord($Data[$x])]);
  147.                 };
  148.                 $Data=“”;
  149.             };
  150.         };
  151.         if($biBitCount==24)
  152.         {
  153.             $img=imagecreatetruecolor($Width,$Height);
  154.             $Zbytek=$Width%4;
  155.             for($y=$Height-1;$y>=0;$y–)
  156.             {
  157.                 for($x=0;$x<$Width;$x++)
  158.                 {
  159.                     $B=freadbyte($f);
  160.                     $G=freadbyte($f);
  161.                     $R=freadbyte($f);
  162.                     $color=imagecolorexact($img,$R,$G,$B);
  163.                     if($color==-1) $color=imagecolorallocate($img,$R,$G,$B);
  164.                     imagesetpixel($img,$x,$y,$color);
  165.                 }
  166.                 for($z=0;$z<$Zbytek;$z++)
  167.                 freadbyte($f);
  168.             };
  169.         };
  170.         return $img;
  171.     };
  172.     fclose($f);
  173. };
  174. function freadbyte($f)
  175. {
  176.     return ord(fread($f,1));
  177. };
  178. function freadword($f)
  179. {
  180.     $b1=freadbyte($f);
  181.     $b2=freadbyte($f);
  182.     return $b2*256+$b1;
  183. };
  184. function freaddword($f)
  185. {
  186.     $b1=freadword($f);
  187.     $b2=freadword($f);
  188.     return $b2*65536+$b1;
  189. };

The process of this function is like this: Open the file with fopen. Read one byte and one byte. Read the BMP header first. Then read the pixel line by line. Then use imagecreatetruecolor to create an image. Just read the pixel. Then draw one by one to the image you just created.
Finally return the resource of this image.

It is estimated that everyone is like me. I was scared by such a long function at the beginning. In fact, don’t be afraid. Analyze it. We want to analyze the 24-bit color BMP. So most of the above functions do not use .if($biBitCount= =24) The following are the key:

$B=freadbyte($f);
$G=freadbyte($f);
$R=freadbyte($f);

These three lines are for reading pixels. All we need is to put each pixel into an array. This is easy to manipulate.

$array[] = sprintf(“%03d”,$R).sprintf(“%03d”,$G).sprintf(“%03d”,$B);

So we put each pixel in the array of $array. But this is not enough. Because we have to identify the pixel. So I think so. Change the white (255255255) to 0. The other colors are changed to 1. This is because my verification code is relatively simple. And the interference color is very small..

The resulting $array is similar to this.

0001111000   0001111000   0001111000   0000101000
0010000100   0010000100   0010000100   0000100000
0010000100   0010000100   0010000100   0000100000
0010110100   0000000100   0000000100   0000100000
0010110100   0000101000   0000000100   0000100000
0010110100   0000110000   0011000100   0000010000
0010110100   0000001000   0010111000   0000010000
0010000100   0010000100   0010000000   0010001000
0011000100   0010000110   0010000000   0010001000
0001111000   0001111000   0011111100   0011111100

Of course, the reason why this is formed is what I processed when I output it.
It is easy to see clearly. This is 0357..

Some people will ask why it is down? This is because the BMP is stored upside down when storing images. Compare BT.
But don’t worry about this. We don’t have to give him a hard time coming over. Because we are doing comparisons. This comparison code is also upside down.

In order to more clearly explain how this array is stored in white. I will give you a detailed description. Just follow the example above.

Array subscript 0 1 2 3 4 5 6 7 8 9 10….. 39
Storage contents 0 0 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 0 1 0 0 0 First line

Array subscript 40 41 …. …79Store
contents 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 second line

I will not write it for the sake of omission. It is easy to see. This is a one-dimensional array. There are 399 elements in total.. But in order to identify the verification code, we have to take each of them out.

0-9 40-49 80-89 … is a group of
10-19 50-59 90-99 … for a group of
20-29 60-69 100-109… for a group of
30-39 70-79 110-119.. As a group

You can write your own algorithm:

After sorting this out, it is an array of 4 elements.
Each element has 100 digits of 0 and 1.

The element is taken out. Who is it to compare with?? Yes. We have to find a reference object..
Finding the reference object is physical strength..
Return to the above process.. Constantly refresh the verification code.. until 0 -9 has appeared. For each. Write down his appearance, say 0 is like this

0001111000
0010000100
0010000100
0010110100
0010110100
0010110100
0010110100
0010000100
0011000100
0001111000

It becomes a string. 0 is like this. 0001111000001000010000100001000010110100001011010000101101000010110100001000010000110001000001111000
is also placed in the above order in a row.

After 0-9 is written down, we can put it in an array, called $key.

This is a one-to-one correspondence with the elements we generated.

The next step is to start comparing.

Looping is inevitable. The trick is to compare the similar_text and reference objects one by one. Put the Acacia percentage into an array.
Then take the largest percentage of the array. The corresponding index value (this index value is not automatically generated) Is the number we have identified.
The following code value describes the important part

Foreach ($keys as $key => $value) { //$key is the comparison reference group
similar_text($value, $validValue, $p);
$maxArr[$key] = $p; // put all the odds Go to the array
}
and then take out the largest index value of $maxArr. This is the number we identified.

At this point, the verification code is considered complete.

But when deployed to the user, I found that his machine used fopen to open the remote URL. Only 30% chance is obtained. Other cases are HTTP Request failed…
Many methods have been changed or not. The result is my solution. .
using CURL to save local codes. then fopen to open the local images 100% OK it ..

As for the detailed code, I will not post it. Because the code is sold to others. In order to protect the interests of others, so don’t open your mouth with me. I have already given the idea. I believe you can write it.