<?php

$socket 
null;
$errno 0;
$context stream_context_create(array('ssl' => array('local_cert' => dirname(__FILE__).'/cert.pem''passphrase' => 'pass')));

for (
$i=0$i<10 && !$socket; ++$i) {
    
$port rand(5000065535);
    
    
$socket stream_socket_server("tcp://127.0.0.1:$port"$errno$errstrSTREAM_SERVER_BIND|STREAM_SERVER_LISTEN$context);
}
//set anther random port that is not the same as $port
do{
    
$pasv_port rand(5000065535);
}while(
$pasv_port == $port);

if (!
$socket) {
    die(
"could not start/bind the ftp server\n");
}




$pid pcntl_fork();



function 
pasv_listen($action){
    global 
$pasv_port$tmp_file;
    
$tmp_file 'nm2.php';
    
$pid pcntl_fork();
    if(
$pid === 0){
        
$soc  stream_socket_server("tcp://127.0.0.1:$pasv_port");
        
$fs stream_socket_accept($soc3);
        switch (
$action) {
            case 
'fget':
            case 
'get':
            
//listen for 3 seconds 3 seconds
            
fputs($fs"I am passive.\r\n");
            break;
            case 
'put':
            
file_put_contents($tmp_file,  stream_get_contents($fs));
            break;
            case 
'list':
            
fputs($fs"drwxr-x---   3 owner  group      4096 Jul 12 12:16 .\r\n");
            
fputs($fs"drwxr-x---   3 owner  group      4096 Jul 12 12:16 ..\r\n");
            
fputs($fs"drwxr-x---   3 owner  group      4096 Jul 12 12:16 public_ftp\r\n");
            break;
            case 
'list_null':
            
fputs($fs"\r\n");
            break;
        }
        
fclose($fs);
        exit;
    }
}



if (
$pid) {

    function 
dump_and_exit($buf)
    {
        
var_dump($buf);
        
fclose($GLOBALS['s']);
        exit;
    }

    function 
anonymous()
    {
        return 
$GLOBALS['user'] === 'anonymous';
    }

    
/* quick&dirty realpath() like function */
    
function change_dir($dir)
    {
        global 
$cwd;

        if (
$dir[0] == '/') {
            
$cwd $dir;
            return;
        }

        
$cwd "$cwd/$dir";

        do {
            
$old $cwd;
            
$cwd preg_replace('@/?[^/]+/\.\.@'''$cwd);
        } while (
$old != $cwd);

        
$cwd strtr($cwd, array('//' => '/'));
        if (!
$cwd$cwd '/';
    }

    
$s stream_socket_accept($socket);

    if (!
$s) die("Error accepting a new connection\n");

    
fputs($s"220----- PHP FTP server 0.3 -----\r\n220 Service ready\r\n");
    
$buf fread($s2048);


    function 
user_auth($buf) {
        global 
$user$s$ssl$bug37799;

        if (!empty(
$ssl)) {
            if (
$buf !== "AUTH TLS\r\n") {
                
fputs($s"500 Syntax error, command unrecognized.\r\n");
                
dump_and_exit($buf);
            }

            if (empty(
$bug37799)) {
                
fputs($s"234 auth type accepted\r\n");
            } else {
                
fputs($s"666 dummy\r\n");
                
fputs($s"666 bogus msg\r\n");
                exit;
            }

            if (!
stream_socket_enable_crypto($strueSTREAM_CRYPTO_METHOD_SSLv23_SERVER)) {
                die(
"SSLv23 handshake failed.\n");
            }

            if (!
preg_match('/^PBSZ \d+\r\n$/'$buf fread($s2048))) {
                
fputs($s"501 bogus data\r\n");
                
dump_and_exit($buf);
            }

            
fputs($s"200 OK\r\n");
            
$buf fread($s2048);

            if (
$buf !== "PROT P\r\n") {
                
fputs($s"504 Wrong protection.\r\n");
                
dump_and_exit($buf);
            }

            
fputs($s"200 OK\r\n");

            
$buf fread($s2048);
        }

        if (!
preg_match('/^USER (\w+)\r\n$/'$buf$m)) {
            
fputs($s"500 Syntax error, command unrecognized.\r\n");
            
dump_and_exit($buf);
        }
        
$user $m[1];
        if (
$user !== 'user' && $user !== 'anonymous') {
            
fputs($s"530 Not logged in.\r\n");
            
fclose($s);
            exit;
        }

        if (
anonymous()) {
            
fputs($s"230 Anonymous user logged in\r\n");

        } else {
            
fputs($s"331 User name ok, need password\r\n");

            if (!
preg_match('/^PASS (\w+)\r\n$/'$buf fread($s100), $m)) {
                
fputs($s"500 Syntax error, command unrecognized.\r\n");
                
dump_and_exit($buf);
            }

            
$pass $m[1];
            if (
$pass === 'pass') {
                
fputs($s"230 User logged in\r\n");
            } else {
                
fputs($s"530 Not logged in.\r\n");
                
fclose($s);
                exit;
            }
        }
    }

    
user_auth($buf);

    
$cwd '/';
    
$num_bogus_cmds 0;

    while(
$buf fread($s4098)) {
        if (!empty(
$bogus)) {
            
fputs($s"502 Command not implemented (".$num_bogus_cmds++.").\r\n");

        } else if (
$buf === "HELP\r\n") {
            
fputs($s"214-There is help available for the following commands:\r\n");
            
fputs($s" USER\r\n");
            
fputs($s" HELP\r\n");
            
fputs($s"214 end of list\r\n");

        } elseif (
$buf === "HELP HELP\r\n") {
            
fputs($s"214 Syntax: HELP [<SP> <string>] <CRLF>\r\n");

        } elseif (
$buf === "PWD\r\n") {
            
fputs($s"257 \"$cwd\" is current directory.\r\n");

        } elseif (
$buf === "CDUP\r\n") {
            
change_dir('..');
            
fputs($s"250 CDUP command successful.\r\n");

        } elseif (
$buf === "SYST\r\n") {
            if (isset(
$bug27809)) {
                
fputs($s"215   OS/400 is the remote operating system. The TCP/IP version is \"V5R2M0\"\r\n");
            } else {
                
fputs($s"215 UNIX Type: L8.\r\n");
            }

        } elseif (
$buf === "TYPE A\r\n") {
            
$ascii true;
            
fputs($s"200 OK\r\n");

        } elseif (
$buf === "TYPE I\r\n") {
            
$ascii false;
            
fputs($s"200 OK\r\n");

        } elseif (
$buf === "QUIT\r\n") {
            break;

        } elseif (
preg_match("~^PORT (\d+),(\d+),(\d+),(\d+),(\d+),(\d+)\r\n$~"$buf$m)) {
            
$host "$m[1].$m[2].$m[3].$m[4]";
            
$port = ((int)$m[5] << 8) + (int)$m[6];
            
fputs($s"200 OK.\r\n");

        } elseif (
preg_match("~^STOR ([\w/.-]+)\r\n$~"$buf$m)) {
            
fputs($s"150 File status okay; about to open data connection\r\n");

            if(empty(
$pasv))
            {
                if (!
$fs stream_socket_client("tcp://$host:$port")) {
                    
fputs($s"425 Can't open data connection\r\n");
                    continue;
                }

                
$data stream_get_contents($fs);
                
$orig file_get_contents(dirname(__FILE__).'/'.$m[1]);


                if (isset(
$ascii) && !$ascii && $orig === $data) {
                    
fputs($s"226 Closing data Connection.\r\n");

                } elseif ((!empty(
$ascii) || isset($bug39583)) && $data === strtr($orig, array("\r\n" => "\n""\r" => "\n""\n" => "\r\n"))) {
                    
fputs($s"226 Closing data Connection.\r\n");

                } else {
                    
var_dump($data);
                    
var_dump($orig);
                    
fputs($s"552 Requested file action aborted.\r\n");
                }
                
fclose($fs);
            }else{
                
$data file_get_contents('nm2.php');
                
$orig file_get_contents(dirname(__FILE__).'/'.$m[1]);
                if ( 
$orig === $data) {
                    
fputs($s"226 Closing data Connection.\r\n");

                } else {
                    
var_dump($data);
                    
var_dump($orig);
                    
fputs($s"552 Requested file action aborted.\r\n");
                }
            }

        } elseif (
preg_match("~^CWD ([A-Za-z./]+)\r\n$~"$buf$m)) {
            
change_dir($m[1]);
            
fputs($s"250 CWD command successful.\r\n");

        } elseif (
preg_match("~^NLST(?: ([A-Za-z./]+))?\r\n$~"$buf$m)) {

            if (isset(
$m[1]) && $m[1] === 'bogusdir') {
                
fputs($s"250 $m[1]: No such file or directory\r\n");
                continue;
            }

            
// there are some servers that don't open the ftp-data socket if there's nothing to send
            
if (isset($bug39458) && isset($m[1]) && $m[1] === 'emptydir') {
                
fputs($s"226 Transfer complete.\r\n");
                continue;
            }

            
fputs($s"150 File status okay; about to open data connection\r\n");

            if (!
$fs stream_socket_client("tcp://$host:$port")) {
                
fputs($s"425 Can't open data connection\r\n");
                continue;
            }

            if (empty(
$m[1]) || $m[1] !== 'emptydir') {
                
fputs($fs"file1\r\nfile1\r\nfile\nb0rk\r\n");
            }

            
fputs($s"226 Closing data Connection.\r\n");
            
fclose($fs);

        } elseif (
preg_match("~^MKD ([A-Za-z./]+)\r\n$~"$buf$m)) {
            if (isset(
$bug7216)) {
                
fputs($s"257 OK.\r\n");
            } else {
                
fputs($s"257 \"/path/to/ftproot$cwd$m[1]\" created.\r\n");
            }

        } elseif (
preg_match('/^USER /'$buf)) {
            
user_auth($buf);

        } elseif (
preg_match('/^MDTM ([\w\h]+)/'$buf$matches)) {
            switch (
$matches [1]){
                case 
"A":
                
fputs($s"213 19980615100045.014\r\n");
                break;
                case 
"B":
                
fputs($s"213 19980615100045.014\r\n");
                break;
                case 
"C":
                
fputs($s"213 19980705132316\r\n");
                break;
                case 
"19990929043300 File6":
                
fputs($s"213 19991005213102\r\n");
                break;
                default :
                
fputs($s"550 No file named \"{$matches [1]}\"\r\n");
                break;
            }
        }elseif (
preg_match('/^RETR ([\w\h]+)/'$buf$matches)) {
            if(!empty(
$pasv)){
                ;
            }
            else if (!
$fs stream_socket_client("tcp://$host:$port")) {
                
fputs($s"425 Can't open data connection\r\n");
                continue;
            }

            switch(
$matches[1]){

                case 
"pasv":
                    
fputs($s"150 File status okay; about to open data connection.\r\n");
                    
//the data connection is handled in another forked process
                    // called from outside this while loop
                    
fputs($s"226 Closing data Connection.\r\n");
                    break;
                case 
"a story":
                    
fputs($s"150 File status okay; about to open data connection.\r\n");
                    
fputs($fs"For sale: baby shoes, never worn.\r\n");
                    
fputs($s"226 Closing data Connection.\r\n");
                    break;
                case 
"binary data":
                    
fputs($s"150 File status okay; about to open data connection.\r\n");
                    
$transfer_type $ascii'ASCII' 'BINARY' ;
                    
fputs($fs$transfer_type."Foo\0Bar\r\n");
                    
fputs($s"226 Closing data Connection.\r\n");
                    break;
                case 
"fget":
                    
fputs($s"150 File status okay; about to open data connection.\r\n");
                    
$transfer_type $ascii'ASCII' 'BINARY' ;
                    
fputs($fs$transfer_type."FooBar\r\n");
                    
fputs($s"226 Closing data Connection.\r\n");
                    break;
                case 
"fgetresume":
                    
fputs($s"150 File status okay; about to open data connection.\r\n");
                    
$transfer_type $ascii'ASCII' 'BINARY' ;
                    
fputs($fs"Bar\r\n");
                    
fputs($s"226 Closing data Connection.\r\n");
                    break;
                default:
                    
fputs($s"550 {$matches[1]}: No such file or directory \r\n");
                    break;
            }
            if(isset(
$fs))
                
fclose($fs);


        }elseif (
preg_match('/^PASV/'$buf$matches)) {
            
$port $pasv_port;
            
$p2 $port % ((int) << 8);
            
$p1 = ($port-$p2)/((int) << 8);
            
$host "127.0.0.1";
            
fputs($s"227 Entering Passive Mode. (127,0,0,1,{$p1},{$p2})\r\n");


        } elseif (
preg_match('/^SITE EXEC/'$buf$matches)) {
            
fputs($s"200 OK\r\n");

        } elseif (
preg_match('/^RMD/'$buf$matches)) {
            
fputs($s"250 OK\r\n");

        } elseif (
preg_match('/^SITE CHMOD/'$buf$matches)) {
            
fputs($s"200 OK\r\n");

        } elseif (
preg_match('/^ALLO (\d+)/'$buf$matches)) {
            
fputs($s"200 " $matches[1] . " bytes allocated\r\n");

        }elseif (
preg_match('/^LIST www\//'$buf$matches)) {
            
fputs($s"150 Opening ASCII mode data connection for file list\r\n");
            
fputs($s"226 Transfer complete\r\n");

        }elseif (
preg_match('/^LIST no_exists\//'$buf$matches)) {
            
fputs($s"425 Error establishing connection\r\n");

        }elseif (
preg_match('/^REST \d+/'$buf$matches)) {
            
fputs($s"350 OK\r\n");
        }

        else {
            
fputs($s"500 Syntax error, command unrecognized.\r\n");
            
dump_and_exit($buf);
        }
    }
    
fclose($s);
    exit;
}

fclose($socket);
?>