CodeIgniter中FTP被动模式需显式调用$this->ftp->passive(TRUE),配置文件中passive => TRUE仅影响初始化、不替代该调用;上传二进制文件必须指定'binary'模式,且服务器防火墙须放行被动端口范围(如49152–65535)。

CodeIgniter中FTP被动模式必须显式设为TRUE
默认情况下,$this->ftp->connect() 并不会自动启用被动模式——即使文档说“默认设置为被动模式”,实际行为取决于底层PHP ftp_connect() 和 ftp_pasv() 的调用逻辑。不手动触发,很多环境(尤其是NAT后、云主机、Docker容器)会卡在数据连接阶段,表现为上传无响应、超时或 227 Entering Passive Mode 后停滞。
正确做法是:连接成功后立即调用 $this->ftp->passive(TRUE),且该调用必须在 upload()、list_files() 等数据操作之前执行。
-
$this->ftp->connect($config)只建立控制连接,不激活被动模式 - 必须紧接其后调用
$this->ftp->passive(TRUE),否则后续操作仍走主动模式 - 若使用配置文件(
config/ftp.php),passive键值只影响connect()内部初始化,不替代显式调用 - 调试时开启
debug => TRUE,可看到227响应里返回的端口,用于验证是否真进被动流程
防火墙需放行FTP被动模式的高端口范围
被动模式下,服务器不是固定用20端口传数据,而是动态分配一个高位端口(如 49152–65535)供客户端连接。如果只开了20/21端口,227 响应里的端口会被防火墙拦截,导致数据通道无法建立。
Windows Server IIS FTP 或 vsftpd 都需要额外配置并开放这个范围:
- vsftpd:在
/etc/vsftpd/vsftpd.conf中设置pasv_min_port=49152和pasv_max_port=65535,再重启服务 - Windows 防火墙:入站规则需放行 TCP 49152–65535(不是 1024–65535,现代系统已收缩动态端口范围)
- 云厂商安全组(如阿里云、AWS):同样需添加对应端口段的入站规则,仅开21端口不够
- 若用 NAT 网关或负载均衡,还需确认其支持 FTP ALG(Application Layer Gateway)或已禁用,否则会改写
227响应中的IP和端口导致失败
配置文件方式设置FTP参数易忽略的加载时机
把FTP配置写进 config/ftp.php 确实能省掉 initialize() 调用,但有个关键前提:$this->load->library('ftp') 必须在配置文件存在且可读之后执行。常见踩坑点是:
- 在
autoload.php中自动加载ftp类时,若config/ftp.php尚未写入或权限不足,CI 会静默失败,$this->ftp对象存在但连接参数为空 - 配置文件中
$config['hostname']等键名必须全小写,CI 不做大小写归一化,写成HostName会被忽略 - 密码含特殊字符(如
@、/)时,需 URL 编码;否则ftp_connect()解析 URL 会出错 - 使用
$this->ftp->connect($config)手动传参时,会完全覆盖配置文件内容,二者不可混用
二进制模式上传大文件必须设 useBinary
CodeIgniter FTP 类默认以 ASCII 模式传输,对文本文件没问题,但遇到 ZIP、PDF、图片等二进制文件时,会错误转换换行符(\r\n ↔ \n),导致文件损坏。尤其上传 >10MB 文件时,这种损坏常表现为解压失败、图片打不开、校验和不一致。
解决方法不是改全局配置,而是在每次 upload() 调用时明确指定第3个参数:
-
$this->ftp->upload('/local/file.zip', '/remote/file.zip', 'binary')—— 推荐写法 - 不能只写
'bin'或'BINARY',CI 只识别小写的'binary'和'ascii' - 若用
mirror(),它内部固定用'auto'模式,此时需提前调用$this->ftp->set_type('binary') - 注意:
set_type()是实例方法,不是静态配置,每次新连接后都要重设
被动模式 + 高端口放行 + 二进制传输,这三项缺一不可。漏掉任意一个,都可能让上传在开发环境正常、上线后随机失败——尤其是当服务器换了云厂商或启用了新防火墙策略时。

















