בעיה: המשתמש מזין 5000 אנשי קשר ידנית, ה-CRM ריק
תרחיש טיפוסי: פורטלי משאבי אנוש, פלטפורמות נטוורקינג ומערכות CRM דורשים מהמשתמש להעלות אנשי קשר. הזנה ידנית של למעלה מ-5000 רשומות אורכת שעות. שגיאות הן בלתי נמנעות, כפילויות מתרבות. דמיינו: לקוח מבלה 3 שעות במילוי טופס, רק כדי לגלות שחצי מאנשי הקשר כבר קיימים. ייבוא מאנשי קשר של Google או Outlook פותר את הכאב הזה. אבל היישום דורש טיפול זהיר ב-OAuth, פגינציה ו-API שונים. אנו מיישמים את הייבוא turnkey: המשתמש מאשר, בוחר את אנשי הקשר הרצויים ומייבא אותם בשתי לחיצות. כתוצאה מכך, מסד הנתונים מתמלא תוך דקות, והמרת ההרשמה גדלה ב-30%. צרו קשר לייעוץ על הפרויקט שלכם.
אילו קשיים טכניים אנו פותרים
פרוטוקולי אימות שונים
Google משתמשת ב-OAuth 2.0 עם Google Identity Platform, Microsoft משתמשת ב-OAuth 2.0 עם Azure AD. לכל אחת יש endpoints, scopes ונוהל קבלת token משלה. שגיאה בהגדרת redirect URI – והמשתמש רואה מסך ריק.
פגינציה עם אלפי רשומות. למשתמש עשויים להיות 5000+ אנשי קשר, אבל ה-API מחזיר מקסימום 1000 לכל בקשה. יש לטפל נכון ב-nextPageToken / @odata.nextLink. ללא פגינציה, הייבוא נעצר בקבוצה הראשונה.
חידוש token. access token חי שעה (Google) או 90 דקות (Outlook). refresh token מאפשר קבלת חדש – יש לאחסן אותו מוצפן במסד הנתונים ולעדכן בלוח זמנים. אם זה לא נעשה, הייבוא נשבר לאחר שעה.
בחירת ממשק משתמש ורספונסיביות. רשימה של 5000 אנשי קשר לא צריכה להאט את הממשק. אנו משתמשים בווירטואליזציה או בטעינה הדרגתית. אחרת, הדפדפן קופא ל-10 שניות.
למה Laravel מתאים לאינטגרציה? + השוואת מורכבות
Laravel 11 מספק תמיכה מובנית ב-OAuth דרך Socialite, הצפנה מוכנה ותורים למשימות רקע. בפרויקט אחד (פורטל משאבי אנוש), שילבנו ייבוא מ-Google ו-Outlook באמצעות ה-SDK הרשמיים – google/apiclient ו-microsoft/microsoft-graph. שני ה-SDK תומכים בחידוש. להלן הקטעים המרכזיים.
Google People API: הגדרת OAuth
ב-Google Cloud Console: צרו פרויקט → הפעילו "People API" → צרו OAuth 2.0 Client ID (סוג: Web application) → הוסיפו redirect URI.
ה-scopes הנדרשים:
-
google/apiclient– קריאת אנשי קשר -
microsoft/microsoft-graph– אנשי קשר מ-"Other contacts"
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". ההרשאות הנדרשות: https://www.googleapis.com/auth/contacts.readonly (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;
}
} ממשק משתמש: בחירת אנשי קשר לייבוא
לאחר קבלת הרשימה, המשתמש בוחר אילו אנשי קשר לייבא:
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>
);
} אחסון tokens
אין לאחסן access tokens ב-session – יש לאחסן אותם במסד הנתונים, מוצפנים:
// Миграция
$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).
- המערכת מפנה לדף ה-OAuth של הספק.
- המשתמש מעניק הרשאה לקריאת אנשי קשר.
- ה-callback שומר את ה-tokens במסד הנתונים.
- ה-frontend טוען את רשימת אנשי הקשר (עם פגינציה).
- המשתמש מסמן את אנשי הקשר הרצויים ולוחץ על "ייבוא".
- אנשי הקשר שנבחרו נשמרים במסד הנתונים של ה-CRM/האתר.
דוגמה להגדרת Google OAuth
ב-Google Cloud Console, צרו פרויקט, הפעילו People API, הגדירו מסך הסכמת OAuth. לאחר מכן צרו אישורי OAuth 2.0 Web application, תוך ציון ה-redirect URI לשרת שלכם. השתמשו ב-client ID וב-secret שהתקבלו בהגדרות Laravel.מה כלול בעבודה
| שלב | מה אנו עושים | תוצאה |
|---|---|---|
| אנליטיקה | מסכמים על רשימת הספקים, scopes, עיצוב ממשק | מפרט טכני |
| עיצוב | מפתחים תוכנית OAuth, אחסון tokens, טיפול בשגיאות | תיעוד ארכיטקטורה |
| יישום | כותבים שירותים ל-Google ו-Outlook, רכיב frontend | ייבוא עובד |
| בדיקות | בודקים פגינציה, חידוש token, מקרי קצה | דוח בדיקות |
| פריסה | פורסים לייצור, מגדירים ניטור | אישורי גישה, מדריך |
| תמיכה | 30 ימי תמיכה לאחר השקה | הדרכה, תיקוני באגים |
השוואת מורכבות: Google People API מול Microsoft Graph API
| פרמטר | Google People API | Microsoft Graph API |
|---|---|---|
| רישום אפליקציה | Google Cloud Console | Azure AD App Registrations |
| מקסימום אנשי קשר לבקשה | 1000 (pageSize) | 1000 ($top) |
| פגינציה | nextPageToken | @odata.nextLink |
| Refresh token | כברירת מחדל (access_type=offline) | יש לבקש offline_access |
| SDK | google/apiclient | microsoft/microsoft-graph |
| מורכבות אינטגרציה | בינונית – פשוטה פי 1.5 מ-Outlook | גבוהה יותר – יותר הגדרות Azure AD |
Google קל יותר להתחיל – האינטגרציה אורכת פי 1.5 פחות זמן. אבל Outlook הוא הסטנדרט במגזר הארגוני. אנו מחברים את שניהם.
למה להפקיד בידינו את האינטגרציה?
לצוות שלנו ניסיון של למעלה מ-10 שנים בפיתוח web ויותר מ-50 פרויקטים עם אינטגרציות API חיצוניות. אנו מוסמכים כ-Google Cloud Partner ויש לנו ניסיון עם Azure AD. אנו משתמשים בפרקטיקות מאובטחות לאחסון tokens, מיישמים הצפנה ובודקים חידוש token באופן קבוע. אוטומציה של ייבוא אנשי קשר חוסכת עד 90% מזמן ההזנה הידנית, ומפחיתה עלויות בעד $2000 לשנה לפורטל משאבי אנוש טיפוסי. צרו קשר להערכת פרויקט – נבחר את הפתרון האופטימלי וניתן לוחות זמנים מדויקים.
לוחות זמנים ומחירים משוערים
- ספק אחד (Google או Outlook) – בין 2 ל-3 ימי עבודה, עלות מ-$500.
- שני הספקים עם תמיכה בסנכרון – בין 4 ל-5 ימי עבודה, עלות מ-$900.
- תכונות נוספות (ממשק מותאם אישית, זיהוי כפילויות) – מתומחרות בנפרד.
הזמינו ייעוץ – נשלח הצעה מסחרית תוך יום עבודה אחד.







