일부공개 ) 개발중인 그누보드용 웹메일 php 라이브러리
페이지 정보
-
조회 189
- 목록
본문
<?php
function decode_mime_header($header) {
$decoded = iconv_mime_decode($header, 0, 'UTF-8');
return $decoded ?: $header;
}
function html_to_text($html) {
$html = html_entity_decode($html, ENT_QUOTES | ENT_HTML5, 'UTF-8');
$html = preg_replace('/<style[^>]*>.*?<\/style>/is', '', $html); // 스타일 제거
$html = preg_replace('/<br\s*\/?>/i', "\n", $html); // 줄바꿈 처리
$html = preg_replace('/<\/p>/i', "\n", $html); // 문단 줄바꿈
$text = strip_tags($html); // 태그 제거
$text = preg_replace("/\n{2,}/", "\n", $text); // 연속 줄바꿈 정리
return trim($text);
}
function decode_mime_header_full($header) {
$decoded = '';
$parts = preg_split('/(=\?.+\?[BQbq]\?.+\?=)/', $header, -1, PREG_SPLIT_DELIM_CAPTURE);
foreach ($parts as $part) {
if (preg_match('/=\?(.+)\?([BQbq])\?(.+)\?=/', $part, $matches)) {
$charset = strtoupper($matches[1]);
$encoding = strtoupper($matches[2]);
$text = $matches[3];
if ($encoding === 'B') {
$decoded_text = base64_decode($text);
} elseif ($encoding === 'Q') {
$decoded_text = quoted_printable_decode(str_replace('_', ' ', $text));
} else {
$decoded_text = $text;
}
$decoded .= iconv($charset, 'UTF-8//IGNORE', $decoded_text);
} else {
$decoded .= $part;
}
}
return $decoded;
}
function decode_html_body($body, $content_type = 'text/html', $charset = 'UTF-8', $encoding = '') {
// 인코딩 방식 확인
if (stripos($encoding, 'base64') !== false) {
$body = base64_decode(trim($body));
} else {
$body = quoted_printable_decode($body);
}
// 문자셋 변환
if ($charset !== 'UTF-8') {
$converted = @iconv($charset, 'UTF-8//IGNORE', $body);
if ($converted !== false) {
$body = $converted;
}
}
// HTML 처리
if ($content_type === 'text/html') {
$body = html_entity_decode($body, ENT_QUOTES | ENT_HTML5, 'UTF-8');
// 불필요한 태그 제거
$body = preg_replace([
'/<style[^>]*>.*?<\/style>/is',
'/<script[^>]*>.*?<\/script>/is',
'/<meta[^>]*>/i',
'/<title[^>]*>.*?<\/title>/is',
'/<html[^>]*>/i',
'/<\/html>/i',
'/<body[^>]*>/i',
'/<\/body>/i'
], '', $body);
}
return trim($body);
}
function parse_mbox_file($user_id) {
$path = MAIL_BOX_PATH . escapeshellcmd($user_id);
if (!file_exists($path)) return [];
$lines = @file($path);
if (!$lines) return [];
$mails = [];
$current = '';
foreach ($lines as $line) {
if (preg_match('/^From\s.+@.+\s.+\d{4}$/', $line) && !empty($current)) {
$mails[] = parse_single_mail($current);
$current = '';
}
$current .= $line;
}
if (!empty($current)) {
$mails[] = parse_single_mail($current);
}
return $mails;
}
function parse_single_mail($raw_mail) {
$headers = [];
$body = '';
$lines = explode("\n", $raw_mail);
$is_header = true;
$last_key = '';
foreach ($lines as $line) {
if ($is_header) {
if (trim($line) === '') {
$is_header = false;
continue;
}
if (preg_match('/^([A-Za-z\-]+):\s*(.*)$/', $line, $matches)) {
$last_key = strtolower($matches[1]);
$headers[$last_key] = $matches[2];
} elseif (preg_match('/^\s+(.*)$/', $line, $matches) && $last_key) {
$headers[$last_key] .= ' ' . $matches[1];
}
} else {
$body .= $line . "\n";
}
}
// boundary 추출
$boundary = '';
if (isset($headers['content-type']) && preg_match('/boundary="([^"]+)"/i', $headers['content-type'], $matches)) {
$boundary = $matches[1];
}
// 파트 분리
$parts = $boundary ? explode('--' . $boundary, $body) : [$body];
$selected_part = '';
$content_type = '';
$charset = 'UTF-8';
$encoding = '';
foreach ($parts as $part) {
// 첨부파일 제외
if (stripos($part, 'Content-Disposition: attachment') !== false ||
stripos($part, 'application/octet-stream') !== false) {
continue;
}
// 본문 파트 선택
if (stripos($part, 'Content-Type: text/html') !== false || stripos($part, 'Content-Type: text/plain') !== false) {
if (preg_match('/Content-Type:\s*([^;\s]+)(?:;\s*charset=([^\s;]+))?/i', $part, $ct_matches)) {
$content_type = strtolower(trim($ct_matches[1]));
if (!empty($ct_matches[2])) {
$charset = strtoupper(trim($ct_matches[2]));
}
}
if (preg_match('/Content-Transfer-Encoding:\s*([^\s]+)/i', $part, $enc_matches)) {
$encoding = strtolower(trim($enc_matches[1]));
}
$selected_part = preg_replace('/^.*?\r?\n\r?\n/s', '', $part); // 헤더 제거
break;
}
}
// fallback: 본문이 없을 경우 전체 body 사용
if (empty($selected_part)) {
$selected_part = $body;
$content_type = 'text/plain';
}
$clean_body = decode_html_body($selected_part, $content_type, $charset, $encoding);
// HTML 템플릿 구성
$html = '<div class="mail-box" style="font-family: Arial, sans-serif; background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1);">';
$html .= '<h2 style="margin-top:0;">' . htmlspecialchars(decode_mime_header_full($headers['subject'] ?? '(제목 없음)')) . '</h2>';
$html .= '<p><strong>보낸 사람:</strong> ' . htmlspecialchars(decode_mime_header_full($headers['from'] ?? '')) . '</p>';
$html .= '<p><strong>받는 사람:</strong> ' . htmlspecialchars(decode_mime_header_full($headers['to'] ?? '')) . '</p>';
$html .= '<p><strong>날짜:</strong> ' . htmlspecialchars($headers['date'] ?? '(날짜 없음)') . '</p>';
$html .= '<div>' . $clean_body . '</div>';
$html .= '</div>';
return [
'mb_mail_id' => md5($raw_mail),
'mb_mail_subject' => decode_mime_header_full($headers['subject'] ?? '(제목 없음)'),
'mb_mail_from_email' => decode_mime_header_full($headers['from'] ?? ''),
'mb_mail_to_email' => decode_mime_header_full($headers['to'] ?? ''),
'mb_mail_date' => $headers['date'] ?? '(날짜 없음)',
'mb_mail_body' => $html,
'mb_mail_attachments' => '[]',
'mb_mail_folder' => 'inbox',
];
}
?>
파싱기반 웹메일인데
노가다의 결과물..ㅠㅠ