在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);
權限控制:實際部署時需要添加認證機制防止非法訪問。
多線程/並發:使用pcntl_fork()或使用swoole 等擴展提升性能。
文件校驗:通過MD5 校驗碼確保文件完整性。
加密傳輸:通過TLS/SSL 實現安全通信。
本文展示瞭如何通過PHP 原生的socket 編程手段,結合socket_accept()實現一個簡易的類FTP 文件傳輸服務。這種方式適合用於學習socket 通信的基本原理,也可作為輕量級傳輸服務的雛形。對於更大規模的項目,建議使用更成熟的解決方案,如FTP/SFTP 服務器或WebDAV 服務。