Началр работы с переработкой

This commit is contained in:
RedHood
2020-07-10 01:17:26 +10:00
parent 64e03a380b
commit 8635fbb301
50 changed files with 7855 additions and 2594 deletions

29
sources/API/LongPoll.php Normal file
View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace VK\API;
class LongPoll extends LongPollAbstract
{
public function __construct(object $robot, array $params = [])
{
return;
echo get_class($robot), PHP_EOL;
die;
if ($_ENV['ROBOT_TYPE']) {
$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();
}
}

View File

@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace VK\API;
abstract class LongPollAbstract
{
abstract public function __construct(object $robot, array $params = []);
}

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace VK\API\Methods;
use VK\Core;
use VK\API\Traits\Request;
class Message
{
use Request;
private const METHOD = 'messages.send';
public static function post($from, $to, $message, $trolling)
{
if (is_int($from)) $from = Core::init()->get($from);
$params = [
'message' => $message,
'peer_id' => $to,
'access_token' => $from->token,
'v' => $from->version,
'random_id' => $trolling
];
self::request(self::METHOD, $params, $from->getBrowser());
}
public static function get()
{
}
public static function delete()
{
}
}

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace VK\API\Methods;
abstract class MethodAbstract
{
abstract public static function post();
abstract public static function get();
abstract public static function delete();
}

View File

@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace VK\API\Traits;
use VK\Browsers\BrowserAbstract;
use Exception;
/**
* Паттерн registry
*/
trait Request
{
private static function request(string $method, array $params, BrowserAbstract $browser)
{
$url = 'https://api.vk.com/method/' . $method;
foreach ($params as $key => $value) {
$post[$key] = $value;
}
// while (True) {
// try {
return $browser::post($url, $post);
// } catch (Exception $e) {
// // if (in_array($e->getCode(), $this->request_ignore_error)) {
// // sleep(1);
// // continue;
// // } else
// // throw new Exception($e->getMessage(), $e->getCode());
// throw new Exception('Жопа');
// }
// }
return false;
}
}

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace VK\Browsers;
abstract class BrowserAbstract
{
abstract public static function post($method, $params);
abstract public static function getToken($url);
abstract protected static function checkSSL($domain);
}

109
sources/Browsers/Curl.php Normal file
View File

@@ -0,0 +1,109 @@
<?php
declare(strict_types=1);
namespace VK\Browsers;
use VK\Core;
use Exception;
class Curl extends BrowserAbstract
{
/**
* SSL шифрование
*
* @var bool
*/
private static bool $ssl = false;
public static function post($url, $params = [])
{
$c = curl_init();
curl_setopt($c, CURLOPT_HTTPHEADER, [
"Content-Type:multipart/form-data"
]);
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_POSTFIELDS, $params);
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, 0);
$result = json_decode(curl_exec($c), True);
curl_close($c);
if (isset($result['response']))
return $result['response'];
else if (isset($result['error']))
throw new Exception(json_encode($result), $result['error']['error_code']);
else if (!isset($result))
self::post($url, $params);
else
return $result;
}
public static function getToken($url)
{
if (!self::checkSSL('localhost')) {
$core = Core::init();
$core->logger->notice('Соединение не защищено. Необходимо включить SSL шифрование');
}
if ($curl = curl_init()) {
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_USERAGENT, $_ENV['USERAGENT']);
if (isset($post_values)) {
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_values);
}
if ($cookie and isset(self::$cookie)) {
$send_cookie = [];
foreach (self::$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];
}
}
protected static function checkSSL($domain)
{
$ssl_check = @fsockopen('ssl://' . $domain, 443, $errno, $errstr, 30);
$res = !!$ssl_check;
if ($ssl_check) {
fclose($ssl_check);
}
return $res;
}
}

141
sources/Builder.php Normal file
View File

@@ -0,0 +1,141 @@
<?php
declare(strict_types=1);
namespace VK;
use Exception;
use VK\Robots\RobotAbstract;
use VK\Browsers\BrowserAbstract;
use VK\Proxies\ProxyAbstract;
use VK\Captchas\CaptchaAbstract;
use VK\Loggers\Jasmo;
/**
* Сборщик
*
* @package Builder
* @author Arsen Mirzaev
*/
class Builder
{
/**
* Собираемый объект
*
* @var object
*/
private object $target;
/**
* Параметры для сборки
*
* @var array
*/
private array $params;
public function __construct(array $params = [])
{
$this->params = $params;
return $this;
}
/**
* Сборщик роботов (паттерн: factory)
*
* Проверка существования получившегося класса и запись в свойство ядра
*
* @return object
*/
public function robot($robot = null): object
{
// Ищет по словарю и подставляет имя метода вместо отправленного идентификатора
if (is_int($robot = (int) ($robot ?? $_ENV['DEFAULT_ROBOT_TYPE'])))
$robot = $this->convert('robot', $robot);
if (class_exists($robot_class = __NAMESPACE__ . '\\Robots\\' . ucfirst($robot))) {
$this->target = new $robot_class($robot);
} else {
throw new Exception("Неизвестный тип робота");
}
// Присвоение параметров из сборщика в экземпляр класса робота
foreach (array_keys(get_class_vars($robot_class)) as $key => $value)
{
if ($value !== null && isset($this->params[$key]))
{
$this->target->$value = $this->params[$key];
}
}
// Добавление в регистр, установка идентификатора и обновление счётчика
if (false !== Core::set($this->target->setID(Core::$robots_amount++), $this->target)) return $this->target;
else throw new Exception('Ошибка при сборке робота "Group"');
}
/**
* Конвертер идентификаторов в значения
*
* Используется конструкция if из-за строгого сравнения
*
* @param string $var Словарь идентификаторов
* @param int $number Идентификатор
* @return string
*/
private function convert(string $var, int $number): string
{
if ($var === 'robot') {
if ($number === 0) {
return 'Group';
} else if ($number === 1) {
return 'Account';
} else throw new Exception('Неизвестный идентификатор робота');
} else throw new Exception('Неизвестный тип словаря');
}
/**
* Установка журналирования
*
* @todo Добавить установку иного журналиста по спецификации PSR-3
* @return RobotAbstract
*/
public function log($file = null): Builder
{
Jasmo::init()::post($file)::postErrorHandler()::postShutdownHandler();
return $this;
}
/**
* Установка браузера
*
* @return RobotAbstract
*/
public function browser(BrowserAbstract $browser): Builder
{
$this->browser = $browser;
return $this;
}
/**
* Установка прокси
*
* @return RobotAbstract
*/
public function proxy(ProxyAbstract $proxy): Builder
{
$this->proxy = $proxy;
return $this;
}
/**
* Установка обработчика капч
*
* @return RobotAbstract
*/
public function captcha(CaptchaAbstract $captcha): Builder
{
$this->captcha = $captcha;
return $this;
}
}

50
sources/Core.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace VK;
use VK\Loggers\Jasmo;
use VK\Traits\Singleton;
use VK\Traits\Registry;
/**
* Ядро фреймворка для работы с VK API
*
* @package VK
* @author Arsen Mirzaev
*/
class Core
{
use Singleton, Registry {
Singleton::__construct insteadof Registry;
}
/**
* Cчётчик роботов
*/
public static int $robots_amount = 0;
/**
* Создание экземпляра сборщика
*
* @return Builder
*/
public function build(...$params): Builder
{
return new Builder($params);
}
/**
* Установка журналирования
*
* @todo Добавить установку иного журналиста по спецификации PSR-3
* @return Core
*/
public function log($file = null): Core
{
Jasmo::init()::post($file)::postErrorHandler()::postShutdownHandler();
return $this;
}
}

129
sources/Loggers/Jasmo.php Normal file
View File

@@ -0,0 +1,129 @@
<?php
declare(strict_types=1);
namespace VK\Loggers;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Jasny\ErrorHandler;
use DateTime;
use VK\Traits\Singleton;
/**
* Журналист Jasmo
*
* Основан на "monolog/monolog" и "jasny/error-handler"
* Monolog + Jasny = Jasmo
*
* @package Log
* @author Arsen Mirzaev
*/
class Jasmo extends LoggerAbstract
{
use Singleton;
/**
* Экземпляр класса журналиста
*
* @var Logger
*/
public static $logger;
// /**
// * Экземпляр класса обработчика ошибок
// *
// * @var ErrorHandler
// */
// public ErrorHandler $handler;
public static function post($file = null): ?Jasmo
{
$file = $file ?? date_format(new DateTime($_ENV['TIMEZONE']), 'd_m_Y');
/**
* Создание логгера по спецификации PSR-3 (Monolog)
*
* @param string Название канала логирования
*/
self::$logger = new Logger(__CLASS__);
/**
* Создание обработчиков (порядок обязателен)
*/
self::$logger->pushHandler(new StreamHandler($_ENV['PATH_ROOT'] . $_ENV['PATH_LOGS'] . "INFO_$file.log", Logger::INFO, false)); // Инфомация о процессе работы
self::$logger->pushHandler(new StreamHandler($_ENV['PATH_ROOT'] . $_ENV['PATH_LOGS'] . "NOTICE_$file.log", Logger::NOTICE, false)); // Уведомления
self::$logger->pushHandler(new StreamHandler($_ENV['PATH_ROOT'] . $_ENV['PATH_LOGS'] . "WARNING_$file.log", Logger::WARNING, false)); // Предупреждения
self::$logger->pushHandler(new StreamHandler($_ENV['PATH_ROOT'] . $_ENV['PATH_LOGS'] . "ERROR_$file.log", Logger::ERROR, false)); // Ошибки
self::$logger->pushHandler(new StreamHandler($_ENV['PATH_ROOT'] . $_ENV['PATH_LOGS'] . "CRITICAL_$file.log", Logger::CRITICAL, false)); // Критические ошибки
self::$logger->pushHandler(new StreamHandler($_ENV['PATH_ROOT'] . $_ENV['PATH_LOGS'] . "ALERT_$file.log", Logger::ALERT, false)); // Критические ошибки
self::$logger->pushHandler(new StreamHandler($_ENV['PATH_ROOT'] . $_ENV['PATH_LOGS'] . "EMERGENCY_$file.log", Logger::EMERGENCY, false)); // Критические ошибки
self::$logger->pushHandler(new StreamHandler($_ENV['PATH_ROOT'] . $_ENV['PATH_LOGS'] . "$file.log", Logger::DEBUG)); // Общий лог
// test
// self::$logger->pushProcessor(function ($record) {
// $record['extra']['dummy'] = 'Hello world!';
// return $record;
// });
echo '[' . date_format(new DateTime($_ENV['TIMEZONE']), 'd-m-Y H:i:s') . '] Начало работы', PHP_EOL;
self::$logger->info('Начало работы');
return self::$instance;
}
public static function get(): ?Jasmo
{
return self::$instance;
}
public static function delete(): ?Jasmo
{
return self::$instance;
}
public static function postErrorHandler(): ?Jasmo
{
/**
* Подключение логгера в обработчик ошибок (Jasny)
*/
$handler = new ErrorHandler(self::$logger);
$handler->logUncaught(E_ALL); // Обрабатывать все ошибки
$handler->onFatalError(function ($error) {
self::$logger->error($error);
}, true);
return self::$instance;
}
public static function deleteErrorHandler(): ?Jasmo
{
return self::$instance;
}
public static function postShutdownHandler(): ?Jasmo
{
register_shutdown_function(array(self::$instance, 'handlerShutdown'));
return self::$instance;
}
public function handlerShutdown(): void
{
self::$logger->info('Завершение работы');
echo '[' . date_format(new DateTime($_ENV['TIMEZONE']), 'd-m-Y H:i:s') . '] Завершение работы', PHP_EOL;
}
// public function handlerErrors($errno, $errstr, $errfile, $errline, $errcontext): bool
// {
// echo "друг, да ты вероянто напортачил $errno $errstr", PHP_EOL, PHP_EOL;
// if ($this->logger->error("друг, да ты вероянто напортачил $errno $errstr")) {
// return true;
// } else {
// return false;
// }
// }
}

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace VK\Loggers;
/**
* Абстрактный класс журналиста
*
*
* @package Log
* @author Arsen Mirzaev
*/
abstract class LoggerAbstract
{
/**
* Экземпляр класса журналиста
*
* @var LoggerAbstract
*/
public static $logger;
abstract static public function post($file = null): ?LoggerAbstract;
abstract static public function get(): ?LoggerAbstract;
abstract static public function delete(): ?LoggerAbstract;
}

94
sources/Robots/Group.php Normal file
View File

@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace VK\Robots;
use VK\Browsers\BrowserAbstract;
use VK\Parsers\Curl;
use Exception;
use VK\API\LongPoll;
/**
* Робот: "Группа"
*
* Класс реализовывающий работу от лица группы ВКонтакте
*
* @package Robots
* @author Arsen Mirzaev
*/
class Group extends RobotAbstract
{
/**
* ВКонтакте: идентификатор
*
* @var string
*/
public int $id;
/**
* ВКонтакте: токен доступа
*
* @var string
*/
public string $token;
/**
* ВКонтакте: версия API
*
* @var float
*/
public float $version;
/**
* ВКонтакте: тип API
*
* @var string
*/
public string $api;
/**
* ВКонтакте: активатор мобильной версии
*
* @var bool
*/
//protected bool $mobile = false;
/**
* ВКонтакте: идентификатор капчи
*
* @var int
*/
//protected int $captcha;
public function __construct($name)
{
if (!isset($this->id)) $this->id = (int) $_ENV['DEFAULT_' . strtoupper($name) . '_ID'];
if (!isset($this->token)) $this->token = (string) $_ENV['DEFAULT_' . strtoupper($name) . '_TOKEN'];
if (!isset($this->version)) $this->version = (float) $_ENV['DEFAULT_API_VERSION'];
}
public function postMethod($method, $params = []): BrowserAbstract
{
$browser = __NAMESPACE__ . '\\Browsers\\' . ucfirst($_ENV['BROWSER_TYPE']);
return (new $browser)->post();
}
public function longpoll(...$params): LongPoll
{
return new LongPoll($this, $params);
}
public function callback()
{
}
protected function genToken(): string
{
return 'test';
}
protected function genTokenMobile(string $captcha_key, int $captcha_id): string
{
return 'test 2';
}
}

View File

@@ -0,0 +1,135 @@
<?php
declare(strict_types=1);
namespace VK\Robots;
use VK\Robots\RobotAbstract;
use VK\Browsers\BrowserAbstract;
use VK\Proxies\ProxyAbstract;
abstract class RobotAbstract
{
/**
* Идентификатор в регистре
*
* @var string
*/
private int $id_registry;
/**
* Используемый браузер
*
* @var BrowserAbstract
*/
protected BrowserAbstract $browser;
/**
* Прокси-сервер
*
* @var ProxyAbstract
*/
protected ProxyAbstract $proxy;
/**
* Обработчик капчи
*
* @var CaptchaAbstract
*/
protected CaptchaAbstract $captcha;
/**
* Установка идентификатора
*
* @return int
*/
public function setID(int $id): int
{
return $this->id_registry = $id;
}
/**
* Получение идентификатора
*
* @return int
*/
public function getID(): int
{
return $this->id;
}
/**
* Получение браузера
*
* @return int
*/
public function getBrowser(): BrowserAbstract
{
// return $this->browser;
return new \VK\Browsers\Curl;
}
/**
* Метод получения токена аккаунта
*
* @return string
*/
public function getToken($captcha_key = null, $captcha_id = null): string
{
if (!empty($_ENV['ACCOUNT_TOKEN'])) {
return $_ENV['ACCOUNT_TOKEN'];
} else if ($this->mobile) {
$this->token_access = $this->genTokenMobile($captcha_key, $this->captcha_id ?? $captcha_id);
} else {
$this->token_access = $this->genToken();
}
return $this->token_access;
}
abstract protected function genToken(): string;
abstract protected function genTokenMobile(string $captcha_key, int $captcha_id): string;
// /**
// * @param null $access_groups
// * @param bool $resend
// * @return mixed
// * @throws VkApiException
// */
// private function getTokenAccess($scope = null, $resend = false)
// {
// $get_url_token = Curl::getToken('https://oauth.vk.com/authorize?client_id=' . $_ENV['APP_ID'] .
// '&scope=' . $_ENV['ACCESS_GROUPS'] . ($resend ? '&revoke=1' : '') .
// '&response_type=token');
// echo 'https://oauth.vk.com/authorize?client_id=' . $_ENV['APP_ID'] .
// '&scope=' . $_ENV['ACCESS_GROUPS'] . ($resend ? '&revoke=1' : '') .
// '&response_type=token', PHP_EOL;
// if ($get_url_token['body'] !== false) {
// 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];
// }
// } else {
// echo 'жопа';
// die;
// }
// echo $url_token, PHP_EOL;
// die;
// $access_token_location = Curl::getToken($url_token)['header']['location'][0];
// if (preg_match("!access_token=(.*?)&!s", $access_token_location, $access_token) != 1)
// throw new Exception("Не удалось найти access_token в строке ридеректа, ошибка:" . Curl::getToken($access_token_location, null, false)['body']);
// echo $url_token, PHP_EOL;
// die;
// return $access_token[1];
// }
}

51
sources/Robots/User.php Normal file
View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace VK\Robots;
class User extends RobotAbstract
{
/**
* Токен авторизации
*/
public string $token;
/**
* Версия используемого API
*/
public float $version;
/**
* Конструктор робота категории: "Пользователь"
*
* Предназначен для работы от лица пользователя ВКонтакте
*
* @return void
*/
public function __construct() {
$this->auth();
}
/**
* Метод авторизации робота
*
* @return void
*/
public function auth(string $token, float $version)
{
if ($token instanceof auth) {
$this->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'));
}
}

View File

@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace VK\Traits;
/**
* Паттерн registry
*/
trait Registry
{
/**
* Хеш-таблица реестра
*
* @var array
*/
protected static array $registry = [];
/**
* Блокировка конструктора
*/
protected function __construct()
{
}
/**
* Положить в реестр
*
* @param string $key
* @param mixed $item
* @return void
*/
public static function set(int $key, $item): bool
{
if (!array_key_exists($key, self::$registry)) {
self::$registry[$key] = $item;
return true;
}
return false;
}
/**
* Получить из реестра по ключу
*
* Если не отправить ключ, то вернёт все значения
*
* @param string $key
* @return false|mixed
*/
public static function get(int $key = null)
{
if (isset($key) && array_key_exists($key, self::$registry)) {
return self::$registry[$key];
} else return self::$registry;
}
/**
* Удалить из реестра
*
* @param string $key
* @return void
*/
public static function remove(int $key): bool
{
if (array_key_exists($key, self::$registry)) {
unset(self::$registry[$key]);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace VK\Traits;
/**
* Паттерн singleton
*/
trait Singleton
{
/**
* Экземпляр класса
*
* @var LoggerAbstract
*/
protected static $instance;
/**
* Блокировка конструктора
*/
protected function __construct()
{
}
/**
* Инициализатор экземпляра класса
*
* @return LoggerAbstract
*/
public static function init(): self
{
if (self::$instance === null) self::$instance = new self;
return self::$instance;
}
/**
* Блокировка магического метода __clone()
*/
private function __clone()
{
}
/**
* Блокировка магического метода __sleep()
*/
private function __sleep()
{
}
/**
* Блокировка магического метода __wakeup()
*/
private function __wakeup()
{
}
}