在 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 服务。