Created
September 28, 2012 19:47
-
-
Save xeoncross/3801764 to your computer and use it in GitHub Desktop.
POP email server in PHP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
http://stackoverflow.com/a/11973533/99923 | |
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. | |
*/ | |
// 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: [email protected]\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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment