Статьи

Как работать с PHP и FTP

В этом руководстве наша цель — создать класс FTP с PHP, который будет хорошо написан, полезен и расширяем.

Всегда важно сначала определить, какие именно функции должен включать ваш класс. В нашем случае:

  • подключение к серверу
  • создать папку на сервере
  • загрузить файл
  • изменить каталог
  • получение списка каталогов
  • скачать файл

Есть несколько случаев, когда можно использовать этот класс. Пара сценариев может быть:

  • Автоматизируйте загрузку изображений, таких как галерея, на веб-сайт клиента (в идеале, в сочетании с моим изменением размера изображения)
  • Выполните резервное копирование вне сайта, передав файл резервной копии базы данных с вашего сервера на другой. ( Примечание: это не рекомендуется для конфиденциальной информации, так как FTP не очень безопасный протокол. )

Примечание. Проблемы с FTP легко возникают из-за различных конфигураций сервера. Этот код был успешно протестирован на нескольких FTP-серверах.


FTP: «Стандартный сетевой протокол, используемый для копирования файла с одного хоста на другой».

FTP, или протокол передачи файлов, как определено в Википедии: «Стандартный сетевой протокол, используемый для копирования файла с одного хоста на другой по сети на основе TCP / IP, такой как Интернет».

По сути, это позволяет копировать файлы с одного компьютера на другой.


Мы начнем как можно проще. В корне вашего нового проекта создайте два файла: index.php и ftp_class.php .

Файл index.php — это наша главная страница, которая создает объект и вызывает необходимые методы. ftp_class.php — это просто наш класс ftp.

На следующем шаге мы собираемся создать каркас для нашего класса. Как только это будет сделано, вы сможете следовать и пробовать каждый шаг.


Сила объектно-ориентированного программирования (ООП) состоит в том, чтобы предоставить сложный код простой в использовании интерфейс. Создавая класс — думайте о классе как о шаблоне — вы можете инкапсулировать данные, что является просто жаргоном для термина, который относится к сокрытию данных. Затем мы можем многократно использовать этот класс без необходимости переписывать какой-либо код. Вместо этого вам нужно только вызвать соответствующие методы (термин « method » такой же, как и function ).

Давайте начнем создавать наш класс ftp. Откройте файл ftp_class.php и добавьте следующий код. Это базовая структура скелета класса, которую я назвал « FTPClient ».

Функция construct , известная как конструктор, представляет собой специальный метод класса, который автоматически вызывается классом при создании нового объекта или экземпляра класса. Обычно это хорошее место для добавления инициализации; но для сегодняшних целей нам это не нужно. Тем не менее, мы будем держать его здесь для будущего использования.

1
2
3
4
5
6
Class FTPClient
{
    // *** Class variables
 
    public function __construct() { }
}

Обратите внимание, что мы используем двойное подчеркивание для этого метода construct .


Далее мы установим некоторые переменные класса или свойства.

1
2
3
private $connectionId;
private $loginOk = false;
private $messageArray = array();

private префикс определяет область действия переменной. В этом случае это означает, что переменная не может быть доступна из-за пределов класса.

Переменная $connectionId будет хранить наш поток соединения. Два других хранят статус и любые сообщения. $loginOk будет полезен при определении, правильно ли мы подключены.


Почти в каждом методе мы будем вызывать метод с именем ‘ 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 переменную messageArray . Мы можем; Тем не менее, это просто не очень хорошая практика.

Примечание. В Интернете есть множество примеров полнофункциональных обработчиков сообщений или посвященных им классов. Мы работаем над простой реализацией для целей этого урока.


На этом шаге мы добавим метод connect . Это позволит нам подключиться к FTP-серверу.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public function connect ($server, $ftpUser, $ftpPassword, $isPassive = false)
{
 
    // *** Set up basic connection
    $this->connectionId = ftp_connect($server);
 
    // *** Login with username and password
    $loginResult = ftp_login($this->connectionId, $ftpUser, $ftpPassword);
 
    // *** Sets passive mode on/off (default off)
    ftp_pasv($this->connectionId, $isPassive);
 
    // *** Check connection
    if ((!$this->connectionId) || (!$loginResult)) {
        $this->logMessage(‘FTP connection has failed!’);
        $this->logMessage(‘Attempted to connect to ‘ . $server . ‘ for user ‘ . $ftpUser, true);
        return false;
    } else {
        $this->logMessage(‘Connected to ‘ . $server . ‘, for user ‘ . $ftpUser);
        $this->loginOk = true;
        return true;
    }
}

Мы передаем информацию о соединении: сервер ( $server ), имя пользователя ( $ftpUser ) и пароль ( $ftpPassword ), чтобы позволить нам установить соединение.

Первая строка кода открывает FTP-соединение с ftp_connect к указанному серверу. Мы сохраняем наше соединение с переменной класса $connectionId описанной выше.

Код ftp_login регистрирует нас на указанное соединение, передавая connection id нашего connection id , наше имя пользователя и пароль.

Вы могли заметить строку кода ftp_pasv . Это, как следует из комментария, включает / выключает пассивный режим. Я бы посоветовал вам отключить его, однако, если у вас возникнут проблемы с подключением, попробуйте включить его. Пассивный режим может вызвать проблемы с подключением через FTP.

Мы определяем, было ли соединение успешным. Затем мы регистрируем результаты, вызывая наш простой метод обработчика сообщений, logMessage() , и передаем строку в log. Помните: мы используем $this-> для доступа к logMessage() , так как это переменная класса.


Теперь, когда наш класс работает, мы можем проверить это! Откройте файл index.php и добавьте следующий код.

Вам понадобится доступ к FTP-серверу, чтобы играть вместе. Если вы хотите настроить свой собственный сервер, попробуйте Filezilla — это тоже бесплатно.

Вы заметите, что я добавил детали FTP-сервера здесь. В идеале они будут храниться в вашем config файле. Измените их в соответствии с настройками вашего FTP-сервера.

После определения деталей нашего FTP-сервера мы включаем класс с помощью include('ftp_class.php'); , Это означает: сделать класс доступным на этой странице. Следующая строка создает объект нашего класса FTP и сохраняет его в переменной $ftpObj . $ftpObj теперь будет использоваться для доступа к любым публичным методам в нашем классе. Это делается с помощью нотации -> , как в следующей строке, вызывая метод $ftpObj -> connect и передавая ему данные нашего сервера.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
// *** Define your host, username, and password
define(‘FTP_HOST’, ‘192.168.1.88’);
define(‘FTP_USER’, ‘Blimpf’);
define(‘FTP_PASS’, ‘catfish’);
 
 
// *** Include the class
include(‘ftp_class.php’);
 
// *** Create the FTP object
$ftpObj = new FTPClient();
 
// *** Connect
$ftpObj -> connect(FTP_HOST, FTP_USER, FTP_PASS);

Как видите, как только наш класс будет на месте, подключиться к нашему FTP-серверу очень просто!


На последнем шаге мы можем заключить вызов connect в оператор if , как показано ниже. Затем, если мы не сможем подключиться, зависимый код не будет выполнен. Затем мы можем вывести любые сообщения пользователю, такие как «подключено» или «не удалось».

01
02
03
04
05
06
07
08
09
10
// *** Connect
if ($ftpObj -> connect(FTP_HOST, FTP_USER, FTP_PASS)) {
 
    // *** Then add FTP code here
 
    echo ‘connected’;
 
} else {
    echo ‘Failed to connect’;
}

Это нормально, хотя наш код быстро раздуется с помощью операторов IF / ELSE, если мы добавим это ко всем нашим вызовам. Вместо этого я хотел бы предложить альтернативу, которая сделает вещи немного чище и легче следовать.

Помните методы обработки сообщений, которые мы добавили? Если вы хотите видеть сообщения, созданные классом — полезные для отладки / обратной связи — вы можете добавить следующий код после любого метода, который вы вызываете.

1
print_r($ftpObj -> getMessages());

Это покажет сообщение класса.


Отлично, теперь пришло время сделать что-то полезное. Первый метод, который мы собираемся создать, это метод makeDir . Как и ожидалось, этот метод создаст для нас каталоги на сервере. Единственный параметр, который мы передадим — это путь к каталогу и имя папки; мы назовем это $directory . Волшебная линия здесь — встроенная функция ftp_mkdir . Он использует наш сохраненный « connectionId » и переданную переменную $directory для создания папки.

Добавьте следующий код в ваш файл ftp_class.php :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public function makeDir($directory)
{
    // *** If creating a directory is successful…
    if (ftp_mkdir($this->connectionId, $directory)) {
 
        $this->logMessage(‘Directory «‘ . $directory . ‘» created successfully’);
        return true;
 
    } else {
 
        // *** …Else, FAIL.
        $this->logMessage(‘Failed creating directory «‘ . $directory . ‘»‘);
        return false;
    }
}

И, чтобы вызвать его из вашего файла index.php , добавьте:

1
2
3
4
$dir = ‘photos’;
 
// *** Make directory
$ftpObj->makeDir($dir);

Переменная $dir установлена ​​на имя папки, которую мы хотим создать на сервере. В данном случае: «фото».

Следующая строка вызывает метод, который создаст папку.

Если вы получили сообщение об ошибке «Отказано в доступе», убедитесь, что вы можете написать в указанной папке. Вам может потребоваться создать папку в каталоге, например /httpdocs .


Продолжая, давайте zoe.jpg фотографию, которая называется zoe.jpg . При загрузке файла нам нужно указать, какой тип файла мы загружаем — binary или ascii ? По сути, если вы загружаете текстовый файл, мы должны использовать ascii ; в противном случае он должен быть установлен в двоичный файл.

Мы начнем с настройки array со всеми расширениями, которые мы должны использовать для загрузки типа ascii .

1
$asciiArray = array(‘txt’, ‘csv’);

Затем мы получаем расширение нашего файла, чтобы мы могли проверить, является ли он одним из типов ascii . Мы определяем это, получая расширение загружаемого файла. Быстрый и грязный метод, который я использовал здесь,
» взорвав » файл с помощью ‘ . ‘как разделитель. Это разделит файл на части и сохранит их в виде array . Используя другую встроенную PHP-функцию « end », мы выбираем последний элемент array который содержит наше расширение. Это немного кода.

1
$extension = end(explode(‘.’, $fileFrom));

Затем мы проверяем, присутствует ли наше расширение в списке (с in_array ) расширений файлов, которые должны быть загружены как тип ascii . Если он появляется в списке, мы устанавливаем переменную $mode в FTP_ASCII ; в противном случае мы предполагаем, что это двоичный тип, и присваиваем $mode значение FTP_BINARY .

1
in_array($extension, $asciiArray)

ftp_put загружает файл из вашего локального местоположения в удаленный файл на FTP-сервере. Мы передаем ему наш « connectionId », путь к файлу, в который мы хотим загрузить ( $fileTo ), путь
файла, который мы хотим загрузить ( $fileFrom ), и режим ( $mode ), который мы только что определили.

Затем добавьте следующий метод в ваш файл ftp_class.php :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public function uploadFile ($fileFrom, $fileTo)
{
    // *** Set the transfer mode
    $asciiArray = array(‘txt’, ‘csv’);
    $extension = end(explode(‘.’, $fileFrom));
    if (in_array($extension, $asciiArray)) {
        $mode = FTP_ASCII;
    } else {
        $mode = FTP_BINARY;
    }
 
    // *** Upload the file
    $upload = ftp_put($this->connectionId, $fileTo, $fileFrom, $mode);
 
    // *** Check upload status
    if (!$upload) {
 
            $this->logMessage(‘FTP upload has failed!’);
            return false;
 
        } else {
            $this->logMessage(‘Uploaded «‘ . $fileFrom . ‘» as «‘ . $fileTo);
            return true;
        }
}

Конечно, вы можете создать или загрузить любое имя папки по вашему желанию! Добавьте следующий фрагмент кода в файл index.php и внесите соответствующие изменения.

1
2
3
4
5
$fileFrom = ‘zoe.jpg’;
$fileTo = $dir .
 
// *** Upload local file to new directory on server
$ftpObj -> uploadFile($fileFrom, $fileTo);

К настоящему времени вы должны прийти к соглашению с тем, насколько просто использовать этот класс! Мы просто делаем отдельные вызовы для выполнения наших задач — все благодаря объектно-ориентированному программированию!


Теперь давайте подтвердим, что наш файл находится в папке с photo . Мы можем сделать это, перейдя в папку « photo » на нашем сервере, а затем отобразить содержимое.

Метод changeDir использует « ftp_chdir » для изменения текущего каталога на ftp-сервере. Просто перейдите в каталог, чтобы перейти к. Просто и мило.

ftp_class.php:

01
02
03
04
05
06
07
08
09
10
public function changeDir($directory)
{
    if (ftp_chdir($this->connectionId, $directory)) {
        $this->logMessage(‘Current directory is now: ‘ . ftp_pwd($this->connectionId));
        return true;
    } else {
        $this->logMessage(‘Couldn\’t change directory’);
        return false;
    }
}

getDirListing отобразит содержимое каталога, в котором вы находитесь, используя функцию » ftp_nlist «. Эта функция возвращает список файлов в данном каталоге. Текущий каталог установлен по умолчанию, поэтому вам не нужно указывать какие-либо параметры.

Если вы хотите, вы можете переопределить это, передав путь к $directory вы хотите просмотреть содержимое. Переменная $parameters умолчанию -la . Это команда Linux для отображения дополнительной информации о каталоге. Не стесняйтесь удалить его или передать пустую строку.

1
2
3
4
5
6
7
public function getDirListing($directory = ‘.’, $parameters = ‘-la’)
{
    // get contents of the current directory
    $contentsArray = ftp_nlist($this->connectionId, $parameters . ‘ ‘ . $directory);
 
    return $contentsArray;
}

Метод getDirListing возвращает array который содержит наш список каталогов.

01
02
03
04
05
06
07
08
09
10
// *** Change to folder
$ftpObj->changeDir($dir);
 
// *** Get folder contents
$contentsArray = $ftpObj->getDirListing();
 
// *** Output our array of folder contents
echo ‘<pre>’;
print_r($contentsArray);
echo ‘

«;

Ваш результат должен выглядеть так:


По мере продвижения к завершению этого урока мы переходим к загрузке файла. Метод начинается с того же кода, что и uploadFile , в том uploadFile , что он определяет, является ли файл, который мы хотим загрузить, ascii или binary .

Для этого метода вы просто передаете имя файла (и, возможно, путь, в зависимости от того, находитесь ли вы в той же папке, что и файл, который вы хотите загрузить) файла для загрузки, и имя, которое вы хотите, чтобы этот файл имел на ваш клиентский компьютер.

Чтобы скачать файл, вам нужно вызвать ftp_get .

1
ftp_get($this->connectionId, $fileTo, $fileFrom, $mode, 0)

Это загружает файл с удаленного сервера на наш локальный компьютер. Он принимает следующий параметр: наш идентификатор соединения, путь и имя файла для сохранения как локально (будет перезаписан, если он
уже существует) ( $fileTo ), местоположение и имя файла на удаленном сервере ( $fileFrom ) и режим ( $mode ).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public function downloadFile ($fileFrom, $fileTo)
{
 
    // *** Set the transfer mode
    $asciiArray = array(‘txt’, ‘csv’);
    $extension = end(explode(‘.’, $fileFrom));
    if (in_array($extension, $asciiArray)) {
        $mode = FTP_ASCII;
    } else {
        $mode = FTP_BINARY;
    }
 
    // try to download $remote_file and save it to $handle
    if (ftp_get($this->connectionId, $fileTo, $fileFrom, $mode, 0)) {
 
        return true;
        $this->logMessage(‘ file «‘ . $fileTo . ‘» successfully downloaded’);
    } else {
 
        return false;
        $this->logMessage(‘There was an error downloading file «‘ . $fileFrom . ‘» to «‘ . $fileTo . ‘»‘);
    }
 
}

Мы собираемся загрузить тот же файл, который мы загрузили, сохранив его под другим именем на нашем клиентском компьютере.

Примечание: еще раз, убедитесь, что ваши разрешения установлены правильно!

Поскольку теперь мы должны находиться внутри нашей папки с photo , мы не добавляем путь к переменной $fileFrom — только имя файла.

1
2
3
4
5
$fileFrom = ‘zoe.jpg’;
$fileTo = ‘zoe-new.jpg’;
 
// *** Download file
$ftpObj->downloadFile($fileFrom, $fileTo);

Чтобы завершить наш класс, давайте добавим магический метод класса __deconstruct . Этот метод закрывает наше соединение, когда ссылка на наш объект больше не существует — возможно, страница была закрыта. В любом случае этот код запускается и соединение закрывается. Это всегда хорошая практика, чтобы включить это, хотя это не совсем необходимо.

1
2
3
4
5
6
public function __deconstruct()
{
    if ($this->connectionId) {
        ftp_close($this->connectionId);
    }
}

Ну, это делает это! Я надеюсь, что теперь вы лучше понимаете, как использовать FTP с PHP. Теперь у вас должны быть необходимые навыки для дальнейшего расширения этого класса для поддержки других распространенных задач, таких как переименование или удаление файлов и папок.

Обязательно сообщите нам, если вы создадите классные PHP FTP-клиенты!