Сегодня копался в модуле, а точнее в передачи через FTP. в результате наткнулся на следующие ошибки.
1. Если FTP сервер поднят на винде средствами IIS (у меня windows 10), то не отображается список файлов архивов.
2. Если бекап создается достаточно долго ( в моем случае это мин 10-15), то загрузка на FTP не происходит, падает в ошибку на строке такой- то(номер не скажу не помню, но если смотреть то она выглядит так:
Код: Выделить всё
if (ftp_chdir($this->conn_id, $this->path) == false)
это в функции uploadBackup.
3. Если даже и приходит загрузка файла на FTP (не полное копирование, время работы копирования 1-2 мин) то они приходят битые.
А теперь ответ на два вопроса - Кто виноват и что делать в сложившейся ситуации.
1. у меня сложилось такое впечатление что IIS отображает файлы не совсем так как это делает тот же VSFTPD (никсы) и как следствие, при чтение списка файлов с сервера FTP формируется не правильный массив имен файлов в функции getList. Следовательно пришлось поправить не много эту функцию. сразу говорю что дату и время создания файла беру из его имени. а сама функция у меня получилась следующая:
Код: Выделить всё
public function getList()
{
if ($this->error) return;
$pattern = IsWindowsOS() ? 'tar' : 'tgz';
if (ftp_chdir($this->conn_id, $this->path) == false) {
$this->logger->log('Change dir failed:'. $this->path);
$this->error='Change dir failed:'. $this->path;
return;
}
$list = ftp_rawlist($this->conn_id, $this->path);
$files = array();
foreach ($list as $current) {
$split = preg_split("[ ]", $current, 9, PREG_SPLIT_NO_EMPTY);
if ($split[0] != "total") {
if ($split[0]{0} === "d") continue;
if (!strpos($split[3],$pattern)) continue;
$file = array();
$file["NAME"] = $split[3];
$time=substr($split[3],15,2).':'.substr($split[3],17,2);
$month = substr($split[3],11,2);
$day = substr($split[3],13,2);
$year=substr($split[3],7,4);
if (strpos($time, ':'))
$timestamp = strtotime($day . "-" . $month. "-". $year. " ". $time);
else
$timestamp = strtotime($day. "-". $month ."-". $year . " 00:00");
$date = date('d-m-Y H:i', $timestamp);
$file["CREATED"] = $date;
$file["SIZE"] = $split[2];
$file["URL"] = "ftp://".$this->ftp_server."$this->path".$file["NAME"];
$files[] = $file;
}
}
return $files;
}
2. Эта ошибка связана с тем, что соединение с FTP сервером создается в момент начала резервирования, т.е. все то время пока происходит копирование файлов во временную папку, выгрузка дампов БД и сжатие всего этого, соединение с FTP остается открытым. и как следствие может быть разорвано сервером по тайм-ауту (что и происходило у меня). от сюда и появляющаяся непонятная ошибка на функцию которая в принципе не может дать такой ответ. лечится это путем установки соединения только в момент выполнения каких-то действий на сервере, например загрузка файлов на сервер, получение списка, удаление и т.д.
в результате пришлось добавить в класс фтп еще 1 функцию ftpConnect() и вызывать ее в при выполнение каких-либо действий на FTP сервере.
полный файл касса работы с фтп сервером ниже.
3. связано это с тем что файлы передаются в кодировки ASCII (точно не разбирался но похоже, что что-то криво перекодируется). так вот для исправления этого достаточно поменять режим передачи файла на фтп сервер в строке
Код: Выделить всё
if (!ftp_put($this->conn_id, $this->path."".$backup, $file, FTP_ASCII)) {
Код: Выделить всё
if (!ftp_put($this->conn_id, $this->path."".$backup, $file, FTP_BINARY)) {
Все выше описанное относится к файлу %WWW DIRECTORY%/modules/backup/provider/ftp.php
ну и как обещал полный код этого файла
Код: Выделить всё
<?php
require_once("IProvider.php");
class FtpBackup implements IProvider
{
public $error;
public $supportUpload = 1;
function __construct($ftp_server, $login, $password, $path, $logger)
{
$this->path = $path;
$this->ftp_server = $ftp_server;
$this->logger = $logger;
$this->login=$login;
$this->password=$password;
}
function ftpConnect()
{
$this->conn_id = ftp_connect($this->ftp_server);
$this->login_result = ftp_login($this->conn_id, $this->login, $this->password);
if (!$this->login_result) {
$this->logger->log('Error autorization');
$this->error='Error autorization';
}
}
public function getFreeSpace()
{
return -1;
}
public function getList()
{
$this->ftpConnect();
if ($this->error) return;
$pattern = IsWindowsOS() ? 'tar' : 'tgz';
if (ftp_chdir($this->conn_id, $this->path) == false) {
$this->logger->log('Change dir failed:'. $this->path);
$this->error='Change dir failed:'. $this->path;
return;
}
$list = ftp_rawlist($this->conn_id, $this->path);
$files = array();
foreach ($list as $current) {
$split = preg_split("[ ]", $current, 9, PREG_SPLIT_NO_EMPTY);
if ($split[0] != "total") {
if ($split[0]{0} === "d") continue;
if (!strpos($split[3],$pattern)) continue;
$file = array();
$file["NAME"] = $split[3];
$time=substr($split[3],15,2).':'.substr($split[3],17,2);
$month = substr($split[3],11,2);
$day = substr($split[3],13,2);
$year=substr($split[3],7,4);
if (strpos($time, ':'))
$timestamp = strtotime($day . "-" . $month. "-". $year. " ". $time);
else
$timestamp = strtotime($day. "-". $month ."-". $year . " 00:00");
$date = date('d-m-Y H:i', $timestamp);
$file["CREATED"] = $date;
$file["SIZE"] = $split[2];
$file["URL"] = "ftp://".$this->ftp_server."$this->path".$file["NAME"];
$files[] = $file;
}
}
ftp_close($this->conn_id);
return $files;
}
public function uploadBackup($file, $backup)
{
$this->ftpConnect();
if ($this->error) return;
if (ftp_chdir($this->conn_id, $this->path) == false) {
$this->logger->log('Change dir failed:'. $this->path);
$this->error='Change dir failed:'. $this->path;
return;
}
if (!ftp_put($this->conn_id, $this->path.$backup, $file, FTP_BINARY)) {
$this->logger->log('Upload failed:'. $this->path.$backup);
$this->error='Upload failed:'. $this->path.$backup;
}
ftp_close($this->conn_id);
}
public function deleteBackup($backup)
{
$this->ftpConnect();
if ($this->error) return;
$filename = $backup;
echo $filename;
if (ftp_chdir($this->conn_id, $this->path) == false) {
$this->logger->log('Change dir failed:'. $this->path);
$this->error='Change dir failed:'. $this->path;
return;
}
if (!ftp_delete($this->conn_id, $filename)) {
$this->logger->log('Delete failed:'. $filename);
$this->error='Delete failed:'. $filename;
}
ftp_close($this->conn_id);
}
public function downloadBackup($backup, $file)
{
$this->ftpConnect();
if ($this->error) return;
$filename = $backup;
if (ftp_chdir($this->conn_id, $this->path) == false) {
$this->logger->log('Change dir failed:'. $this->path);
$this->error='Change dir failed:'. $this->path;
return;
}
if (!ftp_get($this->conn_id, $file, $this->path."/".$backup, FTP_BINARY)) {
$this->logger->log('Upload failed:'. $this->path.$backup);
$this->error='Upload failed:'. $this->path.$backup;
}
ftp_close($this->conn_id);
}
}