From c154c9f438f26499a5a64e4effc1835ba520ed24 Mon Sep 17 00:00:00 2001 From: RedHood Date: Sat, 6 Jun 2020 18:27:31 +1000 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B2=D1=8B=D0=B9=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BC=D0=B8=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Auth.php | 331 ++++++++++++++++ Base.php | 210 ++++++++++ Coin.php | 301 ++++++++++++++ Execute.php | 272 +++++++++++++ Group.php | 45 +++ LongPoll.php | 219 +++++++++++ Message.php | 64 +++ Post.php | 39 ++ SiteAuth.php | 42 ++ VkApiException.php | 29 ++ config_library.php | 20 + vk_api.php | 958 +++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 2530 insertions(+) create mode 100644 Auth.php create mode 100644 Base.php create mode 100644 Coin.php create mode 100644 Execute.php create mode 100644 Group.php create mode 100644 LongPoll.php create mode 100644 Message.php create mode 100644 Post.php create mode 100644 SiteAuth.php create mode 100644 VkApiException.php create mode 100644 config_library.php create mode 100644 vk_api.php diff --git a/Auth.php b/Auth.php new file mode 100644 index 0000000..08e7167 --- /dev/null +++ b/Auth.php @@ -0,0 +1,331 @@ +useragent = $other['useragent']; + if (isset($other['id_app'])) + $this->id_app = $other['id_app']; + } + if (isset($pass)) { + $this->login = $login; + $this->pass = $pass; + $this->method = 'pass'; + if (!$mobile) + $this->auth_method = 1; + } else { + $this->method = 'cookie'; + $this->cookie = json_decode($login, true); + $this->auth_method = 1; + } + } + + /** + * @throws VkApiException + */ + public function auth() + { + if ($this->auth_method == 0) + throw new VkApiException("Только для авторизации через приложение"); + $this->loginInVK(); + } + + /** + * @throws VkApiException + */ + private function loginInVK() + { + $query_main_page = $this->getCURL('https://vk.com/'); + preg_match('/name=\"ip_h\" value=\"(.*?)\"/s', $query_main_page['body'], $ip_h); + preg_match('/name=\"lg_h\" value=\"(.*?)\"/s', $query_main_page['body'], $lg_h); + + $values_auth = [ + 'act' => 'login', + 'role' => 'al_frame', + '_origin' => 'https://vk.com', + 'utf8' => '1', + 'email' => $this->login, + 'pass' => $this->pass, + 'lg_h' => $lg_h[1], + 'ig_h' => $ip_h[1] + ]; + $get_url_redirect_auch = $this->getCURL('https://login.vk.com/?act=login', $values_auth); + + if (!isset($get_url_redirect_auch['header']['location'])) + throw new VkApiException("Ошибка, ссылка редиректа не получена"); + + $auth_page = $this->getCURL($get_url_redirect_auch['header']['location'][0]); + + if (!isset($auth_page['header']['set-cookie'])) + throw new VkApiException("Ошибка, куки пользователя не получены"); + + $this->is_auth = 1; + } + + /** + * @param $url + * @param null $post_values + * @param bool $cookie + * @return array + */ + private function getCURL($url, $post_values = null, $cookie = true) + { + if ($curl = curl_init()) { + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_USERAGENT, $this->useragent); + if (isset($post_values)) { + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $post_values); + } +// +// curl_setopt($curl, CURLOPT_HTTPHEADER, [ +// "Content-Type: application/x-www-form-urlencoded", +// "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", +// "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36" +// ]); + + if ($cookie and isset($this->cookie)) { + $send_cookie = []; + foreach ($this->cookie as $cookie_name => $cookie_val) { + $send_cookie[] = "$cookie_name=$cookie_val"; + } + curl_setopt($curl, CURLOPT_COOKIE, join('; ', $send_cookie)); + } + + curl_setopt($curl, CURLOPT_HEADERFUNCTION, + function ($curl, $header) use (&$headers) { + $len = strlen($header); + $header = explode(':', $header, 2); + if (count($header) < 2) // ignore invalid headers + return $len; + + $name = strtolower(trim($header[0])); + if (isset($headers) and !array_key_exists($name, $headers)) + $headers[$name] = [trim($header[1])]; + else + $headers[$name][] = trim($header[1]); + + return $len; + } + ); + + $out = curl_exec($curl); + curl_close($curl); + if (isset($headers['set-cookie'])) + $this->parseCookie($headers['set-cookie']); + return ['header' => $headers, 'body' => $out]; + } + } + + /** + * @param $new_cookie + */ + private function parseCookie($new_cookie) + { + foreach ($new_cookie as $cookie) { + preg_match("!(.*?)=(.*?);(.*)!s", $cookie, $preger); + if ($preger[2] == 'DELETED') + unset($this->cookie[$preger[1]]); + else + $this->cookie[$preger[1]] = $preger[2] . ';' . $preger[3]; + } + } + + /** + * @return false|string + */ + public function dumpCookie() + { + return json_encode($this->cookie); + } + + /** + * @return bool + */ + public function isAuth() + { + $header = $this->getCURL("https://vk.com/feed")['header']; + if (isset($header['location'][0]) and strpos($header['location'][0], 'login.vk.com')) + return False; + return True; + } + + /** + * @param null $captcha_key + * @param null $captcha_sid + * @return string + * @throws VkApiException + */ + public function getAccessToken($captcha_key = null, $captcha_sid = null) + { + if ($this->access_token != '') + return $this->access_token; + if ($this->auth_method) { + if ($this->is_auth == 0) + $this->loginInVK(); + if ($this->access_token == '') + $this->access_token = $this->generateAccessToken(); + } else { + if (isset($this->captcha_sid)) + $captcha_sid = $this->captcha_sid; + $this->access_token = $this->generateAccessTokenMobile($captcha_key, $captcha_sid); + } + return $this->access_token; + } + + /** + * @param null $scope + * @param bool $resend + * @return mixed + * @throws VkApiException + */ + private function generateAccessToken($scope = null, $resend = false) + { + $this->scope = []; + if (!isset($scope)) { + $scope = $this->default_scope; + } + foreach (preg_split("!,!", $scope) as $one_scope) + $this->scope[] = $one_scope; + $scope = "&scope=$scope"; + + if ($resend) + $scope .= "&revoke=1"; + + $token_url = 'https://oauth.vk.com/authorize?client_id=' . $this->id_app . + $scope . + '&response_type=token'; + + $get_url_token = $this->getCURL($token_url); + + if (isset($get_url_token['header']['location'][0])) + $url_token = $get_url_token['header']['location'][0]; + else { + preg_match('!location.href = "(.*)"\+addr!s', $get_url_token['body'], $url_token); + + if (!isset($url_token[1])) { + throw new VkApiException("Не получилось получить токен на этапе получения ссылки подтверждения"); + } + $url_token = $url_token[1]; + } + + $access_token_location = $this->getCURL($url_token)['header']['location'][0]; + + if (preg_match("!access_token=(.*?)&!s", $access_token_location, $access_token) != 1) + throw new VkApiException("Не удалось найти access_token в строке ридеректа, ошибка:" . $this->getCURL($access_token_location, null, false)['body']); + return $access_token[1]; + } + + /** + * @param $captcha_key + * @param $captcha_sid + * @return mixed + * @throws VkApiException + */ + private function generateAccessTokenMobile($captcha_key, $captcha_sid) + { + if (!isset($this->pass)) + throw new VkApiException("Метод работает только с логином и паролем"); + + $captcha = ''; + $this->scope = []; + $scope = $this->default_scope; + foreach (preg_split("!,!", $scope) as $one_scope) + $this->scope[] = $one_scope; + $scope = "&scope=$scope"; + + if (isset($captcha_sid) and isset($captcha_key)) + $captcha = "&captcha_sid=$captcha_sid&captcha_key=$captcha_key"; + + $token_url = 'https://oauth.vk.com/token?grant_type=password&client_id=2274003&client_secret=hHbZxrka2uZ6jB1inYsH' . + '&username=' . $this->login . + '&password=' . $this->pass . + $scope . + $captcha; + $response_auth = $this->getCURL($token_url, null, false)['body']; + $response_auth = json_decode($response_auth, true); + + if (isset($response_auth['access_token'])) + return $response_auth['access_token']; + else + throw new VkApiException(json_encode($response_auth)); + } +} diff --git a/Base.php b/Base.php new file mode 100644 index 0000000..3b094fe --- /dev/null +++ b/Base.php @@ -0,0 +1,210 @@ +vk_api = $vk_api; + } + + /** + * @throws VkApiException + */ + public function addImage() + { + $this->addMedia(func_get_args(), 'images'); + } + + /** + * @param $media + * @param $selector + * @throws VkApiException + */ + protected function addMedia($media, $selector) + { + if ($this->countMedia() + count($media) > 10) + throw new VkApiException('Вы превысили максимальный лимит в 10 файлов'); + else { + if (is_array($media)) + foreach ($media as $val) { + if (is_array($val) and $selector != 'docs') { + if (isset($this->media[$selector])) + $this->media[$selector] = array_merge($this->media[$selector], $val); + else + $this->media[$selector] = $val; + } else + $this->media[$selector][] = $val; + } + else + $this->media[$selector][] = $media; + } + + } + + /** + * @return int + */ + private function countMedia() + { + $count = 0; + foreach ($this->media as $kye => $var) { + $count += count($var); + } + return $count; + } + + /** + * @param $prop + * @param $value + * @return int + */ + public function addProp($prop, $value) + { + if (!in_array($prop, $this->prop_list)) + return 0; + $this->props += [$prop => $value]; + return $prop; + } + + /** + * @param $docs + * @param null $title + * @throws VkApiException + */ + public function addDocs($docs, $title = null) + { + if (is_string($docs)) + $docs = [0 => ['path' => $docs, 'title' => $title]]; + else + foreach ($docs as $id => $file) { + if (is_string($file)) + $docs[$id] = ['path' => $file, 'title' => null]; + } + $this->addMedia($docs, 'docs'); + } + + /** + * @param $images + * @return int + */ + public function removeImages($images) + { + return $this->removeMedia($images, 'images'); + } + + /** + * @param $media + * @param $selector + * @return int + */ + protected function removeMedia($media, $selector) + { + $search = array_search($media, $this->media[$selector]); + if ($search) { + $remove_val = $this->media[$selector][$search]; + unset($this->media[$selector][$search]); + return $remove_val; + } + if (is_numeric($media) and ($media >= 0 and $media <= count($this->media[$selector]) - 1)) { + $remove_val = $this->media[$selector][$media]; + unset($this->media[$selector][$media]); + return $remove_val; + } + return 0; + } + + /** + * @param $docs + * @return int + */ + public function removeDocs($docs) + { + return $this->removeMedia($docs, 'docs'); + } + + /** + * @param $prop + * @return int|mixed + */ + public function removeProp($prop) + { + $search = array_search($prop, $this->props); + if ($search) { + $remove_val = $this->props[$search]; + unset($this->props[$search]); + return $remove_val; + } + if (is_numeric($prop) and ($prop >= 0 and $prop <= count($this->props) - 1)) { + $remove_val = $this->props[$prop]; + unset($this->props[$prop]); + return $remove_val; + } + return 0; + } + + /** + * @return array + */ + public function getMedia() + { + if (isset($this->media)) + return $this->media; + else return []; + } + + /** + * @return array + */ + public function getMessage() + { + return $this->message; + } + + /** + * @param $message + */ + public function setMessage($message) + { + $this->message = $message; + } + + /** + * @return array + */ + public function getProps() + { + return $this->props; + } + +} \ No newline at end of file diff --git a/Coin.php b/Coin.php new file mode 100644 index 0000000..9812141 --- /dev/null +++ b/Coin.php @@ -0,0 +1,301 @@ +merchant_key = $token; + $this->merchant_id = $merchant_id; + } + + /** + * @param $token + * @param $merchant_id + * @return Coin + */ + public static function create($token, $merchant_id) { + return new self($token, $merchant_id); + } + + /** + * @param $user_id + * @param int $amount + * @return array|bool + */ + public function sendCoins($user_id, $amount) { + try { + $amount = $this->request('send', ['amount' => $amount * 1000, 'toId' => $user_id]); + if (isset($amount['amount']) && isset($amount['current'])) { + $amount['amount'] /= 1000; + $amount['current'] /= 1000; + } + return 1; + } catch (VkApiException $e) { + return 0; + } + } + + + /** + * @param array $user_ids + * @return array|bool + * @throws VkApiException + */ + public function getBalance($user_ids = []) { + if (empty($user_ids) or !is_array($user_ids)) + $user_ids = empty($user_ids) ? [$this->merchant_id] : [$user_ids]; + $results = $this->request('score', ['userIds' => $user_ids]); + if (count($results) < count($user_ids)) { + $nonexistent_id = join(',', (array_diff($user_ids, array_keys($results)))); + throw new VkApiException("Попытка получить баланс следущих несуществующих пользователей:\n$nonexistent_id"); + } + $this->_toCoin($results); + $results = array_combine($user_ids, array_values($results)); + if (is_array($user_ids) && count($user_ids) == 1) + return $results[current($user_ids)]; + else + return $results; + } + + /** + * @param string $name + * @return array|bool + * @throws VkApiException + */ + public function setName($name) { + return $this->request('set', ['name' => $name]); + } + + + /** + * @param string $url + * @return array|bool + * @throws VkApiException + */ + public function setCallBack($url = null) { + return $this->request('set', ['callback' => $url]); + } + + + /** + * @return array|bool + * @throws VkApiException + */ + public function deleteCallBack() { + return $this->request('set', ['callback' => null]); + } + + + /** + * @return array|bool + * @throws VkApiException + */ + public function getLogs() { + return $this->request('set', ['status' => 1]); + } + + /** + * @param int $sum + * @param int $payload + * @param bool $fixed_sum + * @param bool $to_hex + * @return array|string + */ + public function getLink($sum = 0, $fixed_sum = true, $payload = 0, $to_hex = false) { + $payload = ($payload !== 0) ? $payload : rand(-2000000000, 2000000000); + $fixed_sum = $fixed_sum ? '' : '_1'; + if ($sum === 0) + return 'vk.com/coin#t' . $this->merchant_id; + $sum = (int)($sum * 1000); + if ($to_hex) { + $merchant_id = dechex($this->merchant_id); + $sum = dechex($sum); + $payload = dechex($payload); + return ['url' => "vk.com/coin#m{$merchant_id}_{$sum}_{$payload}{$fixed_sum}", 'payload' => $payload]; + } else { + $merchant_id = $this->merchant_id; + return ['url' => "vk.com/coin#x{$merchant_id}_{$sum}_{$payload}{$fixed_sum}", 'payload' => $payload]; + } + } + + /** + * @param array $last_tx + * @return bool|mixed + * @throws VkApiException + */ + public function getStoryShop($last_tx = []) { + return $this->getTransaction(1, $last_tx); + } + + /** + * @param array $last_tx + * @return bool|mixed + * @throws VkApiException + */ + public function getStoryAccount($last_tx = []) { + return $this->getTransaction(2, $last_tx); + } + + /** + * @param array $transaction + * @return bool|mixed + * @throws VkApiException + */ + public function getInfoTransactions($id_transactions) { + if (is_array($id_transactions)) + return $this->getTransaction($id_transactions); + else if (is_numeric($id_transactions)) + return $this->getTransaction([$id_transactions]); + return 0; + } + + /** + * @param $from_id + * @param $amount + * @param $payloadа + * @param $verify + * @param $data + */ + public function initVars(&$from_id, &$amount, &$payload, &$verify, &$data) { + print 'OK'; + $data_request = json_decode(file_get_contents('php://input')); + $data = $this->data_request = $data_request; + if (is_object($this->data_request) && + isset($this->data_request->id) && + isset($this->data_request->from_id) && + isset($this->data_request->amount) && + isset($this->data_request->payload) && + isset($this->data_request->key)) { + $from_id = $data_request->from_id; + $payload = $data_request->payload; + $amount = $data_request->amount; + $verify = $this->verifyKeys(); + } + } + + /** + * @return bool + */ + private function verifyKeys() { + $parameters = [ + $this->data_request->id, + $this->data_request->from_id, + $this->data_request->amount, + $this->data_request->payload, + $this->data_request->merchant_key, + ]; + $key = md5(implode(';', $parameters)); + return $this->data_request->key === $key; + } + + /** + * @param $tx + * @param array $last_tx + * @return bool|mixed + * @throws VkApiException + */ + private function getTransaction($tx, $last_tx = []) { + if (!empty($last_tx)) + $last_tx = ['lastTx' => $last_tx]; + if (!is_array($tx)) + $tx = [$tx]; + $request = $this->request('tx', ['tx' => $tx] + $last_tx); + $this->_toCoin($request); + return $request; + } + + /** + * @param $results + */ + private function _toCoin(&$results) { + if (is_array($results)) + foreach ($results as $key => $value) { + if (is_array($value) && isset($results[$key]['amount'])) + @$results[$key]['amount'] = is_int($results[$key]['amount']) ? + (float)($value['amount'] / 1000) : + $results[$key]['amount']; + else + $results[$key] = (float)($value / 1000); + } + } + + /** + * @param $method + * @param array $params + * @return bool|mixed + * @throws VkApiException + */ + private function request($method, $params = []) { + $params['merchantId'] = $this->merchant_id; + $params['key'] = $this->merchant_key; + + $url = 'https://coin-without-bugs.vkforms.ru/merchant/' . $method . '/'; + try { + return $this->request_core($url, $params); + } catch (VkApiException $e) { + $exception = json_decode($e->getMessage(), true); + if (in_array($exception['error']['code'], [500, 422])) + throw new VkApiException($exception['error']['message']); + else + throw new VkApiException($e->getMessage()); + } + } + + /** + * @param $url + * @param array $params + * @return mixed + * @throws VkApiException + */ + private function request_core($url, $params = []) { + if (function_exists('curl_init')) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json' + ]); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params, JSON_UNESCAPED_UNICODE)); + $result = json_decode(curl_exec($ch), True); + curl_close($ch); + } else { + $result = json_decode(file_get_contents($url, true, stream_context_create([ + 'http' => [ + 'method' => 'POST', + 'header' => "Content-Type: application/json\r\n", + 'content' => http_build_query($params) + ] + ])), true); + } + if (!isset($result) or isset($result['error'])) + throw new VkApiException('Вк вернул ошибку:' . json_encode($result)); + if (isset($result['response'])) + return $result['response']; + else + return $result; + } +} diff --git a/Execute.php b/Execute.php new file mode 100644 index 0000000..d6dc1ca --- /dev/null +++ b/Execute.php @@ -0,0 +1,272 @@ +copyAllDataclass()); + $this->vk = $vk; + } + + public function __destruct() { + $this->exec(); + } + + /** + * @param null $id + * @param null $message + * @param null $payload + * @param null $user_id + * @param null $type + * @param null $data + * @return array|mixed|null + */ + public function initVars(&$id = null, &$message = null, &$payload = null, &$user_id = null, &$type = null, &$data = null) { + if (!$this->vk->debug_mode) + $this->vk->sendOK(); + $data = $this->vk->data; + $data_backup = $this->vk->data; + $type = isset($data->type) ? $data->type : null; + if($type == 'message_new' && isset($data->object->message)) { + $data->object = $data->object->message; + } + $id = isset($data->object->peer_id) ? $data->object->peer_id : null; + $message = isset($data->object->text) ? $data->object->text : null; + $payload = isset($data->object->payload) ? json_decode($data->object->payload, true) : null; + $user_id = isset($data->object->from_id) ? $data->object->from_id : null; + $data = $data_backup; + return $data_backup; + } + + public function sendMessage($id, $message, $props = []) { + $message = $this->vk->placeholders($id, $message); + $this->messages[] = ['peer_id' => $id, 'message' => $message, "random_id" => rand(-2147483648, 2147483647)] + $props; + $this->counter += 1; + $this->checkExec(); + } + + public function sendButton($id, $message, $buttons = [], $inline = false, $one_time = False, $params = []) { + $keyboard = $this->generateKeyboard($buttons, $inline, $one_time); + $message = $this->vk->placeholders($id, $message); + $this->messages[] = ['message' => $message, 'peer_id' => $id, 'keyboard' => $keyboard, "random_id" => rand(-2147483648, 2147483647)] + $params; + $this->counter += 1; + $this->checkExec(); + } + + public function reply($message, $params = []) { + if ($this->vk->data != []) { + return $this->sendMessage($this->vk->data->object->peer_id, $message, $params); + } else { + throw new VkApiException('Вк не прислал callback, возможно вы пытаетесь запустить скрипт с локалки'); + } + } + + private function generateUrlPhotos($id, $count) { + $code = []; + for ($i = 0; $i < $count; ++$i) + $code[] = "API.photos.getMessagesUploadServer({\"peer_id\" : $id})"; + return $this->request("execute", ["code" => "return [".join(',', $code). "];"]); + } + + private function generateUrlDocs($id, $count) { + $code = []; + for ($i = 0; $i < $count; ++$i) + $code[] = "API.docs.getMessagesUploadServer({\"peer_id\" : $id, \"type\": \"doc\"})"; + return $this->request("execute", ["code" => "return [".join(',', $code). "];"]); + } + + public function createMessages($id, $message = [], $props = [], $media = [], $keyboard = []) { + + if (!isset($media['images'])) + $media['images'] = []; + if (!isset($media['docs'])) + $media['docs'] = []; + + if (count($media['docs']) + count($media['images']) + 1 + $this->counter > Execute::$max_counter) + $this->exec(); + + if (count($media['images']) != 0) + $photo_urls = $this->generateUrlPhotos($id, count($media['images'])); + + if (count($media['docs']) != 0) + $doc_urls = $this->generateUrlDocs($id, count($media['docs'])); + + if ($keyboard != []) + $object = [ + 'id' => $id, + 'message' => $message, + 'keyboard_content' => $this->generateKeyboard($keyboard['keyboard'], $keyboard['inline'], $keyboard['one_time']), + 'images_content' => [], + 'docs_content' => [] + ]; + else + $object = [ + 'id' => $id, + 'message' => $message, + 'keyboard_content' => [], + 'images_content' => [], + 'docs_content' => [] + ]; + + foreach ($media as $selector => $massiv) { + switch ($selector) { + case "images": + foreach ($massiv as $key => $image) { + for ($i = 0; $i < $this->try_count_resend_file; ++$i) { + try { + $answer_vk = json_decode($this->sendFiles($photo_urls[$key]['upload_url'], $image, 'photo'), true); + $object['images_content'][] = ['photo' => $answer_vk['photo'], 'server' => $answer_vk['server'], 'hash' => $answer_vk['hash']]; + $this->counter += 1; + break; + } catch (VkApiException $e) { + sleep(1); + $exception = json_decode($e->getMessage(), true); + if ($exception['error']['error_code'] != 121) + throw new VkApiException($e->getMessage()); + } + } + } + break; + case "docs": + foreach ($massiv as $key => $document) { + for ($i = 0; $i < $this->try_count_resend_file; ++$i) { + try { + $title = isset($document['title']) ? $document['title'] : preg_replace("!.*?/!", '', $document); + $answer_vk = json_decode($this->sendFiles($doc_urls[$key]['upload_url'], $document['path']), true); + $object['docs_content'][] = ['file' => $answer_vk['file'], 'title' => $title]; + $this->counter += 1; + break; + } catch (VkApiException $e) { + sleep(1); + $exception = json_decode($e->getMessage(), true); + if ($exception['error']['error_code'] != 121) + throw new VkApiException($e->getMessage()); + } + } + } + break; + case "other": + break; + } + } + $this->counter += 1; + $this->constructors_messages[] = $object; + $this->checkExec(); + return true; + } + + private function getConversationsExec($offset) { + $code = 'var count = API.messages.getConversations({"count": 200, "offset": 0})["count"]; +var start_offset = '. $offset .'; +var temp_count = 0; +var count_apis = 1; +var result = []; +var write_allowed = []; +var ids = []; +while ((temp_count + start_offset) < count && count_apis < 25) { + result = API.messages.getConversations({"count": 200, "offset": (temp_count + start_offset)})["items"]@.conversation; + write_allowed = write_allowed + result@.can_write@.allowed; + ids = ids + result@.peer@.id; + temp_count = temp_count + 200; + count_apis = count_apis + 1; +} +return {"count": count, "offset_ok": (temp_count + start_offset),"write_allowed": write_allowed, "ids": ids};'; +// $code = 'return API.messages.getConversations({"count": 200, "offset": 0})["count"];'; + return $this->request("execute", ["code" => $code]); + } + + private function getConversationsIds() { + $ids = []; + + $exec_result = [ + "count" => 1, + "offset_ok" => 0 + ]; + while ($exec_result['count'] > $exec_result['offset_ok']) { + $exec_result = $this->getConversationsExec($exec_result['offset_ok']); + echo "{$exec_result['offset_ok']} / {$exec_result['count']}, "; + foreach ($exec_result['write_allowed'] as $key => $var) + if ($var) + $ids [] = $exec_result['ids'][$key]; + } + $count = count($ids); + $ids = array_unique($ids); + echo "Complete!\nВсего id: ".$count."\nДубликатов: ".($count - count($ids))."\n"; + return $ids; + } + +// public function sendAllDialogs($message) { +// $ids = $this->getConversationsIds(); +// $ids = array_chunk($ids, 100); +// foreach ($ids as $ids_chunk) { +// $this->messages[] = ['user_ids' => join(',', $ids_chunk), 'message' => $message, "random_id" => rand(-2147483648, 2147483647)]; +// $this->counter += 1; +// $this->checkExec(); +// } +// echo "COUNT = ".$this->counter."\n"; +// } + + private function checkExec() { + if ($this->counter >= Execute::$max_counter) + return $this->exec(); + return false; + } + + public function exec() { + if ($this->counter == 0) + return false; + $this->counter = 0; + $code = 'var query = '. json_encode($this->constructors_messages, JSON_UNESCAPED_UNICODE) .'; +var query_message = '. json_encode($this->messages, JSON_UNESCAPED_UNICODE) .'; + +var count = 0; +var count_image = 0; +var text_attach_photo = ""; +var resulter = []; + +var data_result = []; + +while (query[count] != null) { + text_attach_photo = ""; + resulter = []; + count_image = 0; + while (query[count]["images_content"][count_image] != null) { + resulter = API.photos.saveMessagesPhoto(query[count]["images_content"][count_image]); + if (text_attach_photo == "") { + text_attach_photo = "photo" + resulter[0]["owner_id"] + "_" + resulter[0]["id"]; + } else { + text_attach_photo = text_attach_photo + ",photo" + resulter[0]["owner_id"] + "_" + resulter[0]["id"]; + } + count_image = count_image + 1; + } + count_image = 0; + while (query[count]["docs_content"][count_image] != null) { + resulter = API.docs.save(query[count]["docs_content"][count_image]); + if (text_attach_photo == "") { + text_attach_photo = "doc" + resulter["doc"]["owner_id"] + "_" + resulter["doc"]["id"]; + } else { + text_attach_photo = text_attach_photo + ",doc" + resulter["doc"]["owner_id"] + "_" + resulter["doc"]["id"]; + } + count_image = count_image + 1; + } + data_result.push(API.messages.send({"peer_id": query[count]["id"], "message": query[count]["message"], "random_id": 0, "attachment": text_attach_photo, "keyboard": query[count]["keyboard_content"]})); + count = count + 1; +} + +count = 0; +while (query_message[count] != null) { + data_result.push(API.messages.send(query_message[count])); + count = count + 1; +} + +return data_result;'; + $this->messages = []; + $this->constructors_messages = []; + return $this->request("execute", ["code" => $code]); + } +} diff --git a/Group.php b/Group.php new file mode 100644 index 0000000..1891d40 --- /dev/null +++ b/Group.php @@ -0,0 +1,45 @@ +groupID = $groupID; + parent::setAllDataclass($vk_api->copyAllDataclass()); + } + + /** + * @param $method + * @param $params + * @return array + */ + protected function editRequestParams($method, $params) + { +// if ($method == 'messages.send' or $method == 'photos.saveMessagesPhoto') + $params['group_id'] = $this->groupID; + return [$method, $params]; + } +} \ No newline at end of file diff --git a/LongPoll.php b/LongPoll.php new file mode 100644 index 0000000..bd0a9ee --- /dev/null +++ b/LongPoll.php @@ -0,0 +1,219 @@ +copyAllDataclass()); + $this->vk = $vk; + $data = $this->vk->userInfo(); + if ($data != false) { + $this->vk->auth_type = 'user'; + $this->user_id = $data['id']; + } else { + $this->vk->auth_type = 'group'; + $this->group_id = $this->vk->request('groups.getById', [])[0]['id']; + $this->vk->request('groups.setLongPollSettings', [ + 'group_id' => $this->group_id, + 'enabled' => 1, + 'api_version' => $this->vk->version, + 'message_new' => 1, + ]); + } + $this->getLongPollServer(); + } + + /** + * + */ + public function getLongPollServer() + { + if ($this->vk->auth_type == 'user') + $data = $this->vk->request('messages.getLongPollServer', ['need_pts' => 1, 'lp_version' => 3]); + else + $data = $this->vk->request('groups.getLongPollServer', ['group_id' => $this->group_id]); + unset($this->key); + unset($this->server); + unset($this->ts); + list($this->key, $this->server, $this->ts) = [$data['key'], $data['server'], $data['ts']]; + } + + /** + * @param $anon + * @throws VkApiException + */ + public function listen($anon) + { + while ($data = $this->processingData()) { + foreach ($data->updates as $event) { + unset($this->vk->data); + $this->vk->data = $event; + $anon($event); + } + if ($this->vk instanceof Execute) { + $this->vk->exec(); + } + } + } + + /** + * @return mixed + * @throws VkApiException + */ + public function processingData() + { + $data = $this->getData(); + if (isset($data->failed)) { + if ($data->failed == 1) { + unset($this->ts); + $this->ts = $data->ts; + } + else { + $this->getLongPollServer(); + $data = $this->getData(); + } + } + unset($this->ts); + $this->ts = $data->ts; + return $data; + } + + /** + * @return mixed + * @throws VkApiException + */ + public function getData() + { + $defult_params = ['act' => 'a_check', 'key' => $this->key, 'ts' => $this->ts, 'wait' => 55]; + if($this->vk->auth_type == 'user') { + $params = ['mode' => 32, 'version' => 3]; + $data = $this->request_core('https://' . $this->server . '?', $defult_params + $params); + } else { + $data = $this->request_core($this->server . '?', $defult_params); + } + return $data; + } + + /** + * @param $type + * @param $anon + */ + public function on($type, $anon) + { + $summands = []; + $data = json_decode(json_encode($this->vk->data), true); + switch ($type) { + case 'message_new': + { + if ($data[0] == 4) { + foreach ([1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 65536] as $key) { + if ($data[2] & $key) + $summands[] = $key; + } + if (!in_array(2, $summands)) { //только входящие сообщения + $this->vk->data = []; + $this->vk->data['object']['peer_id'] = $data[3]; + $this->vk->data['object']['text'] = $data[5]; + $this->vk->data = json_decode(json_encode($this->vk->data)); + $anon($data); + } + } + break; + } + } + } + + /** + * @param $id + * @param null $message + * @param null $payload + * @param null $user_id + * @param null $type + * @param null $data + * @return |null + */ + public function initVars(&$id = null, &$message = null, &$payload = null, &$user_id = null, &$type = null, &$data = null) + { + $data = $this->vk->data; + $data_backup = $this->vk->data; + $type = isset($data->type) ? $data->type : null; + if($type == 'message_new' && isset($data->object->message)) { + $data->object = $data->object->message; + } + $id = isset($data->object->peer_id) ? $data->object->peer_id : null; + $message = isset($data->object->text) ? $data->object->text : null; + $payload = isset($data->object->payload) ? json_decode($data->object->payload, true) : null; + $user_id = isset($data->object->from_id) ? $data->object->from_id : null; + $data = $data_backup; + return $data_backup; + } + + public function reply($message, $params = []) { + $message = $this->vk->placeholders($this->vk->data->object->peer_id, $message); + return $this->vk->request('messages.send', ['message' => $message, 'peer_id' => $this->vk->data->object->peer_id] + $params); + } + + /** + * @param $url + * @param array $params + * @return mixed + * @throws VkApiException + */ + private function request_core($url, $params = []) + { + if (function_exists('curl_init')) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url.http_build_query($params)); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + $result = json_decode(curl_exec($ch)); + curl_close($ch); + } else { + $result = json_decode(file_get_contents($url, true, stream_context_create([ + 'http' => [ + 'method' => 'POST', + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'content' => http_build_query($params) + ] + ]))); + } + if (!isset($result) or isset($result->error)) + throw new VkApiException(json_encode($result)); + return $result; + } +} diff --git a/Message.php b/Message.php new file mode 100644 index 0000000..87c5fb2 --- /dev/null +++ b/Message.php @@ -0,0 +1,64 @@ +prop_list = ['random_id', 'domain', 'chat_id', 'user_ids', 'lat', 'long', 'forward_messages', + 'sticker_id', 'payload']; + parent::__construct($vk_api); + } + + /** + * @return array + */ + public function getKeyboard() + { + return $this->keyboard; + } + + /** + * @param array $keyboard + * @param bool $inline + * @param bool $one_time + */ + public function setKeyboard($keyboard = [], $inline = false, $one_time = false) + { + $this->keyboard = ['keyboard' => $keyboard, 'inline' => $inline, 'one_time' => $one_time]; + } + + public function addVoice() + { + $this->addMedia(func_get_args(), 'voice'); + } + + public function removeVoice($voice) + { + return $this->removeMedia($voice, 'voice'); + } + + /** + * @param $id + * @return mixed + */ + public function send($id) + { + return $this->vk_api->createMessages($id, $this->message, $this->props, $this->media, $this->keyboard); + } +} diff --git a/Post.php b/Post.php new file mode 100644 index 0000000..c36687e --- /dev/null +++ b/Post.php @@ -0,0 +1,39 @@ +prop_list = ['friends_only', 'from_group', 'services', 'signed', 'publish_date', 'lat', 'long', 'place_id', + 'post_id', 'guid', 'mark_as_ads', 'close_comments']; + parent::__construct($vk_api); + } + + /** + * @param $id + * @param null $publish_date + * @return mixed + * @throws VkApiException + */ + public function send($id, $publish_date = null) + { + if ($publish_date >= time()) + $this->props['publish_date'] = $publish_date; + else if ($publish_date == null) + $this->props['publish_date'] = time(); + else + throw new VkApiException('Неверно указан $publish_date'); + return $this->vk_api->createPost($id, $this->message, $this->props, $this->media); + } +} \ No newline at end of file diff --git a/SiteAuth.php b/SiteAuth.php new file mode 100644 index 0000000..060c69f --- /dev/null +++ b/SiteAuth.php @@ -0,0 +1,42 @@ +settings = $settings; + } + } + + public function auth() { + if (isset($_GET['code'])) { + $query = urldecode(http_build_query($this->settings + ["code" => $_GET['code']])); + $token = json_decode(file_get_contents("https://oauth.vk.com/access_token?" . $query), true); + if (isset($token["access_token"])) { + $this->data = $token; + return true; + } + } + return false; + } + + public function get_link() { + $query = urldecode(http_build_query([ + "client_id" => $this->settings["client_id"], + "redirect_uri" => $this->settings["redirect_uri"], + "response_type" => "code" + ])); + return "https://oauth.vk.com/authorize?" . $query; + } +} diff --git a/VkApiException.php b/VkApiException.php new file mode 100644 index 0000000..2687c77 --- /dev/null +++ b/VkApiException.php @@ -0,0 +1,29 @@ +__toString()."\n"; + parent::__construct($message, $code, $previous); + } + + public function __toString() { + $error = "[Exception]: возникла ошибка:"; + $error .= "\r\n[Exception]: текст: {$this->getMessage()}"; + $error .= "\r\n[Exception]: код ошибки: {$this->getCode()}"; + $error .= "\r\n[Exception]: файл: {$this->getFile()}:{$this->getLine()}"; + $error .= "\r\n[Exception]: путь ошибки: {$this->getTraceAsString()}\r\n"; + if (!is_dir('error')) + mkdir('error'); + $file = fopen('error/error_log' . date('d-m-Y_h') . ".log", 'a'); + fwrite($file, $error); + fclose($file); +// exit(); + return $error; + // parent::__toString(); // TODO: Change the autogenerated stub + } +} diff --git a/config_library.php b/config_library.php new file mode 100644 index 0000000..df128ec --- /dev/null +++ b/config_library.php @@ -0,0 +1,20 @@ +auth = $token; + $this->version = $version; + $this->token = $this->auth->getAccessToken(); + } else if (isset($also_version)) { + $this->auth = new Auth($token, $version); + $this->token = $this->auth->getAccessToken(); + $this->version = $also_version; + } else { + $this->token = $token; + $this->version = $version; + } + $this->data = json_decode(file_get_contents('php://input')); + } + + /** + * @param $token + * @param $version + * @param null $also_version + * @return vk_api + * + * @throws VkApiException + */ + public static function create($token, $version, $also_version = null) { + return new self($token, $version, $also_version); + } + + /** + * @param $str + * @return vk_api + */ + public function setConfirm($str) { + if (isset($this->data->type) && $this->data->type == 'confirmation') { //Если vk запрашивает ключ + exit($str); //Завершаем скрипт отправкой ключа + } + return $this; + } + + /** + * @param null $id + * @param null $message + * @param null $payload + * @param null $user_id + * @param null $type + * @param null $data + * @return array|mixed|null + */ + public function initVars(&$id = null, &$message = null, &$payload = null, &$user_id = null, &$type = null, &$data = null) { + if (!$this->debug_mode) + $this->sendOK(); + $data = $this->data; + $data_backup = $this->data; + $type = isset($data->type) ? $data->type : null; + if(isset($data->object->message) and $type == 'message_new') { + $data->object = $data->object->message; //какая-то дичь с ссылками, но $this->data теперь тоже переопределился + } + $id = isset($data->object->peer_id) ? $data->object->peer_id : null; + $message = isset($data->object->text) ? $data->object->text : null; + $payload = isset($data->object->payload) ? json_decode($data->object->payload, true) : null; + $user_id = isset($data->object->from_id) ? $data->object->from_id : null; + $data = $data_backup; + return $data_backup; + } + + /** + * @return bool + */ + protected function sendOK() { + set_time_limit(0); + ini_set('display_errors', 'Off'); + + // для Nginx + if (is_callable('fastcgi_finish_request')) { + echo 'ok'; + session_write_close(); + fastcgi_finish_request(); + return True; + } + // для Apache + ignore_user_abort(true); + + ob_start(); + header('Content-Encoding: none'); + header('Content-Length: 2'); + header('Connection: close'); + echo 'ok'; + ob_end_flush(); + flush(); + return True; + } + + /** + * @param $message + * @param array $params + * @return bool|mixed + * @throws VkApiException + */ + public function reply($message, $params = []) { + if ($this->data != []) { + $message = $this->placeholders($this->data->object->peer_id, $message); + return $this->request('messages.send', ['message' => $message, 'peer_id' => $this->data->object->peer_id] + $params); + } else { + throw new VkApiException('Вк не прислал callback, возможно вы пытаетесь запустить скрипт с локалки'); + } + } + + public function forward($id, $id_messages, $params = []) { + $forward_messages = (is_array($id_messages)) ? join(',', $id_messages) : $id_messages; + return $this->request('messages.send', ['peer_id' => $id, 'forward_messages' => $forward_messages] + $params); + } + + public function sendAllChats($message, $params = []) { + unset($this->request_ignore_error[array_search(10, $this->request_ignore_error)]); //убираем код 10 из исключений + $i = 0; + $count = 0; + print "Начинаю перебор всех бесед...\n"; + while (true) { + print(++$i . " "); + try { + $this->sendMessage(2000000000 + $i, $message, $params); + $count++; + } catch (VkApiException $e) { + if ($e->getCode() == 10) { + print "\nВсего было разослано в $count бесед"; + break; + } + } + } + } + + protected function placeholders($id, $message) { + if($id >= 2000000000) { + $id = isset($this->data->object->from_id) ? $this->data->object->from_id : null; + } + if($id == null) { + print "Попытка использовать заполнители при передаче id беседы"; + return $message; + } else { + if (strpos($message, '%') !== false) { + $data = $this->userInfo($id); + $f = $data['first_name']; + $l = $data['last_name']; + $tag = ['%fn%', '%ln%', '%full%', '%a_fn%', '%a_ln%', '%a_full%']; + $replace = [$f, $l, "$f $l", "@id{$id}($f)", "@id{$id}($l)", "@id{$id}($f $l)"]; + return str_replace($tag, $replace, $message); + } else + return $message; + } + } + + /** + * @param $method + * @param array $params + * @return bool|mixed + * @throws VkApiException + */ + public function request($method, $params = []) { + list($method, $params) = $this->editRequestParams($method, $params); + $url = 'https://api.vk.com/method/' . $method; + $params['access_token'] = $this->token; + $params['v'] = $this->version; + $params['random_id'] = rand(-2147483648, 2147483647); + + while (True) { + try { + return $this->request_core($url, $params); + } catch (VkApiException $e) { + if (in_array($e->getCode(), $this->request_ignore_error)) { + sleep(1); + continue; + } + else + throw new VkApiException($e->getMessage(), $e->getCode()); + } + } + return false; + } + + /** + * @param $method + * @param $params + * @return array + */ + protected function editRequestParams($method, $params) { + return [$method, $params]; + } + + /** + * @param $url + * @param array $params + * @return mixed + * @throws VkApiException + */ + private function request_core($url, $params = []) { + if (function_exists('curl_init')) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + "Content-Type:multipart/form-data" + ]); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $params); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + $result = json_decode(curl_exec($ch), True); + curl_close($ch); + } else { + $result = json_decode(file_get_contents($url, true, stream_context_create([ + 'http' => [ + 'method' => 'POST', + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'content' => http_build_query($params) + ] + ])), true); + } + if (!isset($result)) + $this->request_core($url, $params); + if (isset($result['error'])) { + throw new VkApiException(json_encode($result), $result['error']['error_code']); + } + if (isset($result['response'])) + return $result['response']; + else + return $result; + } + + /** + * @param $message + * @param null $keyboard + * @param string $filter + * @param array $params + * @throws VkApiException + */ + public function sendAllDialogs($message, $keyboard = null, $filter = 'all', $params = []) { + $ids = []; + for ($count_all = 1, $offset = 0; $offset <= $count_all; $offset += 200) { + $members = $this->request('messages.getConversations', ['count' => 200, 'offset' => $offset, 'filter' => $filter]);//'filter' => 'unread' + if ($count_all != 1) + $offset += $members['count'] - $count_all; + $count_all = $members['count']; + + foreach ($members["items"] as $user) + if ($user['conversation']["can_write"]["allowed"] == true) + $ids [] = $user['conversation']['peer']['id']; + } + $ids = array_chunk($ids, 100); + foreach ($ids as $ids_chunk) { + try { + $this->request('messages.send', ['user_ids' => join(',', $ids_chunk), 'message' => $message, 'keyboard' => $keyboard] + $params); + } catch (Exception $e) { + continue; + } + } + } + + /** + * @param $id + * @param null $n + * @return string + * @throws VkApiException + */ + public function getAlias($id, $n = null) { //получить обращение к юзеру или группе + if (!is_numeric($id)) { //если короткая ссылка + $obj = $this->request('utils.resolveScreenName', ['screen_name' => $id]); //узнаем, кому принадлежит, сообществу или юзеру + $id = ($obj["type"] == 'group') ? -$obj['object_id'] : $obj['object_id']; + } + if (isset($n)) { + if (is_string($n)) { + if ($id < 0) + return "@club" . ($id * -1) . "($n)"; + else + return "@id{$id}($n)"; + } else { + if ($id < 0) { + $id = -$id; + $group_name = $this->request('groups.getById', ['group_id' => $id])[0]['name']; + return "@club{$id}({$group_name})"; + } else { + $info = $this->userInfo($id); + if ($n) + return "@id{$id}($info[first_name] $info[last_name])"; + else + return "@id{$id}($info[first_name])"; + } + } + } else { + if ($id < 0) + return "@club" . ($id * -1); + else + return "@id{$id}"; + } + } + + /** + * @param null $user_url + * @param array $scope + * @return mixed + * @throws VkApiException + */ + public function userInfo($user_url = '', $scope = []) { + $scope = ["fields" => join(",", $scope)]; + if (isset($user_url)) { + $user_url = preg_replace("!.*?/!", '', $user_url); + $user_url = ($user_url == '') ? [] : ["user_ids" => $user_url]; + } + try { + return current($this->request('users.get', $user_url + $scope)); + } catch (Exception $e) { + return false; + } + } + + + /** + * @param $chat_id + * @param $user_id + * @return bool|null|string + * @throws VkApiException + */ + public function isAdmin($user_id, $chat_id) { //возвращает привелегию по id + try { + $members = $this->request('messages.getConversationMembers', ['peer_id' => $chat_id])['items']; + } catch (\Exception $e) { + throw new VkApiException('Бот не админ в этой беседе, или бота нет в этой беседе'); + } + foreach ($members as $key) { + if ($key['member_id'] == $user_id) + return (isset($key["is_owner"])) ? 'owner' : ((isset($key["is_admin"])) ? 'admin' : false); + } + return null; + } + + /** + * @param $id + * @param $message + * @param array $params + * @return bool|mixed + * @throws VkApiException + */ + public function sendMessage($id, $message, $params = []) { + if ($id < 1) + return 0; + $message = $this->placeholders($id, $message); + return $this->request('messages.send', ['message' => $message, 'peer_id' => $id] + $params); + } + + /** + * + */ + public function debug() { + ini_set('error_reporting', E_ALL); + ini_set('display_errors', 1); + ini_set('display_startup_errors', 1); + echo 'ok'; + $this->debug_mode = 1; + } + + /** + * @param $id + * @param $message + * @param array $buttons + * @param bool $inline + * @param bool $one_time + * @param array $params + * @return mixed + * @throws VkApiException + */ + public function sendButton($id, $message, $buttons = [], $inline = false, $one_time = False, $params = []) { + $keyboard = $this->generateKeyboard($buttons, $inline, $one_time); + $message = $this->placeholders($id, $message); + return $this->request('messages.send', ['message' => $message, 'peer_id' => $id, 'keyboard' => $keyboard] + $params); + } + + public function buttonLocation($payload = null) { + return ['location', $payload]; + } + + public function buttonPayToGroup($group_id, $amount, $description = null, $data = null, $payload = null) { + return ['vkpay', $payload, 'pay-to-group', $group_id, $amount, $description, $data]; + } + + public function buttonPayToUser($user_id, $amount, $description = null, $payload = null) { + return ['vkpay', $payload, 'pay-to-user', $user_id, $amount, $description]; + } + + public function buttonDonateToGroup($group_id, $payload = null) { + return ['vkpay', $payload, 'transfer-to-group', $group_id]; + } + + public function buttonDonateToUser($user_id, $payload = null) { + return ['vkpay', $payload, 'transfer-to-user', $user_id]; + } + + public function buttonApp($text, $app_id, $owner_id = null, $hash = null, $payload = null) { + return ['open_app', $payload, $text, $app_id, $owner_id, $hash]; + } + + public function buttonText($text, $color, $payload = null) { + return ['text', $payload, $text, $color]; + } + + /** + * @param array $buttons + * @param bool $inline + * @param bool $one_time + * @return array|false|string + */ + public function generateKeyboard($buttons = [], $inline = false, $one_time = False) { + $keyboard = []; + $i = 0; + foreach ($buttons as $button_str) { + $j = 0; + foreach ($button_str as $button) { + $keyboard[$i][$j]["action"]["type"] = $button[0]; + if ($button[1] != null) + $keyboard[$i][$j]["action"]["payload"] = json_encode($button[1], JSON_UNESCAPED_UNICODE); + switch ($button[0]) { + case 'text': { + $color = $this->replaceColor($button[3]); + $keyboard[$i][$j]["color"] = $color; + $keyboard[$i][$j]["action"]["label"] = $button[2]; + break; + } + case 'vkpay': { + $keyboard[$i][$j]["action"]["hash"] = "action={$button[2]}"; + $keyboard[$i][$j]["action"]["hash"] .= ($button[3] < 0) ? "&group_id=".$button[3]*-1 : "&user_id={$button[3]}"; + $keyboard[$i][$j]["action"]["hash"] .= (isset($button[4])) ? "&amount={$button[4]}" : ''; + $keyboard[$i][$j]["action"]["hash"] .= (isset($button[5])) ? "&description={$button[5]}" : ''; + $keyboard[$i][$j]["action"]["hash"] .= (isset($button[6])) ? "&data={$button[6]}" : ''; + $keyboard[$i][$j]["action"]["hash"] .= "&aid=1"; + break; + } + case 'open_app': { + $keyboard[$i][$j]["action"]["label"] = $button[2]; + $keyboard[$i][$j]["action"]["app_id"] = $button[3]; + if(isset($button[4])) + $keyboard[$i][$j]["action"]["owner_id"] = $button[4]; + if(isset($button[5])) + $keyboard[$i][$j]["action"]["hash"] = $button[5]; + break; + } + } + $j++; + } + $i++; + } + $keyboard = ["one_time" => $one_time, "buttons" => $keyboard, 'inline' => $inline]; + $keyboard = json_encode($keyboard, JSON_UNESCAPED_UNICODE); + return $keyboard; + } + + /** + * @param $color + * @return string + */ + private function replaceColor($color) { + switch ($color) { + case 'red': + $color = 'negative'; + break; + case 'green': + $color = 'positive'; + break; + case 'white': + $color = 'default'; + break; + case 'blue': + $color = 'primary'; + break; + } + return $color; + } + + /** + * @param $group_url + * @return mixed + * @throws VkApiException + */ + public function groupInfo($group_url) { + $group_url = preg_replace("!.*?/!", '', $group_url); + return current($this->request('groups.getById', ["group_ids" => $group_url])); + } + + /** + * @param $id + * @param $local_file_path + * @param array $params + * @return mixed + * @throws VkApiException + */ + public function sendImage($id, $local_file_path, $params = []) { + $upload_file = $this->uploadImage($id, $local_file_path); + return $this->request('messages.send', ['attachment' => "photo" . $upload_file[0]['owner_id'] . "_" . $upload_file[0]['id'], 'peer_id' => $id] + $params); + } + + /** + * @param $id + * @param $local_file_path + * @return mixed + * @throws VkApiException + */ + private function uploadImage($id, $local_file_path) { + $upload_url = $this->getUploadServerMessages($id, 'photo')['upload_url']; + for ($i = 0; $i < $this->try_count_resend_file; ++$i) { + try { + $answer_vk = json_decode($this->sendFiles($upload_url, $local_file_path, 'photo'), true); + return $this->savePhoto($answer_vk['photo'], $answer_vk['server'], $answer_vk['hash']); + } catch (VkApiException $e) { + sleep(1); + $exception = json_decode($e->getMessage(), true); + if ($exception['error']['error_code'] != 121) + throw new VkApiException($e->getMessage(), $exception['error']['error_code']); + } + } + $answer_vk = json_decode($this->sendFiles($upload_url, $local_file_path, 'photo'), true); + return $this->savePhoto($answer_vk['photo'], $answer_vk['server'], $answer_vk['hash']); + } + + /** + * @param $peer_id + * @param string $selector + * @return mixed|null + * @throws VkApiException + */ + private function getUploadServerMessages($peer_id, $selector = 'doc') { + $result = null; + if ($selector == 'doc') + $result = $this->request('docs.getMessagesUploadServer', ['type' => 'doc', 'peer_id' => $peer_id]); + else if ($selector == 'photo') + $result = $this->request('photos.getMessagesUploadServer', ['peer_id' => $peer_id]); + else if ($selector == 'audio_message') + $result = $this->request('docs.getMessagesUploadServer', ['type' => 'audio_message', 'peer_id' => $peer_id]); + return $result; + } + + private function uploadVoice($id, $local_file_path) { + $upload_url = $this->getUploadServerMessages($id, 'audio_message')['upload_url']; + $answer_vk = json_decode($this->sendFiles($upload_url, $local_file_path, 'file'), true); + return $this->saveDocuments($answer_vk['file'], 'voice'); + } + + public function sendVoice($id, $local_file_path, $params = []) { + $upload_file = $this->uploadVoice($id, $local_file_path); + return $this->request('messages.send', ['attachment' => "doc" . $upload_file['audio_message']['owner_id'] . "_" . $upload_file['audio_message']['id'], 'peer_id' => $id] + $params); + } + + /** + * @param $url + * @param $local_file_path + * @param string $type + * @return mixed + * @throws VkApiException + */ + protected function sendFiles($url, $local_file_path, $type = 'file') { + $post_fields = [ + $type => new CURLFile(realpath($local_file_path)) + ]; + + for ($i = 0; $i < $this->try_count_resend_file; ++$i) { + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + "Content-Type:multipart/form-data" + ]); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields); + $output = curl_exec($ch); + if ($output != '') + break; + else + sleep(1); + } + if ($output == '') + throw new VkApiException('Не удалось загрузить файл на сервер'); + return $output; + } + + /** + * @param $photo + * @param $server + * @param $hash + * @return mixed + * @throws VkApiException + */ + private function savePhoto($photo, $server, $hash) { + return $this->request('photos.saveMessagesPhoto', ['photo' => $photo, 'server' => $server, 'hash' => $hash]); + } + + /** + * @param $groupID + * @param $local_file_path + * @param null $title + * @return mixed + * + * @throws VkApiException + */ + public function uploadDocsGroup($groupID, $local_file_path, $title = null) { + return $this->uploadDocs($groupID, $local_file_path, $title); + } + + /** + * @param $id + * @param $local_file_path + * @param null $title + * @return mixed + * @throws VkApiException + */ + private function uploadDocs($id, $local_file_path, $title = null) { + if (!isset($title)) + $title = preg_replace("!.*?/!", '', $local_file_path); + $upload_url = $this->getUploadServerPost($id)['upload_url']; + $answer_vk = json_decode($this->sendFiles($upload_url, $local_file_path), true); + $upload_file = $this->saveDocuments($answer_vk['file'], $title); + return $upload_file; + } + + /** + * @param array $peer_id + * @return mixed + * @throws VkApiException + */ + private function getUploadServerPost($peer_id = []) { + if ($peer_id < 0) + $peer_id = ['group_id' => $peer_id * -1]; + else + $peer_id = []; + $result = $this->request('docs.getUploadServer', $peer_id); + return $result; + } + + /** + * @param $file + * @param $title + * @return mixed + * @throws VkApiException + */ + private function saveDocuments($file, $title) { + return $this->request('docs.save', ['file' => $file, 'title' => $title]); + } + + /** + * @param $id + * @param $local_file_path + * @param null $title + * @param array $params + * @return bool|mixed + * @throws VkApiException + */ + public function sendDocMessage($id, $local_file_path, $title = null, $params = []) { + $upload_file = current($this->uploadDocsMessages($id, $local_file_path, $title)); + if ($id != 0 and $id != '0') { + return $this->request('messages.send', ['attachment' => "doc" . $upload_file['owner_id'] . "_" . $upload_file['id'], 'peer_id' => $id] + $params); + } else { + return true; + } + } + + /** + * @param $id + * @param $local_file_path + * @param null $title + * @return mixed + * @throws VkApiException + */ + private function uploadDocsMessages($id, $local_file_path, $title = null) { + if (!isset($title)) + $title = preg_replace("!.*?/!", '', $local_file_path); + $upload_url = $this->getUploadServerMessages($id)['upload_url']; + $answer_vk = json_decode($this->sendFiles($upload_url, $local_file_path), true); + $upload_file = $this->saveDocuments($answer_vk['file'], $title); + return $upload_file; + } + + /** + * @param $id + * @param array $message + * @param array $props + * @param array $media + * @return mixed + * @throws VkApiException + */ + public function createPost($id, $message = [], $props = [], $media = []) { + $send_attachment = []; + + foreach ($media as $selector => $massive) { + switch ($selector) { + case "images": + foreach ($massive as $image) { + $upload_url = $this->getWallUploadServer($id); + for ($i = 0; $i <= $this->try_count_resend_file; ++$i) { + try { + $answer_vk = json_decode($this->sendFiles($upload_url['upload_url'], $image, 'photo'), true); + $upload_file = $this->savePhotoWall($answer_vk['photo'], $answer_vk['server'], $answer_vk['hash'], $id); + $send_attachment[] = "photo" . $upload_file[0]['owner_id'] . "_" . $upload_file[0]['id']; + break; + } catch (VkApiException $e) { + if ($i == $this->try_count_resend_file) + throw new VkApiException($e->getMessage(), $e->getCode()); + sleep(1); + $exception = json_decode($e->getMessage(), true); + if ($exception['error']['error_code'] != 121) + throw new VkApiException($e->getMessage(), $e->getCode()); + } + } + } + break; + case "docs": + foreach ($massive as $docs) { + $upload_file = $this->uploadDocsUser($docs); + if (isset($upload_file['type'])) + $upload_file = $upload_file[$upload_file['type']]; + else + $upload_file = current($upload_file); + $send_attachment[] = "doc" . $upload_file['owner_id'] . "_" . $upload_file['id']; + } + break; + case "other": + break; + } + } + if (count($send_attachment) != 0) + $send_attachment = ["attachment" => join(',', $send_attachment)]; + if (is_string($message)) + $message = ['message' => $message]; + return $this->request('wall.post', ['owner_id' => $id] + $message + $props + $send_attachment); + } + + /** + * @param $owner_id , $post_id, $message + * @param $post_id + * @param $message + * @return mixed + * @throws VkApiException + */ + public function sendWallComment($owner_id, $post_id, $message) { + return $this->request('wall.createComment', ['owner_id' => $owner_id, 'post_id' => $post_id, 'message' => $message]); + } + + /** + * @param $id + * @return mixed + * @throws VkApiException + */ + private function getWallUploadServer($id) { + if ($id < 0) { + $id *= -1; + return $this->request('photos.getWallUploadServer', ['group_id' => $id]); + } else { + return $this->request('photos.getWallUploadServer', ['user_id' => $id]); + } + } + + /** + * @param $photo + * @param $server + * @param $hash + * @param $id + * @return mixed + * @throws VkApiException + */ + private function savePhotoWall($photo, $server, $hash, $id) { + if ($id < 0) { + $id *= -1; + return $this->request('photos.saveWallPhoto', ['photo' => $photo, 'server' => $server, 'hash' => $hash, 'group_id' => $id]); + } else { + return $this->request('photos.saveWallPhoto', ['photo' => $photo, 'server' => $server, 'hash' => $hash, 'user_id' => $id]); + } + } + + /** + * @param $local_file_path + * @param null $title + * @return mixed + * + * @throws VkApiException + */ + public function uploadDocsUser($local_file_path, $title = null) { + return $this->uploadDocs([], $local_file_path, $title); + } + + /** + * @param $id + * @param array $message + * @param array $props + * @param array $media + * @param array $keyboard + * @return mixed + * @throws VkApiException + */ + public function createMessages($id, $message = [], $props = [], $media = [], $keyboard = []) { + if ($id < 1) + return 0; + $send_attachment = []; + + foreach ($media as $selector => $massiv) { + switch ($selector) { + case "images": + foreach ($massiv as $image) { + $upload_file = $upload_file = $this->uploadImage($id, $image); + $send_attachment[] = "photo" . $upload_file[0]['owner_id'] . "_" . $upload_file[0]['id']; + } + break; + case "docs": + foreach ($massiv as $document) { + $upload_file = $this->uploadDocsMessages($id, $document['path'], $document['title']); + if (isset($upload_file['type'])) + $upload_file = $upload_file[$upload_file['type']]; + else + $upload_file = current($upload_file); + $send_attachment[] = "doc" . $upload_file['owner_id'] . "_" . $upload_file['id']; + } + break; + case "voice": + foreach ($massiv as $voice) { + $upload_file = $this->uploadVoice($id, $voice); + $send_attachment[] = "doc" . $upload_file['audio_message']['owner_id'] . "_" . $upload_file['audio_message']['id']; + } + break; + case "other": + break; + } + } + if (count($send_attachment) != 0) + $send_attachment = ["attachment" => join(',', $send_attachment)]; + if (is_string($message)) + $message = ['message' => $message]; + if ($keyboard != []) + $keyboard = ['keyboard' => $this->generateKeyboard($keyboard['keyboard'], $keyboard['inline'], $keyboard['one_time'])]; + return $this->request('messages.send', ['peer_id' => $id] + $message + $props + $send_attachment + $keyboard); + } + + /** + * @param array $id + * @param int $extended + * @param array $props + * @return mixed + * @throws VkApiException + */ + public function getGroupsUser($id = [], $extended = 1, $props = []) { + if (is_numeric($id)) + $id = ['user_id' => $id]; + if (!is_array($props)) + $props = []; + if ($extended == 1) + $extended = ['extended' => 1]; + else + $extended = []; + return $this->request('groups.get', $id + $props + $extended); + } + + /** + * @param $var + * @throws VkApiException + */ + public function setTryCountResendFile($var) { + if (is_integer($var)) + $this->try_count_resend_file = $var; + else + throw new VkApiException("Параметр должен быть числовым"); + } + + /** + * @param $var + * @throws VkApiException + */ + public function setRequestIgnoreError($var) { + if (is_array($var)) + $this->request_ignore_error = $var; + else if (is_integer($var)) + $this->request_ignore_error = [$var]; + else + throw new VkApiException("Параметр должен быть числовым либо массивом"); + } + + /** + * @param $id + * @return mixed + */ + public function dateRegistration($id) { + $site = file_get_contents("https://vk.com/foaf.php?id={$id}"); + preg_match('', $site, $data); + $data = explode('T', $data[1]); + $date = date("d.m.Y", strtotime($data[0])); + $time = mb_substr($data[1], 0, 8); + return "$time $date"; + } + + /** + * @return array + */ + protected function copyAllDataclass() { + return [$this->token, $this->version, $this->auth, $this->request_ignore_error, $this->try_count_resend_file]; + } + + /** + * @param $id_vk_vars + */ + protected function setAllDataclass($id_vk_vars) { + list($this->token, $this->version, $this->auth, $this->request_ignore_error, $this->try_count_resend_file) = $id_vk_vars; + } +}