ftp_systype() 函数用于获取远程 FTP 服务器的系统类型。
该函数通过发送 FTP 的 SYST 命令来获取服务器操作系统的类型信息,这对于调整文件传输行为(如行结束符处理)非常有用。
ftp_systype ( resource $ftp_stream ) : string|false
| 参数 | 类型 | 描述 |
|---|---|---|
$ftp_stream |
resource | 必需的。FTP 连接的标识符,由 ftp_connect() 或 ftp_ssl_connect() 返回。 |
| 返回值 | 描述 |
|---|---|
| string | 成功时返回一个字符串,表示远程服务器的系统类型。 |
false |
失败时返回 false。失败原因可能包括:
|
不同的 FTP 服务器可能返回不同的系统类型字符串。以下是一些常见的返回值:
| 返回值 | 描述 |
|---|---|
UNIX 或 UNIX Type: L8 |
Unix/Linux 系统。这是最常见的返回值之一。 |
Windows_NT 或 WIN32 或 Windows |
Windows 系统。 |
MACOS 或 MACOS Peter's Server |
MacOS 系统。 |
NetWare |
Novell NetWare 系统。 |
VMS |
VMS 操作系统。 |
OS/2 |
IBM OS/2 系统。 |
MVS |
IBM 主机系统。 |
空字符串 |
某些服务器可能返回空字符串。 |
| 自定义字符串 | 一些 FTP 服务器软件允许自定义系统类型字符串。 |
以下示例展示了如何获取 FTP 服务器的系统类型。
<?php
// 连接 FTP 服务器
$ftp_server = "ftp.example.com";
$ftp_user = "username";
$ftp_pass = "password";
$conn = ftp_connect($ftp_server);
if (!$conn) {
die("无法连接到 $ftp_server");
}
// 登录
if (!@ftp_login($conn, $ftp_user, $ftp_pass)) {
die("登录失败");
}
// 获取系统类型
$system_type = ftp_systype($conn);
if ($system_type !== false) {
echo "FTP 服务器系统类型: " . $system_type . "\n";
// 根据系统类型调整行为
switch (strtoupper($system_type)) {
case 'UNIX':
case 'UNIX TYPE: L8':
echo "检测到 Unix/Linux 系统\n";
echo "建议使用二进制模式传输可执行文件\n";
break;
case 'WINDOWS_NT':
case 'WIN32':
case 'WINDOWS':
echo "检测到 Windows 系统\n";
echo "注意行结束符差异(CRLF vs LF)\n";
break;
case 'MACOS':
echo "检测到 MacOS 系统\n";
break;
default:
echo "未知系统类型,使用默认设置\n";
}
} else {
echo "无法获取系统类型。服务器可能不支持 SYST 命令。\n";
}
// 关闭连接
ftp_close($conn);
?>
根据服务器系统类型自动选择合适的传输模式。
<?php
$conn = ftp_connect("ftp.example.com");
ftp_login($conn, "username", "password");
/**
* 根据系统类型确定文件传输模式
* @param resource $conn FTP 连接
* @param string $filename 文件名
* @return int 传输模式常量(FTP_ASCII 或 FTP_BINARY)
*/
function determine_transfer_mode($conn, $filename) {
$system_type = ftp_systype($conn);
if ($system_type === false) {
// 如果无法获取系统类型,则根据文件扩展名判断
return determine_mode_by_extension($filename);
}
$system_type_upper = strtoupper($system_type);
// Windows 系统通常需要 ASCII 模式处理文本文件
if (strpos($system_type_upper, 'WINDOWS') !== false ||
strpos($system_type_upper, 'WIN32') !== false ||
strpos($system_type_upper, 'WIN') !== false) {
// 对于文本文件使用 ASCII 模式
if (is_text_file($filename)) {
return FTP_ASCII;
}
}
// 其他系统通常使用二进制模式
return FTP_BINARY;
}
/**
* 根据文件扩展名判断是否为文本文件
*/
function is_text_file($filename) {
$text_extensions = ['txt', 'html', 'htm', 'php', 'js', 'css', 'xml', 'json', 'csv'];
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
return in_array($extension, $text_extensions);
}
/**
* 根据文件扩展名判断传输模式(备用方法)
*/
function determine_mode_by_extension($filename) {
$binary_extensions = ['exe', 'zip', 'rar', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'mp3', 'mp4'];
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (in_array($extension, $binary_extensions)) {
return FTP_BINARY;
} else {
return FTP_ASCII;
}
}
// 使用示例
$filename = "document.txt";
$transfer_mode = determine_transfer_mode($conn, $filename);
echo "文件: $filename\n";
echo "传输模式: " . ($transfer_mode == FTP_ASCII ? "ASCII" : "BINARY") . "\n";
echo "系统类型: " . ftp_systype($conn) . "\n";
ftp_close($conn);
?>
批量检查多个 FTP 服务器的系统类型。
<?php
/**
* 检查多个 FTP 服务器的系统类型
*/
class FTPChecker {
private $servers = [];
public function addServer($hostname, $username, $password, $port = 21) {
$this->servers[] = [
'hostname' => $hostname,
'username' => $username,
'password' => $password,
'port' => $port
];
}
public function checkAll() {
$results = [];
foreach ($this->servers as $server) {
echo "检查服务器: " . $server['hostname'] . "...\n";
$result = [
'hostname' => $server['hostname'],
'success' => false,
'system_type' => null,
'error' => null
];
// 尝试连接
$conn = @ftp_connect($server['hostname'], $server['port'], 10);
if (!$conn) {
$result['error'] = "连接失败";
$results[] = $result;
continue;
}
// 尝试登录
if (!@ftp_login($conn, $server['username'], $server['password'])) {
$result['error'] = "登录失败";
ftp_close($conn);
$results[] = $result;
continue;
}
// 获取系统类型
$system_type = ftp_systype($conn);
if ($system_type !== false) {
$result['success'] = true;
$result['system_type'] = $system_type;
} else {
$result['error'] = "无法获取系统类型";
}
// 关闭连接
ftp_close($conn);
$results[] = $result;
// 添加延迟,避免请求过快
sleep(1);
}
return $results;
}
public function generateReport($results) {
echo "\n========== FTP 服务器系统类型报告 ==========\n\n";
$success_count = 0;
$type_counts = [];
foreach ($results as $result) {
echo "服务器: " . $result['hostname'] . "\n";
if ($result['success']) {
$success_count++;
$system_type = $result['system_type'];
echo "系统类型: " . $system_type . "\n";
// 统计系统类型
if (!isset($type_counts[$system_type])) {
$type_counts[$system_type] = 0;
}
$type_counts[$system_type]++;
} else {
echo "状态: 失败\n";
echo "错误: " . $result['error'] . "\n";
}
echo str_repeat("-", 40) . "\n";
}
// 统计信息
echo "\n========== 统计信息 ==========\n";
echo "总共检查: " . count($results) . " 个服务器\n";
echo "成功获取: " . $success_count . " 个服务器\n";
echo "失败: " . (count($results) - $success_count) . " 个服务器\n";
if (!empty($type_counts)) {
echo "\n系统类型分布:\n";
foreach ($type_counts as $type => $count) {
echo " " . $type . ": " . $count . " 个\n";
}
}
}
}
// 使用示例
$checker = new FTPChecker();
// 添加要检查的服务器
$checker->addServer('ftp.example1.com', 'user1', 'pass1');
$checker->addServer('ftp.example2.com', 'user2', 'pass2');
$checker->addServer('ftp.example3.com', 'user3', 'pass3');
// 执行检查
$results = $checker->checkAll();
// 生成报告
$checker->generateReport($results);
?>
根据系统类型调整目录列表的解析方式。
<?php
$conn = ftp_connect("ftp.example.com");
ftp_login($conn, "username", "password");
/**
* 根据系统类型解析目录列表
* @param resource $conn FTP 连接
* @param string $directory 要列出的目录
* @return array 解析后的文件列表
*/
function ftp_parsed_list($conn, $directory = ".") {
$system_type = ftp_systype($conn);
$raw_list = ftp_rawlist($conn, $directory);
if ($raw_list === false) {
return [];
}
$parsed_list = [];
foreach ($raw_list as $line) {
if (empty($line)) {
continue;
}
// 根据系统类型选择解析方式
if (strpos(strtoupper($system_type), 'UNIX') !== false) {
// Unix/Linux 格式的列表
$parsed = parse_unix_listing($line);
} elseif (strpos(strtoupper($system_type), 'WINDOWS') !== false ||
strpos(strtoupper($system_type), 'WIN') !== false) {
// Windows 格式的列表
$parsed = parse_windows_listing($line);
} else {
// 默认解析(尝试自动检测)
$parsed = parse_unknown_listing($line);
}
if ($parsed !== null) {
$parsed_list[] = $parsed;
}
}
return $parsed_list;
}
/**
* 解析 Unix/Linux 格式的目录列表
*/
function parse_unix_listing($line) {
// Unix 格式示例: "drwxr-xr-x 2 user group 4096 Jan 12 10:30 directory"
$pattern = '/^([d\-l])([rwx\-]{9})\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\w{3}\s+\d{1,2}\s+[\d:]+)\s+(.+)$/';
if (preg_match($pattern, $line, $matches)) {
return [
'type' => $matches[1] == 'd' ? 'directory' : ($matches[1] == 'l' ? 'link' : 'file'),
'permissions' => $matches[2],
'links' => $matches[3],
'owner' => $matches[4],
'group' => $matches[5],
'size' => $matches[6],
'date' => $matches[7],
'name' => $matches[8]
];
}
return null;
}
/**
* 解析 Windows 格式的目录列表
*/
function parse_windows_listing($line) {
// Windows 格式示例: "01-12-24 10:30AM directory"
// 或: "01-12-24 10:30AM 4096 file.txt"
$pattern = '/^(\d{2}-\d{2}-\d{2})\s+(\d{1,2}:\d{2}(?:AM|PM)?)\s+((?:|\d+))\s+(.+)$/i';
if (preg_match($pattern, $line, $matches)) {
return [
'type' => strtoupper($matches[3]) == '' ? 'directory' : 'file',
'date' => $matches[1],
'time' => $matches[2],
'size' => strtoupper($matches[3]) == '' ? 0 : $matches[3],
'name' => $matches[4]
];
}
return null;
}
/**
* 解析未知格式的目录列表
*/
function parse_unknown_listing($line) {
// 尝试多种格式
$parsed = parse_unix_listing($line);
if ($parsed === null) {
$parsed = parse_windows_listing($line);
}
return $parsed;
}
// 使用示例
$system_type = ftp_systype($conn);
echo "系统类型: " . ($system_type ?: '未知') . "\n";
$files = ftp_parsed_list($conn);
echo "找到 " . count($files) . " 个项目\n";
foreach ($files as $file) {
echo ($file['type'] == 'directory' ? '[DIR] ' : '[FILE] ') . $file['name'];
if (isset($file['size'])) {
echo " (" . $file['size'] . ")";
}
echo "\n";
}
ftp_close($conn);
?>
SYST 命令。较旧或配置受限的服务器可能不会响应。false,并准备好处理不支持的情况。| 问题 | 解决方案 |
|---|---|
| 始终返回 false | 服务器可能不支持 SYST 命令。检查服务器配置或考虑使用其他方法检测系统类型。 |
| 返回空字符串 | 某些服务器返回空字符串表示未知。这是有效响应,不同于 false。 |
| 返回值不一致 | 不同的 FTP 服务器软件可能返回不同的字符串。编写代码时应灵活处理。 |
| 性能问题 | 每次调用都会向服务器发送命令。在单个会话中缓存结果以提高性能。 |
| 安全考虑 | 在生产环境中,考虑是否真的需要系统类型信息,以及是否可能暴露服务器信息。 |