From e973a0e0fe57d094ba39cda22c1c1aa29e10f445 Mon Sep 17 00:00:00 2001 From: woxcab Date: Tue, 6 Dec 2016 16:33:37 +0300 Subject: [PATCH] init implementation --- Vk2rss.php | 96 +++++++++++++++++++++++++++++++++++++----------------- index.php | 3 +- utils.php | 27 +++++++++++++-- 3 files changed, 93 insertions(+), 33 deletions(-) diff --git a/Vk2rss.php b/Vk2rss.php index 15df8cc..db9118b 100644 --- a/Vk2rss.php +++ b/Vk2rss.php @@ -95,7 +95,7 @@ class Vk2rss protected $proxy = null; public function __construct($id, $count = 20, $include = null, $exclude = null, $disable_html=false, - $owner_only = false, $access_token = null, + $owner_only = false, $access_token = null, $phone = null, $proxy = null, $proxy_type = null, $proxy_login = null, $proxy_password = null) { if (empty($id)) { @@ -127,6 +127,7 @@ public function __construct($id, $count = 20, $include = null, $exclude = null, $this->disable_html = $disable_html; $this->owner_only = $owner_only; $this->access_token = $access_token; + $this->phone = isset($phone) ? preg_replace('/\D+/u', '', $phone) : null; if (isset($proxy)) { try { $this->proxy = new ProxyDescriptor($proxy, $proxy_type, $proxy_login, $proxy_password); @@ -151,32 +152,32 @@ public function generateRSS() $connector = new ConnectionWrapper($this->proxy); if (!empty($this->domain) || (!empty($this->owner_id) && $this->owner_id < 0)) { - $group_response = $this->getContent($connector, "groups.getById"); - if (property_exists($group_response, 'error') && $group_response->error->error_code != 100) { - throw new APIError($group_response, $connector->getLastUrl()); + try { + $group_response = $this->getContent($connector, "groups.getById"); + } catch (APIError $exc) { + if ($exc->getApiErrorCode() != 100) { + throw $exc; + } } } - if (isset($group_response) && !property_exists($group_response, 'error') && !empty($group_response->response)) { + if (isset($group_response) && !empty($group_response->response)) { $group = $group_response->response[0]; $title = $group->name; $feed_description = self::GROUP_FEED_DESCRIPTION_PREFIX . $group->name; } else { + sleep(1); try { $user_response = $this->getContent($connector, "users.get"); - if (property_exists($user_response, 'error')) { - throw new APIError($user_response, $connector->getLastUrl()); - } } catch (APIError $exc) { throw $exc->getApiErrorCode() == 113 ? new Exception("Invalid user or group identifier", 400) : $exc; } - if (!empty($user_response->response)) { - $profile = $user_response->response[0]; - $title = $profile->first_name . ' ' . $profile->last_name; - $feed_description = self::USER_FEED_DESCRIPTION_PREFIX . $profile->first_name . ' ' . $profile->last_name; - } else { + if (empty($user_response->response)) { throw new Exception("Invalid user or group identifier", 400); } + $profile = $user_response->response[0]; + $title = $profile->first_name . ' ' . $profile->last_name; + $feed_description = self::USER_FEED_DESCRIPTION_PREFIX . $profile->first_name . ' ' . $profile->last_name; } $feed = new FeedWriter(RSS2); @@ -194,9 +195,6 @@ public function generateRSS() for ($offset = 0; $offset < $this->count; $offset += 100) { sleep(1); $wall_response = $this->getContent($connector, "wall.get", $offset); - if (property_exists($wall_response, 'error')) { - throw new APIError($wall_response, $connector->getLastUrl()); - } if (empty($wall_response->response->items)) { break; @@ -421,20 +419,60 @@ protected function getContent($connector, $api_method, $offset = null) } $connector->openConnection(); $content = null; - try { - $content = $connector->getContent($url, null, true); - $connector->closeConnection(); - } catch (Exception $exc) { - $connector->closeConnection(); - throw new Exception("Failed to get content of URL ${url}: " . $exc->getMessage(), $exc->getCode()); - } - if (!$this->disable_html) { - $content = strtr($content, array('<' => '<', - '>' => '>', - '\"' => '"', - '\'' => ''')); + for ($attempt = 0; $attempt < 2; $attempt++) { + try { + error_log("Attempt {$attempt}. URL {$url}"); + $content = $connector->getContent($url, null, true); + } catch (Exception $exc) { + $connector->closeConnection(); + throw new Exception("Failed to get content of URL ${url}: " . $exc->getMessage(), $exc->getCode()); + } + if (!$this->disable_html) { + $content = strtr($content, array('<' => '<', + '>' => '>', + '\"' => '"', + '\'' => ''')); + } + $response = json_decode($content); + if (is_null($response)) { + throw new Exception("Failed to decode content of URL ${url}", 500); + } + if (!property_exists($response, 'error')) { + break; + } + $error = new APIError($response, $url); + if ($error->getApiErrorCode() != 17) { + throw $error; + } + $valid_resp = $connector->getContent($response->error->redirect_uri, null, true); + file_put_contents('/var/www/dev/vkrss/responses.log', + "Got API Error 17. Opened redirect_uri {$response->error->redirect_uri}. " + . "FIRST RESPONSE: " . PHP_EOL. PHP_EOL . $valid_resp. PHP_EOL. PHP_EOL. PHP_EOL, + FILE_APPEND); + if (mb_strlen($valid_resp) > 300) { + if (!isset($this->phone) || $attempt > 0) { + throw $error; + } +// parse_str(parse_url($response->error->redirect_uri, PHP_URL_QUERY), $redirect_params); + preg_match('/form method="post" action="([^"]+)"/u', $valid_resp, $match); + $valid_url = 'https://vk.com' . $match[1]; + preg_match_all('/"field_prefix">\D*(\d+)/u', $valid_resp, $match); + if (mb_substr($this->phone, 0, mb_strlen($match[1][0])) !== $match[1][0] + || mb_substr($this->phone, -mb_strlen($match[1][1])) !== $match[1][1]) { + throw new Exception("Invalid phone number {$this->phone}. " + . "The phone must starts with {$match[1][0]} and ends with {$match[1][1]}", + 400); + } + $post_params = array('code' => mb_substr($this->phone, mb_strlen($match[1][0]), -mb_strlen($match[1][1]))); + $valid_resp = $connector->getContent($valid_url, null, true, true, $post_params); + file_put_contents('/var/www/dev/vkrss/responses.log', + "SENT POST request with phone. SECOND RESPONSE: " . PHP_EOL. PHP_EOL. $valid_resp. PHP_EOL. PHP_EOL. PHP_EOL, + FILE_APPEND); + } + sleep(1); } - return json_decode($content); + $connector->closeConnection(); + return $response; } /** diff --git a/index.php b/index.php index 9a20655..8bcb201 100644 --- a/index.php +++ b/index.php @@ -3,7 +3,7 @@ header("Content-type: text/xml; charset=utf-8"); $supported_parameters = array('id', 'domain', 'owner_id', 'count', 'include', 'exclude', - 'disable_html', 'owner_only', 'access_token', + 'disable_html', 'owner_only', 'access_token', 'phone', 'proxy', 'proxy_type', 'proxy_login', 'proxy_password'); try { @@ -23,6 +23,7 @@ isset($_GET['disable_html']), isset($_GET['owner_only']), isset($_GET['access_token']) ? $_GET['access_token'] : null, + isset($_GET['phone']) ? $_GET['phone'] : null, isset($_GET['proxy']) ? $_GET['proxy'] : null, isset($_GET['proxy_type']) ? mb_strtolower($_GET['proxy_type']) : null, isset($_GET['proxy_login']) ? $_GET['proxy_login'] : null, diff --git a/utils.php b/utils.php index ecedbaf..3c5599c 100644 --- a/utils.php +++ b/utils.php @@ -220,6 +220,7 @@ public function __construct($proxy = null) case self::BUILTIN_DOWNLOADER: $opts = array(); $opts['http']['timeout'] = self::CONNECT_TIMEOUT; + $opts['http']['user_agent'] = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0'; if (isset($proxy)) { $this->proxyType = $proxy->getType(); $address = $proxy->getAddress(); @@ -237,7 +238,9 @@ public function __construct($proxy = null) case self::CURL_DOWNLOADER: $this->curlOpts = array(CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, - CURLOPT_CONNECTTIMEOUT => self::CONNECT_TIMEOUT); + CURLOPT_CONNECTTIMEOUT => self::CONNECT_TIMEOUT, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_USERAGENT => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0'); if (isset($proxy)) { $this->curlOpts[CURLOPT_PROXY] = $proxy->getAddress(); $this->proxyType = $proxy->getType(); @@ -300,10 +303,12 @@ public function closeConnection() * @param string|null $url URL * @param string|null $https_url URL with HTTPS protocol. If it's null then it's equal to $url where HTTP is replaced with HTTPS * @param bool $http_to_https Whether to use HTTP URL with replacing its HTTP protocol on HTTPS protocol + * @param bool $use_http_post Whether to use HTTP POST method + * @param array $post_params Request parameters for POST method * @return mixed Response body or FALSE on failure * @throws Exception If HTTPS url is passed and PHP or its extension does not support OpenSSL */ - public function getContent($url, $https_url = null, $http_to_https = false) + public function getContent($url, $https_url = null, $http_to_https = false, $use_http_post=false, $post_params=array()) { if ($this->httpsAllowed && (!empty($https_url) || $http_to_https)) { $request_url = empty($https_url) ? preg_replace('/^http:/ui', 'https:', $url) : $https_url; @@ -316,6 +321,12 @@ public function getContent($url, $https_url = null, $http_to_https = false) $this->lastUrl = $request_url; switch ($this->downloader) { case self::BUILTIN_DOWNLOADER: + if ($use_http_post) { + $this->context['http']['method'] = 'POST'; + $this->context['http']['content'] = http_build_query($post_params); + } else { + $this->context['http']['method'] = 'GET'; + } $body = @file_get_contents($request_url, false, $this->context); $response_code = isset($http_response_header) ? (int)substr($http_response_header[0], 9, 3) : null; if (empty($body)) { @@ -329,7 +340,16 @@ public function getContent($url, $https_url = null, $http_to_https = false) break; case self::CURL_DOWNLOADER: curl_setopt($this->curlHandler, CURLOPT_URL, $request_url); + curl_setopt($this->curlHandler, CURLOPT_POST, $use_http_post); + if ($use_http_post) { + curl_setopt($this->curlHandler, CURLOPT_POSTFIELDS, http_build_query($post_params)); + } $response = curl_exec($this->curlHandler); + if ($use_http_post) { + file_put_contents('/var/www/dev/vkrss/responses.log', + 'INTERMEDIATE RESPONSE: ' . PHP_EOL. PHP_EOL. $response. PHP_EOL. PHP_EOL. PHP_EOL, + FILE_APPEND); + } if (empty($response)) { throw new Exception("Cannot retrieve data from URL '${request_url}': " . curl_error($this->curlHandler)); } @@ -343,7 +363,8 @@ public function getContent($url, $https_url = null, $http_to_https = false) } list($header, ) = explode("\r\n", $header, 2); $response_code = (int)substr($header, 9, 3); - if ($response_code != 200) { + error_log($response_code); + if ($response_code != 200 && $response_code != 302) { throw new Exception("Cannot retrieve data from URL '${request_url}': " . substr($header, 13), $response_code); } break;