PHP ftp_exec() 函数

ftp_exec() 函数在FTP服务器上执行一个命令。

注意:这个函数在PHP 7.0.0中已被移除,使用ftp_raw()函数代替。本页面仅作历史参考。
替代方案:在PHP 7.0.0及以上版本,请使用ftp_raw()函数来发送原始FTP命令。

语法(历史版本)

ftp_exec(resource $ftp_stream, string $command): bool

参数说明

参数 描述
$ftp_stream 必需。FTP连接的资源标识符,由ftp_connect()ftp_ssl_connect()函数返回。
$command 必需。要在FTP服务器上执行的命令。

返回值

  • 成功时返回 true
  • 失败时返回 false

替代函数:ftp_raw()

在PHP 7.0.0及以上版本,使用ftp_raw()函数发送原始FTP命令:

ftp_raw(resource $ftp_stream, string $command): array

ftp_raw()返回服务器响应数组。

示例

示例1:使用ftp_raw()执行SITE命令

使用ftp_raw()执行SITE命令(原ftp_exec()的主要用途):

<?php
// FTP服务器信息
$ftp_server = "ftp.example.com";
$ftp_user = "username";
$ftp_pass = "password";

// 建立FTP连接
$conn_id = ftp_connect($ftp_server);
if ($conn_id === false) {
    die("无法连接到FTP服务器");
}

// 登录FTP服务器
if (!ftp_login($conn_id, $ftp_user, $ftp_pass)) {
    ftp_close($conn_id);
    die("FTP登录失败");
}

// 开启被动模式
ftp_pasv($conn_id, true);

// 使用ftp_raw()执行SITE命令
echo "执行SITE命令...\n";

// SITE CHMOD - 更改文件权限
$command = "SITE CHMOD 755 public_html/index.php";
$response = ftp_raw($conn_id, $command);

echo "命令: {$command}\n";
echo "服务器响应:\n";
foreach ($response as $line) {
    echo "  {$line}\n";
}

// 执行其他SITE命令
$commands = [
    "SITE HELP",           // 获取SITE命令帮助
    "SITE STAT",           // 获取服务器状态
    "SITE WHO",            // 查看谁在服务器上
    "SITE IDLE 3600",      // 设置空闲超时时间
    "SITE UTIME 20231231120000 public_html/file.txt", // 设置文件时间戳
];

foreach ($commands as $cmd) {
    echo "\n执行命令: {$cmd}\n";
    $response = ftp_raw($conn_id, $cmd);
    foreach ($response as $line) {
        echo "  响应: {$line}\n";
    }
}

// 关闭连接
ftp_close($conn_id);
?>

示例2:自定义FTP命令执行器

<?php
/**
 * FTP命令执行器类(使用ftp_raw())
 */
class FTPCommandExecutor {
    private $connection;

    public function __construct($host, $username, $password, $port = 21, $timeout = 30) {
        $this->connect($host, $username, $password, $port, $timeout);
    }

    private function connect($host, $username, $password, $port, $timeout) {
        $this->connection = ftp_connect($host, $port, $timeout);
        if (!$this->connection) {
            throw new Exception("无法连接到FTP服务器: {$host}:{$port}");
        }

        if (!ftp_login($this->connection, $username, $password)) {
            ftp_close($this->connection);
            throw new Exception("FTP登录失败");
        }

        ftp_pasv($this->connection, true);
    }

    /**
     * 执行FTP命令
     */
    public function execute($command, $expectedCode = null) {
        if (!is_resource($this->connection)) {
            throw new Exception("FTP连接已关闭或无效");
        }

        $response = ftp_raw($this->connection, $command);

        if ($expectedCode !== null && !empty($response)) {
            $firstLine = $response[0];
            $code = substr($firstLine, 0, 3);

            if ($code != $expectedCode) {
                throw new Exception("命令执行失败: {$firstLine}");
            }
        }

        return $response;
    }

    /**
     * 执行SITE命令
     */
    public function site($subcommand, $params = '') {
        $command = "SITE " . $subcommand;
        if (!empty($params)) {
            $command .= " " . $params;
        }
        return $this->execute($command);
    }

    /**
     * 获取服务器特性
     */
    public function getFeatures() {
        return $this->execute("FEAT", 211);
    }

    /**
     * 获取系统类型
     */
    public function getSystemType() {
        return $this->execute("SYST", 215);
    }

    /**
     * 获取服务器状态
     */
    public function getStatus() {
        return $this->execute("STAT", 211);
    }

    /**
     * 关闭连接
     */
    public function close() {
        if (is_resource($this->connection)) {
            ftp_close($this->connection);
            $this->connection = null;
        }
    }

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

// 使用示例
try {
    $ftp = new FTPCommandExecutor(
        "ftp.example.com",
        "username",
        "password"
    );

    echo "=== FTP服务器信息 ===\n";

    // 获取系统类型
    $response = $ftp->getSystemType();
    echo "系统类型: " . implode(" ", $response) . "\n";

    // 获取服务器特性
    $response = $ftp->getFeatures();
    echo "服务器特性:\n";
    foreach ($response as $line) {
        if (strpos($line, '211-') === 0 || strpos($line, '211 ') === 0) {
            continue; // 跳过状态行
        }
        echo "  {$line}\n";
    }

    // 执行自定义SITE命令
    echo "\n=== 执行SITE命令 ===\n";
    $response = $ftp->site("HELP");
    echo "SITE HELP:\n";
    foreach ($response as $line) {
        echo "  {$line}\n";
    }

    // 设置文件权限
    echo "\n设置文件权限...\n";
    $response = $ftp->site("CHMOD", "755 public_html/index.php");
    foreach ($response as $line) {
        echo "  {$line}\n";
    }

    $ftp->close();

} catch (Exception $e) {
    echo "错误: " . $e->getMessage() . "\n";
}
?>

示例3:高级FTP操作

<?php
/**
 * 高级FTP操作类
 */
class AdvancedFTP {
    private $conn;

    public function connect($host, $user, $pass) {
        $this->conn = ftp_connect($host);
        if (!$this->conn) return false;

        if (!ftp_login($this->conn, $user, $pass)) {
            ftp_close($this->conn);
            return false;
        }

        ftp_pasv($this->conn, true);
        return true;
    }

    /**
     * 设置文件时间戳(使用SITE UTIME)
     */
    public function setFileTimestamp($remote_file, $timestamp) {
        // 将时间戳转换为FTP服务器接受的格式
        $ftp_time = date('YmdHis', $timestamp);
        $command = "SITE UTIME {$ftp_time} {$remote_file}";

        $response = ftp_raw($this->conn, $command);

        // 检查响应代码
        if (!empty($response)) {
            $firstLine = $response[0];
            return strpos($firstLine, '213') === 0; // 213表示成功
        }

        return false;
    }

    /**
     * 更改文件所有者(需要服务器支持)
     */
    public function changeOwner($remote_file, $owner, $group = null) {
        $command = "SITE CHOWN {$owner}";
        if ($group !== null) {
            $command .= ":{$group}";
        }
        $command .= " {$remote_file}";

        $response = ftp_raw($this->conn, $command);

        if (!empty($response)) {
            $firstLine = $response[0];
            return strpos($firstLine, '200') === 0;
        }

        return false;
    }

    /**
     * 获取详细的文件列表(使用LIST命令)
     */
    public function getDetailedList($directory = '.') {
        $command = "LIST {$directory}";
        $response = ftp_raw($this->conn, $command);

        $files = [];
        foreach ($response as $line) {
            // 跳过状态行
            if (strpos($line, '150') === 0 || strpos($line, '226') === 0) {
                continue;
            }

            // 解析LIST输出
            if (preg_match('/^([d\-l])([rwx\-]{9})\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+)\s+(\w+\s+\d+\s+[\d:]+)\s+(.+)$/', $line, $matches)) {
                $files[] = [
                    'type' => $matches[1],
                    'permissions' => $matches[2],
                    'links' => $matches[3],
                    'owner' => $matches[4],
                    'group' => $matches[5],
                    'size' => $matches[6],
                    'date' => $matches[7],
                    'name' => $matches[8]
                ];
            }
        }

        return $files;
    }

    /**
     * 执行原始命令并获取响应
     */
    public function rawCommand($command) {
        return ftp_raw($this->conn, $command);
    }

    public function close() {
        if (is_resource($this->conn)) {
            ftp_close($this->conn);
        }
    }
}

// 使用示例
$ftp = new AdvancedFTP();
if ($ftp->connect("ftp.example.com", "username", "password")) {

    // 设置文件时间戳
    echo "设置文件时间戳...\n";
    $timestamp = strtotime('2023-12-31 12:00:00');
    if ($ftp->setFileTimestamp("public_html/index.php", $timestamp)) {
        echo "时间戳设置成功\n";
    } else {
        echo "时间戳设置失败(可能服务器不支持SITE UTIME)\n";
    }

    // 获取详细文件列表
    echo "\n获取文件列表...\n";
    $files = $ftp->getDetailedList();
    foreach ($files as $file) {
        printf("%-10s %-10s %-10s %s\n",
            $file['permissions'],
            $file['owner'],
            $file['size'],
            $file['name']
        );
    }

    // 执行自定义命令
    echo "\n执行自定义命令...\n";
    $response = $ftp->rawCommand("HELP");
    foreach ($response as $line) {
        echo "{$line}\n";
    }

    $ftp->close();
} else {
    echo "连接失败\n";
}
?>

示例4:错误处理和兼容性检查

<?php
/**
 * FTP命令执行器(带错误处理和兼容性检查)
 */
class SafeFTPExecutor {
    private $conn;
    private $serverType;
    private $supportedCommands = [];

    public function __construct($host, $user, $pass) {
        $this->connect($host, $user, $pass);
        $this->detectCapabilities();
    }

    private function connect($host, $user, $pass) {
        $this->conn = ftp_connect($host);
        if (!$this->conn) {
            throw new Exception("无法连接到FTP服务器");
        }

        if (!ftp_login($this->conn, $user, $pass)) {
            ftp_close($this->conn);
            throw new Exception("FTP登录失败");
        }

        ftp_pasv($this->conn, true);
    }

    /**
     * 检测服务器支持的命令
     */
    private function detectCapabilities() {
        try {
            // 获取系统类型
            $response = ftp_raw($this->conn, "SYST");
            if (!empty($response) && strpos($response[0], '215') === 0) {
                $this->serverType = $response[0];
            }

            // 获取支持的FEATURES
            $response = ftp_raw($this->conn, "FEAT");
            foreach ($response as $line) {
                if (preg_match('/^\s+([A-Z-]+)/', $line, $matches)) {
                    $this->supportedCommands[] = $matches[1];
                }
            }

        } catch (Exception $e) {
            // 忽略检测错误
        }
    }

    /**
     * 安全执行命令
     */
    public function safeExecute($command, $params = '') {
        $fullCommand = $command;
        if (!empty($params)) {
            $fullCommand .= ' ' . $params;
        }

        echo "执行命令: {$fullCommand}\n";

        try {
            $response = ftp_raw($this->conn, $fullCommand);

            // 检查响应代码
            if (!empty($response)) {
                $firstLine = $response[0];
                $code = substr($firstLine, 0, 3);

                switch ($code) {
                    case '200':
                    case '213':
                    case '215':
                    case '220':
                        echo "命令成功\n";
                        break;
                    case '500':
                    case '502':
                    case '504':
                        echo "命令不支持或语法错误\n";
                        break;
                    case '550':
                        echo "操作不允许或文件不存在\n";
                        break;
                    default:
                        echo "未知响应: {$firstLine}\n";
                }

                // 输出详细响应
                foreach ($response as $line) {
                    echo "  {$line}\n";
                }
            }

            return $response;

        } catch (Exception $e) {
            echo "命令执行失败: " . $e->getMessage() . "\n";
            return false;
        }
    }

    /**
     * 检查是否支持某个命令
     */
    public function supports($command) {
        return in_array($command, $this->supportedCommands);
    }

    /**
     * 获取服务器信息
     */
    public function getServerInfo() {
        return [
            'type' => $this->serverType,
            'supported_commands' => $this->supportedCommands
        ];
    }

    public function close() {
        if (is_resource($this->conn)) {
            ftp_close($this->conn);
        }
    }
}

// 使用示例
try {
    $ftp = new SafeFTPExecutor("ftp.example.com", "username", "password");

    $info = $ftp->getServerInfo();
    echo "服务器类型: {$info['type']}\n";
    echo "支持的命令: " . implode(', ', $info['supported_commands']) . "\n";

    echo "\n=== 测试命令 ===\n";

    // 测试各种命令
    $commands = [
        ['SITE', 'HELP'],
        ['SITE', 'CHMOD 755 test.php'],
        ['STAT', ''],
        ['HELP', ''],
        ['NOOP', ''], // 空操作命令,用于保持连接
    ];

    foreach ($commands as $cmd) {
        $ftp->safeExecute($cmd[0], $cmd[1]);
        echo str_repeat("-", 50) . "\n";
    }

    $ftp->close();

} catch (Exception $e) {
    echo "错误: " . $e->getMessage() . "\n";
}
?>

示例5:文件上传后执行远程处理

<?php
/**
 * 文件上传处理器
 */
class FTPUploadProcessor {
    private $ftp;

    public function __construct($host, $user, $pass) {
        $this->ftp = ftp_connect($host);
        if (!$this->ftp) {
            throw new Exception("FTP连接失败");
        }

        if (!ftp_login($this->ftp, $user, $pass)) {
            ftp_close($this->ftp);
            throw new Exception("FTP登录失败");
        }

        ftp_pasv($this->ftp, true);
    }

    /**
     * 上传文件并执行处理命令
     */
    public function uploadAndProcess($local_file, $remote_file, $process_command = null) {
        echo "上传文件: {$local_file} -> {$remote_file}\n";

        // 上传文件
        if (!ftp_put($this->ftp, $remote_file, $local_file, FTP_BINARY)) {
            throw new Exception("文件上传失败");
        }

        echo "文件上传成功\n";

        // 如果指定了处理命令,则执行
        if ($process_command !== null) {
            echo "执行处理命令: {$process_command}\n";

            $response = ftp_raw($this->ftp, $process_command);

            echo "命令响应:\n";
            foreach ($response as $line) {
                echo "  {$line}\n";
            }

            // 检查命令是否成功
            if (!empty($response)) {
                $firstLine = $response[0];
                if (strpos($firstLine, '2') !== 0) { // 2xx表示成功
                    throw new Exception("处理命令执行失败: {$firstLine}");
                }
            }
        }

        return true;
    }

    /**
     * 上传图片并生成缩略图
     */
    public function uploadImageWithThumbnail($local_image, $remote_dir) {
        $filename = basename($local_image);
        $remote_image = $remote_dir . '/' . $filename;

        // 上传原始图片
        $this->uploadAndProcess($local_image, $remote_image);

        // 执行图像处理命令(假设服务器上有图像处理脚本)
        $thumb_command = "SITE PROCESS {$remote_image} thumb 150x150";
        $this->executeCommand($thumb_command);

        echo "缩略图生成命令已发送\n";
    }

    /**
     * 上传日志文件并触发分析
     */
    public function uploadLogAndAnalyze($local_log, $remote_dir) {
        $filename = basename($local_log);
        $remote_log = $remote_dir . '/' . $filename;

        // 上传日志文件
        $this->uploadAndProcess($local_log, $remote_log);

        // 触发日志分析
        $analyze_command = "SITE ANALYZE " . $remote_log;
        $this->executeCommand($analyze_command);

        echo "日志分析已触发\n";
    }

    private function executeCommand($command) {
        $response = ftp_raw($this->ftp, $command);

        if (!empty($response)) {
            $firstLine = $response[0];
            return strpos($firstLine, '2') === 0;
        }

        return false;
    }

    public function close() {
        if (is_resource($this->ftp)) {
            ftp_close($this->ftp);
        }
    }
}

// 使用示例
try {
    $processor = new FTPUploadProcessor("ftp.example.com", "username", "password");

    // 上传普通文件
    $processor->uploadAndProcess(
        "/local/path/file.txt",
        "public_html/uploads/file.txt"
    );

    // 上传并处理文件
    $processor->uploadAndProcess(
        "/local/path/data.csv",
        "public_html/data/data.csv",
        "SITE IMPORT public_html/data/data.csv"
    );

    $processor->close();

} catch (Exception $e) {
    echo "错误: " . $e->getMessage() . "\n";
}
?>

兼容性说明

版本兼容性:

PHP版本 ftp_exec()状态 替代方案
PHP 5.x 可用 可以直接使用
PHP 7.0.0 已移除 使用ftp_raw()
PHP 7.1+ 不可用 使用ftp_raw()
PHP 8.x 不可用 使用ftp_raw()

常见的SITE命令

命令 描述 示例
SITE HELP 获取SITE命令帮助 SITE HELP
SITE CHMOD 更改文件权限 SITE CHMOD 755 filename
SITE UTIME 设置文件时间戳 SITE UTIME 20231231120000 filename
SITE STAT 获取服务器状态 SITE STAT
SITE WHO 查看在线用户 SITE WHO
SITE IDLE 设置空闲超时 SITE IDLE 3600
注意事项:
  • 不是所有FTP服务器都支持SITE命令
  • 不同的FTP服务器支持不同的SITE子命令
  • 使用前先用SITE HELP查看服务器支持的命令
  • 生产环境中谨慎执行服务器端命令
  • 考虑使用SSH替代FTP进行复杂的远程操作

相关函数

函数 描述
ftp_raw() 向FTP服务器发送原始命令
ftp_site() 向FTP服务器发送SITE命令
ftp_systype() 获取FTP服务器的系统类型
ssh2_exec() 在SSH连接上执行命令
exec() 执行本地系统命令