/home/altere25/public_html
Edit: /home/altere25/public_html/email-forwarder-debug.php (12220B)
#!/usr/bin/php
$att) {
debugLog(" 📎 [$i] " . $att['filename'] . " (" . $att['size'] . " bytes)");
}
// Prepare webhook data
$webhookUrl = 'https://featfzcywzwcyckzcllw.supabase.co/functions/v1/make-server-55f34896/email-webhook';
$data = [
'to' => $parsed['to'],
'from' => $parsed['from'],
'subject' => $parsed['subject'],
'body' => $parsed['plain'], // Use 'body' instead of 'plain'
'text' => $parsed['plain'], // Also include 'text' for compatibility
'plain' => $parsed['plain'], // Keep 'plain' as fallback
'html' => $parsed['html'],
'attachments' => $parsed['attachments'],
'headers' => $parsed['headers'],
'messageId' => $parsed['message_id'], // Use camelCase
'message_id' => $parsed['message_id'], // Also keep snake_case
'inReplyTo' => $parsed['in_reply_to'], // Use camelCase
'in_reply_to' => $parsed['in_reply_to'], // Also keep snake_case
'references' => $parsed['references'],
'timestamp' => $parsed['timestamp'],
'metadata' => [
'script_version' => '5.1',
'script_path' => __FILE__,
'source' => 'cPanel_piping_script',
'php_version' => phpversion(),
'parsed_at' => date('c')
],
'script_path' => __FILE__ // Triggers custom format handler
];
debugLog("📤 Sending to webhook...");
debugLog("📤 Payload size: " . strlen(json_encode($data)) . " bytes");
// Send to webhook
$ch = curl_init($webhookUrl);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZlYXRmemN5d3p3Y3lja3pjbGx3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3Njc4MDIyNzksImV4cCI6MjA4MzM3ODI3OX0.Wrln7-kR9IXFp4gl2QheedhMfXDJFIl80kghs3xN1Go'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
debugLog("📥 Response HTTP: $httpCode");
if ($curlError) {
debugLog("❌ cURL Error: $curlError");
exit(1);
}
if ($httpCode >= 200 && $httpCode < 300) {
debugLog("✅ SUCCESS! Email processed with " . count($parsed['attachments']) . " attachments");
debugLog("========================================");
exit(0);
} else {
debugLog("❌ ERROR: Webhook returned HTTP $httpCode");
debugLog("Response: " . substr($response, 0, 200));
exit(1);
}
/**
* Parse MIME email and extract all parts including attachments
*/
function parseMimeEmail($rawEmail) {
debugLog("🔍 Parsing MIME structure...");
$headers = [];
$body = '';
$htmlBody = '';
$attachments = [];
// Split into lines
$lines = explode("\n", $rawEmail);
debugLog("📄 Lines: " . count($lines));
// Parse headers section
$i = 0;
$currentHeader = '';
while ($i < count($lines)) {
$line = rtrim($lines[$i], "\r\n");
// Empty line = end of headers
if (trim($line) === '') {
debugLog("📋 Headers end at line $i");
$i++;
break;
}
// Continuation line (starts with space/tab)
if (preg_match('/^[\s\t]/', $line) && $currentHeader) {
$headers[$currentHeader] .= ' ' . trim($line);
}
// New header
elseif (preg_match('/^([^:]+):\s*(.*)$/', $line, $m)) {
$currentHeader = $m[1];
$headers[$currentHeader] = $m[2];
}
$i++;
}
debugLog("📋 Headers: " . count($headers));
// Extract boundary for multipart emails
$boundary = '';
if (isset($headers['Content-Type'])) {
debugLog("📋 Content-Type: " . substr($headers['Content-Type'], 0, 80));
if (preg_match('/boundary=["\']?([^"\'\s;]+)["\']?/i', $headers['Content-Type'], $m)) {
$boundary = $m[1];
debugLog("🔖 Boundary: '$boundary'");
}
}
// Get body content (everything after headers)
$bodyContent = implode("\n", array_slice($lines, $i));
debugLog("📄 Body: " . strlen($bodyContent) . " bytes");
// Parse multipart email
if ($boundary) {
debugLog("🔀 Multipart email detected");
$parts = parseMultipartBody($bodyContent, $boundary);
debugLog("🔀 Parts found: " . count($parts));
foreach ($parts as $idx => $part) {
$pH = $part['headers'];
$pB = $part['body'];
$cType = isset($pH['Content-Type']) ? $pH['Content-Type'] : 'text/plain';
$cDisp = isset($pH['Content-Disposition']) ? $pH['Content-Disposition'] : '';
$cEnc = isset($pH['Content-Transfer-Encoding']) ? trim($pH['Content-Transfer-Encoding']) : '';
debugLog(" Part $idx: " . substr($cType, 0, 40));
debugLog(" Disposition: " . substr($cDisp, 0, 40));
debugLog(" Encoding: '$cEnc'");
debugLog(" Size: " . strlen($pB) . " bytes");
// Is this an attachment?
if (stripos($cDisp, 'attachment') !== false || stripos($cDisp, 'filename=') !== false) {
debugLog(" 🎯 ATTACHMENT!");
// Extract filename
$filename = 'unknown';
if (preg_match('/filename=["\']?([^"\';]+)["\']?/i', $cDisp, $m)) {
$filename = trim($m[1]);
} elseif (preg_match('/name=["\']?([^"\';]+)["\']?/i', $cType, $m)) {
$filename = trim($m[1]);
}
debugLog(" 📎 Filename: '$filename'");
// Decode content
$decoded = decodeContent($pB, strtolower($cEnc));
debugLog(" 📦 Decoded: " . strlen($decoded) . " bytes");
// Extract MIME type
$mimeType = 'application/octet-stream';
if (preg_match('/^([^;]+)/', $cType, $m)) {
$mimeType = trim($m[1]);
}
$attachments[] = [
'filename' => $filename,
'contentType' => $mimeType,
'size' => strlen($decoded),
'content' => base64_encode($decoded)
];
debugLog(" ✅ Added to attachments array");
}
// Text body
elseif (stripos($cType, 'text/plain') !== false) {
debugLog(" 📝 Text body");
$body = decodeContent($pB, strtolower($cEnc));
}
// HTML body
elseif (stripos($cType, 'text/html') !== false) {
debugLog(" 🌐 HTML body");
$htmlBody = decodeContent($pB, strtolower($cEnc));
}
}
} else {
// Simple email (no multipart)
debugLog("📄 Simple email (no multipart)");
$enc = isset($headers['Content-Transfer-Encoding']) ? strtolower(trim($headers['Content-Transfer-Encoding'])) : '';
$body = decodeContent($bodyContent, $enc);
}
debugLog("✅ Parse complete: " . count($attachments) . " attachments");
return [
'to' => isset($headers['To']) ? $headers['To'] : '',
'from' => isset($headers['From']) ? $headers['From'] : '',
'subject' => isset($headers['Subject']) ? decodeHeader($headers['Subject']) : 'No Subject',
'plain' => $body,
'html' => $htmlBody,
'attachments' => $attachments,
'headers' => $headers,
'message_id' => isset($headers['Message-ID']) ? $headers['Message-ID'] : '',
'in_reply_to' => isset($headers['In-Reply-To']) ? $headers['In-Reply-To'] : '',
'references' => isset($headers['References']) ? $headers['References'] : '',
'timestamp' => isset($headers['Date']) ? $headers['Date'] : date('c')
];
}
/**
* Parse multipart body into individual parts
*/
function parseMultipartBody($body, $boundary) {
$parts = [];
// Split by boundary
$boundaryPattern = '--' . preg_quote($boundary, '/');
$sections = preg_split('/' . $boundaryPattern . '(--)?\r?\n/', $body);
debugLog(" Sections: " . count($sections));
foreach ($sections as $section) {
if (trim($section) === '') continue;
// Split section into headers and body
$sLines = explode("\n", $section);
$sHeaders = [];
$bodyStart = 0;
$curHeader = '';
for ($i = 0; $i < count($sLines); $i++) {
$line = rtrim($sLines[$i], "\r\n");
if (trim($line) === '') {
$bodyStart = $i + 1;
break;
}
if (preg_match('/^[\s\t]/', $line) && $curHeader) {
$sHeaders[$curHeader] .= ' ' . trim($line);
} elseif (preg_match('/^([^:]+):\s*(.*)$/', $line, $m)) {
$curHeader = $m[1];
$sHeaders[$curHeader] = $m[2];
}
}
$sBody = implode("\n", array_slice($sLines, $bodyStart));
// Check for nested multipart
if (isset($sHeaders['Content-Type']) && preg_match('/boundary=["\']?([^"\'\s;]+)["\']?/i', $sHeaders['Content-Type'], $m)) {
$nestedBoundary = $m[1];
debugLog(" 🔀 Nested: $nestedBoundary");
$nested = parseMultipartBody($sBody, $nestedBoundary);
$parts = array_merge($parts, $nested);
} else {
$parts[] = [
'headers' => $sHeaders,
'body' => $sBody
];
}
}
return $parts;
}
/**
* Decode content based on transfer encoding
*/
function decodeContent($content, $encoding) {
$content = trim($content);
switch ($encoding) {
case 'base64':
$decoded = base64_decode($content);
debugLog(" Base64: " . strlen($content) . " -> " . strlen($decoded));
return $decoded;
case 'quoted-printable':
return quoted_printable_decode($content);
default:
return $content;
}
}
/**
* Decode MIME encoded headers (e.g., =?UTF-8?B?...?=)
*/
function decodeHeader($header) {
if (function_exists('iconv_mime_decode')) {
return iconv_mime_decode($header, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, 'UTF-8');
}
return $header;
}
?>