PHP Classes

File: example/get.php

Recommend this page to a friend!
  Packages of Engin Ypsilon   PHP Ymap   example/get.php   Download  
File: example/get.php
Role: Example script
Content type: text/plain
Description: Example script
Class: PHP Ymap
Retrieve email messages from an IMAP server
Author: By
Last change: feat(demo): add UID-based load-more pagination and lazy message hydration
Date: 28 days ago
Size: 9,069 bytes
 

Contents

Class file image Download
<?php declare(strict_types=1);

/**
 * IMAP API Endpoint - Powered by ImapService
 */

use Yai\Ymap\ImapService;
use
Yai\Ymap\Exceptions\ConnectionException;

error_reporting(E_ALL);

header('Content-Type: application/json');

require_once
dirname(__DIR__) . '/vendor/autoload.php';

if (
$_SERVER['REQUEST_METHOD'] !== 'POST') {
   
http_response_code(405);
    echo
json_encode(['success' => false, 'error' => 'Method not allowed']);
    exit;
}

$messageUid = isset($_GET['message']) ? (int) $_GET['message'] : null;
if (
null !== $messageUid && $messageUid <= 0) {
   
$messageUid = null;
}
$messageAction = $_GET['action'] ?? null;
$messageDetails = isset($_GET['details']) && '1' === (string) $_GET['details'];
$beforeUid = isset($_POST['before_uid']) ? (int) $_POST['before_uid'] : null;
if (
null !== $beforeUid && $beforeUid <= 0) {
   
$beforeUid = null;
}

$bodyLength = (int) ($_POST['body_length'] ?? 500);
if (
$bodyLength < 100) {
   
$bodyLength = 100;
} elseif (
$bodyLength > 20000) {
   
$bodyLength = 20000;
}

$username = trim($_POST['username'] ?? '');
$password = trim($_POST['password'] ?? '');

if (!
$username || !$password) {
   
http_response_code(400);
    echo
json_encode(['success' => false, 'error' => 'Username and password required']);
    exit;
}

try {
   
$imap = ImapService::create()
        ->
connect(
           
$_POST['mailbox'] ?: '{imap.gmail.com:993/imap/ssl}INBOX',
           
$username,
           
$password
       
);

   
$listFields = [
       
'uid',
       
'subject',
       
'from',
       
'to',
       
'cc',
       
'replyTo',
       
'date',
       
'seen',
       
'answered',
       
'size',
    ];

   
$detailFields = [
       
'uid',
       
'subject',
       
'from',
       
'to',
       
'cc',
       
'replyTo',
       
'date',
       
'textBody',
       
'htmlBody',
       
'attachments',
       
'seen',
       
'answered',
       
'size',
    ];

   
$imap
       
->fields($messageDetails ? $detailFields : $listFields)
        ->
limit((int) ($_POST['limit'] ?? 10))
        ->
orderBy('desc');

   
// Add optional filters
   
if (!empty($_POST['date_from'])) {
       
$imap->since($_POST['date_from']);
    }
    if (!empty(
$_POST['date_to'])) {
       
$imap->before($_POST['date_to']);
    }
    if ((
$_POST['read_status'] ?? '') === 'UNREAD') {
       
$imap->unreadOnly();
    } elseif ((
$_POST['read_status'] ?? '') === 'READ') {
       
$imap->readOnly();
    }
    if ((
$_POST['answered_status'] ?? '') === 'ANSWERED') {
       
$imap->answeredOnly();
    } elseif ((
$_POST['answered_status'] ?? '') === 'UNANSWERED') {
       
$imap->unansweredOnly();
    }
    if (!empty(
$_POST['search_text'])) {
       
match ($_POST['search_field'] ?? 'SUBJECT') {
           
'FROM' => $imap->from($_POST['search_text']),
           
'TO' => $imap->to($_POST['search_text']),
           
'BODY', 'TEXT' => $imap->bodyContains($_POST['search_text']),
            default =>
$imap->subjectContains($_POST['search_text']),
        };
    }

   
// Exclusion filters from textareas (one pattern per line)
   
if (!empty($_POST['exclude_from'])) {
       
$patterns = array_filter(array_map('trim', explode("\n", $_POST['exclude_from'])));
        if (
$patterns) {
           
$imap->excludeFrom($patterns);
        }
    }
    if (!empty(
$_POST['exclude_subject'])) {
       
$patterns = array_filter(array_map('trim', explode("\n", $_POST['exclude_subject'])));
        if (
$patterns) {
           
$imap->excludeSubjectContains($patterns);
        }
    }

   
$mapAddresses = static function (array $addresses): array {
       
$result = [];

        foreach (
$addresses as $entry) {
            if (
is_array($entry)) {
               
$result[] = [
                   
'email' => (string) ($entry['email'] ?? ''),
                   
'name' => $entry['name'] ?? null,
                ];
                continue;
            }

           
$value = (string) $entry;
            if (
preg_match('/^(.*)<([^>]+)>$/', $value, $matches)) {
               
$result[] = [
                   
'email' => trim($matches[2]),
                   
'name' => trim($matches[1]) ?: null,
                ];
            } else {
               
$result[] = [
                   
'email' => $value,
                   
'name' => null,
                ];
            }
        }

        return
$result;
    };

   
$formatMessage = static function (array $msg) use ($bodyLength, $mapAddresses) {
       
$textBody = trim((string) ($msg['textBody'] ?? ''));
       
$htmlBody = isset($msg['htmlBody']) ? (string) $msg['htmlBody'] : null;
       
$body = $textBody;

        if (
'' === $body && null !== $htmlBody && '' !== $htmlBody) {
           
$body = trim(strip_tags($htmlBody));
        }

       
$bodyPreview = '' !== $body ? mb_substr($body, 0, $bodyLength) : '';
       
$isTruncated = '' !== $body && mb_strlen($body) > $bodyLength;
       
$hasDetails = array_key_exists('textBody', $msg) || array_key_exists('htmlBody', $msg);

       
$size = (int) ($msg['size'] ?? 0);
        if (
$size >= 1048576) {
           
$sizeFormatted = number_format($size / 1048576, 1) . ' MB';
        } elseif (
$size >= 1024) {
           
$sizeFormatted = number_format($size / 1024, 1) . ' KB';
        } elseif (
$size > 0) {
           
$sizeFormatted = $size . ' B';
        } else {
           
$sizeFormatted = '-';
        }

        return [
           
'uid' => $msg['uid'],
           
'subject' => $msg['subject'] ?? '',
           
'from' => $mapAddresses($msg['from'] ?? []),
           
'to' => $mapAddresses($msg['to'] ?? []),
           
'cc' => $mapAddresses($msg['cc'] ?? []),
           
'replyTo' => $mapAddresses($msg['replyTo'] ?? []),
           
'date' => $msg['date'] ? date('M j, Y H:i', strtotime($msg['date'])) : null,
           
'bodyPreview' => $bodyPreview,
           
'bodyFull' => $body,
           
'bodyTruncated' => $isTruncated,
           
'htmlBody' => $htmlBody,
           
'detailsLoaded' => $hasDetails,
           
'seen' => (bool) ($msg['seen'] ?? false),
           
'answered' => (bool) ($msg['answered'] ?? false),
           
'size' => $size,
           
'sizeFormatted' => $sizeFormatted,
           
'attachments' => array_map(static fn($a) => [
               
'filename' => $a['filename'],
               
'size' => $a['size'],
               
'sizeFormatted' => number_format($a['size'] / 1024, 1) . ' KB',
            ],
$msg['attachments'] ?? []),
        ];
    };

    if (
null !== $messageUid) {
       
$actionMap = [
           
'mark-read' => 'markAsRead',
           
'mark-unread' => 'markAsUnread',
           
'mark-answered' => 'markAsAnswered',
           
'mark-unanswered' => 'markAsUnanswered',
        ];

        if (
null !== $messageAction) {
            if (!isset(
$actionMap[$messageAction])) {
               
http_response_code(400);
                echo
json_encode(['success' => false, 'error' => 'Invalid action requested']);
                exit;
            }

           
$imap->{$actionMap[$messageAction]}($messageUid);
        }

       
$singleMessage = $imap->getMessage($messageUid);
        if (
null === $singleMessage) {
           
http_response_code(404);
            echo
json_encode(['success' => false, 'error' => 'Message not found']);
            exit;
        }

        echo
json_encode([
           
'success' => true,
           
'message' => $formatMessage($singleMessage),
        ],
JSON_INVALID_UTF8_SUBSTITUTE);

        exit;
    }

   
$listOverrides = [];
    if (
null !== $beforeUid) {
       
$listOverrides['before_uid'] = $beforeUid;
    }

   
$messages = $imap->getMessages($listOverrides);

   
// Format for frontend
   
$output = array_map($formatMessage, $messages);

   
// Get counts for UI and pagination
   
$baseCriteria = $imap->getConfig()->toImapCriteria();
   
$effectiveConfig = [] !== $listOverrides ? $imap->getConfig()->merge($listOverrides) : $imap->getConfig();
   
$pagedCriteria = $effectiveConfig->toImapCriteria();
   
$totalFound = $imap->getTotalCount($baseCriteria);
   
$remainingForCursor = $imap->getTotalCount($pagedCriteria);
   
$hasMore = $remainingForCursor > count($output);
   
$nextBeforeUid = null;
    if ([] !==
$output) {
       
$uids = array_column($output, 'uid');
       
$lowestUid = (int) min($uids);
        if (
$lowestUid > 1) {
           
$nextBeforeUid = $lowestUid - 1;
        }
    }

    echo
json_encode([
       
'success' => true,
       
'count' => count($output),
       
'totalFound' => $totalFound,
       
'remainingForCursor' => $remainingForCursor,
       
'hasMore' => $hasMore,
       
'nextBeforeUid' => $nextBeforeUid,
       
'searchCriteria' => $baseCriteria,
       
'messages' => $output,
    ],
JSON_INVALID_UTF8_SUBSTITUTE);

} catch (
ConnectionException $e) {
   
http_response_code(401);
    echo
json_encode(['success' => false, 'error' => 'Connection failed: ' . $e->getMessage()]);
} catch (\
Throwable $e) {
   
http_response_code(500);
    echo
json_encode(['success' => false, 'error' => 'Error: ' . $e->getMessage()]);
}