Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Klient FTP oparty na Socketach
Forum PHP.pl > Forum > PHP
k0b3
Witam

Chciałbym zaczerpnąć trochę opinii.
Mam stworzyć aplikację do komunikacji i wymiany plików między klientem, a serwerem przez port FTP z interfacem w przeglądarce WWW
Wiem, że php ma w sobie odpowiednie mechanizmy i funkcję w związku z wymianą CLient->FTP, jednak muszę oprzeć się na Socketach.

Metody Połączenia, utrzymywania połączenia (listen), rozłączania i wiele innych obsługują sockety, jednak jak to ma się do listowania katalogów? Czy za pomocą socketów mogę usuwać lub uploadować pliki. Czy taka wymiana jest bezpieczna?
erix
Sockety umożliwiają łączność taką samą, jak w normalnych programach przy użyciu protokołów TCP/UDP. Więc pytanie jest co najmniej dziwne -> to tak samo, jak pytać, czy zwykły klient FTP może pobierać/wysyłać zbiory.

Cytat
Wiem, że php ma w sobie odpowiednie mechanizmy i funkcję w związku z wymianą CLient->FTP, jednak muszę oprzeć się na Socketach.

Ale po co wymyślać koło na nowo...?
k0b3
Cytat
Ale po co wymyślać koło na nowo...?

Niestety muszę, praca zaliczeniowa. Chciałbym od razu wykorzystać tą aplikację do własnych celów przy realizacji stron. Rozumiem, że mechanizmy o których wspomniałem, np: http://pl.php.net/manual/pl/ftp.examples-basic.php wywodzą i opierają się na Socketach?

Ma ktoś coś co by mogło się mi przydać? Od czego zaczyć, aby wymyśleć to wszystko na nowo? I czy ma to sens w aplikacji, która ma być wykorzystana nie tylko w formie zaliczenia>
erix
Cytat
Ma ktoś coś co by mogło się mi przydać? Od czego zaczyć, aby wymyśleć to wszystko na nowo? I czy ma to sens w aplikacji, która ma być wykorzystana nie tylko w formie zaliczenia>

No jak prowadzący się uczepił, to cóż...

Cytat
Rozumiem, że mechanizmy o których wspomniałem, np: http://pl.php.net/manual/pl/ftp.examples-basic.php wywodzą i opierają się na Socketach?

Noż a FTP nie jest połączeniem TCP? :/ Człowieku, to podstawy sieci.

Co się może przydać? Na pewno specyfikacja protokołu, reszta, to otwarcie uchwytu przez którąś z funkcji (prawie na pewno wystarczy fsockopen + funkcje do manipulacji plikami, zakładając że użyjesz trybu pasywnego) i odpowiednie wklepywanie komend protokołu.

FTP jest dość prosty w realizacji, to są tylko komendy tekstowe, wszystko w RFC opisane.
k0b3
Co jest w tym nie tak.

Z ftp łącze się w ten sposób:
Kod
public function connect() {
        $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

        if($this->socket) {
            $result = socket_connect($this->socket, $this->address, $this->port);

            if($result === true) {
                $this->conn = TRUE;
                return '<span id="command">Open '.$this->address.':'.$this->port.'</span><br />'.
                          '<span id="command_recv">'.socket_read($this->socket, 2048).'</span><br />';
            }
        } else {
            $this->conn = FALSE;
            return '<span id="command">Open '.$this->address.':'.$this->port.'</span><br />'.
                     '<span id="command_recv">Error: Socket Fail</span><br />';
        }

    }


Komendy do serwera oraz odpowiedź serwera uzyskuje w ten sposób:
Kod
public function send($command) {
    $command = $command."\r\n";
    socket_write($this->socket, $command, strlen($command));
    return $command;
}


Kod
public function recv() {
    usleep(100);
    $out = socket_read($this->socket, 10000).'<br />';
    return $out;
}


Po odpowiednim wywołaniu metod
Kod
    setcookie('host', $_POST['host']);
    setcookie('pass', $_POST['pass']);
    setcookie('login', $_POST['login']);
    echo $this->model->connect($_POST['host']);
    echo $this->model->send("USER ".$_POST['login']);
    echo $this->model->recv();
    echo $this->model->send("PASS ".$_POST['pass']);
    echo $this->model->recv();
    echo $this->model->send("PWD");
    echo $this->model->recv();
    echo $this->model->send("LIST");
    echo $this->model->recv();


Cytat
Open 195.88.30.227:21
220 Microsoft FTP Service
USER ***
331 Password required for kobe.
PASS ***
230 User kobe logged in.
PWD
257 "/kobe" is current directory.
LIST
150 Opening ASCII mode data connection for /bin/ls.


Gdy dodam jeszcze jedno wywołanie metody zwracającej (recv()) to:
Cytat
425 Can't open data connection

Gdzie tu jest problem? Czy php blokuje jakieś porty?
erix
Wymuszaj tryb pasywny.
k0b3
To samo... :/

Cytat
Open 195.88.30.227:21
220 Microsoft FTP Service
USER ***
331 Password required for kobe.
PASS ***
230 User kobe logged in.
SYST
215 Windows_NT
FEAT
211-FEAT
SIZE MDTM 211 END
PWD
257 "/kobe" is current directory.
TYPE A
200 Type set to A.
PASV
227 Entering Passive Mode (195,88,30,227,40,247)
LIST
425 Can't open data connection.


Jeszcze inaczej.... utworzyłem swój serwer korzystając z proftpd... zwraca mi jeszcze inny błąd
Cytat
Open 127.0.0.1:21
220 TesTest
USER ***
331 Password required for user1
PASS ***
230 Anonymous access granted, restrictions apply
SYST
215 UNIX Type: L8
FEAT
211-Features: MDTM MFMT UTF8 LANG pl-PL.utf8* MFF modify;UNIX.group;UNIX.mode; MLST modify*;perm*;size*;type*;unique*;UNIX.group*;UNIX.mode*;UNIX.owner*; REST STREAM SIZE 211 End
TYPE A
200 Type set to A
PWD
257 "/" is the current directory
PASV
227 Entering Passive Mode (127,0,0,1,204,244).
LIST
421 Idle timeout (10 seconds): closing control connection


---------------------------------------------------------------------------------------------------------------------------

Tak się zastanawiam. Gdy korzystam z klienta ftp spod konsoli wszystko działa. Może tu cos blokuje apache lub samo php?
marcio
http://www.php.net/manual/en/function.socket-strerror.php
http://www.php.net/manual/en/function.socket-last-error.php
Dodaj do kodu i pokaz czy daje jakies bledy snitch.gif

P.S na wszeldki wypadek ustaw tez na full error_reporting()
k0b3
Bardzo dziwna sprawa.
Błędów składniowo językowych nie sypie. Również nie wyrzuca błędów z socketami:

Do każdego wywołania operacji dodałem wartość jaką zwraca socket_last_error()

Cytat
Open 195.88.30.227:21
220 Microsoft FTP Service

USER *** ErrorMessage: Success
331 Password required for kobe. ErrorMessage: Success

PASS *** ErrorMessage: Success
230 User kobe logged in. ErrorMessage: Success

SYST ErrorMessage: Success
215 Windows_NT ErrorMessage: Success

TYPE A ErrorMessage: Success
200 Type set to A. ErrorMessage: Success

PASV ErrorMessage: Success
227 Entering Passive Mode (195,88,30,227,47,3) ErrorMessage: Success

LIST ErrorMessage: Success
425 Can't open data connection. ErrorMessage: Success

No i gdzie tu jest błąd?


Dodaje całą klase która zarządza socketami, może znajdziecie problem

Kod
require_once('./Model.php');

class Ftp {

    public $host=null;
    public $port=null;


    private $socket;
    private $conn=FALSE;
    private $address;
    private $login=FALSE;

    public function __construct($host, $port=21) {
        $this->host = $host;
        $this->port = $port;
        $this->address = gethostbyname($host);
        $this->buffor();
    }

    public function connect() {
        $this->socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

        if($this->socket !== false) {
            $result = socket_connect($this->socket, $this->address, $this->port);

            if($result === true) {
                $this->conn = TRUE;
                return '<span id="command">Open '.$this->address.':'.$this->port.'</span><br />'.
                          '<span id="command_recv">'.socket_read($this->socket, 2048).'</span><br />';
            }
        } else {
            $this->conn = FALSE;
            return '<span id="command">Open '.$this->address.':'.$this->port.'</span><br />'.
                     '<span id="command_recv">Error: '.socket_strerror(socket_last_error($this->socket)).'</span><br />';
        }

    }


    public function isConnected() {
        return $this->conn;
    }

    public function send($command) {
        $command = $command."\r\n";
        socket_write($this->socket, $command, strlen($command));
        //Model::valideCommnad(&$command);
        $errorcode = socket_last_error();
        $errormsg = socket_strerror($errorcode);
        return $command.'ErrorMessage: '.$errormsg.'<br />';
    }

    public function recv($time) {
        usleep(100);
        $out = socket_read($this->socket, 2048);
        $errorcode = socket_last_error();
        $errormsg = socket_strerror($errorcode);

        return $out.'ErrorMessage: '.$errormsg.'<br />';
    }


    public function isLogin() {
        return $this->login;
    }


    public function getHost() {
        return $host;
    }

    public function getPort() {
        return $host;
    }

    public function __destruct() {
        socket_close($this->socket);
    }

}
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.