Реалізація імпорту контактів (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 робочих днів.







