function ftp_get_file($url)
{
function ftp_send($f, $query)
{
fputs($f, $query); //Отправляем запрос
$ans = fgets($f); //Читаем ответ сервера
return $ans;
}
function ftp_send_pasv($f, $host, &$answers)
{
$pasv = ftp_send($f, "PASV\r\n");
$answers .= $pasv;
/* Определяем номер порта, на котором нас ждёт сервер после команды PASV */
$res = array();
if (preg_match('/^227.*\((\d{1,3}\,){4}(\d{1,3})\,(\d{1,3})\).*/', $pasv, $res) != 0)
$port_num = $res[2] * 256 + $res[3];
else
return FALSE;
/*************************************************************************/
$errno2 = 0;
$errstr2 = '';
if ($f2 = @fsockopen($host, $port_num, $errno2, $errstr2, 15)) //Открываем сокет для передачи данных
return $f2;
else
return FALSE;
}
function write_logs($logs)
{
$logs_fname = 'logs.htm';
$fl = fopen($logs_fname, 'a');
clearstatcache();
if (filesize($logs_fname) == 0) $logs = str_replace("\r\n<br><b>", '<b>', $logs);
fputs($fl, $logs);
fclose($fl);
}
function logs_abort()
{
return date('d.m.Y H:i:s').' - <font color="#ff0000"><b>download aborted</b></font><br>'."\r\n";
}
$MAX_TRIES = 5; //Максимальное число попыток
$logs = "\r\n<br><b>{URL}</b><br>\r\n";
$logs_end = "--------------------------------------------------------------------------<br>\r\n";
$logs = str_replace('{URL}', $url, $logs);
$url_ar = @parse_url($url);
if (empty($url_ar['port']))
if ($url_ar['scheme'] == 'ftp') //Только ftp
$url_ar['port'] = 21;
else
{
$logs .= date('d.m.Y H:i:s').' - bad URL: only FTP supported'."<br>\r\n".logs_abort().$logs_end;
write_logs($logs);
return FALSE;
}
if ($url_ar['path'] == '')
{
$logs .= date('d.m.Y H:i:s').' - bad URL: no file name'."<br>\r\n".logs_abort().$logs_end;
write_logs($logs);
return FALSE;
}
$fname = basename($url);
$size = 0; //Размер скачанного файла
$old_size = 0;
$cont = ''; //Содержание скачанного файла
$remote_size = 0; //Размер удаленного файла
$tries = 0; //Число попыток
$time_b = time(); //Начало закачки
while ($tries <= $MAX_TRIES)
{
$tries++;
if ($tries > $MAX_TRIES) //Превысили максимальное число попыток
{
$logs .= date('d.m.Y H:i:s').' - max ('.$MAX_TRIES.') tries reached<br>'."\r\n".logs_abort();
break;
}
$errno = 0;
$errstr = '';
$f = @fsockopen($url_ar['host'], $url_ar['port'], $errno, $errstr, 15); //Открываем сокет для передачи команд
if (!$f)
{
$logs .= date('d.m.Y H:i:s').' - could not connect to '.$url_ar['host']."<br>\r\n".logs_abort();
break;
}
$logs .= date('d.m.Y H:i:s').' - connected to '.$url_ar['host']."<br>\r\n";
$answers = ''; //Для отладки
$user_send = empty($url_ar['user'])?'anonymous':$url_ar['user'];
$pass_send = empty($url_ar['pass'])?'guest':$url_ar['pass'];
$answers .= fgets($f); //220 Welcome to *** FTP service.
$answers .= ftp_send($f, "USER ".$user_send."\r\n");
$pass = ftp_send($f, "PASS ".$pass_send."\r\n");
$answers .= $pass;
$pass = substr($pass, 0, 4); //Извлекаем код сообщения
if ($pass == '230-') //Расширенный ответ сервера
{
do
{
$tmp = fgets($f);
$answers .= $tmp;
$tmp = substr($tmp, 0, 4);
}
while ($tmp != '230 ');
}
elseif ($pass == '530 ') //530 Incorrect login или Maximum number of allowed clients are already connected.
{
$answers .= ftp_send($f, "QUIT\r\n");
fclose($f);
$logs .= date('d.m.Y H:i:s').' - incorrect login or max number of connected clients reached'."<br>\r\n";
write_logs($logs);
$logs = '';
sleep(10);
continue;
}
$rest = ftp_send($f, "REST 100\r\n"); //Проверка возможности докачки
$answers .= $rest;
$rest = substr($rest, 0, 3); //Извлекаем код сообщения
if ($rest != '350')
{
$answers .= ftp_send($f, "QUIT\r\n");
fclose($f);
$logs .= date('d.m.Y H:i:s').' - server doesn\'t support partial download'."<br>\r\n".logs_abort();
break;
}
$answers .= ftp_send($f, "REST 0\r\n"); //Устанавливаем маркер обратно в 0
$answers .= ftp_send($f, "TYPE A\r\n"); //200 Switching to ASCII mode.
$logs .= date('d.m.Y H:i:s').' - getting '.$url_ar['path']."<br>\r\n";
if (empty($remote_size))
{
$f2 = ftp_send_pasv($f, $url_ar['host'], $answers); //Открываем канал для передачи данных - для определения размера файла
if (!$f2)
{
$answers .= ftp_send($f, "QUIT\r\n");
fclose($f);
$logs .= date('d.m.Y H:i:s').' - could not establish data stream connection'."<br>\r\n".logs_abort();
break;
}
$answers .= ftp_send($f, "LIST ".$url_ar['path']."\r\n"); //150 Here comes the directory listing.
$file_info = fgets($f2); //Информация о файле
fclose($f2);
$answers .= $file_info;
$answers .= fgets($f); //226 Directory send OK.
/* Определяем размер файла */
$res = array();
preg_match('/^[rwx\-]{10}[ ]+\w+ (\w+[ ]+){2}([\d]+).*/', $file_info, $res);
$remote_size = $res[2];
if (empty($remote_size)) //Если не получилось через LIST, пробуем через SIZE
{
$size_req = ftp_send($f, "SIZE ".$url_ar['path']."\r\n");
$answers .= $size_req;
$res = array();
preg_match('/^213 (\d+).*/', $size_req, $res);
$remote_size = $res[1];
}
/***************************/
if (empty($remote_size))
{
$answers .= ftp_send($f, "QUIT\r\n");
fclose($f);
$logs .= date('d.m.Y H:i:s').' - file size: unknown'."<br>\r\n".logs_abort();
break;
}
}
if (empty($size))
if (file_exists($fname)) //Если файл уже существует, то докачиваем его
{
$size = filesize($fname); //Размер уже скачанной части
if ($size >= $remote_size) //Если файл уже скачан
{
$logs .= date('d.m.Y H:i:s').' - already downloaded'."<br>\r\n".logs_abort().$logs_end;
write_logs($logs);
return FALSE;
}
$lf = fopen($fname, 'r');
$cont = fread($lf, $size); //Содержание уже скачанной части
fclose($lf);
$old_size = $size;
}
$logs .= date('d.m.Y H:i:s').' - file size: '.sprintf('%.0f', $remote_size / 1024).' KB<br>'."\r\n".
date('d.m.Y H:i:s').' - download started'."<br>\r\n";
write_logs($logs);
$logs = '';
$answers .= ftp_send($f, "TYPE I\r\n"); //200 Switching to Binary mode.
$f2 = ftp_send_pasv($f, $url_ar['host'], $answers);
if (!$f2)
{
$answers .= ftp_send($f, "QUIT\r\n");
fclose($f);
$logs .= date('d.m.Y H:i:s').' - could not establish data stream connection'."<br>\r\n".logs_abort();
break;
}
$answers .= ftp_send($f, "REST ".$size."\r\n"); //Устанавливаем маркер на позицию, равную размеру уже скачанного файла
$retr = ftp_send($f, "RETR ".$url_ar['path']."\r\n");
$answers .= $retr;
$retr = substr($retr, 0, 3); //Извлекаем код сообщения
if ($retr != '150')
{
$answers .= ftp_send($f, "ABOR\r\n");
$answers .= ftp_send($f, "QUIT\r\n");
fclose($f2); fclose($f);
$logs .= date('d.m.Y H:i:s').' - could not retreive part of file'."<br>\r\n".logs_abort();
break;
}
while (!feof($f2)) //Читаем содержимое файла
$cont .= fgets($f2, 2048);
fclose($f2);
$size = strlen($cont);
if ($size >= $remote_size) //Файл успешно скачан
{
$answers .= fgets($f); //226 File send OK.
$answers .= ftp_send($f, "QUIT\r\n");
fclose($f);
break;
}
fclose($f);
$logs .= date('d.m.Y H:i:s').' - server disconnected'."<br>\r\n";
}
$time_e = time(); //Конец закачки
if ($size <= $old_size) //Если ничего скачать не удалось
{
$logs .= $logs_end;
write_logs($logs);
return FALSE;
}
$dtime = $time_e - $time_b;
$dtime = ($dtime == 0)?1:$dtime; //Чтобы не делить на ноль
if ($fout = @fopen($fname, 'w'))
{
$speed = sprintf('%.2f', ($size - $old_size) / 1024 / $dtime); //Приблизительная скорость закачки
fwrite($fout, $cont);
fclose($fout);
if ($size >= $remote_size)
$logs .= date('d.m.Y H:i:s').' - <font color="#0000ff"><b>downloaded at '.$speed.' KB/s in '.$tries.' tries</b></font><br>'."\r\n";
else
{
$degr = sprintf('%.0f', $size / $remote_size * 100).'%';
$d_size = sprintf('%.0f', $size / 1024).' KB';
$logs .= date('d.m.Y H:i:s').' - <font color="#ff0000"><b>downloaded '.$degr.' ('.$d_size.') at '.$speed.' KB/s</b></font><br>'."\r\n";
}
}
else //Не удалось записать в выходной файл
$logs .= date('d.m.Y H:i:s').' - <font color="#ff0000"><b>could not write to output file</b></font><br>'."\r\n";
echo '<pre>', $answers, '</pre>';
$logs .= $logs_end;
write_logs($logs);
return TRUE;
}