Дозакачка с ФТП через скрипт и регулирование скорости скачки.

Space

Новичок
Дозакачка с ФТП через скрипт и регулирование скорости скачки.

Что бы не создавать флейм, я решил объеденить 2 проблемы в одну.

Предисловие:
В скрипт передается id скачиваемой программы. Далее из mysql берется имя этой программы и она скачивается с ФТП.

проблема 1.
как сделать дозакачку с фтп через файл?
причем не используя пример с php.net про ftp_fget и ftp_nb_fget, а через fopen.

проблема 2.
В связи с тем, что нельзя нагружать удаленный ФТП(иначе закроют) пришлось в цикле while (!feof ($file)) писать еще один цикл for($i..
Но на меня наехал хостер - говорит что скрипт нагружает ресурсы свыше 50%.. :( как сделать ограничение по скорости скачивания(не мой "for $i")?


прошу подумать прежде чем ответить :)


вот вырезка из действующего скрипта:

PHP:
....
  $file = fopen ("ftp://".$user.":".$pass."@".$ftp_server."/".$FILE_NAME, "r");
 ...
  while (!feof ($file))
  {
  for($i=1;$i<350000;$i++){$asd="asdasda";}    // speed: 0,8 k
  $FILE_DATA = fgets($file, 4096);
  echo $FILE_DATA;
  flush();
  }
...
 

Макс

Старожил PHPClub
как сделать дозакачку с фтп через файл?
причем не используя пример с php.net про ftp_fget и ftp_nb_fget, а через fopen.
в твоем случае есть 2 докачки :
1. когда юзер скачивает файл с сервера (то есть по HTTP-протоколу)
2. когда скрипт скачивает файл с FTP-сервера

первую на форуме уже обсуждали, а вторая - делается через FTP-комманду REST (смотри что шлет твой FTP-менеджер при докачке файлов + RFC по FTP). Через fopen ты ее не сделаешь
(может как-то и можно через контекст, но я с ним не работал), делай через сокеты
 

Space

Новичок
ForJest
сенькс.

Maxim Matyukhin. по HTTP никак. т.к. у меня доступ только по ФТП.
REST - постараюсь найти доку. спасибо.
 

Space

Новичок
Maxim Matyukhin
я извиняюсь.. но я не разобрался с RESTи закачкой файла.
как адаптировать данный пример кода, что бы он качал конкретно названный файл:

PHP:
$fp = fsockopen ($ftp_server, 21, $errno, $errstr, 30);
if($fp){
fputs($fp, "USER $user\n");
fputs($fp, "PASS $pass\n");
fputs($fp, "SYST\n");
fputs($fp, "REST 100\n");
fputs($fp, "REST 0\n");
fputs($fp, "PWD\n");
fputs($fp, "TYPE A\n");


}
какой функцией файл даьше дергать?
 

fixxxer

К.О.
Партнер клуба
ну да, а еще какой то PORT и какой то еще один fsockopen. :)
 

Space

Новичок
Я извиняюсь за непонимание сути FTP-команд и за предоставленный ниже код. Но мне ЖАЛКО юзеров - которые хотят скачать что им надо - но не могут!!!! Т.к. нет дозакачки :(
PHP:
$fp = fsockopen ($ftp_server, 21, $errno, $errstr, 30);
if (!$fp)
 {
 echo "$errstr ($errno)<br>\n";
 }
else
 {
 fputs($fp, "USER $user\n");
 fputs($fp, "PASS $pass\n");
 fputs($fp, "SYST\n");
 fputs($fp, "REST 100\n");
 fputs($fp, "REST 0\n");
 fputs($fp, "PWD\n");
 fputs($fp, "TYPE A\n");
 fputs($fp, "PORT 168,158,20,192,150,4\n");

 if (!$fp)
  {
  echo "$errstr ($errno)<br>\n";
  }
 else
  {
  while(!feof($fp))
   {
   echo fgets ($fp,4096);
    flush();
   }
  }
 fclose ($fp);
 }
данный код не работает. выводит следующее:
220 Welcome to R1.chels.ru FTP service.
331 Please specify the password.
230 Login successful. Have fun.
215 UNIX Type: L8
350 Restart position accepted (100).
350 Restart position accepted (0).
257 "/"
200 Switching to ASCII mode.
500 Illegal PORT command.

fixxxer, я не понял, зачем использовать еще один fsockopen? И, если не трудно, объясни, что значат цифры в команде PORT - я их взял из доки по ФТП.
 

Space

Новичок
Может стоит вместо:
PHP:
 fputs($fp, "PORT 168,158,20,192,150,4\n");
написать что-то вроде этого:
PHP:
 fputs($fp, "PASV\n");
 fputs($fp, "RETR $FILE_NAME\n");
только как тот-же RETR использовать...

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

ЗЫ: я не пойму, почему в нете никто не офишировал подобную проблему. вроде глобально... :))))
 

Макс

Старожил PHPClub
ЖАЛКО юзеров - которые хотят скачать что им надо - но не могут!!!! Т.к. нет дозакачки
если организуешь дозакачку по FTP протоколу, это лишь означает что твой скрипт может, при прерванной связи, начнет скачивать файл с места обрыва, а не с начала.
Для юзеров нужно организовать дозакачку по HTTP-протоколу
 

Space

Новичок
Maxim Matyukhin
тогда я совсем не понимаю...
т.е. сначала надо определить сколько юзер закачал по HTTP и резултат передать на ФТП?
 

Макс

Старожил PHPClub
Space
да, надо синхронизировать дозакачку по обоим протоколам.
 

Space

Новичок
Вот что у меня в результате получилось(прошу не ругать).
Сразу говорю - код как-то странно работает. где ошибки?

PHP:
 $FILE_NAME="".$a[patch_name]."";
 $conn_id = ftp_connect($ftp_server);
 $login_result = ftp_login($conn_id, $user, $pass);

 $FILE_SIZE = ftp_size($conn_id, urldecode($FILE_NAME));
 $FILE_PATCH= "ftp://".$user.":".$pass."@".$ftp_server."/".$FILE_NAME;
 if($FILE_SIZE>0)
  {

  $fd = fopen ($FILE_PATCH, "r");
  $FILE_SIZE = filesize($FILE_PATCH);
  $FILE_TIME = date("D, d M Y H:i:s T", filemtime($FILE_PATCH));

  if($HTTP_SERVER_VARS["HTTP_RANGE"])
   {
   $range = $HTTP_SERVER_VARS["HTTP_RANGE"];
   $range = str_replace("bytes=", "", $range);
   $range = str_replace("-", "", $range);
   if ($range) {fseek($fd, $range);}
   }

  header("Content-Disposition: attachment; filename=$FILE_NAME");
  header("Last-Modified: $FILE_TIME");
  header("Accept-Ranges: bytes");
  header("Content-Length: ".($FILE_SIZE-$range));
  header("Content-Range: bytes $range-".($FILE_SIZE -1)."/".$FILE_SIZE);
  header("Content-type: application/octet-stream");
  $REST_RANGE=$range-($FILE_SIZE -1)."/".$FILE_SIZE;

  $fp = fsockopen ($ftp_server, 21, $errno, $errstr, 30);
  if (!$fp)
   {
   echo "$errstr ($errno)<br>\n";
   }
  else
   {
   fputs($fp, "USER $user\n");
   fputs($fp, "PASS $pass\n");
   fputs($fp, "SYST\n");
   fputs($fp, "REST $REST_RANGE\n");
   fputs($fp, "REST 0\n");
   fputs($fp, "PWD\n");
   fputs($fp, "TYPE A\n");
   fputs($fp, "PASV\n");
   fputs($fp, "RETR $FILE_NAME\n");


  while(!feof($fp))
   {
   echo fgets ($fp,4096);
    flush();
   }
 fclose ($fp);
 }
   }
 else
  {
  print "
  <pre>
  <b>File not found</b>
  </pre>
  ";
  }
мне кажеться дело здесь:
fputs($fp, "REST $REST_RANGE\n");
 

fixxxer

К.О.
Партнер клуба
Господа, думаю, имеет смысл прочитать RFC 959, прежде чем продолжать подобные извращения. После прочтения все станет ясно и про циферки в команде PORT, и про второй fsockopen, и про то, что ручная реализация передачи файла по FTP на PHP без использования команды PASV весьма затруднительнa, и про связь с ответом на последнюю и цифрами в предпоследней.
 

fixxxer

К.О.
Партнер клуба
Кстати говоря - читайте маны, они рулез.

bool [m]ftp_fget[/m] ( resource ftp_stream, resource handle, string remote_file, int mode [, int resumepos])

ftp_fget() retrieves remote_file from the FTP server, and writes it to the given file pointer, handle. The transfer mode specified must be either FTP_ASCII or FTP_BINARY.

Note: The resumepos parameter was added in PHP 4.3.0.
Ну а если религия или хостер не позволяют использовать ftp-функции - тогда вперед, ручками, по rfc...
 

Space

Новичок
fixxxer
Спасибо за линки - щаз будем читать.
по поводу ФТП-функций. меня пров тогда просто убъет :) ведь сначала файл выкачивается с другого ФТП на локальный ФТП - а ведь это мало того трафик - так это и обалденная нагрузка. мой(на своем компе) фтпшник не выдерживал :)))
ладно. за чтение.
 

fixxxer

К.О.
Партнер клуба
Насчет ftp-функций.
Использовать в качеств resource handle fopen("php://stdout"..) тоже религия не позволяет? :)
 

Space

Новичок
fixxxer
мне надо отдавать файл сразу. фтп-функции работают через локалку.
 

fixxxer

К.О.
Партнер клуба
И чем в данном случае не устраивает мое последнее предложение?
 
Сверху