понедельник, 8 ноября 2010 г.

Life:)SMS. Нет API? Сделаем!

Являюсь обладателем сим-карты от мобильного оператора life:). И недавно обратил внимание на возможность отправлять смс-ки через их сайт. 
Особенности проекта: 
  • ежедневно 3 бесплатных смс на абонентов life:) для незарегистрированных пользователей.
  • ежедневно 3 бесплатных смс на всех мобильных операторов украины, для абонентов life:)
  • гарантированная доставка смс, senderid - ваш номер мобильного, для абонентов life:)
  • акционные смс-пакеты (100 смс за 12 грн / месяц), остальные тарифицируются по стандартным расценкам. 
Недостатки:
  • отсутствие API для работы с смс-ками.
Пишем класс на PHP под linux эмулирующий работу API для сайта life:)sms.

<?php class lifesms {
   private 
$_urlsms "https://www.life.com.ua/sms/";
   private 
$_urlbot "https://www.life.com.ua/sms/antiBot.html";
   private 
$_urlreg "https://www.life.com.ua/sms/j_security_check";
   private 
$_urlredirect "";
   private 
$_session = array( );
   private 
$_user "free";
   private 
$_code "";
   private 
$_number "";
   private 
$_pass "";
   private 
$_auth false;
   private 
$_free 0;
   private 
$_debug false;
   private 
$_error "";

   private function 
debug$in ) {
     if( 
$this->_debug ) {
       echo 
"<pre>";
       
print_r$in );
       echo 
"</pre>";
     }
   }
   public function 
geterror( ) {
     return 
$this->_error;
   }
   public function 
setdebug$stat ) {
     
$this->debug"DEBUG ALREADY RUN" );
     
$this->_debug $stat;
     
$this->debug"DEBUG RUNNING" );
   }
   private function 
getstream$in ) {
     
$this->debug"PARSE RESULT STREAM" );
     foreach( 
$in as $response ) {
       if( 
substrstrtolower$response ), 010 ) == 'location: ' ) {
         
$this->_urlredirect substr$response10 );
       }
       if( 
substrstrtolower$response ), 012 ) == 'set-cookie: ' ) {
         
$pos strpos$response";" ); if( $pos === false $pos 12;
         
$this->_session[ ] = substr$response12$pos 12 );
       }
     }
     
$this->_session array_unique$this->_session );
   }
   private function 
setstream$query false$ajax false ) {
     
$opts = array(
       
'http' => array(
         
'method' => "GET",
         
'header' => array(
           
"Accept: " $_SERVER['HTTP_ACCEPT'],
           
"Accept-language: " $_SERVER['HTTP_ACCEPT_LANGUAGE'],
           
"Cookie: " implode";"$this->_session ),
           
"Referer: " $this->_urlredirect
         
),
         
'user_agent' => $_SERVER['HTTP_USER_AGENT']
       )
     );
     if( 
$query ) {
       
$query http_build_query$query );
       
$opts'http' ][ 'method' ] = 'POST';
       
$opts'http' ][ 'header' ][ ] = "Content-type: application/x-www-form-urlencoded; charset=UTF-8";
       
$opts'http' ][ 'header' ][ ] = "Content-Length: " strlen$query );
       
$opts'http' ][ 'content' ] = $query;
     }
     if( 
$ajax ) {
       
$opts'http' ][ 'header' ][ ] = "X-Prototype-Version: 1.6.0.1";
       
$opts'http' ][ 'header' ][ ] = "X-Requested-With: XMLHttpRequest";
     }
     
$this->debug'CREATE CONTEXT STREAM' );
     
$this->debug$opts );
     return 
stream_context_create$opts ); 
   }
   public function 
isready( ) {
     
$file file_get_contents$this->_urlsmsfalse$this->setstream( ) );
     
$this->getstream$http_response_header );
     
preg_match'/id="freeSmsRemain"\>(.*)\</'$file$tmp );
     
$this->_free $tmp];
     
$this->debug$this );
     
$this->debug$http_response_header );
     if( 
$this->_user == "user" && strpos$this->_urlredirect"smsFree" ) !== false ) {
       
$this->debug'USER SESSION FAILED' );
       return 
false;
     }
     return 
true;
   }
   public function 
setfree( ) {
     
$this->debug"SET USER TO FREE" );
     
$this->_user "free";
     
$this->_session = array( );
     return 
$this->isready( );
   }
   private function 
auth( ) {
     
file_put_contents"./img.jpg"file_get_contents$this->_urlbotfalse$this->setstream( ) ) );
     `
convert -compress none img.jpg img.tif`;
     `
tesseract img.tif res nobatch digits`;
     
$arr file"res.txt"FILE_IGNORE_NEW_LINES FILE_SKIP_EMPTY_LINES );
     
$antibot $arr];
     
$query = array(
       
"j_username" => "{$this->_code}{$this->_number}",
       
"j_prefix" => "{$this->_code}",
       
"j_usernumber" => "{$this->_number}",
       
"j_password" => "{$this->_pass}",
       
"j_antibot" => "{$antibot}",
       
"login" => "Enter"
     
);
     
$file file_get_contents$this->_urlregfalse$this->setstream$query ) );
     
$this->getstream$http_response_header );
     
$this->debug$this );
     
$this->debug$http_response_header );
     if( 
strpos$this->_urlredirect"smsFree" ) !== false ) {
       
$this->_auth false;
       
preg_match'/showMessage\(\){(.*)alert\(\"(.*)\"\)(.*)}/smU'$file$tmp );
       
$this->debug'USER AUTH FAILED' );
       
$this->debug$tmp] );
       
$this->_error $tmp];
       return 
False;
     }
     
$this->debug'USER AUTH OK' );
     
$this->_auth true;
     return 
True;
   }
   public function 
setuser$code ""$number ""$pass "" ) {
     
$this->setfree( );
     
$this->_code $code;
     
$this->_number $number;
     
$this->_pass $pass;
     
$this->_user "user";
     
$this->debug"SET NEW USER OPTIONS" );
     return 
$this->auth( );
   }
   public function 
sendsms$code$number$text$signature "" ) {
     if( 
$this->_user == "free" ) {
       
file_put_contents"./img.jpg"file_get_contents$this->_urlbot "?type=sms"false$this->setstream( ) ) );
       `
convert -compress none img.jpg img.tif`;
       `
tesseract img.tif res nobatch digits`;
       
$arr file"res.txt"FILE_IGNORE_NEW_LINES FILE_SKIP_EMPTY_LINES );
       
$antibot $arr];
       
$query = array(
         
"smsNumberPrefix" => "{$code}",
         
"smsNumber" => "{$number}",
         
"promotionTextObj.id" => 0,
         
"text" => "{$text}",
         
"signature" => "{$signature}",
         
"antibot" => "{$antibot}",
         
"save" => "Send SMS"
       
);
       
$file file_get_contents$this->_urlsms "smsFree.html"false$this->setstream$query ) );
       
$this->getstream$http_response_header );
       
//$this->debug( $file );
       
$this->debug$this );
       
$this->debug$http_response_header );
       if( 
preg_match'/main\"(.*)class=\"error\"(.*)\/\>(.*)<br \/\>/smU'$file$tmp ) ) {
         
$this->_error $tmp];
       }
       if( 
preg_match'/infomessages\"(.*)class=\"message\"(.*)5px;\">(.*)<\/span>/smU'$file$tmp ) ) {
         
$this->_error $tmp];
       }
       if( 
$this->_error ) {
         
$this->debug$this->_error );
         return 
False;
       }
       return 
True;
     }
     if( 
$this->_user == "user" && $this->_auth == true ) {
       
$query = array(
         
"text" => "{$text}",
         
"sendDate" => "",
         
"notifyMe" => false,
         
"noCache" => roundmicrotimetrue ) * 1000 )
       );
       
$url "sms.html?ajax=true&sms.contacts=38{$code}{$number}&sms.contactIds=null&campaignId=";
       
$file = @file_get_contents$this->_urlsms $urlfalse$this->setstream$querytrue ) );
       
$this->getstream$http_response_header );
     }
     return 
False;
   }
 }



пример использования:
$a = new lifesms( ); 
$a->setdebugtrue ); 
$a->setuser"код_оператора""номер_телефона""супер_пароль" ); 
//$a->setfree( ); 
$a->sendsms"код_оператора""номер_телефона""текст_сообщения" ); 
//echo $a->geterror( );
//$a->isready( ); 


Результаты тестирования.

Скрипт был написан на скорую руку и описывает общую картину работы нашего API с сайтом life:)sms. Без проблем отправляет сообщения в режиме setfree( ) (незарегистрированного пользователя). Главное обрабатывать ответы от сервера, т.к. иногда наш ocr (tasseract) не всегда верно обрабатывает цифры из-за плохого качества captcha-картинки. В режиме setuser отправка смс почти всегда заканчивается ответом false, но эта ошибка связана из-за специфики отправки самого сообщения в режиме зарегистрированного пользователя (функция file_get_contents не корректно обрабатывает длинные url'ы с кучей передаваемых параметров). Возможно ошибка скрывается не в функции, а моей обработке данных. Необходимо это дело дописать и на основании имеющейся API можно прикручивать возможность отправки довольно дешевых смс-сообщений к др.проектам.

2 комментария:

  1. огромный респект!
    правда сразу не сработало, пришлось вникать в код:
    - исправить "./img.jpg" на "img.jpg";
    - chmod 777 на каталог с классом;
    - установить пакет tesseract-ocr;

    P.S. Сколько времени ушло на это добро?

    ОтветитьУдалить
  2. Рад, что кому-то пригодилось. )))

    1. "./img.jpg" - говорит, что файл находится в текущем каталоге.
    2. необходимые права на каталог выставляются согласно настроек сервера.
    3. про tesseract-ocr упоминал в предыдущем посте - http://freetime-at-work.blogspot.com/2010/11/tesseract.html

    Времени на написание наброска-кода немного ушло, а вот найти само свободное время было трудновато )))

    ОтветитьУдалить