Десктопное приложение для форума, На Python
http://phpforum.ru/index.php?showtopic=75116
написал 3 класса - по сути пассивное API для этого форума (обновил 8.11.13)
1. Curl - по сути обёртка для работы с курлом
Свернутый текст
//Вспомогательный класс курла
class Curl{
public $options;
public $returndata;
public function _construct(){
}
static public function getPage($options, $returndata=true){
$curl = curl_init();
//Таймаут на подключение 20 сек
$options[CURLOPT_CONNECTTIMEOUT] = 20;
curl_setopt_array($curl, $options);
$out = iconv('windows-1251', 'utf-8', curl_exec($curl));
$info = curl_getinfo($curl);
if($info['http_code'] != 200)
exit('Прошло много времени, а форум так и не ответил...');
curl_close($curl);
return ($returndata !== false) ? $out : null;
}
}
2. Parser - самый что ненаесть настоящий парсер контента
Свернутый текст
//Класс парсера, для разбора страниц, полученных курлом
class Parser{
const NEW_THEMES = 'new';
const ACTIVE_THEMES = 'active';
const SMS_CHAT = 'sms';
const ONLINE_USERS = 'online';
public $what;
protected $new_message = 'http://phpforum.ru/index.php?act=Search&CODE=getnew';
protected $active_theme = 'http://phpforum.ru/index.php?act=Search&CODE=getactive';
protected $index_page = 'http://phpforum.ru/index.php?';
protected $sms = 'http://phpforum.ru/index.php?&act=Shoutbox';
protected $userAgent = 'PHP Forum API ver.Vasinsky';
private $cookie_file = 'cookie.txt';
private $hashed_url;
public $username;
public $password;
public function __construct(){
}
//Первичное получение контента по указонному URL
private function getTempData(){
$options = array(
CURLOPT_REFERER=>$this->index_page,
CURLOPT_URL=>$this->getUrl(),
CURLOPT_RETURNTRANSFER=>true
);
return Curl::getPage($options);
}
//Метод авторизации
public function autorize($username,$password){
//Очищаю файл кук
file_put_contents($this->cookie_file, "");
//Отправка данных в форму авторизации
$options = array(
CURLOPT_URL=>'http://phpforum.ru/index.php?act=Login&CODE=01&CookieDate=1',
CURLOPT_REFERER=>$this->index_page,
CURLOPT_RETURNTRANSFER=>true,
CURLOPT_USERAGENT=> $this->userAgent,
CURLOPT_COOKIEJAR=>$this->cookie_file,
CURLOPT_COOKIEFILE=>$this->cookie_file,
CURLOPT_FOLLOWLOCATION=>true,
CURLOPT_POST=>true ,
CURLOPT_POSTFIELDS=>"UserName=".iconv('utf-8','windows-1251',$username)
."&PassWord=".iconv('utf-8','windows-1251',$password)
);
$out = Curl::getPage($options);
//Переход по ссылке редиректа после авторизации
preg_match("#url=(.*)'#", $out, $url);
$cookie = file($this->cookie_file);
$sid = explode('session_id', $cookie['5']);
$sid = trim($sid[1]);
$hash = explode('pass_hash', $cookie['7']);
$hash = $hash[1];
if(isset($url[1])){
$this->hashed_url = $url[1];
$options = array(
CURLOPT_REFERER=>$this->index_page.'act=Login&CODE=01&CookieDate=1',
CURLOPT_URL => $this->index_page.'s='.$sid.'&',
CURLOPT_RETURNTRANSFER=>true
);
$out = Curl::getPage($options);
}
else
return 'Сбой при авторизации';
}
//Установка режимов new,active,sms,online
public function setParam($what){
$this->what = $what;
}
//Сам парсер контента для разных режимов
protected function parseData(){
//echo $this->getTempData();
switch($this->what){
case self::ONLINE_USERS :
$options = array(
CURLOPT_URL=>$this->getUrl(),
CURLOPT_REFERER=>$this->index_page,
CURLOPT_RETURNTRANSFER=>true,
CURLOPT_USERAGENT=> $this->userAgent,
CURLOPT_COOKIEJAR=>$this->cookie_file,
CURLOPT_COOKIEFILE=>$this->cookie_file,
CURLOPT_FOLLOWLOCATION=>false,
);
$out = Curl::getPage($options);
preg_match("#(<div class='thin'>(.*)</div>)#usU", $out, $matches);
if(!isset($matches[2]))
return 'Не смог получить список онлайн посетителей, а может и нет никого дома';
else{
$matches[2] = preg_replace("#<a href\='http\://phpforum\.ru/index\.php\?showuser\=[0-9]*'>#u", ""
, strtr($matches[2], array('</a>'=>'')));
$matches[2] = mb_substr($matches[2],0,-3,'utf-8');
$online = explode(',', strtr($matches[2], array("\n"=>'')));
return $online;
}
//echo $out;
//echo '<pre>' . print_r($matches, 1) . '</pre>';
break;
case self::SMS_CHAT :
$options = array(
CURLOPT_REFERER=>$this->index_page,
CURLOPT_URL=>$this->getUrl(),
CURLOPT_RETURNTRANSFER=>true
);
$out = Curl::getPage($options);
preg_match_all("#<span style='color:[a-z]*'><b>(.*)</b></span>#suU", $out, $user);
//бредово, но вместо 7.11.2013 - 10:55 парситься 7th November 2013
preg_match_all("#</a><br /><b>(.*)</b><br />#suU", $out, $pub);
preg_match_all("#</div><div align='left'>(.*)</div>#suU", $out, $mess);
if(empty($user[0]))
return 'СМС чат пуст';
else{
foreach($user[0] as $k=>$u){
$result[] = array(
'date'=>date("d.m.y", strtotime($pub[1][$k])),
'user'=>$user[0][$k],
'text'=>$mess[1][$k]
);
}
return $result;
}
break;
case self::ACTIVE_THEMES :
$tpl_date_theme = " <a title=\"Этот топик создан: (.*)\"";
preg_match_all("#".$tpl_date_theme."#iuU", $this->getTempData(), $temp_date);
$tpl_name_theme = "&hl='>(.*)</a>\s";
preg_match_all("#".$tpl_name_theme."#iuU", $this->getTempData(), $temp_name);
$tpl_href_theme = "<a title=\"Этот топик создан: .*\" href='(.*)&hl='>";
preg_match_all("#".$tpl_href_theme."#iuU", $this->getTempData(), $temp_href);
$tpl_author_theme = "<td align='center' class='row2'>(.*)</td>";
preg_match_all("#".$tpl_author_theme."#iuU", $this->getTempData(), $temp_author);
$tpl_answer_theme = "Автор:</a> (.*)</td>";
preg_match_all("#".$tpl_answer_theme."#iuU", $this->getTempData(), $temp_answer);
if(!isset($temp_href[1]) || empty($temp_href[1])) return 'Не смог получить ссылки на новых темы';
if(!isset($temp_name[1]) || empty($temp_name[1])) return 'Не смог получить названия новых тем';
if(!isset($temp_date[1]) || empty($temp_date[1])) return 'Не смог получить даты новых тем';
if(!isset($temp_author[1]) || empty($temp_author[1])) return 'Не смог получить авторов новых тем';
if(!isset($temp_answer[1]) || empty($temp_answer[1])) return 'Не смог получить последних ответивших новых тем';
foreach($temp_author[1] as $k=>$v)
if($k == 0 || $k%2 == 0)
$author[] = $v;
elseif($k > 0 || $k%2 != 0)
$posts[] = $v;
foreach($temp_href[1] as $k=>$v){
if(!empty($v)){
$res_array[] = array(
'href'=>$v,
'name'=>strip_tags($temp_name[1][$k]),
'posts'=>strip_tags($posts[$k]),
'data'=>$temp_date[1][$k],
'author'=>strip_tags($author[$k]),
'last_answer'=>strip_tags($temp_answer[1][$k])
);
}
}
return $res_array;
break;
case self::NEW_THEMES :
$options = array(
CURLOPT_URL=>$this->getUrl(),
CURLOPT_REFERER=>$this->index_page,
CURLOPT_RETURNTRANSFER=>true,
CURLOPT_USERAGENT=> $this->userAgent,
CURLOPT_COOKIEJAR=>$this->cookie_file,
CURLOPT_COOKIEFILE=>$this->cookie_file,
CURLOPT_FOLLOWLOCATION=>false,
);
$out = Curl::getPage($options);
//preg_match("#show&searchid=(.*)&search_in#u", $out, $url);
$turl = $this->new_message;
$options = array(
CURLOPT_URL=>$turl,
CURLOPT_REFERER=>$this->index_page,
CURLOPT_RETURNTRANSFER=>true,
CURLOPT_USERAGENT=> $this->userAgent,
CURLOPT_COOKIEJAR=>$this->cookie_file,
CURLOPT_COOKIEFILE=>$this->cookie_file,
CURLOPT_FOLLOWLOCATION=>false,
);
$out = Curl::getPage($options);
if(preg_match("#Ничего не найдено по Вашему запросу. Расширьте критерии поиска и попробуйте снова.#iu", $out))
return 'Нет новых тем';
$tpl_date_theme = " <a title=\"Этот топик создан: (.*)\"";
preg_match_all("#".$tpl_date_theme."#iuU", $out, $temp_date);
$tpl_name_theme = "&hl='>(.*)</a>\s";
preg_match_all("#".$tpl_name_theme."#iuU", $out, $temp_name);
$tpl_href_theme = "<a title=\"Этот топик создан: .*\" href='(.*)&hl='>";
preg_match_all("#".$tpl_href_theme."#iuU", $out, $temp_href);
$tpl_author_theme = "<td align='center' class='row2'>(.*)</td>";
preg_match_all("#".$tpl_author_theme."#iuU", $out, $temp_author);
$tpl_answer_theme = "Автор:</a> (.*)</td>";
preg_match_all("#".$tpl_answer_theme."#iuU", $out, $temp_answer);
if(!isset($temp_href[1]) || empty($temp_href[1])) return 'Не смог получить ссылки на активные темы';
if(!isset($temp_name[1]) || empty($temp_name[1])) return 'Не смог получить названия активных тем';
if(!isset($temp_date[1]) || empty($temp_date[1])) return 'Не смог получить даты активных тем';
if(!isset($temp_author[1]) || empty($temp_author[1])) return 'Не смог получить авторов тем';
if(!isset($temp_answer[1]) || empty($temp_answer[1])) return 'Не смог получить последних ответивших тем';
foreach($temp_author[1] as $k=>$v)
if($k == 0 || $k%2 == 0)
$author[] = $v;
elseif($k > 0 || $k%2 != 0)
$posts[] = $v;
foreach($temp_href[1] as $k=>$v){
if(!empty($v)){
$res_array[] = array(
'href'=>$v,
'name'=>strip_tags($temp_name[1][$k]),
'posts'=>strip_tags($posts[$k]),
'data'=>$temp_date[1][$k],
'author'=>strip_tags($author[$k]),
'last_answer'=>strip_tags($temp_answer[1][$k])
);
}
}
return $res_array;
break;
}
}
//Метод возращает ссылку (необходимо при смене режима) - для курла
public function getUrl(){
switch($this->what){
case self::ONLINE_USERS : return $this->index_page; break;
case self::NEW_THEMES : return $this->new_message; break;
case self::ACTIVE_THEMES : return $this->active_theme; break;
case self::SMS_CHAT : return $this->sms; break;
}
}
}
3. Phpforum - результирующий класс, ради которого писались 2 предыдущих.
Свернутый текст
//Класс для получения отпарсенных данных с форума
class Phpforum extends Parser{
public function __construct(){
parent::__construct();
}
//В виде массива
public function getData(){
return $this->parseData();
}
//В виде sjon строки
public function getDataJSON(){
//echo '<pre>' . print_r($this->parseData(),1) . '</pre>';
return (is_array($this->parseData())) ? json_encode($this->parseData()) : $this->parseData();
}
//Экспорт в формате XML, для всех режимов, кроме "online"
public function getDataXML(){
if(!is_array($this->parseData()) || $this->what == self::ONLINE_USERS)
return $this->parseData();
else{
header("Content-type: text/xml; charset=utf-8");
$xml=new DomDocument('1.0','utf-8');
$root = $xml->createElement('root');
$root->setAttribute('date',date('d.m.Y H:i:s'));
foreach($this->parseData() as $k=>$v){
$section = $xml->createElement('section');
$root->appendChild($section);
foreach($v as $key=>$val){
$elem = $xml->createElement($key);
$section->appendChild($elem);
$text = $xml->createTextNode($val);
$elem->appendChild($text);
//echo $key.'<br/>';
}
$root->appendChild($section);
}
$xml->appendChild($root);
return $xml->saveXML();
}
}
}
Данный класс может работать в 4х режимах
1. new - покажет новые темы на форуме
2. active - покажет список активных тем
3. sms - смс чат
4. online - покажет, с подсветкой ника, кто на форуме есть
Возвращаемые (после парсинга) данные можно получать в 3х форматах (режим online - только первые 2 формата)
1. массив
2. json строка
3. XML древо (не работает в режиме online)
Так же класс Parser содержит момент удалённой авторизации (с созданием файла печенек) на форуме (для режимов new, sms - это необходимо)
Как работать с этим мини API
1. session_start()
2. Подключить все 3 класса
//Создание экземпляра класса
$obj = new Phpforum();
//Авторизация - рекомендую не пропускать данный шаг
$obj->autorize('логин','пароль');
//Установка режима
// доступные режимы
//1. new - покажет новые темы на форуме
//2. active - покажет список активных тем
//3. sms - смс чат
//4. online - покажет, с подсветкой ника, кто на форуме есть (формат )
$obj->setParam('new');
//Ответ в виде массива
$new = $obj->getData();
или
//Ответ в виде JSON строки
$new = $obj->getDataJSON();
или
//Ответ ввиде XML дерева
$new = $obj->getDataXML();
_____________
HTML, CSS (Bootstrap), JS(JQuery, ExtJS), PHP, MySQL, MSSql, Posgres, (TSql, BI OLAP, MDX), Mongo, Git, SVN, CodeIgnater, Symfony, Yii 2, JiRA, Redmine, Bitbucket, Composer, Rabbit MQ, Amazon (SQS, S3, Transcribe), Docker