Как я разгадывал капчу

Discussion in 'PHP' started by wirusoalll, 6 Mar 2012.

  1. wirusoalll

    wirusoalll New Member

    Joined:
    2 Mar 2012
    Messages:
    10
    Likes Received:
    4
    Reputations:
    0
    Ну что ж вот ещё одна моя статья это уже вторая по счету.
    И так, речь пойдет о разгадывании капчи. Возьмем за основу мою первую статью. То есть капча будет та же.
    Действия которые мы будем производить:
    1)Чистим капчу(Моя первая статья) .
    2)Немного обрежем капчу(Немного переделаем код из первой статьи).
    3)Переведем картинку в 0 и 1(где 0 – фон, а 1-составляющая цифры или буквы).
    4)Грубо говоря вытаскиваем символы.
    5)Чистим их от ненужного.
    6)Находим в массиве схождения и выдаем уже расшифрованные символы.
    Вот в 6 шагов мы уложимся для того что бы написать код.
    Начнем с начала. Давайте вот эту капчу немного обрежем сразу
    Было
    [​IMG]
    Стало
    [​IMG]
    То есть немного изменив код из первой статьи мы достигли именно такого результата(много объяснять не буду, а сразу скину код)
    Code:
    <?php
    $img = @imagecreatefrompng($file);
    header ('Content-Type: image/png');
    
    $img_o = imagecreatetruecolor(68, 15);
    imagecopy($img_o, $img, 0, 0, 5, 4, 68, 15);
    imagepng($img_o);
    $new_image = imagecreatetruecolor(68, 15);
    
    for($x=0;$x<69;$x++){
     for($y=0;$y<16;$y++){
       $rgb = imagecolorat($img_o,$x,$y);
        $r = 0;
         if(imagecolorat($img_o,$x-1,$y) == $rgb){
          $r++;
         }
           if(imagecolorat($img_o,$x+1,$y) == $rgb){
             $r++;
            }
             if(imagecolorat($img_o,$x,$y-1) == $rgb){
               $r++;
              }
               if(imagecolorat($img_o,$x,$y+1) == $rgb){
                $r++;
                }
                     if($r == 0){
                    	imagesetpixel($new_image,$x,$y,'15265527');
                      }else{
                        imagesetpixel($new_image,$x,$y,$rgb);
                      }
     }
    }
    Imagepng($new_image);
    ?>
    
    В общем вот так размеры стали 68х15
    Первые два шага мы выполнили теперь будем переводить в 0 и 1
    Тут вообще нет ничего сложного
    Снова запускаем цикл for который будет читать с первого пикселя по последний(с учетом что размеры у нас уже другие картинка обрезана)
    Code:
    for($y=0;$y<15;$y++){
    for($x=0;$x<68;$x++){
    
    Вот так запустили цикл и смотрим пиксели если он равен фону(фон кстати не белый учтите это) то ставим 0, а если это другой цвет то 1 сделать это можно с помощью одной строчки кода
    Code:
    $num = (imagecolorat($new_image,$x,$y) == '15265527')? '0':'1';
    
    Вот и все. Просто, да? Иначе это можно записать вот так
    Code:
    If(imagecolorat($new_image,$x,$y) == '15265527'){
    $num .= ‘0’;
    }else{
    $num .= ‘1’;
    }
    
    В результате у нас будет получаться вот такой вывод
    [​IMG]
    Можно увидеть 4 символа “916f”
    Так теперь грубо говоря вытаскиваем символы но для этого подсчитав сколько символов в одной строке уходит на сам символ(немного непонятно объяснил но вот на скрине ниже поймете)
    [​IMG]
    В общем просто воспользовавшись вот таким кодом(если честно то я сейчас горю желанием просто все бросить и дописать завтра, но увы нет)
    Code:
    if($x<8){
        $num1[$y] .= $num;
       }
         if($x>19 and $x<28){
          $num2[$y] .= $num;
         }
           if($x>39 and $x<48){
            $num3[$y] .= $num;
           }
             if($x>59 and $x<68){
               $num4[$y] .= $num;
             }
    
    Мы создаем массив с символами где $num1, $num2, $num3, $num4 это 4 символа и все они сейчас выглядят вот так,
    [​IMG]
    Это наша 9 так же выглядят другие массивы то есть один символ из 8 символов.
    Теперь снова займемся чисткой, уберем строки с 0 и приведем к вот такому виду
    [​IMG]
    Вот этой функцией
    Code:
    for($q=0;$q<count($num1);$q++){
     if($num1[$q] != '00000000'){
      $numi1[$nums1++] = $num1[$q];
     }
       if($num2[$q] != '00000000'){
        $numi2[$nums2++] = $num2[$q];
       }
         if($num3[$q] != '00000000'){
          $numi3[$nums3++] = $num3[$q];
         }
           if($num4[$q] != '00000000'){
            $numi4[$nums4++] = $num4[$q];
           }
    }
    
    Ах, да забыл сказать для чего мы это делаем если ещё сгенерировать пару капч на том сайте от куда я взял эту то можно видеть что они постоянно меняют положение то выше то ниже, но не сдвигаются в лево в право.(Да и если ты продвинутый php программист и уже считаем меня говно кодером, то это твое право, просто я делаю для себя и меня такой метод устраивает)
    Ладно, далее объединяем массивы в строку
    Code:
    $string1 = '';
     $string2 = '';
      $string3 = '';
       $string4 = '';
        for($q=0;$q<count($numi1);$q++){
    	 $string1 .= $numi1[$q];
    	};
         for($q=0;$q<count($numi2);$q++){
    	  $string2 .= $numi2[$q];
    	 };
          for($q=0;$q<count($numi3);$q++){
    	   $string3 .= $numi3[$q];
    	  };
           for($q=0;$q<count($numi4);$q++){
         	$string4 .= $numi4[$q];
    	   };
    
    И сравниваем с заранее подготовленным шаблоном ответов
    Code:
    $array = Array('00011000001111000110011011000011110000111100001111000011011001100011110000011000'=>'0',
    '00011000001110000111100000011000000110000001100000011000000110000001100001111110'=>'1',
    '00111100011001101100001100000011000001100000110000011000001100000110000011111111'=>'2',
    '01111100110001100000001100000110000111000000011000000011000000111100011001111100'=>'3',
    '00000110000011100001111000110110011001101100011011111111000001100000011000000110'=>'4',
    '11111110110000001100000011011100111001100000001100000011110000110110011000111100'=>'5',
    '00111100011001101100001011000000110111001110011011000011110000110110011000111100'=>'6',
    '11111111000000110000001100000110000011000001100000110000011000001100000011000000'=>'7',
    '00111100011001101100001101100110001111000110011011000011110000110110011000111100'=>'8',
    '00111100011001101100001111000011011001110011101100000011010000110110011000111100'=>'9',
    '00111110011000110000001101111111110000111100011101111011'=>'a',
    '11000000110000001100000011011100111001101100001111000011110000111110011011011100'=>'b',
    '00111110011000111100000011000000110000000110001100111110'=>'c',
    '00000011000000110000001100111011011001111100001111000011110000110110011100111011'=>'d',
    '00111100011001101100001111111111110000000110001100111110'=>'e',
    '00011110001100110011001100110000001100001111110000110000001100000011000000110000'=>'f'
    );
    
    Я не знаю почему эта капча которую я отгадываю постоянно генерирует цифры от “0” до “9” и буквы от “a” до “f”
    Да что бы не запутать возьмем один параметр из массива для примера
    Code:
    '00111110011000111100000011000000110000000110001100111110'=>'c',
    
    Если отсчитывать по 8 символов и жать enter то получится вот так
    Code:
    '00111110
     01100011 
     11000000
     11000000
     11000000
     01100011
     00111110'=>'c',
    
    То вот с чем мы сравниваем, я сделал распознавание в виде функции
    Code:
    function captcha($file){
    
    где $file эта файл капчи
    а в конце
    Code:
    return $array[$string1].$array[$string2].$array[$string3].$array[$string4];
    }
    
    Конечный код выглядит вот так
    Code:
    <?php
    function captcha($file){
    $img = @imagecreatefrompng($file);
    //header ('Content-Type: image/png');
    
    $img_o = imagecreatetruecolor(68, 15);
    imagecopy($img_o, $img, 0, 0, 5, 4, 68, 15);
    
    $new_image = imagecreatetruecolor(68, 15);
    
    for($x=0;$x<69;$x++){
     for($y=0;$y<16;$y++){
       $rgb = imagecolorat($img_o,$x,$y);
        $r = 0;
         if(imagecolorat($img_o,$x-1,$y) == $rgb){
          $r++;
         }
           if(imagecolorat($img_o,$x+1,$y) == $rgb){
             $r++;
            }
             if(imagecolorat($img_o,$x,$y-1) == $rgb){
               $r++;
              }
               if(imagecolorat($img_o,$x,$y+1) == $rgb){
                $r++;
                }
                     if($r == 0){
                    	imagesetpixel($new_image,$x,$y,'15265527');
                      }else{
                        imagesetpixel($new_image,$x,$y,$rgb);
                      }
     }
    }
    
    
    for($y=0;$y<15;$y++){
    
     for($x=0;$x<68;$x++){
      $num = (imagecolorat($new_image,$x,$y) == '15265527')? '0':'1';
       if($x<8){
        $num1[$y] .= $num;
       }
         if($x>19 and $x<28){
          $num2[$y] .= $num;
         }
           if($x>39 and $x<48){
            $num3[$y] .= $num;
           }
             if($x>59 and $x<68){
               $num4[$y] .= $num;
             }
     }
    }
    
    $nums1 = 0;
    $nums2 = 0;
    $nums3 = 0;
    $nums4 = 0;
    for($q=0;$q<count($num1);$q++){
     if($num1[$q] != '00000000'){
      $numi1[$nums1++] = $num1[$q];
     }
       if($num2[$q] != '00000000'){
        $numi2[$nums2++] = $num2[$q];
       }
         if($num3[$q] != '00000000'){
          $numi3[$nums3++] = $num3[$q];
         }
           if($num4[$q] != '00000000'){
            $numi4[$nums4++] = $num4[$q];
           }
    }
    
    $array = Array('00011000001111000110011011000011110000111100001111000011011001100011110000011000'=>'0',
    '00011000001110000111100000011000000110000001100000011000000110000001100001111110'=>'1',
    '00111100011001101100001100000011000001100000110000011000001100000110000011111111'=>'2',
    '01111100110001100000001100000110000111000000011000000011000000111100011001111100'=>'3',
    '00000110000011100001111000110110011001101100011011111111000001100000011000000110'=>'4',
    '11111110110000001100000011011100111001100000001100000011110000110110011000111100'=>'5',
    '00111100011001101100001011000000110111001110011011000011110000110110011000111100'=>'6',
    '11111111000000110000001100000110000011000001100000110000011000001100000011000000'=>'7',
    '00111100011001101100001101100110001111000110011011000011110000110110011000111100'=>'8',
    '00111100011001101100001111000011011001110011101100000011010000110110011000111100'=>'9',
    '00111110011000110000001101111111110000111100011101111011'=>'a',
    '11000000110000001100000011011100111001101100001111000011110000111110011011011100'=>'b',
    '00111110011000111100000011000000110000000110001100111110'=>'c',
    '00000011000000110000001100111011011001111100001111000011110000110110011100111011'=>'d',
    '00111100011001101100001111111111110000000110001100111110'=>'e',
    '00011110001100110011001100110000001100001111110000110000001100000011000000110000'=>'f'
    );
    
    $string1 = '';
     $string2 = '';
      $string3 = '';
       $string4 = '';
        for($q=0;$q<count($numi1);$q++){
    	 $string1 .= $numi1[$q];
    	};
         for($q=0;$q<count($numi2);$q++){
    	  $string2 .= $numi2[$q];
    	 };
          for($q=0;$q<count($numi3);$q++){
    	   $string3 .= $numi3[$q];
    	  };
           for($q=0;$q<count($numi4);$q++){
         	$string4 .= $numi4[$q];
    	   };
    return $array[$string1].$array[$string2].$array[$string3].$array[$string4];
    }
    
    echo "<img src='default.png'>|".captcha("default.png");
    ?>
    
    Ну и скрин примера
    [​IMG]

    Вот и все.Надеюсь суть мне удалось передать, я не хотел расписывать сильно,да и вторая статья,ну и спать тянет.Ладно удачи в ваших продвижениях и проектах
     
    #1 wirusoalll, 6 Mar 2012
    Last edited: 7 Mar 2012
    2 people like this.
  2. banned

    banned Banned

    Joined:
    20 Nov 2006
    Messages:
    3,324
    Likes Received:
    1,193
    Reputations:
    252
    Еще один выучил функции gd2 либы. Молодец!
     
  3. R0nin

    R0nin Member

    Joined:
    11 Jul 2010
    Messages:
    261
    Likes Received:
    24
    Reputations:
    8
    Автору бы ознакомиться с тэгом [code], а так думаю "статья" подходящая, для новичков.
     
  4. banned

    banned Banned

    Joined:
    20 Nov 2006
    Messages:
    3,324
    Likes Received:
    1,193
    Reputations:
    252
    http://forum.antichat.ru/thread173897-captcha.html
    Таких статей только на ачате штук 5.
     
  5. petryxa-mixa

    petryxa-mixa Member

    Joined:
    8 Jun 2010
    Messages:
    174
    Likes Received:
    7
    Reputations:
    0
    ну много не мало.
    Выспись поредактируй если не лень будет.
     
  6. b3

    b3 Banned

    Joined:
    5 Dec 2004
    Messages:
    2,170
    Likes Received:
    1,155
    Reputations:
    202
    Я думал тут нейронные сети и опять промах :(
     
  7. InSys

    InSys Member

    Joined:
    2 Feb 2012
    Messages:
    24
    Likes Received:
    20
    Reputations:
    31
    На самом деле вы выбрали слишком простую капчу. Позиции символов известны, деформации отсутствуют, простенький шум. А слабо распознавать такие капчи (оригинал тут)?
    [​IMG]
    Мой вариант смотреть здесь(кстати я приложил исходные коды моей распознавалки, я думаю вам не помешает их изучить)

    Ну и просто почитайте мою статью:
    Анализ алгоритмов генерации CAPTCHA
    В ней я обобщенно рассматривал подход к методам защиты при генерации капчей, и способы их обхода.