示例
示例 1:基本用法 - 切换FTP目录
<?php
// 连接到FTP服务器
$ftp_server = "ftp.example.com";
$ftp_user = "username";
$ftp_pass = "password";
$conn_id = ftp_connect($ftp_server);
if (!$conn_id) {
die("无法连接到 $ftp_server");
}
// 登录到FTP服务器
if (@ftp_login($conn_id, $ftp_user, $ftp_pass)) {
echo "已连接到 $ftp_server,用户为 $ftp_user<br>";
} else {
echo "无法以 $ftp_user 身份登录<br>";
ftp_close($conn_id);
exit;
}
// 启用被动模式
ftp_pasv($conn_id, true);
// 获取当前目录
$current_dir = ftp_pwd($conn_id);
echo "当前目录: " . htmlspecialchars($current_dir) . "<br>";
// 切换到 public_html 目录(相对路径)
if (ftp_chdir($conn_id, "public_html")) {
echo "成功切换到 public_html 目录<br>";
$current_dir = ftp_pwd($conn_id);
echo "当前目录: " . htmlspecialchars($current_dir) . "<br>";
} else {
echo "无法切换到 public_html 目录<br>";
}
// 切换到 images 子目录
if (ftp_chdir($conn_id, "images")) {
echo "成功切换到 images 子目录<br>";
$current_dir = ftp_pwd($conn_id);
echo "当前目录: " . htmlspecialchars($current_dir) . "<br>";
}
// 使用绝对路径切换到根目录
if (ftp_chdir($conn_id, "/")) {
echo "成功切换到根目录<br>";
$current_dir = ftp_pwd($conn_id);
echo "当前目录: " . htmlspecialchars($current_dir) . "<br>";
}
// 切换到父目录
if (ftp_chdir($conn_id, "..")) {
echo "成功切换到父目录(由于在根目录,可能失败)<br>";
} else {
echo "无法切换到父目录(可能在根目录)<br>";
}
// 关闭FTP连接
ftp_close($conn_id);
?>
示例 2:封装安全的目录操作类
<?php
/**
* 安全的FTP目录操作类
*/
class SecureFTPDirectory {
private $conn_id;
private $current_path;
private $history = [];
private $max_history = 50;
public function __construct($server, $username, $password) {
$this->conn_id = @ftp_connect($server);
if (!$this->conn_id) {
throw new Exception("无法连接到FTP服务器: $server");
}
if (!@ftp_login($this->conn_id, $username, $password)) {
throw new Exception("FTP登录失败");
}
ftp_pasv($this->conn_id, true);
$this->current_path = $this->getCurrentDirectory();
$this->addToHistory($this->current_path);
}
/**
* 获取当前目录
*/
private function getCurrentDirectory() {
$dir = @ftp_pwd($this->conn_id);
if ($dir === false) {
throw new Exception("无法获取当前目录");
}
return $dir;
}
/**
* 添加到历史记录
*/
private function addToHistory($path) {
$this->history[] = $path;
// 限制历史记录数量
if (count($this->history) > $this->max_history) {
array_shift($this->history);
}
}
/**
* 安全的改变目录
*/
public function changeDirectory($directory) {
// 验证目录参数
if (!is_string($directory) || trim($directory) === '') {
throw new InvalidArgumentException("目录参数不能为空");
}
$original_path = $this->current_path;
try {
// 尝试切换目录
if (!@ftp_chdir($this->conn_id, $directory)) {
throw new Exception("无法切换到目录: $directory");
}
// 验证切换是否成功
$new_path = $this->getCurrentDirectory();
// 检查是否真的改变了目录
if ($new_path === $original_path && $directory !== '.' && $directory !== './') {
// 这可能意味着目录不存在或权限不足
throw new Exception("目录切换失败或目录不存在: $directory");
}
$this->current_path = $new_path;
$this->addToHistory($new_path);
return [
'success' => true,
'from' => $original_path,
'to' => $new_path,
'message' => "成功切换到目录: $new_path"
];
} catch (Exception $e) {
// 恢复原始目录
@ftp_chdir($this->conn_id, $original_path);
$this->current_path = $original_path;
return [
'success' => false,
'error' => $e->getMessage(),
'attempted' => $directory,
'current' => $original_path
];
}
}
/**
* 切换到绝对路径
*/
public function changeToAbsolutePath($absolute_path) {
// 确保路径以/开头
if (strpos($absolute_path, '/') !== 0) {
$absolute_path = '/' . $absolute_path;
}
return $this->changeDirectory($absolute_path);
}
/**
* 切换到父目录
*/
public function goToParent() {
return $this->changeDirectory('..');
}
/**
* 导航到指定路径(支持相对和绝对路径)
*/
public function navigateTo($path) {
// 处理相对路径
if (strpos($path, '/') !== 0) {
// 相对路径:基于当前目录
$path = $this->normalizePath($this->current_path . '/' . $path);
}
return $this->changeToAbsolutePath($path);
}
/**
* 规范化路径
*/
private function normalizePath($path) {
$path = str_replace('\\', '/', $path);
$parts = explode('/', $path);
$result = [];
foreach ($parts as $part) {
if ($part === '' || $part === '.') {
continue;
}
if ($part === '..') {
if (!empty($result)) {
array_pop($result);
}
} else {
$result[] = $part;
}
}
return '/' . implode('/', $result);
}
/**
* 获取当前路径
*/
public function getCurrentPath() {
return $this->current_path;
}
/**
* 检查目录是否存在
*/
public function directoryExists($directory) {
$current = $this->current_path;
try {
$result = $this->changeDirectory($directory);
// 切换回原始目录
$this->changeDirectory($current);
return $result['success'];
} catch (Exception $e) {
return false;
}
}
/**
* 获取目录历史
*/
public function getHistory() {
return $this->history;
}
/**
* 列出目录内容
*/
public function listDirectory($path = '.') {
$result = $this->changeDirectory($path);
if (!$result['success']) {
return $result;
}
$list = @ftp_nlist($this->conn_id, '.');
if ($list === false) {
return [
'success' => false,
'error' => '无法列出目录内容',
'path' => $this->current_path
];
}
// 切换回原始目录
$original_path = $result['from'];
$this->changeDirectory($original_path);
return [
'success' => true,
'path' => $result['to'],
'items' => $list,
'count' => count($list)
];
}
/**
* 创建目录
*/
public function createDirectory($directory_name, $recursive = false) {
if ($recursive) {
return $this->createDirectoryRecursive($directory_name);
}
if (!@ftp_mkdir($this->conn_id, $directory_name)) {
return [
'success' => false,
'error' => "无法创建目录: $directory_name"
];
}
return [
'success' => true,
'message' => "成功创建目录: $directory_name"
];
}
/**
* 递归创建目录
*/
private function createDirectoryRecursive($directory_name) {
$parts = explode('/', trim($directory_name, '/'));
$current_path = $this->current_path;
foreach ($parts as $part) {
if (!@ftp_chdir($this->conn_id, $part)) {
if (!@ftp_mkdir($this->conn_id, $part)) {
// 恢复原始路径
@ftp_chdir($this->conn_id, $current_path);
return [
'success' => false,
'error' => "无法创建目录: $part"
];
}
@ftp_chdir($this->conn_id, $part);
}
}
// 恢复原始路径
@ftp_chdir($this->conn_id, $current_path);
return [
'success' => true,
'message' => "成功创建目录: $directory_name"
];
}
/**
* 关闭连接
*/
public function close() {
if ($this->conn_id) {
ftp_close($this->conn_id);
$this->conn_id = null;
}
}
public function __destruct() {
$this->close();
}
}
// 使用示例
echo "<h4>安全的FTP目录操作示例:</h4>";
try {
// 创建安全FTP目录操作实例
$ftp = new SecureFTPDirectory(
"ftp.example.com",
"username",
"password"
);
echo "初始目录: " . htmlspecialchars($ftp->getCurrentPath()) . "<br><br>";
// 示例1:切换到相对路径
echo "<strong>示例1:切换到相对路径</strong><br>";
$result = $ftp->changeDirectory("public_html");
if ($result['success']) {
echo "✓ " . $result['message'] . "<br>";
echo " 从: " . htmlspecialchars($result['from']) . "<br>";
echo " 到: " . htmlspecialchars($result['to']) . "<br><br>";
} else {
echo "✗ " . $result['error'] . "<br><br>";
}
// 示例2:切换到绝对路径
echo "<strong>示例2:切换到绝对路径</strong><br>";
$result = $ftp->changeToAbsolutePath("/var/www/html");
if ($result['success']) {
echo "✓ " . $result['message'] . "<br><br>";
} else {
echo "✗ " . $result['error'] . "<br><br>";
}
// 示例3:切换到父目录
echo "<strong>示例3:切换到父目录</strong><br>";
$result = $ftp->goToParent();
if ($result['success']) {
echo "✓ " . $result['message'] . "<br><br>";
} else {
echo "✗ " . $result['error'] . "<br><br>";
}
// 示例4:导航到路径(自动处理相对/绝对)
echo "<strong>示例4:导航到复杂路径</strong><br>";
$result = $ftp->navigateTo("uploads/2023/images");
if ($result['success']) {
echo "✓ " . $result['message'] . "<br><br>";
} else {
echo "✗ " . $result['error'] . "<br><br>";
}
// 示例5:检查目录是否存在
echo "<strong>示例5:检查目录是否存在</strong><br>";
$exists = $ftp->directoryExists("uploads");
echo "目录 'uploads' " . ($exists ? "存在" : "不存在") . "<br><br>";
// 示例6:列出目录内容
echo "<strong>示例6:列出目录内容</strong><br>";
$result = $ftp->listDirectory();
if ($result['success']) {
echo "目录: " . htmlspecialchars($result['path']) . "<br>";
echo "包含 " . $result['count'] . " 个项目:<br>";
foreach ($result['items'] as $item) {
echo " - " . htmlspecialchars(basename($item)) . "<br>";
}
} else {
echo "✗ " . $result['error'] . "<br>";
}
// 显示历史记录
echo "<br><strong>目录历史记录:</strong><br>";
$history = $ftp->getHistory();
foreach ($history as $index => $path) {
echo ($index + 1) . ". " . htmlspecialchars($path) . "<br>";
}
// 自动关闭连接
} catch (Exception $e) {
echo "<div class='alert alert-danger'>错误: " . htmlspecialchars($e->getMessage()) . "</div>";
}
?>
示例 3:FTP文件管理器实现
<?php
/**
* FTP文件管理器类
*/
class FTPFileManager {
private $conn_id;
private $current_path;
private $session_id;
public function __construct($server, $username, $password, $session_id = null) {
$this->conn_id = @ftp_connect($server);
if (!$this->conn_id) {
throw new Exception("无法连接到FTP服务器: $server");
}
if (!@ftp_login($this->conn_id, $username, $password)) {
throw new Exception("FTP登录失败");
}
ftp_pasv($this->conn_id, true);
$this->current_path = ftp_pwd($this->conn_id);
$this->session_id = $session_id ?: uniqid('ftp_', true);
// 初始化会话数据
$this->initSession();
}
/**
* 初始化会话数据
*/
private function initSession() {
if (!isset($_SESSION['ftp_manager'][$this->session_id])) {
$_SESSION['ftp_manager'][$this->session_id] = [
'history' => [],
'bookmarks' => [],
'last_operation' => null
];
}
$this->addToHistory($this->current_path);
}
/**
* 添加到历史记录
*/
private function addToHistory($path) {
$_SESSION['ftp_manager'][$this->session_id]['history'][] = [
'path' => $path,
'time' => time()
];
// 限制历史记录数量
if (count($_SESSION['ftp_manager'][$this->session_id]['history']) > 100) {
array_shift($_SESSION['ftp_manager'][$this->session_id]['history']);
}
}
/**
* 改变目录
*/
public function changeDirectory($directory) {
$original_path = $this->current_path;
if (!@ftp_chdir($this->conn_id, $directory)) {
throw new Exception("无法切换到目录: $directory");
}
$this->current_path = ftp_pwd($this->conn_id);
$this->addToHistory($this->current_path);
// 记录操作
$_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
'type' => 'change_directory',
'from' => $original_path,
'to' => $this->current_path,
'time' => time()
];
return $this->current_path;
}
/**
* 获取当前目录信息
*/
public function getCurrentDirectoryInfo() {
$info = [
'path' => $this->current_path,
'items' => [],
'stats' => [
'directories' => 0,
'files' => 0,
'total_size' => 0
]
];
$items = @ftp_rawlist($this->conn_id, '.');
if ($items === false) {
return $info;
}
foreach ($items as $item) {
$parsed = $this->parseRawListItem($item);
if ($parsed) {
$info['items'][] = $parsed;
if ($parsed['type'] === 'dir') {
$info['stats']['directories']++;
} else {
$info['stats']['files']++;
$info['stats']['total_size'] += $parsed['size'];
}
}
}
return $info;
}
/**
* 解析原始列表项
*/
private function parseRawListItem($line) {
// Unix格式解析
if (preg_match('/^([-d])([-rwxs]{9})\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\w{3}\s+\d+\s+[\d:]+)\s+(.+)$/', $line, $matches)) {
return [
'type' => $matches[1] === 'd' ? 'dir' : 'file',
'permissions' => $matches[2],
'links' => (int)$matches[3],
'owner' => $matches[4],
'group' => $matches[5],
'size' => (int)$matches[6],
'date' => $matches[7],
'name' => $matches[8],
'icon' => $matches[1] === 'd' ? 'folder' : 'file'
];
}
return null;
}
/**
* 上传文件
*/
public function uploadFile($local_path, $remote_name = null) {
if (!file_exists($local_path)) {
throw new Exception("本地文件不存在: $local_path");
}
if (!$remote_name) {
$remote_name = basename($local_path);
}
if (!@ftp_put($this->conn_id, $remote_name, $local_path, FTP_BINARY)) {
throw new Exception("文件上传失败: $local_path");
}
// 记录操作
$_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
'type' => 'upload_file',
'file' => $remote_name,
'size' => filesize($local_path),
'time' => time()
];
return true;
}
/**
* 下载文件
*/
public function downloadFile($remote_name, $local_path = null) {
if (!$local_path) {
$local_path = './downloads/' . $remote_name;
}
// 确保下载目录存在
$dir = dirname($local_path);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
if (!@ftp_get($this->conn_id, $local_path, $remote_name, FTP_BINARY)) {
throw new Exception("文件下载失败: $remote_name");
}
// 记录操作
$_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
'type' => 'download_file',
'file' => $remote_name,
'local_path' => $local_path,
'time' => time()
];
return $local_path;
}
/**
* 创建目录
*/
public function createDirectory($name) {
if (!@ftp_mkdir($this->conn_id, $name)) {
throw new Exception("无法创建目录: $name");
}
// 记录操作
$_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
'type' => 'create_directory',
'name' => $name,
'path' => $this->current_path . '/' . $name,
'time' => time()
];
return true;
}
/**
* 删除文件或目录
*/
public function delete($name) {
// 检查是文件还是目录
if (@ftp_chdir($this->conn_id, $name)) {
// 是目录,切换回
ftp_chdir($this->conn_id, '..');
// 递归删除目录
if (!$this->deleteDirectoryRecursive($name)) {
throw new Exception("无法删除目录: $name");
}
} else {
// 是文件
if (!@ftp_delete($this->conn_id, $name)) {
throw new Exception("无法删除文件: $name");
}
}
// 记录操作
$_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
'type' => 'delete',
'name' => $name,
'time' => time()
];
return true;
}
/**
* 递归删除目录
*/
private function deleteDirectoryRecursive($directory) {
$items = @ftp_nlist($this->conn_id, $directory);
if ($items) {
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$full_path = $directory . '/' . basename($item);
if (@ftp_chdir($this->conn_id, $full_path)) {
ftp_chdir($this->conn_id, '..');
$this->deleteDirectoryRecursive($full_path);
} else {
@ftp_delete($this->conn_id, $full_path);
}
}
}
return @ftp_rmdir($this->conn_id, $directory);
}
/**
* 重命名文件或目录
*/
public function rename($old_name, $new_name) {
if (!@ftp_rename($this->conn_id, $old_name, $new_name)) {
throw new Exception("重命名失败: $old_name -> $new_name");
}
// 记录操作
$_SESSION['ftp_manager'][$this->session_id]['last_operation'] = [
'type' => 'rename',
'old_name' => $old_name,
'new_name' => $new_name,
'time' => time()
];
return true;
}
/**
* 添加书签
*/
public function addBookmark($name, $path = null) {
if (!$path) {
$path = $this->current_path;
}
$_SESSION['ftp_manager'][$this->session_id]['bookmarks'][$name] = [
'path' => $path,
'time' => time()
];
return true;
}
/**
* 跳转到书签
*/
public function goToBookmark($name) {
if (!isset($_SESSION['ftp_manager'][$this->session_id]['bookmarks'][$name])) {
throw new Exception("书签不存在: $name");
}
$path = $_SESSION['ftp_manager'][$this->session_id]['bookmarks'][$name]['path'];
return $this->changeDirectory($path);
}
/**
* 获取书签列表
*/
public function getBookmarks() {
return $_SESSION['ftp_manager'][$this->session_id]['bookmarks'];
}
/**
* 获取操作历史
*/
public function getHistory() {
return $_SESSION['ftp_manager'][$this->session_id]['history'];
}
/**
* 获取最后操作
*/
public function getLastOperation() {
return $_SESSION['ftp_manager'][$this->session_id]['last_operation'];
}
/**
* 渲染文件管理器界面
*/
public function renderInterface() {
$info = $this->getCurrentDirectoryInfo();
echo "<div class='ftp-file-manager'>";
echo "<div class='card'>";
// 头部:路径导航
echo "<div class='card-header bg-light'>";
echo "<div class='row align-items-center'>";
echo "<div class='col-md-8'>";
echo "<h5 class='mb-0'><i class='fas fa-folder'></i> " . htmlspecialchars($this->current_path) . "</h5>";
echo "</div>";
echo "<div class='col-md-4 text-end'>";
// 父目录按钮
if ($this->current_path !== '/') {
echo "<button class='btn btn-sm btn-outline-primary' onclick='ftpGoToParent()'>";
echo "<i class='fas fa-level-up-alt'></i> 上级目录";
echo "</button> ";
}
// 根目录按钮
echo "<button class='btn btn-sm btn-outline-secondary' onclick='ftpGoToRoot()'>";
echo "<i class='fas fa-home'></i> 根目录";
echo "</button>";
echo "</div>";
echo "</div>";
echo "</div>";
// 统计信息
echo "<div class='card-body py-2 bg-light'>";
echo "<small class='text-muted'>";
echo "目录: {$info['stats']['directories']} | ";
echo "文件: {$info['stats']['files']} | ";
echo "大小: " . $this->formatSize($info['stats']['total_size']);
echo "</small>";
echo "</div>";
// 文件列表
echo "<div class='card-body p-0'>";
echo "<div class='table-responsive'>";
echo "<table class='table table-hover mb-0'>";
echo "<thead class='table-light'>";
echo "<tr><th>名称</th><th>大小</th><th>修改时间</th><th>权限</th><th>操作</th></tr>";
echo "</thead>";
echo "<tbody>";
// 父目录链接
if ($this->current_path !== '/') {
echo "<tr onclick='ftpChangeDirectory(\"..\")' style='cursor: pointer;'>";
echo "<td><i class='fas fa-level-up-alt text-primary'></i> ..</td>";
echo "<td>-</td><td>-</td><td>-</td><td></td>";
echo "</tr>";
}
// 目录和文件列表
foreach ($info['items'] as $item) {
$icon = $item['type'] === 'dir' ? '<i class="fas fa-folder text-warning"></i>' :
'<i class="fas fa-file text-secondary"></i>';
$size = $item['type'] === 'dir' ? '-' : $this->formatSize($item['size']);
echo "<tr>";
echo "<td>$icon " . htmlspecialchars($item['name']) . "</td>";
echo "<td>$size</td>";
echo "<td>" . htmlspecialchars($item['date']) . "</td>";
echo "<td>" . htmlspecialchars($item['permissions']) . "</td>";
echo "<td>";
if ($item['type'] === 'dir') {
echo "<button class='btn btn-sm btn-outline-primary' onclick='ftpChangeDirectory(\"" . htmlspecialchars($item['name']) . "\")'>进入</button> ";
} else {
echo "<button class='btn btn-sm btn-outline-success' onclick='ftpDownloadFile(\"" . htmlspecialchars($item['name']) . "\")'>下载</button> ";
}
echo "<button class='btn btn-sm btn-outline-danger' onclick='ftpDeleteItem(\"" . htmlspecialchars($item['name']) . "\")'>删除</button>";
echo "</td>";
echo "</tr>";
}
echo "</tbody>";
echo "</table>";
echo "</div>";
echo "</div>";
// 操作面板
echo "<div class='card-footer bg-light'>";
echo "<div class='row'>";
echo "<div class='col-md-6'>";
echo "<div class='input-group input-group-sm'>";
echo "<input type='text' id='ftpNewDir' class='form-control' placeholder='新目录名'>";
echo "<button class='btn btn-outline-success' onclick='ftpCreateDirectory()'>创建目录</button>";
echo "</div>";
echo "</div>";
echo "<div class='col-md-6'>";
echo "<div class='input-group input-group-sm'>";
echo "<input type='file' id='ftpUploadFile' class='form-control'>";
echo "<button class='btn btn-outline-primary' onclick='ftpUploadFile()'>上传文件</button>";
echo "</div>";
echo "</div>";
echo "</div>";
echo "</div>";
echo "</div>";
echo "</div>";
}
/**
* 格式化文件大小
*/
private function formatSize($bytes) {
if ($bytes == 0) return '0 B';
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$i = floor(log($bytes, 1024));
return round($bytes / pow(1024, $i), 2) . ' ' . $units[$i];
}
/**
* 关闭连接
*/
public function close() {
if ($this->conn_id) {
ftp_close($this->conn_id);
$this->conn_id = null;
}
}
public function __destruct() {
$this->close();
}
}
// 使用示例(需要会话支持)
echo "<h4>FTP文件管理器示例:</h4>";
// 启动会话(如果尚未启动)
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
try {
// 创建FTP文件管理器实例
// 注意:在实际应用中,这些参数应该来自表单输入或配置文件
$ftp_manager = new FTPFileManager(
"ftp.example.com",
"username",
"password",
"example_session"
);
// 处理操作(在实际应用中应该通过AJAX或表单提交处理)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 这里应该处理各种操作
// 为了示例清晰,省略具体处理代码
}
// 渲染文件管理器界面
$ftp_manager->renderInterface();
// 显示附加信息
echo "<div class='row mt-3'>";
// 历史记录
echo "<div class='col-md-6'>";
echo "<div class='card'>";
echo "<div class='card-header'>最近访问</div>";
echo "<div class='card-body' style='max-height: 200px; overflow-y: auto;'>";
$history = $ftp_manager->getHistory();
foreach (array_slice($history, -5) as $item) {
echo "<div>" . date('H:i:s', $item['time']) . " - " . htmlspecialchars($item['path']) . "</div>";
}
echo "</div></div></div>";
// 最后操作
echo "<div class='col-md-6'>";
echo "<div class='card'>";
echo "<div class='card-header'>最后操作</div>";
echo "<div class='card-body'>";
$last_op = $ftp_manager->getLastOperation();
if ($last_op) {
echo "类型: " . htmlspecialchars($last_op['type']) . "<br>";
echo "时间: " . date('Y-m-d H:i:s', $last_op['time']) . "<br>";
if (isset($last_op['file'])) {
echo "文件: " . htmlspecialchars($last_op['file']) . "<br>";
}
} else {
echo "暂无操作记录";
}
echo "</div></div></div>";
echo "</div>";
// 添加JavaScript函数(简化版)
echo "<script>
function ftpChangeDirectory(dir) {
alert('在实际应用中,这里会通过AJAX调用changeDirectory方法,切换到: ' + dir);
}
function ftpGoToParent() {
ftpChangeDirectory('..');
}
function ftpGoToRoot() {
ftpChangeDirectory('/');
}
function ftpDownloadFile(file) {
alert('下载文件: ' + file);
}
function ftpDeleteItem(item) {
if (confirm('确定要删除 ' + item + ' 吗?')) {
alert('删除: ' + item);
}
}
function ftpCreateDirectory() {
var dir = document.getElementById('ftpNewDir').value;
if (dir) {
alert('创建目录: ' + dir);
}
}
function ftpUploadFile() {
var file = document.getElementById('ftpUploadFile').files[0];
if (file) {
alert('上传文件: ' + file.name);
}
}
</script>";
} catch (Exception $e) {
echo "<div class='alert alert-danger'>错误: " . htmlspecialchars($e->getMessage()) . "</div>";
}
?>
示例 4:批量目录操作
<?php
/**
* FTP批量目录操作类
*/
class FTPBatchOperations {
private $conn_id;
public function __construct($conn_id) {
$this->conn_id = $conn_id;
}
/**
* 批量创建目录
*/
public function createDirectories($directories) {
$results = [];
$success_count = 0;
$fail_count = 0;
foreach ($directories as $directory) {
$result = $this->createDirectory($directory);
$results[] = $result;
if ($result['success']) {
$success_count++;
} else {
$fail_count++;
}
}
return [
'total' => count($directories),
'success' => $success_count,
'failed' => $fail_count,
'results' => $results
];
}
/**
* 创建单个目录
*/
private function createDirectory($directory) {
$original_dir = ftp_pwd($this->conn_id);
try {
if (@ftp_mkdir($this->conn_id, $directory)) {
return [
'success' => true,
'directory' => $directory,
'message' => '目录创建成功'
];
} else {
return [
'success' => false,
'directory' => $directory,
'error' => '目录创建失败'
];
}
} catch (Exception $e) {
return [
'success' => false,
'directory' => $directory,
'error' => $e->getMessage()
];
} finally {
@ftp_chdir($this->conn_id, $original_dir);
}
}
/**
* 批量切换目录并执行操作
*/
public function executeInDirectories($operations) {
$results = [];
$original_dir = ftp_pwd($this->conn_id);
foreach ($operations as $operation) {
$directory = $operation['directory'];
$callback = $operation['callback'];
// 切换到目录
if (!@ftp_chdir($this->conn_id, $directory)) {
$results[] = [
'directory' => $directory,
'success' => false,
'error' => '无法切换到目录'
];
continue;
}
// 执行回调函数
try {
if (is_callable($callback)) {
$result = call_user_func($callback, $this->conn_id);
$results[] = [
'directory' => $directory,
'success' => true,
'result' => $result
];
} else {
throw new Exception('无效的回调函数');
}
} catch (Exception $e) {
$results[] = [
'directory' => $directory,
'success' => false,
'error' => $e->getMessage()
];
}
}
// 返回原始目录
@ftp_chdir($this->conn_id, $original_dir);
return $results;
}
/**
* 查找文件
*/
public function findFiles($pattern, $start_directory = '.') {
$results = [];
$original_dir = ftp_pwd($this->conn_id);
// 递归查找函数
$findRecursive = function($directory, $pattern, &$results) use (&$findRecursive) {
// 切换到目标目录
if (!@ftp_chdir($this->conn_id, $directory)) {
return;
}
// 获取目录列表
$items = @ftp_nlist($this->conn_id, '.');
if ($items === false) {
return;
}
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
// 检查是否是目录
if (@ftp_chdir($this->conn_id, $item)) {
// 是目录,递归查找
ftp_chdir($this->conn_id, '..');
$findRecursive($directory . '/' . $item, $pattern, $results);
} else {
// 是文件,检查是否匹配模式
if (fnmatch($pattern, basename($item))) {
$results[] = $directory . '/' . $item;
}
}
}
};
// 开始查找
$findRecursive($start_directory, $pattern, $results);
// 返回原始目录
@ftp_chdir($this->conn_id, $original_dir);
return $results;
}
/**
* 同步目录结构
*/
public function syncDirectoryStructure($local_dir, $remote_dir) {
if (!is_dir($local_dir)) {
return [
'success' => false,
'error' => '本地目录不存在'
];
}
$results = [];
$original_remote_dir = ftp_pwd($this->conn_id);
// 递归同步函数
$syncRecursive = function($local_path, $remote_path) use (&$syncRecursive, &$results) {
// 在远程创建目录
if (!@ftp_chdir($this->conn_id, $remote_path)) {
if (!@ftp_mkdir($this->conn_id, $remote_path)) {
$results[] = [
'type' => 'mkdir',
'path' => $remote_path,
'success' => false,
'error' => '无法创建目录'
];
return false;
}
$results[] = [
'type' => 'mkdir',
'path' => $remote_path,
'success' => true
];
}
// 获取本地目录内容
$local_items = scandir($local_path);
foreach ($local_items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$local_item_path = $local_path . '/' . $item;
$remote_item_path = $remote_path . '/' . $item;
if (is_dir($local_item_path)) {
// 递归处理子目录
$syncRecursive($local_item_path, $remote_item_path);
} else {
// 上传文件
if (!@ftp_put($this->conn_id, $remote_item_path, $local_item_path, FTP_BINARY)) {
$results[] = [
'type' => 'upload',
'file' => $item,
'success' => false,
'error' => '上传失败'
];
} else {
$results[] = [
'type' => 'upload',
'file' => $item,
'success' => true
];
}
}
}
return true;
};
// 开始同步
$sync_success = $syncRecursive($local_dir, $remote_dir);
// 返回原始目录
@ftp_chdir($this->conn_id, $original_remote_dir);
return [
'success' => $sync_success,
'results' => $results
];
}
}
// 使用示例
echo "<h4>FTP批量操作示例:</h4>";
// 假设已经建立了FTP连接
$ftp_server = "ftp.example.com";
$ftp_user = "username";
$ftp_pass = "password";
$conn_id = ftp_connect($ftp_server);
if (!$conn_id) {
die("无法连接到FTP服务器");
}
if (!ftp_login($conn_id, $ftp_user, $ftp_pass)) {
die("登录失败");
}
ftp_pasv($conn_id, true);
// 创建批量操作实例
$batch_ops = new FTPBatchOperations($conn_id);
echo "<h5>1. 批量创建目录:</h5>";
$directories = [
'uploads/2023',
'uploads/2023/images',
'uploads/2023/documents',
'backups/daily',
'backups/weekly',
'temp'
];
$create_results = $batch_ops->createDirectories($directories);
echo "批量创建目录结果:<br>";
echo "总数: {$create_results['total']},成功: {$create_results['success']},失败: {$create_results['failed']}<br>";
echo "<table class='table table-sm'>";
echo "<thead><tr><th>目录</th><th>结果</th><th>信息</th></tr></thead>";
echo "<tbody>";
foreach ($create_results['results'] as $result) {
$class = $result['success'] ? 'table-success' : 'table-danger';
echo "<tr class='$class'>";
echo "<td>" . htmlspecialchars($result['directory']) . "</td>";
echo "<td>" . ($result['success'] ? '成功' : '失败') . "</td>";
echo "<td>" . htmlspecialchars($result['message'] ?? $result['error'] ?? '') . "</td>";
echo "</tr>";
}
echo "</tbody></table>";
echo "<h5>2. 查找文件:</h5>";
echo "查找所有 .jpg 文件:<br>";
$jpg_files = $batch_ops->findFiles('*.jpg', '.');
if (empty($jpg_files)) {
echo "未找到 .jpg 文件<br>";
} else {
echo "找到 " . count($jpg_files) . " 个文件:<br>";
foreach ($jpg_files as $file) {
echo htmlspecialchars($file) . "<br>";
}
}
echo "<h5>3. 在不同目录执行操作:</h5>";
$operations = [
[
'directory' => 'uploads/2023',
'callback' => function($conn) {
// 计算文件数量和大小的回调函数
$files = ftp_nlist($conn, '.');
$file_count = 0;
$total_size = 0;
foreach ($files as $file) {
if ($file === '.' || $file === '..') continue;
if (!@ftp_chdir($conn, $file)) {
$size = ftp_size($conn, $file);
if ($size !== -1) {
$file_count++;
$total_size += $size;
}
}
}
return [
'files' => $file_count,
'total_size' => $total_size
];
}
]
];
$execute_results = $batch_ops->executeInDirectories($operations);
echo "<pre>" . print_r($execute_results, true) . "</pre>";
echo "<h5>4. 同步目录结构:</h5>";
echo "(此示例需要真实的本地目录)<br>";
// $sync_results = $batch_ops->syncDirectoryStructure('/local/path', '/remote/path');
// echo "<pre>" . print_r($sync_results, true) . "</pre>";
// 关闭连接
ftp_close($conn_id);
?>
示例 5:高级错误处理和日志记录
<?php
/**
* 带错误处理和日志记录的FTP操作类
*/
class FTPWithLogging {
private $conn_id;
private $logger;
private $error_count = 0;
private $operation_count = 0;
public function __construct($server, $username, $password, $logger = null) {
$this->logger = $logger;
$this->log("正在连接到FTP服务器: $server", 'info');
$this->conn_id = @ftp_connect($server);
if (!$this->conn_id) {
$this->log("无法连接到FTP服务器: $server", 'error');
throw new Exception("无法连接到FTP服务器: $server");
}
$this->log("正在登录FTP服务器,用户: $username", 'info');
if (!@ftp_login($this->conn_id, $username, $password)) {
$this->log("FTP登录失败,用户: $username", 'error');
ftp_close($this->conn_id);
throw new Exception("FTP登录失败");
}
ftp_pasv($this->conn_id, true);
$this->log("FTP连接成功建立", 'success');
}
/**
* 日志记录
*/
private function log($message, $level = 'info') {
$timestamp = date('Y-m-d H:i:s');
$log_entry = "[$timestamp] [$level] $message";
// 如果提供了日志记录器,使用它
if ($this->logger && is_callable($this->logger)) {
call_user_func($this->logger, $log_entry, $level);
}
// 同时输出到页面(仅用于演示)
$css_class = '';
switch ($level) {
case 'error': $css_class = 'text-danger'; break;
case 'warning': $css_class = 'text-warning'; break;
case 'success': $css_class = 'text-success'; break;
case 'info': $css_class = 'text-info'; break;
default: $css_class = 'text-muted';
}
echo "<div class='ftp-log $css_class' style='font-family: monospace; font-size: 12px;'>$log_entry</div>";
}
/**
* 安全的改变目录
*/
public function changeDirectory($directory, $retry_count = 2) {
$this->operation_count++;
$original_dir = ftp_pwd($this->conn_id);
$this->log("尝试切换到目录: $directory (当前: $original_dir)", 'info');
for ($attempt = 1; $attempt <= $retry_count; $attempt++) {
try {
if (!@ftp_chdir($this->conn_id, $directory)) {
$error_msg = "第{$attempt}次尝试切换目录失败: $directory";
// 分析可能的错误原因
$error_analysis = $this->analyzeDirectoryError($directory);
$this->log("$error_msg - $error_analysis", 'warning');
if ($attempt < $retry_count) {
sleep(1); // 等待后重试
continue;
}
$this->error_count++;
$this->log("切换目录最终失败: $directory", 'error');
throw new Exception("无法切换到目录: $directory - $error_analysis");
}
$new_dir = ftp_pwd($this->conn_id);
$this->log("成功切换到目录: $new_dir", 'success');
return $new_dir;
} catch (Exception $e) {
if ($attempt == $retry_count) {
// 最后一次尝试也失败,恢复原始目录
@ftp_chdir($this->conn_id, $original_dir);
throw $e;
}
}
}
return false;
}
/**
* 分析目录错误原因
*/
private function analyzeDirectoryError($directory) {
$original_dir = ftp_pwd($this->conn_id);
$analysis = [];
// 检查是否是绝对路径
if (strpos($directory, '/') !== 0) {
$analysis[] = '相对路径';
} else {
$analysis[] = '绝对路径';
}
// 检查目录是否存在
if ($this->directoryExists($directory)) {
$analysis[] = '目录存在';
} else {
$analysis[] = '目录可能不存在';
}
// 检查路径是否包含特殊字符
if (preg_match('/[<>:"|?*]/', $directory)) {
$analysis[] = '路径包含非法字符';
}
// 检查路径长度(某些FTP服务器有路径长度限制)
if (strlen($directory) > 255) {
$analysis[] = '路径可能过长';
}
return implode('; ', $analysis);
}
/**
* 检查目录是否存在
*/
private function directoryExists($directory) {
$current_dir = ftp_pwd($this->conn_id);
if (@ftp_chdir($this->conn_id, $directory)) {
ftp_chdir($this->conn_id, $current_dir);
return true;
}
return false;
}
/**
* 递归列出目录结构
*/
public function listDirectoryRecursive($directory = '.', $max_depth = 5) {
$this->operation_count++;
$this->log("递归列出目录: $directory (最大深度: $max_depth)", 'info');
$result = $this->listRecursive($directory, 0, $max_depth);
$this->log("目录列表完成,找到 " . count($result) . " 个项目", 'success');
return $result;
}
private function listRecursive($directory, $depth, $max_depth) {
if ($depth > $max_depth) {
return [];
}
$result = [];
$original_dir = ftp_pwd($this->conn_id);
try {
// 切换到目标目录
$this->changeDirectory($directory);
// 获取目录列表
$items = @ftp_nlist($this->conn_id, '.');
if ($items === false) {
throw new Exception("无法列出目录内容");
}
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$full_path = ($directory === '.') ? $item : $directory . '/' . $item;
// 检查是否是目录
if (@ftp_chdir($this->conn_id, $item)) {
// 是目录,递归处理
ftp_chdir($this->conn_id, '..');
$result[] = [
'type' => 'dir',
'path' => $full_path,
'depth' => $depth
];
// 递归处理子目录
$sub_items = $this->listRecursive($full_path, $depth + 1, $max_depth);
$result = array_merge($result, $sub_items);
} else {
// 是文件
$size = @ftp_size($this->conn_id, $item);
$result[] = [
'type' => 'file',
'path' => $full_path,
'size' => ($size !== -1) ? $size : null,
'depth' => $depth
];
}
}
} catch (Exception $e) {
$this->log("列出目录时出错: " . $e->getMessage(), 'error');
} finally {
// 确保返回原始目录
@ftp_chdir($this->conn_id, $original_dir);
}
return $result;
}
/**
* 创建目录树
*/
public function createDirectoryTree($tree) {
$this->operation_count++;
$this->log("开始创建目录树", 'info');
$results = $this->createTreeRecursive($tree, '.');
$success_count = 0;
$fail_count = 0;
foreach ($results as $result) {
if ($result['success']) {
$success_count++;
} else {
$fail_count++;
}
}
$this->log("目录树创建完成: $success_count 成功, $fail_count 失败",
$fail_count > 0 ? 'warning' : 'success');
return $results;
}
private function createTreeRecursive($tree, $base_path) {
$results = [];
$original_dir = ftp_pwd($this->conn_id);
try {
// 确保在基础路径
$this->changeDirectory($base_path);
foreach ($tree as $name => $subtree) {
$full_path = ($base_path === '.') ? $name : $base_path . '/' . $name;
// 创建当前目录
if (!@ftp_chdir($this->conn_id, $name)) {
if (@ftp_mkdir($this->conn_id, $name)) {
$results[] = [
'path' => $full_path,
'success' => true,
'message' => '目录创建成功'
];
$this->log("创建目录: $full_path", 'success');
} else {
$results[] = [
'path' => $full_path,
'success' => false,
'error' => '目录创建失败'
];
$this->log("创建目录失败: $full_path", 'error');
continue;
}
}
// 递归处理子目录
if (is_array($subtree)) {
$sub_results = $this->createTreeRecursive($subtree, $full_path);
$results = array_merge($results, $sub_results);
}
}
} catch (Exception $e) {
$results[] = [
'path' => $base_path,
'success' => false,
'error' => $e->getMessage()
];
} finally {
@ftp_chdir($this->conn_id, $original_dir);
}
return $results;
}
/**
* 获取统计信息
*/
public function getStats() {
return [
'operations' => $this->operation_count,
'errors' => $this->error_count,
'success_rate' => $this->operation_count > 0 ?
(($this->operation_count - $this->error_count) / $this->operation_count * 100) : 100,
'current_dir' => ftp_pwd($this->conn_id),
'server_type' => @ftp_systype($this->conn_id)
];
}
/**
* 关闭连接
*/
public function close() {
if ($this->conn_id) {
$stats = $this->getStats();
$this->log("关闭FTP连接,操作统计: " .
"{$stats['operations']} 次操作, " .
"{$stats['errors']} 次错误, " .
"成功率: " . round($stats['success_rate'], 2) . "%", 'info');
ftp_close($this->conn_id);
$this->conn_id = null;
}
}
public function __destruct() {
$this->close();
}
}
// 使用示例
echo "<h4>带日志记录的FTP操作示例:</h4>";
// 自定义日志记录器
$custom_logger = function($message, $level) {
// 在实际应用中,这里可以写入文件、数据库等
// 这里只是简单输出
$colors = [
'error' => '#dc3545',
'warning' => '#ffc107',
'success' => '#198754',
'info' => '#0dcaf0'
];
$color = $colors[$level] ?? '#6c757d';
// 可以在这里添加更多的日志处理逻辑
};
try {
// 创建带日志记录的FTP操作实例
$ftp = new FTPWithLogging(
"ftp.example.com",
"username",
"password",
$custom_logger
);
echo "<div style='border: 1px solid #ddd; padding: 10px; margin: 10px 0; max-height: 300px; overflow-y: auto; background: #f8f9fa;'>";
echo "<strong>操作日志:</strong><br>";
// 示例1:切换到目录
$ftp->changeDirectory("public_html");
// 示例2:递归列出目录
$list = $ftp->listDirectoryRecursive(".", 2);
echo "</div>";
// 显示目录列表
echo "<h5>目录结构(前20项):</h5>";
echo "<div style='max-height: 200px; overflow-y: auto; border: 1px solid #ddd; padding: 10px;'>";
$count = 0;
foreach (array_slice($list, 0, 20) as $item) {
$indent = str_repeat(' ', $item['depth']);
$icon = $item['type'] === 'dir' ? '📁' : '📄';
$size = isset($item['size']) ? " (" . formatSize($item['size']) . ")" : "";
echo $indent . $icon . " " . htmlspecialchars(basename($item['path'])) . $size . "<br>";
$count++;
}
if (count($list) > 20) {
echo "... 还有 " . (count($list) - 20) . " 项<br>";
}
echo "</div>";
// 示例3:创建目录树
echo "<h5>创建测试目录树:</h5>";
$directory_tree = [
'test_dir' => [
'subdir1' => [],
'subdir2' => [
'deep_dir' => []
],
'subdir3' => []
]
];
$create_results = $ftp->createDirectoryTree($directory_tree);
// 显示统计信息
$stats = $ftp->getStats();
echo "<div class='alert alert-info'>";
echo "<strong>统计信息:</strong><br>";
echo "操作次数: {$stats['operations']}<br>";
echo "错误次数: {$stats['errors']}<br>";
echo "成功率: " . round($stats['success_rate'], 2) . "%<br>";
echo "当前目录: " . htmlspecialchars($stats['current_dir']) . "<br>";
echo "服务器类型: " . htmlspecialchars($stats['server_type'] ?? '未知');
echo "</div>";
// 自动关闭连接
} catch (Exception $e) {
echo "<div class='alert alert-danger'>错误: " . htmlspecialchars($e->getMessage()) . "</div>";
}
/**
* 格式化文件大小
*/
function formatSize($bytes) {
if ($bytes == 0) return '0 B';
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$i = floor(log($bytes, 1024));
return round($bytes / pow(1024, $i), 2) . ' ' . $units[$i];
}
?>