IMAP or POP3 server implemented in PHP

时光总嘲笑我的痴心妄想 提交于 2019-11-30 14:22:37

Well, just to show that it is in fact possible to write a POP3 server in PHP, here it is. The server does no authentication--or pretty much anything else. It just keep sending the same message over and over. But it works. Thunderbird was able to retrieve messages from it. Totally useless, but sort of cool.

My setup is Apache 2 on Windows with PHP 5.2.

<?php

// echo something so fopen() would return
header("Content-type: text/plain");
echo "OK\n";
flush();

// listen for incoming connection
$listen_socket = socket_create_listen(110, 1);
$r = $w = $e = array($listen_socket);
$n = socket_select($r, $w, $e, 120);
$client_socket = ($n == 1) ? socket_accept($listen_socket) : null;
socket_close($listen_socket);

// spawn copy of myself
$internal_url = "http://{$_SERVER['HTTP_HOST']}:{$_SERVER['SERVER_PORT']}{$_SERVER['SCRIPT_NAME']}";
$stream_context_options = array (
    'http' => array (
        'method' => 'GET',
        'timeout' => 1
    )
);
$context = stream_context_create($stream_context_options);
if($f = fopen($internal_url, "rb", 0, $context)) {
    fclose($f);
}

if(!$client_socket) {
    // timed out
    exit;
}

// start handling the session
$read_buffer = "";
$write_buffer = "+OK POP3 server ready\r\n";
$active = true;

$messages = array(
    "From: webmaster@example.com\r\nSubject: This is a test\r\n\r\nHello world!\r\n"
);


$idle_start = time();
while(true) {
    $r = $w = $e = array($client_socket);
    $n = socket_select($r, $w, $e, 60);
    if($n) {
        if($r) {
            // read from the socket
            $read_buffer .= socket_read($client_socket, 128);
            $idle_start = time();
        }
        if($w) {
            if($write_buffer) {
                // write to the socket
                $written = socket_write($client_socket, $write_buffer);
                $write_buffer = substr($write_buffer, $written);
                $idle_start = time();
            } else if($active) {
                $now = time();
                $idle_time = $now - $idle_start;
                if($idle_time > 10) {
                    // exit if nothing happened for 10 seconds
                    break;
                } else if($idle_time > 2) {
                    // start napping when the client is too slow
                    sleep(1);
                }
            } else {
                break;
            }
        }
        if($e) {
            break;
        }
        if($read_buffer) {
            if(preg_match('/(.*?)(?:\s+(.*?))?[\r\n]+/', $read_buffer, $matches)) {
                $read_buffer = substr($read_buffer, strlen($matches[0]));
                $command = $matches[1];
                $argument = $matches[2];
                switch($command) {
                    case 'USER':
                        $username = $argument;
                        $write_buffer .= "+OK $username is welcome here\r\n";
                        break;
                    case 'PASS':
                        $message_count = count($messages);
                        $write_buffer .= "+OK mailbox has $message_count message(s)\r\n";
                        break;
                    case 'QUIT': 
                        $write_buffer .= "+OK POP3 server signing off\r\n";
                        $active = false;
                        break;
                    case 'STAT':
                        $message_count = count($messages);
                        $mailbox_size = 0;
                        foreach($messages as $message) {
                            $mailbox_size += strlen($message);
                        }
                        $write_buffer .= "+OK $message_count $mailbox_size\r\n";
                        break;
                    case 'LIST':
                        $start_index = (int) $argument;
                        $message_count = count($messages) - $start_index;
                        $total_size = 0;
                        for($i = $start_index; $i < count($messages); $i++) {
                            $total_size += strlen($messages[$i]);
                        }
                        $write_buffer .= "+OK $message_count messages ($total_size octets)\r\n";
                        for($i = $start_index; $i < count($messages); $i++) {
                            $message_id = $i + 1;
                            $message_size = strlen($messages[$i]);
                            $write_buffer .= "$message_id $message_size\r\n";
                        }
                        $write_buffer .= ".\r\n";
                        break;
                    case 'RETR':
                        $message_id = (int) $argument;
                        $message = $messages[$message_id - 1];
                        $message_size = strlen($message);
                        $write_buffer .= "+OK $message_size octets\r\n";
                        $write_buffer .= "$message\r\n";
                        $write_buffer .= ".\r\n";
                        break;
                    case 'DELE':
                        $write_buffer .= "+OK\r\n";
                        break;
                    case 'NOOP':
                        $write_buffer .= "+OK\r\n";
                        break;
                    case 'LAST':
                        $message_count = count($messages) - $start_index;
                        $write_buffer .= "+OK $message_count\r\n";
                        break;
                    case 'RSET':
                        $write_buffer .= "+OK\r\n";
                        break;
                    default:
                        $write_buffer .= "-ERR Unknown command '$command'\r\n";
                }
            }
        }
    } else {
        break;
    }
}

?>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!