От автора: в этом учебнике нашей целью является создание класса FTP при помощи PHP, хорошо написанного, полезного и расширяемого.
Краткое описание задачи
Очень важно сначала кратко и точно описать, какую функциональность должен включать ваш класс. В нашем случае:
Соединение с сервером
Создание на сервере папки
Выгрузка файла
Изменение директории
Возврат списка директории
Закачка файла
Детали учебника
Программа: PHP 5+
Требования: и сервер FTP
Сложность: средняя
Примерное время выполнения: 30 минут
Когда нужно использовать класс FTP?
Этот вид класса можно применять в нескольких случаях. Парой сценариев могут быть:
Автоматизирование выгрузки изображений, таких как галерея, на вебсайт клиента (в идеале – в сочетании с моей подсказкой по изменению размера изображения);
Делайте бэкапы вне сайта, передавая файл бэкапа базы данных со своего сервера на другой. (Примечание: не рекомендуется для секретной информации, потому что FTP – не очень защищенный протокол).
Примечание: можно легко наткнуться на затруднения при работе с FTP, так как у разных серверов различные конфигурации. Данный код был успешно протестирован на многих серверах FTP.
Что такое FTP?
FTP: "Стандартный сетевой протокол, используемый для копирования файла с одного хоста на другой."
FTP, или File Transfer Protocol – это, по определению Wikipedia: "Стандартный сетевой протокол, используемый для копирования файла с одного хоста на другой через основанную на TCP/IP сеть, такую, как Интернет."
В действительности, он позволяет копировать файл(ы) с одного компьютера на другой.
Шаг 1 – Подготовка
Начнем по возможности с самого легкого. В корне своего нового проекта создайте два файла: index.php и ftp_class.php.
Файл, который создает объект и вызывает необходимые методы — index.php – это наша главная страница. ftp_class.php – это наш класс ftp.
В следующем шаге мы создадим «скелет» класса. Когда он будет готов, вы сможете пойти далее и попробовать проделать каждый этап.
Шаг 2 – Устанавливаем класс
Сильной стороной объектно-ориентированного программирования (Object-Oriented Programming (OOP)) является то, что оно дает сложному коду легкий в использовании интерфейс. Создавая класс — считайте класс шаблоном — вы можете инкапсулировать (герметизировать) данные, что является простым жаргонным словом для термина, относящегося к сокрытию данных. Затем можно опять использовать этот класс снова и снова без нужды в переписывании частей кода. Вместо того вам нужно всего лишь вызывать подходящие методы (термин “method” – это то же самое, что function).
Давайте начнем создавать свой класс ftp. Откройте файл ftp_class.php и добавьте следующий код. Это основная структура скелета класса, которую я назвал ‘FTPClient‘.
Функция construct, известная как конструктор, это специальный метод класса, автоматически им вызываемый, когда вы создаете новый объект, или пример класса. Обычно это отличное место, подходящее для добавления инициализации; но для сегодняшней цели она нам не нужна. Тем не менее, мы положим ее здесь для использования на будущее.
1 2 3 4 5 6 |
Class FTPClient { // *** переменные класса public function __construct() { } } |
Пожалуйста, обратите внимание, что для метода construct мы используем двойное подчеркивание.
Шаг 3 – Переменные класса
Далее мы установим несколько переменных класса или свойств.
1 2 3 |
private $connectionId; private $loginOk = false; private $messageArray = array(); |
Префикс "private" определяет область действия переменной. В данном случае это означает, что доступа к переменной извне класса нет ниоткуда.
Переменная $connectionId будет содержать наш поток соединения. Две других содержат статус и сообщения. $loginOk будет полезна для определения того, правильно ли мы соединены.
Шаг 4 – Запись простого сообщения
Почти в каждом методе мы будем вызывать метод с названием ‘logMessage. Это – самый основной обработчик сообщения, который даст нам возможность собирать любые сообщения, созданные нашим классом так, чтобы было можно гарантировать пользователю ответную реакцию.
Обратите внимание, что мы не делаем return (возврат) настоящих сообщений из своих методов. Вместо того мы возвращаем true или false, основанные на том, была ли успешной отдельная операция. У этого есть свои преимущества, но, кроме того, оно не детализирует пользователю то, что происходит.
Добавьте два следующих метода, чтобы было можно определить, что прошло успешно.
Этот метод принимает переменную $message. Содержимое переменной затем сохраняется в массиве класса благодаря строке: $this->messageArray[] = $message;
1 2 3 4 |
private function logMessage($message) { $this->messageArray[] = $message; } |
Так как $messageArray – переменная класса, мы можем получить к ней доступ через запись $this->.
Будучи внутри класса, $this относится к самому объекту.
Чтобы вернуть это сообщение, мы вызываем getMessages.
1 2 3 4 |
public function getMessages() { return $this->messageArray; } |
Этот метод – открытый. Как уже упоминалось, эти закрытые/открытые дела просто относятся к области действия переменной или, в данном случае, метода. К закрытому методу (или переменной) нельзя получить доступ снаружи класса, в то время, как к открытому методу (или переменной) можно.
Так как наша переменная закрытая, нам нужен способ получения к ней доступа. Мы делаем это, назначая своему классу метод public, к которому мы имеем затем доступ снаружи класса. Вам, может быть, интересно, почему мы не можем просто сделать messageArray открытой переменной. Можем; просто это не очень хорошо.
Примечание: в сети полно примеров обработчиков сообщения в полном цвете, или классов, посвященных им. Мы же работаем над простой реализацией цели этого учебника.
Шаг 5 – Соединение
На этом этапе мы добавим метод connect. Он позволит нам соединяться с сервером FTP.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public function connect ($server, $ftpUser, $ftpPassword, $isPassive = false) { // *** Установить основное соединение $this->connectionId = ftp_connect($server); // *** Логин с именем пользователя и паролем $loginResult = ftp_login($this->connectionId, $ftpUser, $ftpPassword); // *** Устанавливает пассивный режим вкл/выкл (on/off) (по умолчанию стоит off) ftp_pasv($this->connectionId, $isPassive); // *** Проверка соединения if ((!$this->connectionId) || (!$loginResult)) { $this->logMessage(Ошибка подключения по FTP!'); $this->logMessage('Попытка подключения к ' . $server . ' для пользователя ' . $ftpUser, true); return false; } else { $this->logMessage('Соединение к ' . $server . ', для пользователя ' . $ftpUser); $this->loginOk = true; return true; } } |
Мы предаем информацию: сервер ($server), имя пользователя ($ftpUser) и пароль ($ftpPassword) для установки соединения.
Первая строка кода открывает соединение FTP с отдельным сервером при помощи ftp_connect. Мы сохраняем свое соединение в переменную класса, $connectionId, описанную выше.
Код ftp_login записывает нас в отдельное соединение, передавая наш connection id, имя пользователя и пароль.
Вы, возможно, заметили строку кода ftp_pasv. Она, как поясняет комментарий, включает и выключает пассивный режим on/off. Я бы советовал оставить его в режиме off, однако, если у вас имеются некоторые проблемы со связью, попробуйте включить его на on. Пассивный режим может вызывать кошмары при соединении через FTP.
Определяем, было ли соединение успешным. Затем записываем результаты, вызывая метод обработчика простого сообщения logMessage() и передаем в лог строку. Помните: для получения доступа в logMessage() мы пользуемся $this->, так как это переменная класса.
Шаг 6 – Вызываем объект
Теперь, когда наш класс работает, мы можем его протестировать! Откройте файл index.php и добавьте следующий код.
Вам понадобится доступ на сервер FTP. Если хотите установить свой собственный сервер, попробуйте Filezilla – он бесплатный.
Вы заметите, что я добавил здесь подробности сервера FTP. В идеале они будут храниться в файле config. Измените их на установки своего FTP.
После определения подробностей сервера мы включаем класс с include(‘ftp_class.php’);. Это означает: сделать класс доступным изнутри этой страницы. Следующая строка создает объект класса FTP и сохраняет его в переменной $ftpObj. $ftpObj теперь будет использоваться для доступа к любым открытым методам внутри нашего класса. Это делается с использованием записи ->, в точности как это делает следующая строка, вызывая метод $ftpObj -> connect и передавая ему детали нашего сервера.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// *** Определите свой хостинг, имя пользователя и пароль define('FTP_HOST', '192.168.1.88'); define('FTP_USER', 'Blimpf'); define('FTP_PASS', 'catfish'); // *** Включите класс include('ftp_class.php'); // *** Создайте объект FTP $ftpObj = new FTPClient(); // *** Установите соединение $ftpObj -> connect(FTP_HOST, FTP_USER, FTP_PASS); |
Когда класс уже на месте, легко заметить, что соединение с сервером FTP – действительно легкая задача!
Шаг 6б – Просмотр исходящих
В последнем шаге мы могли бы обернуть вызов соединения в if-предложение, как показано ниже. Затем, если соединение не удастся установить, зависимый код не будет выполняться. Далее мы можем послать пользователю несколько сообщений, таких как «соединение установлено» ("connected") или «установить соединение не удалось» ("failed").
1 2 3 4 5 6 7 8 9 10 |
// *** Установите соединение if ($ftpObj -> connect(FTP_HOST, FTP_USER, FTP_PASS)) { // *** Затем добавьте сюда код FTP echo ' соединение установлено '; } else { echo ' установить соединение не удалось '; } |
Получается нормально, хотя наш код довольно быстро распухнет от предложений IF/ELSE, если мы добавим это ко всем своим вызовам. Вместо того я предложил бы альтернативу, которая облегчит продолжение работы и сделает код почище.
Помните добавленные нами методы обработчика сообщения? Если хотите видеть сообщения, произведенные классом – полезные для отладки и ответной реакции – можете добавить следующий код после любого вызываемого метода.
1 |
print_r($ftpObj -> getMessages()); |
Он отобразит сообщение класса.
Шаг 7 – Делаем свою первую директорию
Прекрасно, нам пора сделать что-нибудь полезное. Первый метод, который мы создадим, это makeDirmethod. Как и ожидается, он создаст для нас на сервере директории. Единственный параметр, который мы передадим – это путь директории и название папки; назовем ее $directory. Магической строкой здесь является функция ftp_mkdirbuilt-in. Для создания папки она использует наш сохраненный "connectionId" и переданную переменную $directory.
Добавьте в файл ftp_class.php следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public function makeDir($directory) { // *** Если удалось создать директорию… if (ftp_mkdir($this->connectionId, $directory)) { $this->logMessage('Директория "' . $directory . '" успешно создана'); return true; } else { // *** …Если не удалось $this->logMessage('Ошибка создания директории "' . $directory . '"'); return false; } } |
Переменная $dir установлена к названию папки, которую нам нужно создать на сервере. В данном случае «фото» ("photos"). Следующая строка вызывает метод, который создаст папку.
Если вы получаете сообщение об ошибке «право доступа отсутствует» ("Permission denied"), убедитесь, что можете писать в указанной папке. Вам, возможно, придется создать папку внутри директории, такую как /httpdocs.
Шаг 8 – Выгрузка файла
В продолжение работы давайте выгрузим фотографию с названием zoe.jpg. При выгрузке файла нам нужно определить, с каким типом файла мы работаем – binary или ascii? В основном при выгрузке текстового файла следует пользоваться ascii; в противном случае он должен быть установлен на binary.
Мы начинаем с установления массива со всеми расширениями, которые будут использоваться для выгрузки типа ascii.
1 |
$asciiArray = array('txt', 'csv'); |
Затем возвратите расширение нашего файла, чтобы можно было протестировать, не принадлежит ли он к типам ascii. Мы определяем это, получив расширение выгружаемого файла. Простой и быстрый метод, использованный мною здесь – «извлечение» файла с помощью ‘.‘ в качестве разделителя. Так файл разбивается на фрагменты и сохраняется как array. Используя другую встроенную функцию PHP, "end", мы выбираем последний элемент array, содержащий наше расширение. Это очень аккуратный маленький фрагмент кода.
1 |
$extension = end(explode('.', $fileFrom)); |
Далее мы тестируем, появляется ли наше расширение в списке (с in_array) файловых расширений, которые следует выгружать как тип ascii. Если оно появляется в списке, устанавливаем переменную $mode на FTP_ASCII; иначе делаем заключение, что это тип binary и назначаем $mode значение FTP_BINARY.
1 |
in_array($extension, $asciiArray) |
ftp_put выгружает файл с вашего местоположения в удаленный файл на сервере ftp. Мы передаем ему свой "connectionId", путь к файлу, который нам нужно выгрузить ($fileTo), путь файла, который нужно выгрузить ($fileFrom) и режим ($mode), который мы только что определили.
Далее добавляем в файл ftp_class.php следующий метод:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public function uploadFile ($fileFrom, $fileTo) { // *** Установите режим передачи $asciiArray = array('txt', 'csv'); $extension = end(explode('.', $fileFrom)); if (in_array($extension, $asciiArray)) { $mode = FTP_ASCII; } else { $mode = FTP_BINARY; } // *** Выгрузите файл $upload = ftp_put($this->connectionId, $fileTo, $fileFrom, $mode); // *** Проверьте статус выгрузки if (!$upload) { $this->logMessage('Не удалось загрузить файл!'); return false; } else { $this->logMessage('Загружен "' . $fileFrom . '" как "' . $fileTo); return true; } } |
Конечно, вы можете создать или выгрузить любое название папки на свое усмотрение! Добавьте в файл index.php следующий фрагмент кода и соответственно его измените.
1 2 3 4 5 |
$fileFrom = 'zoe.jpg'; $fileTo = $dir . '/' . $fileFrom; // *** Выгрузите локальный файл в новую директорию на сервере $ftpObj -> uploadFile($fileFrom, $fileTo); |
На данный момент вы должны привыкнуть к тому, насколько легко использовать этот класс! Мы всего лишь делаем отдельные вызовы для выполнения своих задач – и все благодаря объектно-ориентированному программированию!
Шаг 9 – Просмотр файлов
Давайте теперь подтвердим, что наш файл находится в папке с фотографиями. Это можно сделать, пройдя в папку ‘photo‘ на сервере, а затем показав ее содержимое.
Метод changeDir применяет "ftp_chdir" для изменения текущей директории на сервере ftp. Для изменения директории просто передайте ее. Легко и просто.
ftp_class.php:
1 2 3 4 5 6 7 8 9 10 |
public function changeDir($directory) { if (ftp_chdir($this->connectionId, $directory)) { $this->logMessage('Текущая директория: ' . ftp_pwd($this->connectionId)); return true; } else { $this->logMessage('Не возможно изменить директорию'); return false; } } |
getDirListing покажет содержимое директории, в которой вы находитесь, с помощью функции “ftp_nlist“. Она возвращает список файлов в данной директории. Текущая директория установлена по умолчанию, так что вам не нужно обеспечивать никаких параметров.
Если хотите, можете отменить этот момент, передав путь папки $directory, контент которой вы хотите просмотреть. Переменная $parameters установлена по умолчанию на ‘-la‘. Это – команда Linux для показа большего количества информации о директории. Не стесняйтесь удалить ее или передать в пустую строку.
ftp_class.php:
1 2 3 4 5 6 7 |
public function getDirListing($directory = '.', $parameters = '-la') { // получить содержимое текущей директории $contentsArray = ftp_nlist($this->connectionId, $parameters . ' ' . $directory); return $contentsArray; } |
Метод getDirListing возвращает массив, содержащий listing нашей директории.
index.php
1 2 3 4 5 6 7 8 9 10 11 |
// *** Сменить папку $ftpObj->changeDir($dir); // *** Получить содержимое папки $contentsArray = $ftpObj->getDirListing(); // *** Вывести массив содержимого папки echo ' <pre>'; print_r($contentsArray); echo ' |
‘;
Ваш результат должен выглядеть примерно так:
Шаг 10 – Закачиваем файл
По мере приближения к концу учебника мы переходим к закачке файла. Метод начинается с того же кода, что и uploadFile, где определяет, является ли файл, который нам нужно закачать, ascii или binary.
Для этого метода вы просто передаете название файла (и, возможно, путь в зависимости от того, находитесь ли вы в той же папке, что и файл, который следует скачать), который нужно закачать и названия, которое вам хотелось бы присвоить этому файлу на своей клиентской машине.
Для закачки файла нужно вызвать ftp_get.
1 |
ftp_get($this->connectionId, $fileTo, $fileFrom, $mode, 0) |
Так скачивается файл с удаленного сервера на нашу локальную машину. Он принимает следующий параметр: id нашего соединения, путь или название файла для его локального сохранения (будет переписано, если такое уже существует) ($fileTo), расположение и название файла на удаленном сервере ($fileFrom) и режим ($mode).
ftp_class.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public function downloadFile ($fileFrom, $fileTo) { // *** Установите режим передачи $asciiArray = array('txt', 'csv'); $extension = end(explode('.', $fileFrom)); if (in_array($extension, $asciiArray)) { $mode = FTP_ASCII; } else { $mode = FTP_BINARY; } // попробуйте скачать $remote_file и сохранить его в $handle if (ftp_get($this->connectionId, $fileTo, $fileFrom, $mode, 0)) { return true; $this->logMessage(' файл "' . $fileTo . '" успешно скачен'); } else { return false; $this->logMessage('Ошибка при скачивании файла "' . $fileFrom . '" to "' . $fileTo . '"'); } } |
Мы собираемся скачать тот же файл, который выгрузили, сохранив его под другим названием на своей клиентской машине.
Примечание: снова убедитесь, что права доступа правильно установлены!
Так как сейчас мы должны находиться внутри папки с фотографиями, то не добавляем путь к переменной $fileFrom – только название файла.
index.php
1 2 3 4 5 |
$fileFrom = 'zoe.jpg'; # The location on the server $fileTo = 'zoe-new.jpg'; # Local dir to save to // *** Скачайте файл $ftpObj->downloadFile($fileFrom, $fileTo); |
Шаг 11 — Заканчиваем
Чтобы закончить полностью со своим классом, давайте добавим метод class magic method, __deconstruct. Этот метод закрывает наше соединение, когда ссылки на объект уже не существует – возможно, страница была закрыта. В любом случае, этот код запустился и соединение закрыто. Это правильно – включать его, хотя он не является обязательным.
1 2 3 4 5 6 |
public function __deconstruct() { if ($this->connectionId) { ftp_close($this->connectionId); } } |
Заключение
Ну, что же, вот и все! Надеюсь, вы теперь лучше понимаете, как использовать FTP при помощи PHP. У вас сейчас уже должны быть необходимые навыки дальнейшего расширения этого класса для поддержки прочих простых задач, таких как переименование или удаление файлов и папок.
Не стесняйтесь дать нам знать, если создадите какие-нибудь классные клиенты PHP FTP!
Автор: Jarrod Oberto
Источник: //net.tutsplus.com/
Редакция: Рог Виктор и Андрей Бернацкий. Команда webformyself.
Комментарии (8)