Для кода ниже потребуется curl, которого может и не быть у хостера, поэтому полной работоспособности у всех и вся не обещаю.
Класс Social_Larva_Exception - это просто обертка
для Exception. В принципе его можно было и не делать, но мне оно как-то
спокойнее с ним
<?php /* * (c) Pavel Ladygin (digitorum) http://digitorum.ru */ Class Social_Larva_Exception extends Exception { } ?>
Класс Social_Larva_Base - содержит все необходимое для парсинга страниц и отправки запросов к социальной сети.
<?php /* * (c) Pavel Ladygin (digitorum) http://digitorum.ru */ Class Social_Larva_Base { /* * Печеньки для запросов */ protected $_cookies = NULL; /* * Закэшированные данные */ protected $_cache = array(); /* * Юзерагент */ protected $_userAgent = 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7'; /* * Базовое доменное имя */ protected $_baseDomain = ''; /* * Базовый протокол */ protected $_baseProtocol = 'http'; /* * Установить юзерагент */ public function setUserAgent($userAgent = '') { $this->_userAgent = $userAgent; } /* * Запомнить значение */ protected function _setCacheValue($key = '', $value = '') { $this->_cache[$key] = $value; } /* * Вспомнить значение */ protected function _getCacheValue($key = '') { return isset($this->_cache[$key]) ? $this->_cache[$key] : false; } /* * Удалить кэш */ protected function _clearCache($key = '') { $this->_cache = array(); } /* * Получить список печенегк из ответа */ protected function _getCookiesFromResponse($result) { $cookies = array(); preg_match_all('~Set-Cookie:\s*([^;]+)~i', $result, $cookies); if(!count($cookies)) { return array(); } return $cookies[1]; } /* * Отправляем запрос */ protected function _sendRequest($options = array()) { $ch = curl_init(); foreach($options as $option => $value) { curl_setopt($ch, $option, $value); } curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($ch, CURLOPT_USERAGENT, $this->_userAgent); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); //curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); $result = curl_exec($ch); curl_close($ch); if ($result) { return $result; } else { throw new Social_Larva_Exception(curl_error($ch)); } } /* * Получить форму со страницы */ protected function _getFormHtml($pageHtml, $formUniqueAttribute) { if(preg_match('~<form[^<]+' . $formUniqueAttribute . '.*?</form>~is', $pageHtml, $matches)) { return $matches[0]; } return ''; } /* * Получаем поля формы */ protected function _getFormFields($formHtml) { $fields = array(); // пока забираем только инпуты preg_match_all('~<input[^>]+>~is', $formHtml, $matches); foreach($matches[0] as $match) { preg_match_all('~(<|name|type|value)[^\s]+~is', $match, $attributes); $tmp = array(); foreach($attributes[0] as $attribute) { $attribute = explode("=", str_replace(array('\'', '"', '<'), array('','',''), $attribute)); if(count($attribute) == 1) { $tmp['element'] = $attribute[0]; } else { $tmp[$attribute[0]] = $attribute[1]; } } if(isset($tmp['name']) && isset($tmp['element'])) { switch($tmp['element']) { case 'input' : if(isset($tmp['value'])) { $fields[$tmp['name']] = $tmp['value']; } break; default : break; } } } return $fields; } /* * Разбираем форму */ protected function _parseForm($formHtml = '') { $result = array( 'fields' => $this->_getFormFields($formHtml), 'action' => '', 'method' => '' ); if(preg_match_all('~(action=|method=).*?\s~is', $formHtml, $matches)) { foreach($matches[0] as $match) { $match = explode('=', str_replace(array('\'', '"'), array('', ''), $match), 2); if(count($match) == 2) { $result[strtolower($match[0])] = trim($match[1]); } } } if($result['method'] == '') { throw new Social_Larva_Exception('No request method detected'); } if($result['action'] == '') { throw new Social_Larva_Exception('No form action detected'); } $result['method'] = strtoupper($result['method']); if(!preg_match('~https?://~', $result['action'])) { $result['action'] = $this->_baseProtocol . '://' . $this->_baseDomain . $result['action']; } return $result; } /* * Получить главную страницу */ protected function _getMainPageHtml() { $url = $this->_baseProtocol . '://' . $this->_baseDomain; if(!$this->_getCacheValue($url)) { $this->_setCacheValue( $url, $this->_sendRequest( array( CURLOPT_URL => $url, CURLOPT_COOKIE => $this->_cookies ) ) ); } return $this->_getCacheValue($url); } } ?>
Класс Social_Larva_Facebook - это уже непосредственно класс для работы с facebook.
<?php /* * (c) Pavel Ladygin (digitorum) http://digitorum.ru */ Class Social_Larva_Facebook extends Social_Larva_Base { /* * Базовое доменное имя */ protected $_baseDomain = 'www.facebook.com'; /* * Конструктор */ public function __construct($email = '', $password = '') { $this->_login($email, $password); } /* * Деструктор */ public function __destruct() { $this->_logout(); } /* * Авторизация */ private function _login($email = '', $password = '') { $form = $this->_parseForm($this->_getFormHtml($this->_getMainPageHtml(), 'login_form')); $form['fields']['email'] = $email; $form['fields']['pass'] = $password; $result = $this->_sendRequest( array( CURLOPT_URL => $form['action'], CURLOPT_HEADER => true, CURLOPT_NOBODY => true, CURLOPT_CUSTOMREQUEST => $form['method'], CURLOPT_POST => 1, CURLOPT_POSTFIELDS => http_build_query($form['fields']), CURLOPT_COOKIE => NULL ) ); $this->_cookies = $this->_getCookiesFromResponse($result); if(!count($this->_cookies)) { throw new Social_Larva_Exception('Can\'t receive cookies at first step authorization'); } $this->_cookies = $this->_cookies[0]; $result = $this->_sendRequest( array( CURLOPT_URL => $form['action'], CURLOPT_HEADER => true, CURLOPT_NOBODY => true, CURLOPT_CUSTOMREQUEST => $form['method'], CURLOPT_POST => 1, CURLOPT_POSTFIELDS => http_build_query($form['fields']), CURLOPT_COOKIE => $this->_cookies ) ); $this->_cookies = implode(';', $this->_getCookiesFromResponse($result)); if(strpos($this->_cookies, 'c_user') === false) { // если не получилось авторизоваться - выбрасываем эксепшн throw new Social_Larva_Exception('Authorization failed'); } // сбрасываем весь кэш после авторизации $this->_clearCache(); } /* * Выход */ private function _logout() { if($this->_cookies !== NULL) { // ищем форму и поля в ней $form = $this->_parseForm($this->_getFormHtml($this->_getMainPageHtml(), 'logout_form')); // отправляем запрос $result = $this->_sendRequest( array( CURLOPT_URL => $form['action'], CURLOPT_HEADER => true, CURLOPT_CUSTOMREQUEST => $form['method'], CURLOPT_POST => 1, CURLOPT_POSTFIELDS => http_build_query($form['fields']), CURLOPT_COOKIE => $this->_cookies ) ); // смотрим не удалялась ли кука if(strpos($result, 'c_user=deleted') !== false) { $this->_cookies = NULL; $this->_clearCache(); return true; } } return false; } /* * Обновить статус */ public function updateStatus($statusText = '', $privacy = false) { // ищем форму и поля в ней $form = $this->_parseForm($this->_getFormHtml($this->_getMainPageHtml(), '/ajax/updatestatus.php')); $form['fields']['xhpc_message'] = $statusText; $form['fields']['xhpc_message_text'] = $form['fields']['xhpc_message']; if($privacy) { switch(true) { case $privacy == 'Public' : $form['fields']['audience[0][value]'] = 80; break; case $privacy == 'Friends' : $form['fields']['audience[0][value]'] = 40; break; case $privacy == 'Only me' : $form['fields']['audience[0][value]'] = 10; break; default: $form['fields']['audience[0][value]'] = $privacy; break; } } // отправляем запрос $result = $this->_sendRequest( array( CURLOPT_URL => $form['action'], CURLOPT_HEADER => true, CURLOPT_NOBODY => false, CURLOPT_CUSTOMREQUEST => $form['method'], CURLOPT_POST => 1, CURLOPT_POSTFIELDS => http_build_query($form['fields']), CURLOPT_COOKIE => $this->_cookies ) ); // если статус обновился - есть локейшн в заголовках if(strpos($result, 'Location:') !== false) { return true; } return false; } } ?>
Код прозрачен и прокомментирован, поэтому останавливаться на его описании думаю не стоит.
Пример использования:
<?php try { $larva = new Social_Larva_Facebook('ваш@емэйл', 'пароль'); $larva->updateStatus('Test', 'Only me'); } catch (Social_Larva_Exception $e) { print $e->getMessage(); } ?>
Ну и свидетельство того, что все работает:
Так же не стоит забывать о том, что facebook шибко умный, и в случае
огромного количества запросов бан минут на 20 прилетает
моментально
Обновления на GitHub.