Підпишись та читай
найцікавіші
статті першим!

Підключення API. Якщо файл відсутній, є три шляхи виправлення помилки З'єднання api

API(Англ. Application Programming Interface) - це інтерфейс програмування програм. API конкретної програми або сервісу надає набір готових процедур, функцій та змінних, за допомогою яких сторонні розробники можуть створювати свої програми та скрипти для роботи з цим сервісом.

При роботі через API програма відправляє запит до сервісу та отримує відповідь, що містить запитані дані, незалежно від того, якою мовою програмування вони створені.

Власники інтернет-магазинів за допомогою сторонніх сервісів та власних додатків мають можливість звертатися за API до:

Інформація про оформлені замовлення

Доступні дії (методи) обробки інформації про замовлення:

  1. Вибір інформації про замовлення на ID
  2. Вибір інформації про замовлення по фільтру
  3. Кількість замовлень по фільтру
  4. Створення замовлення
  5. Видалення замовлення
  6. Масове видалення замовлень
  7. Вибір усіх доступних статусів для замовлень
  8. Оновлення статусу замовлення
  9. Додавання коментарю до замовлення

Інформація про передплатників

  1. Додавання передплатника
  2. Видалення передплатника
  3. Масове видалення передплатників
  4. Вибір даних про передплатників по фільтру
  5. Кількість передплатників за фільтром

Інформація про зареєстрованих користувачів

Доступні дії (методи) обробки інформації про передплатників:

  1. Вибір інформації про зареєстрованих користувачів за ID
  2. Вибір інформації про всіх зареєстрованих користувачів
  3. Вибір інформації про всі дані зазначені користувачем при реєстрації:
    • Прізвище ім'я по батькові;
    • Контактна адреса електронної пошти;
    • Контактний номер телефону;
    • Вказана адреса доставки: індекс, назва населеного пункту, назва вулиці, номер будинку, номер корпусу, номер квартири, поверх;

Зверніть увагу!При реєстрації користувач може не заповнити всі вказані вище поля.

Плани розвитку API

Найближчим часом ми плануємо відкрити інтерфейси для підтримки взаємодії магазинів зі сторонніми програмами та сервісами по роботі з:

  1. Розділами каталогу.
  2. товарами.
  3. Кошиком.
  4. Знижки.
  5. способами доставки.
  6. способами оплати.

Для тестування взаємодії з API платформи beseller створено тестовий магазин beseller-api.shop.by.

Для доступу до тестового магазину необхідно вказати логін та пароль. Їх ви можете отримати на запит у вашого персонального менеджера.

Перед тестуванням взаємодії з API ми рекомендуємо:

  1. оформити самостійно кілька замовлень;
  2. Підписатися на розсилку;
  3. переглянути як інформація про оформлені замовлення та передплатники відображається в панелі адміністрування магазину.

Панель керування магазином доступна за адресою: beseller-api.shop.by/manager/. Логін та пароль при вході в панель управління аналогічні логіну та паролю доступу до магазину.

Як підключитися API до свого магазину?

Для зв'язку програми з вашим магазином необхідно вказати URL-адресу доступу до API виду:

http://адреса_вашого_сайту:8082/graphql?token=ваш_персональний_секретний_ключ

Секретний ключ ви можете отримати на запит у вашого персонального менеджера.

Функції та змінні GraphQL для роботи з API платформи beseller

Як підключитися до API за допомогою мови програмування PHP

Для зручності роботи з API платформи beseller ви можете скористатися:

  1. Класами, розробленими нами під PHP.
    1. GraphqlClient- здійснює прийом та передачу даних на сервер;
    2. GraphQlHelper- містить у собі реалізовані query та mutation API;
  2. Прикладами використання класів для здійснення вибірок та змін у базі даних інтернет-магазину.

Налаштування локального оточення

Для того, щоб наочно продемонструвати надсилання запитів до API та відповіді, що ви отримуєте, ви можете скористатися локальним оточенням.

Як локальне оточення використовується GraphiQL Feen, це розширення для браузера Google Chrome, яке дозволяє формувати запити до API.

Після встановлення програми у вас у браузері біля адресного рядка з'явиться іконка програми.

Відкрийте програму GraphiQL Feen і перейдіть на вкладку «SERVERS», виберіть метод надсилання POST, після чого вкажіть URL-адресу доступу до API.

Як тестовий url необхідно використовувати наступну адресу:

Локальне оточення настроєне, можна формувати запити до API. Для цього потрібно відкрити вкладку «QUERIES»

Формування запиту до API beseller за допомогою GraphiQL Feen та отримана відповідь

Пояснення до скріншоту:

  1. Збережені запити
  2. Поле для введення запитів
  3. Поле введення змінних
  4. Отримана відповідь
  5. Кнопка запуску

Приклад запиту отримання списку оформлених замовлень за вказаний проміжок часу

query ($first:Int, $offset:Int, $filter: OrdersFilterType)(
orders(first:$first, offset:$offset, filter:$filter)(
comment
status(
id
description
name
}
create_date
update_date
total (
suffix
value
}
payment (
name
description
cost (
suffix
value
}
}
delivery (
name
description
cost (
suffix
value
}
}
currencies (
bank_code
course
suffix
}
user_data (
name
description
value
}
}
}

Вказівка ​​часу для вибірки даних про оформлені замовлення

{
"filter": (
"date_after": "2017-11-16T00:00:01Z",
"date_before": "2017-11-23T00:00:01Z"
}
}

Приклад відповіді API

{{
"data": (
"orders": [
{
"comment": "Culpa officiis vel ut.",
"create_date": "2017-11-22 16:23:28",
"currencies": [
{
"bank_code": "BYN",
"course": 10000,
"suffix": "крб."
}
],
"delivery": (
"cost": [
{
"suffix": "руб.",
"value": 0
}
],
"description": "Кур'єр",
"name": "custom"
},
"payment": (
"cost": [
{
"suffix": "руб.",
"value": 0
}
],
"description": "Пластикові картки",
"name": "custom"
},
"status": (
"description": "Новий",
"id": 1,
"name": "new"
},
"total": [
{
"suffix": "руб.",
"value": 4450
}
],
"update_date": "2017-11-22 16:23:28",
"user_data": [
{
"description": "Адреса e-mail",
"name": "email",
"value": " [email protected]"
},
{
"description": "Телефон",
"name": "phone",
"value": "784.392.3949 x69329"
},
{
"description": "Адреса",
"name": "registration",
"value": "607 Erik Station Suite 057 Reynaberg, WY 83542-0037"
},
{
"description": "Коментар",
"name": "comment",
"value": "Id nam illo optio."
},
{
"description": "ПІБ",
"name": "fio",
"value": "Jordi Mann MD"
}
]
}

Я намагаюся використовувати віддалений відладчик Visual Studio 2012 на сервері Windows Server 2008 R2 SP1 x64, розташований в DMZ, в середовищі розробки. Цей сервер не має доступу до Інтернету безпосередньо, а через брандмауер. Отже, я завантажив Remote Tools для Visual Studio 2012 з моєї робочої станції і скопіював його на сервер, встановив його, і все гаразд.

Добре, коли я запустив майстер налаштування віддаленого відладчика і спробував встановити API веб-служби Windows, він не працює і відображає таке повідомлення:

Не вдалося виконати майстер налаштування віддаленого відладчика Visual Studio

Налагоджувач не зміг встановити API веб-служб Windows. Не вдалося завантажити програму інсталяції оновлень. Переконайтеся, що комп'ютер має доступ до Інтернету.

Але я чоловік! Я не буду плакати і продовжувати пошуки в Інтернеті (пошук?), Але на цей раз я шукав WWSAPI Redistributable, але в той час не мав успіху, потім я шукав аналогічну ситуацію для мене тут, і це те, що я отримав Не вдається встановити API веб-служб Windows для віддаленого налагодження за допомогою VS2012 , але не має рішення, тому я вирішив запитати у StackOverflow, тому що я майже відчайдушно шукаю рішення для цього. Тому, сподіваюся, ви можете допомогти мені знайти вирішення моєї ситуації. Спасибі!

Розробляючи проект, я зіткнувся з необхідністю організації клієнт-серверної взаємодії додатків на платформах iOS та Android з моїм сайтом, на якому зберігалася вся інформація - власне БД на mysql, картинки, файли та інший контент.
Завдання, які потрібно було вирішувати - досить прості:
реєстрація/авторизація користувача;
відправка/отримання деяких даних (наприклад, список товарів).

І тут мені захотілося написати свій API для взаємодії з серверною стороною - більшою частиною для практичного інтересу.

Вхідні дані

У своєму розпорядженні я мав:
Сервер - Apache, PHP 5.0, MySQL 5.0
Клієнт - Android, iOS пристрої, будь-який браузер

Я вирішив, що для запитів до сервера та відповідей від нього використовуватиму JSON формат даних - за його простоту та нативну підтримку в PHP та Android. Тут мене засмутила iOS - вона не має нативної підтримки JSON (тут довелося використовувати сторонню розробку).

Також було прийнято рішення, що запити можна буде відсилати як через GET так і через запити POST (тут допоміг $_REQUEST в PHP). Таке рішення дозволило проводити тестування API через GET запити у будь-якому доступному браузері.

Зовнішній вигляд запитів було вирішено зробити таким:
http://[адреса сервера]/[шлях до папки api]/?[назва_api].[назва_методу]=

Шлях до папки api - каталог на який потрібно робити запити, в корені якого лежить файл index.php - він відповідає за виклик функцій та обробку помилок
Назва api – для зручності я вирішив розділити API групи – користувач, база даних, конент і т.д. У такому разі кожен api отримав свою назву
Назва методу - ім'я методу, який потрібно викликати у вказаному api
JSON - рядкове представлення JSON об'єкта для параметрів методу

Скелет API

Скелет API на серверній стороні складається з кількох базових класів:
index.php - індексний файл каталогу в Apache на нього припадають усі виклики API, він здійснює парсинг параметрів та виклик API методів
MySQLiWorker - клас-одинак ​​для роботи з базою MySQL через MySQLi
apiBaseCalss.php - батьківський клас для всіх API в системі - кожен API має бути успадкований від цього класу для коректної роботи
apiEngine.php - основний клас системи - здійснює розбір переданих параметрів (після їх попереднього парсингу в index.php) підключення потрібного класу api (через require_once метод), виклик у ньому потрібного методу та повернення результату в JSON форматі
apiConstants.php - клас з константами для api викликів та передачі помилок
apitest.php - тестовий api для тестування нових методів перед їх включенням у продакшн версію

Весь механізм виглядає так:
Ми запитуємо сервер - наприклад www.example.com/api/?apitest.helloWorld= ()
На серверній стороні файл index.php – робить парсинг переданих параметрів. Index.php бере завжди тільки перший елемент зі списку переданих параметрів $_REQUEST - це означає, що конструкція виду www.example.com/api/?apitest.helloWorld= ()&apitest.helloWorld2 - здійснить виклик тільки методу helloWorld в apitest. Виклику ж методу helloWorld2 не відбудеться

Тепер докладніше про кожного

Я спробував достатньо документувати файли, щоб не зайняти багато місця під текст. Однак у тих файлах де немає коментарів, я все ж таки наведу опис.

Index.php

Як вже говорив раніше це вхідний індексний файл для Apache, а значить всі виклики виду www.example.com/api буде приймати він.

0)( require_once "apiEngine.php"; foreach ($_REQUEST як $apiFunctionName => $apiFunctionParams) ( $APIEngine=new APIEngine($apiFunctionName,$apiFunctionParams); echo $APIEngine->cal ( $jsonError->error="No function called"; echo json_encode($jsonError); ) ?>

Насамперед встановлюємо тип контенту - text/html (потім можна змінити в самих методах) та кодування - UTF-8.
Далі перевіряємо, що в нас щось запитують. Якщо ні, то виводимо JSON з помилкою.
Якщо є параметри запиту, підключаємо файл движка API - apiEngine.php і створюємо клас движка з переданими параметрами і робимо виклик api методу.
Виходимо з циклу, тому що ми вирішили, що будемо обробляти тільки один виклик.

apiEngine.php

Другим за важливістю є клас apiEngine - він є двигуном для виклику api та їх методів.
apiFunctionParams = stripcslashes($apiFunctionParams); //Парсим на масив із двох елементів - назва API, - назва методу API $this->apiFunctionName = explode("_", $apiFunctionName); ) //Створюємо JSON відповіді function createDefaultJson() ( $retObject = json_decode("()"); $response = APIConstants::$RESPONSE; $retObject->$response = json_decode("()"); return $retObject; ) //Виклик функції за переданими параметрами в конструкторі function callApiFunction() ( $resultFunctionCall = $this->createDefaultJson();//Створюємо JSON відповіді $apiName = strtolower($this->apiFunctionName);//назву API проводимо регістру if (file_exists($apiName . ".php")) ( $apiClass = APIEngine::getApiEngineByName($apiName);//Отримуємо об'єкт API $apiReflection = new ReflectionClass($apiName);//Через рефлексію отримаємо інформацію про клас об'єкта try ( $functionName = $this->apiFunctionName;// Назва методу для виклику $apiReflection->getMethod($functionName);// Перевіряємо наявність методу $response = APIConstants::$RESPONSE; >apiFunctionParams);//Декодуємо параметри запиту в JSON об'єкт if ($jsonParams) ( if (isset($jsonParams->responseBinary) ))(//Для можливості повернення не JSON, а бінарних даних таких як zip, png та ін. контенту = $apiClass->$functionName($jsonParams);//Викликаємо метод в API який поверне JSON об'єкт ) ) else ( //Якщо помилка декодування JSON параметрів запиту $resultFunctionCall->errno = APIConstants::$ERROR_ENGINE_PARAMS; $resultFunctionCall->error = "Error given params"; ) ) catch (Exception $ex) ( //Непередбачуваний виняток $resultFunctionCall->error = $ex->getMessage(); ) ) else ( //Якщо запитуваний API не знайдено $resultFunctionCall->errno = APIConstants::$ERROR_ENGINE_PARAM; $resultFunctionCall->error = "File not found"; $resultFunctionCall->REQUEST = $_REQUEST; ) return json_encode($resultFunctionCall); ) ) ?>

apiConstants.php

Цей клас використовується тільки для зберігання констант.

MySQLiWorker.php

Клас-одиначка для роботи з базою. В іншому це звичайний одинак ​​- таких прикладів у мережі дуже багато.

dbName = $dbName; self::$instance->dbHost = $dbHost; self::$instance->dbUser = $dbUser; self::$instance->dbPassword = $dbPassword; self::$instance->openConnection(); ) return self::$instance; ) //Визначаємо типи параметрів запиту до бази і повертаємо рядок для прив'язки через ->bind function prepareParams($params) ( $retSTMTString = ""; foreach ($params as $value) ( ​​if (is_int($value) || is_double) ($value)) ( $retSTMTString.="d"; ) if (is_string($value)) ( $retSTMTString.="s"; ) ) return $retSTMTString; ) //З'єднуємося з базою public function openConnection() ( if (is_null($this->connectLink)) ( $this->connectLink = new mysqli($this->dbHost, $this->dbUser, $this->dbPassword, $this->dbName); $this-> connectLink->query("SET NAMES utf8"); if (mysqli_connect_errno()) ( printf("Підключення неможливо: %s\n", mysqli_connect_error()); $this->connectLink = null; ) else ( mysqli_report(MYSQLI_REPORT_ERROR) ); ) ) return $this->connectLink; ) //Закриваємо з'єднання з базою public function closeConnection() ( if (!is_null($this->connectLink)) ( $this->connectLink->close(); ) ) //Перетворимо відповідь на асоціативний масив public function stmt_bind_assoc(&$s tmt, &$out) ( $data = mysqli_stmt_result_metadata($stmt); $fields = array(); $out = array(); $fields = $stmt; $ count = 1; $ currentTable = ""; while ($field = mysqli_fetch_field($data)) ( if (strlen($currentTable) == 0) ( $currentTable = $field->table; ) $fields[$count] = &$out[$field->name ];$count++; ) call_user_func_array("mysqli_stmt_bind_result", $fields); ) ) ?>

apiBaseClass.php

Ну ось ми підійшли до одного з найважливіших класів системи – базовий клас для всіх API у системі.

mySQLWorker = MySQLiWorker::getInstance($dbName,$dbHost,$dbUser,$dbPassword); ) ) function __destruct() ( if (isset($this->mySQLWorker))( //Якщо було встановлено з'єднання з базою, $this->mySQLWorker->closeConnection(); //то закриваємо його коли наш клас більше не потрібен ) ) //Створюємо дефолтний JSON для відповідей function createDefaultJson() ( $retObject = json_decode("()"); return $retObject; ) //Заповнюємо JSON об'єкт з відповіді з MySQLiWorker function fillJSON(&$jsonObject, &$stmt, &$mySQLWorker) ( $row = array(); $mySQLWorker->stmt_bind_assoc($stmt, $row); while ($stmt->fetch()) ( foreach ($row as $key => $value) ( ​​$ key = strtolower($key); $jsonObject->$key = $value; ) break; ) return $jsonObject; ) )

Як видно, цей клас містить у собі кілька «утилітних» методів, таких як:
конструктор, у якому здійснюється з'єднання з базою, якщо поточне API збирається працювати з базою;
деструктор - стежить за визволенням ресурсів - розрив встановленого з'єднання з базою
createDefaultJson - створює дефолтний JSON для відповіді методу
fillJSON - якщо мається на увазі, що запит поверне лише один запис, то даний метод заповнить JSON для відповіді даними з першого рядка відповіді від БД

Створимо свій API

Ось і весь кістяк цього API. Тепер розглянемо як це все використовувати на прикладі створення першого API під назвою apitest. І напишемо у ньому пару простих функцій:
одну без параметрів
одну з параметрами і їх вона нам і поверне, щоб було видно, що вона їх прочитала
одну яка поверне нам бінарні дані

І так створюємо клас apitest.php наступного змісту

createDefaultJson(); $retJSON->withoutParams = "It\"s method called without parameters"; return $retJSON; ) //http://www.example.com/api/?apitest.helloAPIWithParams=("TestParamOne":"Text of first parameter") function helloAPIWithParams($apiMethodParams) ( $retJSON = $this->createDefaultJson(); if (isset($apiMethodParams->TestParamOne))( //Всі ок параметри вірні, їх і повернемо $retJSON->ret apiMethodParams->TestParamOne; )else( $retJSON->errorno= APIConstants::$ERROR_PARAMS; ) return $retJSON; ) //http://www.example.com/api/?apitest.helloAPIResponseBinary=("responseBinary": 1) function helloAPIResponseBinary($apiMethodParams)( header("Content-type: image/png"); echo file_get_contents("http://habrahabr.ru/i/error-404-monster.jpg"); ) ) ?>

Для зручності тестування методів, я дописую до них адресу, за якою я можу зробити швидкий запит для тестування.

І так у нас три методи

Function helloAPI() ( $retJSON = $this->createDefaultJson(); $retJSON->withoutParams = "It's method called without parameters"; return $retJSON; )

Це найпростіший метод без параметрів. Його адреса для GET виклику www.example.com/api/?apitest.helloAPI= ()

Результатом виконання буде ось така сторінка (у браузері)

Цей метод приймає параметри. Обов'язковим є TestParamOne, для нього зробимо перевірку. Його його не передати, то буде видано JSON з помилкою

Function helloAPIWithParams($apiMethodParams) ( $retJSON = $this->createDefaultJson(); if (isset($apiMethodParams->TestParamOne))( //Всі ок параметри вірні, їх і повернемо $retJSON->retParameter=$a TestParamOne; )else( $retJSON->errorno= APIConstants::$ERROR_PARAMS; ) return $retJSON; )
Результат виконання

helloAPIResponseBinary

І останній метод helloAPIResponseBinary - поверне бінарні дані - картинку хабра про неіснуючу сторінку (як приклад)
function helloAPIResponseBinary($apiMethodParams)( header("Content-type: image/jpeg"); echo file_get_contents("http://habrahabr.ru/i/error-404-monster.jpg"); )
Як видно – тут є заміна заголовка для виведення графічного контенту.
Результат буде такий

У геймерів часто виникає неполадка, яка говорить про незнаходження системи файлу Steam_api.dll, тому хочеться дізнатися Steam_api.dll, що це за помилка? Сервіс Steam – відома платформа із широким вибором ігрових програм та програм. До складу даного сервісу входить динамічна бібліотека, необхідна для запуску, функціонування та взаємодії сервера з програмами – це Steam_api.dll для Windows 7,8,10, яка дозволяє вибудовувати взаємозв'язки. Однак, іноді у користувача запуск гри супроводжується повідомленням, що на комп'ютері відсутня Steam_api.dll. Причиною неполадки може бути дублювання файлів бібліотеки, тому система зчитує неправильне ім'я або через блокування антивірусом.

Коли немає Steam api dll, що робити? Користувачеві потрібно завантажити файл Steam_api.dll на ПК. Для усунення помилки існують кілька шляхів вирішення: якщо Steam_api.dll був заблокований антивірусом, його відновлюють з карантину. Необхідно додати файл до списку винятків. Також можна заново завантажити гру, перед тим, відключивши антивірус, а Steam_api.dll встановиться автоматично в комплексі з грою. Наступним способом зробити програми робітниками – встановити сам Steam, який розпакує всі необхідні файли на комп'ютер. Але перед завантаженням потрібно видалити попередню версію програми з усіх джерел.

Третій варіант усунення проблеми із втратою динамічної бібліотеки – окремий файл Steam_api.dll завантажити безкоштовно. Він доступний для безкоштовного скачування з сайтів, що надають необхідні ігри утиліти та програми. Бібліотека завантажується на комп'ютер, а розташування, куди слід помістити файл, залежить від розрядності виндовс, її можна дізнатися, якщо подивитися у відомостях про систему.

Як виправити помилку?

Спосіб 1.

Файл Steam_api.dlll, належить бібліотеці Steam, тому достатньо її встановити якщо у Вас її немає, або перевстановити якщо у Вас вона пошкоджена.

Спосіб 2.

Це додатковий варіант виправлення даної помилки, в якому додається файли вручну і виконувати їх реєстрацію в системі.

Послідовність реєстрації файлів:

  1. Визначаємо який розрядності Ваша Windows;
  2. Для 32 біт завантажуємо лише файл 32біт;
  3. Для 64 біт завантажуємо як 32 і 64 біт;
  4. Файл 32 біт поміщаємо до папки: C:\Windows\System32;
  5. Файл 64 біт поміщаємо в папку: C: Windows SysWOW64;
  6. Для реєстрації натискаємо комбінацію Win + R;
  7. Прописуємо команду для 32: regsvr32 имя.dll(ім'я замінюємо назвою файлу 32);
  8. Прописуємо команду для 64: regsvr32 имя.dll(ім'я замінюємо назвою файлу 64);
  9. Тиснемо "OK і перезавантажуємо ПК;

Нещодавно один з моїх відвідувачів мені поставив питання щодо e-mail: "Я вирішив, що це буде дуже корисно іншим користувачам, тим більше, що на здавалося б складність процесу, все дуже і дуже просто. Необхідно лише мати найелементарніші знання. PHP.

Якщо Ви раптом не знаєте, про що йдеться, то прочитайте спочатку статтю: . Йдемо далі. Давайте розберемо, а для яких сайтів потрібний взагалі API:

Перше, що необхідно засвоїти – це те, що APIпотрібен далеко не кожному сайту (навіть якщо він належить до однієї з вищевказаних груп).

Якщо ж Ви вважаєте, що APIна вашому сайті необхідний, то давайте розберемо приклад того, як він створюється. Нехай у нас буде таке завдання: є ЕПС (як, наприклад, WebMoney). І ми хочемо, щоб користувач міг зі свого коду, користуючись нашим API, дізнатися про свій баланс на рахунку.

Створимо файл (наприклад, api.php), який у нас прийматиме GET-запитивід користувачів отримання різної інформації. Напишемо в цьому обробнику такий код:

if ($_GET["action"] == "getbalance") (
$ balance;
/ / Дізнаємося з бази даних баланс акаунта і записуємо в змінну balance
echo $balance;
}
?>

Тепер розробники APIповинні дати інформацію користувачам про те, як треба надсилати запит, щоб користувач міг дізнатися свій баланс на обліковому записі:

http://mysite.ru/api.php?action=getbalance&key=fa9sgwlgjs9gdsjlgjdsjglsdlgs

Цей запит користувачі формують у своїх скриптах (наприклад, через CURL). Параметр key- Це унікальний ключ кожного користувача. І відповідь цього запиту буде число, що відповідає за баланс користувача. Аналогічно створюються та інші можливості API. Можна додавати інші параметри: наприклад, отримати список операцій поповнення рахунку з однієї дати до іншої. Бажано самі списки повертати у форматі JSON.

Включайся в дискусію
Читайте також
Які знаки зодіаку підходять один одному у коханні - гороскоп сумісності
Як склалася доля переможниць шоу
Весілля не дочекалися: як живуть фіналістки всіх сезонів «Холостяка Максим Черняєв та марія дрігола