clientId = $clientId; $this->clientSecret = $clientSecret; $this->tenantId = $tenantId; $this->defaultUserEmail = $defaultUserEmail; // Authentifizierung gegen Microsoft Graph API durchführen $this->authenticate(); } /** * Authentifiziert sich mit dem Client-Credentials-Flow (ohne Benutzerinteraktion) */ private function authenticate() { $tokenUrl = "https://login.microsoftonline.com/{$this->tenantId}/oauth2/v2.0/token"; // Daten für den OAuth2 Token-Request $data = [ 'grant_type' => 'client_credentials', 'client_id' => $this->clientId, 'client_secret' => $this->clientSecret, 'scope' => 'https://graph.microsoft.com/.default', // Zugriff auf alle berechtigten Graph APIs ]; // Token abrufen $response = $this->postCurl($tokenUrl, ['Content-Type: application/x-www-form-urlencoded'], $data); $decoded = json_decode($response, true); $this->token = $decoded['access_token']; // Standard-Header für alle API-Requests $this->headers = [ "Authorization: Bearer {$this->token}", "Content-Type: application/json" ]; } /** * Gibt eine gültige Benutzer-E-Mail zurück oder wirft einen Fehler */ private function resolveUserEmail($userEmail) { if (!empty($userEmail)) { return $userEmail; } elseif (!empty($this->defaultUserEmail)) { return $this->defaultUserEmail; } else { throw new Exception("Keine Benutzer-E-Mail angegeben."); } } /** * Gibt alle oder ein bestimmtes Kalender-Event zurück */ public function getEvents($eventId = "", $userEmail = "") { $email = $this->resolveUserEmail($userEmail); if($eventId == ""){ // Alle Events des Nutzers abrufen $eventsResponse = $this->getCurl("$this->graphUrl/users/{$email}/calendar/events", $this->headers); return json_decode($eventsResponse, true)['value'] ?? []; } else { // Nur ein einzelnes Event anhand der ID abrufen $eventsResponse = $this->getCurl("{$this->graphUrl}/users/{$email}/calendar/events/{$eventId}", $this->headers); return json_decode($eventsResponse, true) ?? []; } } /** * Erstellt ein neues Kalender-Event (mit optionalem Teams-Link und Teilnehmern) */ public function createEvent($subject, $startTime, $endTime, $isTeamsTermin = false, $description = '', $location = "", $gustArray = array(), $userEmail = "", $timezone = 'Europe/Berlin') { $email = $this->resolveUserEmail($userEmail); // Event-Daten vorbereiten $event = [ 'subject' => $subject, 'start' => [ 'dateTime' => $startTime, 'timeZone' => $timezone ], 'end' => [ 'dateTime' => $endTime, 'timeZone' => $timezone ], 'body' => [ 'contentType' => 'HTML', 'content' => $description ], 'location' => [ 'displayName' => $location ] ]; // Optional: Teams-Termin aktivieren if($isTeamsTermin == true){ $event['isOnlineMeeting'] = true; $event['onlineMeetingProvider'] = 'teamsForBusiness'; } // Teilnehmer hinzufügen, falls vorhanden if(count($gustArray) > 0){ $event['attendees'] = $gustArray; } // Event erstellen $url = "{$this->graphUrl}/users/{$email}/calendar/events"; $response = $this->postJsonCurl($url, $this->headers, $event); return json_decode($response, true); } /** * Bestehendes Event aktualisieren */ public function updateEvent($eventId, $subject, $startTime, $endTime, $isTeamsTermin = false, $description = '', $location = "", $gustArray = array(), $userEmail = "", $timezone = 'Europe/Berlin') { $email = $this->resolveUserEmail($userEmail); // Neue Eventdaten $event = [ 'subject' => $subject, 'start' => [ 'dateTime' => $startTime, 'timeZone' => $timezone ], 'end' => [ 'dateTime' => $endTime, 'timeZone' => $timezone ], 'body' => [ 'contentType' => 'HTML', 'content' => $description ], 'location' => [ 'displayName' => $location ], 'isOnlineMeeting' => $isTeamsTermin ]; // Teams-Link ggf. setzen if($isTeamsTermin == true){ $event['onlineMeetingProvider'] = 'teamsForBusiness'; } // Teilnehmer aktualisieren if(count($gustArray) > 0){ $event['attendees'] = $gustArray; } // Event patchen (aktualisieren) $url = "{$this->graphUrl}/users/{$email}/calendar/events/{$eventId}"; $result = $this->patchJsonCurl($url, $this->headers, $event); return [ 'status' => $result['status'], 'response' => json_decode($result['response'], true) ]; } /** * Löscht ein Kalender-Event anhand der ID */ public function deleteEvent($eventId, $userEmail = "") { $email = $this->resolveUserEmail($userEmail); $url = "{$this->graphUrl}/users/{$email}/calendar/events/{$eventId}"; return $this->deleteCurl($url, $this->headers); } /** * Hängt eine Datei als Attachment an ein Kalender-Event. * * @param string $eventId Die ID des Events * @param string $fileName Der Dateiname (z.B. "dokument.pdf") * @param string $fileContent Der Inhalt der Datei als Base64-kodierter String * @param string $contentType Der MIME-Typ der Datei (z.B. "application/pdf") * @param string $userEmail Optional: Benutzer-E-Mail, falls abweichend * @return array Antwort von der Graph API */ public function addAttachmentToEvent($eventId, $fileName, $fileContent, $contentType = 'application/octet-stream', $userEmail = '') { $email = $this->resolveUserEmail($userEmail); // Attachment-Objekt $attachment = [ '@odata.type' => '#microsoft.graph.fileAttachment', 'name' => $fileName, 'contentType' => $contentType, 'contentBytes' => base64_encode($fileContent) ]; $url = "{$this->graphUrl}/users/{$email}/events/{$eventId}/attachments"; $response = $this->postJsonCurl($url, $this->headers, $attachment); return json_decode($response, true); } // === HELPER-FUNKTIONEN FÜR CURL === /** * POST-Request mit URL-encoded Daten */ private function postCurl($url, $headers, $data) { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_POSTFIELDS => http_build_query($data), ]); $response = curl_exec($ch); curl_close($ch); return $response; } /** * GET-Request */ private function getCurl($url, $headers) { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $headers, ]); $response = curl_exec($ch); curl_close($ch); return $response; } /** * POST-Request mit JSON-Daten */ private function postJsonCurl($url, $headers, $json) { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_POSTFIELDS => json_encode($json), ]); $response = curl_exec($ch); curl_close($ch); return $response; } /** * PATCH-Request (teilweises Update von Ressourcen) */ private function patchJsonCurl($url, $headers, $json) { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'PATCH', CURLOPT_HTTPHEADER => $headers, CURLOPT_POSTFIELDS => json_encode($json), ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return ['status' => $httpCode, 'response' => $response]; } /** * DELETE-Request */ private function deleteCurl($url, $headers) { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'DELETE', CURLOPT_HTTPHEADER => $headers, ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return $httpCode; } }