Реалізація імпорту контактів (Google/Outlook) на сайті

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

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

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація імпорту контактів (Google/Outlook) на сайті
Середня
від 1 робочого дня до 3 робочих днів
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація імпорту контактів (Google/Outlook) на сайт

Імпорт контактів з Google або Outlook на сайт — типова задача для CRM-систем, HR-порталів, платформ нетворкінгу. Користувач авторизується через OAuth, дає дозвіл на читання контактів, сайт отримує список і пропонує вибрати, кого запросити чи синхронізувати. Технічно Google та Outlook — принципово різні API, об'єднані одним UI-флоу.

Google Contacts API: налаштування OAuth

У Google Cloud Console: створити проект → включити «People API» → створити OAuth 2.0 Client ID (тип: Web application) → додати redirect URI.

Необхідні scopes:

  • https://www.googleapis.com/auth/contacts.readonly — читання контактів
  • https://www.googleapis.com/auth/contacts.other.readonly — контакти з «Інших контактів»
use Google\Client as GoogleClient;

class GoogleContactsService
{
    private GoogleClient $client;

    public function __construct()
    {
        $this->client = new GoogleClient();
        $this->client->setClientId(config('services.google.client_id'));
        $this->client->setClientSecret(config('services.google.client_secret'));
        $this->client->setRedirectUri(config('services.google.redirect'));
        $this->client->addScope('https://www.googleapis.com/auth/contacts.readonly');
        $this->client->setAccessType('offline'); // отримуємо refresh_token
    }

    public function getAuthUrl(): string
    {
        return $this->client->createAuthUrl();
    }

    public function handleCallback(string $code): array
    {
        $token = $this->client->fetchAccessTokenWithAuthCode($code);
        // Зберігаємо токен для користувача
        return $token;
    }
}

Отримання контактів з Google People API

public function getContacts(array $accessToken): array
{
    $this->client->setAccessToken($accessToken);

    if ($this->client->isAccessTokenExpired() && isset($accessToken['refresh_token'])) {
        $this->client->fetchAccessTokenWithRefreshToken($accessToken['refresh_token']);
    }

    $service  = new \Google\Service\PeopleService($this->client);
    $contacts = [];
    $pageToken = null;

    do {
        $params = [
            'personFields' => 'names,emailAddresses,phoneNumbers',
            'pageSize'     => 1000,
        ];
        if ($pageToken) {
            $params['pageToken'] = $pageToken;
        }

        $result = $service->people_connections->listPeopleConnections('people/me', $params);

        foreach ($result->getConnections() ?? [] as $person) {
            $name   = $person->getNames()[0] ?? null;
            $email  = $person->getEmailAddresses()[0] ?? null;
            $phone  = $person->getPhoneNumbers()[0] ?? null;

            if (!$email) continue; // пропускаємо без email

            $contacts[] = [
                'name'  => $name?->getDisplayName() ?? '',
                'email' => $email->getValue(),
                'phone' => $phone?->getValue() ?? '',
            ];
        }

        $pageToken = $result->getNextPageToken();
    } while ($pageToken);

    return $contacts;
}

Пагінація обов'язкова: у користувача може бути 5000+ контактів, API повертає максимум 1000 за запит.

Microsoft Graph API: Outlook/Office 365 контакти

Реєстрація додатка в Azure AD → «App registrations» → «New registration». Необхідні дозволи: Contacts.Read (Delegated).

use Microsoft\Graph\Graph;
use Microsoft\Graph\Model\Contact;

class OutlookContactsService
{
    public function getAuthUrl(): string
    {
        $params = http_build_query([
            'client_id'     => config('services.microsoft.client_id'),
            'response_type' => 'code',
            'redirect_uri'  => config('services.microsoft.redirect'),
            'scope'         => 'offline_access Contacts.Read',
            'response_mode' => 'query',
        ]);

        return "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?{$params}";
    }

    public function getToken(string $code): array
    {
        $response = Http::asForm()->post(
            'https://login.microsoftonline.com/common/oauth2/v2.0/token',
            [
                'client_id'     => config('services.microsoft.client_id'),
                'client_secret' => config('services.microsoft.client_secret'),
                'code'          => $code,
                'redirect_uri'  => config('services.microsoft.redirect'),
                'grant_type'    => 'authorization_code',
            ]
        );

        return $response->json();
    }

    public function getContacts(string $accessToken): array
    {
        $graph    = new Graph();
        $graph->setAccessToken($accessToken);

        $contacts = [];
        $url      = '/me/contacts?$select=displayName,emailAddresses,mobilePhone&$top=100';

        do {
            $result  = $graph->createRequest('GET', $url)->execute();
            $data    = $result->getBody();

            foreach ($data['value'] as $contact) {
                $email = $contact['emailAddresses'][0]['address'] ?? null;
                if (!$email) continue;

                $contacts[] = [
                    'name'  => $contact['displayName'] ?? '',
                    'email' => $email,
                    'phone' => $contact['mobilePhone'] ?? '',
                ];
            }

            $url = $data['@odata.nextLink'] ?? null;
            // Видаляємо базовий URL для Graph SDK
            if ($url) {
                $url = str_replace('https://graph.microsoft.com/v1.0', '', $url);
            }
        } while ($url);

        return $contacts;
    }
}

UI: вибір контактів для імпорту

Після отримання списку користувач вибирає, які контакти імпортувати:

function ContactImportModal({ contacts, onImport }) {
    const [selected, setSelected] = useState(new Set());

    const toggle = (email) => {
        setSelected(prev => {
            const next = new Set(prev);
            next.has(email) ? next.delete(email) : next.add(email);
            return next;
        });
    };

    return (
        <div>
            <div className="actions">
                <button onClick={() => setSelected(new Set(contacts.map(c => c.email)))}>
                    Вибрати все ({contacts.length})
                </button>
            </div>
            <ul>
                {contacts.map(contact => (
                    <li key={contact.email}>
                        <label>
                            <input
                                type="checkbox"
                                checked={selected.has(contact.email)}
                                onChange={() => toggle(contact.email)}
                            />
                            {contact.name} — {contact.email}
                        </label>
                    </li>
                ))}
            </ul>
            <button onClick={() => onImport([...selected])}>
                Імпортувати вибрані ({selected.size})
            </button>
        </div>
    );
}

Зберігання токенів

Токени доступу не можна зберігати в сесії — вони повинні бути в БД, зашифровані:

// Міграція
$table->text('google_access_token')->nullable();
$table->text('google_refresh_token')->nullable();
$table->timestamp('google_token_expires_at')->nullable();

// У моделі User — автоматичне шифрування
protected $casts = [
    'google_access_token'  => 'encrypted',
    'google_refresh_token' => 'encrypted',
];

Терміни

Імпорт з одного провайдера (Google або Outlook) з UI вибору контактів, OAuth-флоу та збереженням у базу: 2–3 робочих дні. Обидва провайдери одночасно з оновленням токенів і повторною синхронізацією: 4–5 робочих днів.