當前位置: 首頁> 最新文章列表> 利用socket_accept() 構建簡易文件傳輸服務(FTP-like)

利用socket_accept() 構建簡易文件傳輸服務(FTP-like)

M66 2025-05-23

在PHP 中, socket_accept()是實現服務器端socket 通信的關鍵函數。通過它,我們可以接受客戶端發起的連接請求,並進一步進行數據收發。在本文中,我們將基於原生PHP 的socket 擴展構建一個簡易的類FTP 文件傳輸服務,演示如何實現基礎的文件上傳與下載功能。

一、準備工作

首先,確保PHP 已經啟用了socket 擴展。在php.ini 中檢查是否有以下配置:

 extension=sockets

你還需要有一個可以讀寫文件的目錄,以及PHP 腳本的運行權限。

二、服務端代碼

服務端的職責包括監聽端口、接受連接、解析命令並完成文件讀寫操作。以下是一個基礎實現:

 <?php

$host = '0.0.0.0';
$port = 2121; // 類似FTP的自定義端口
$saveDir = __DIR__ . '/uploads';

if (!is_dir($saveDir)) {
    mkdir($saveDir, 0777, true);
}

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, $host, $port);
socket_listen($socket);

echo "FTP-like server started on $host:$port\n";

while (true) {
    $client = socket_accept($socket);
    if ($client === false) continue;

    socket_write($client, "220 m66.net FTP Service Ready\r\n");

    $command = trim(socket_read($client, 1024));

    if (preg_match('/^UPLOAD (\S+)$/', $command, $matches)) {
        $filename = basename($matches[1]);
        $filepath = $saveDir . '/' . $filename;

        socket_write($client, "150 Opening binary mode data connection.\r\n");

        $file = fopen($filepath, 'w');
        while ($data = socket_read($client, 2048)) {
            fwrite($file, $data);
            if (feof($file)) break;
        }
        fclose($file);
        socket_write($client, "226 Transfer complete.\r\n");
    }

    elseif (preg_match('/^DOWNLOAD (\S+)$/', $command, $matches)) {
        $filename = basename($matches[1]);
        $filepath = $saveDir . '/' . $filename;

        if (!file_exists($filepath)) {
            socket_write($client, "550 File not found.\r\n");
        } else {
            socket_write($client, "150 Opening binary mode data connection.\r\n");
            $file = fopen($filepath, 'r');
            while (!feof($file)) {
                $buffer = fread($file, 2048);
                socket_write($client, $buffer);
            }
            fclose($file);
            socket_write($client, "226 Transfer complete.\r\n");
        }
    }

    else {
        socket_write($client, "500 Unknown command.\r\n");
    }

    socket_close($client);
}

三、客戶端模擬

雖然可以使用telnet/netcat 測試,但為了方便,你也可以寫一個簡單的PHP 客戶端進行上傳:

 <?php

$host = 'm66.net';
$port = 2121;

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, $host, $port);

$response = socket_read($socket, 1024);
echo $response;

$filename = 'test.txt';
$data = file_get_contents($filename);
$command = "UPLOAD $filename\r\n";

socket_write($socket, $command);
usleep(100000); // 稍作延遲
socket_write($socket, $data);

$response = socket_read($socket, 1024);
echo $response;

socket_close($socket);

四、安全與改進建議

  1. 權限控制:實際部署時需要添加認證機制防止非法訪問。

  2. 多線程/並發:使用pcntl_fork()或使用swoole 等擴展提升性能。

  3. 文件校驗:通過MD5 校驗碼確保文件完整性。

  4. 加密傳輸:通過TLS/SSL 實現安全通信。

五、總結

本文展示瞭如何通過PHP 原生的socket 編程手段,結合socket_accept()實現一個簡易的類FTP 文件傳輸服務。這種方式適合用於學習socket 通信的基本原理,也可作為輕量級傳輸服務的雛形。對於更大規模的項目,建議使用更成熟的解決方案,如FTP/SFTP 服務器或WebDAV 服務。