Мощный многопоточный FTP-UPLOADER.

Тема в разделе "Как сделать...", создана пользователем ewg777, 11 дек 2008.

Статус темы:
Закрыта.
  1. ewg777

    ewg777

    Регистр.:
    6 авг 2007
    Сообщения:
    763
    Симпатии:
    321
    Необходим мощный многопоточный FTP-UPLOADER на PHP.

    Пример простейшей фукции upload
    PHP:
    function do_upload($dir 'upload')
    {   
       global 
    $conn_id$ftp_root$transfer_mode$local_dir;
       
    $ftp_dir preg_replace('/^'.$local_dir.'\/?/'''$dir);
       if (
    $ftp_dir != '')
          echo 
    'Папка '$ftp_dir . ((ftp_mkdir($conn_id$ftp_root $ftp_dir)) ? ' создана' ' не создана').'<br />';
       
    $filelist glob(($dir!='') ? $dir.'/*' '*');
       if (
    $filelist == array())
          return 
    0;
       foreach (
    $filelist as $file)
          {
          if (
    is_file($file))
             {
             
    $transfer_mode = (preg_match('/\.(gif|jpg|png)$/'$file)) ? FTP_BINARY FTP_ASCII;
             echo 
    'Файл ' $file . ((ftp_put($conn_id$ftp_root preg_replace('/^'.$local_dir.'\//'''$file), $file$transfer_mode)) ? ' загружен' ' не загружен').'<br />';
             }
          else    
             
    do_upload($file);
          }
       return 
    0;   
    }

    $conn_id ftp_connect($ftp_server);
    $login_result ftp_login($conn_id$ftp_login$ftp_password);
    if (!
    $conn_id || !$login_result)
       exit(
    "Не удалось установить соединение с FTP сервером!\n Попытка подключения к серверу $ftp_server!");
    else
       echo 
    "Установлено соединение с FTP сервером $ftp_server<br>";
    do_upload($local_dir);
    ftp_close($conn_id);
    Заранее спасибо.
     
  2. KillDead

    KillDead

    Регистр.:
    11 авг 2006
    Сообщения:
    890
    Симпатии:
    561
    Многопоточность в пхп- оч больной вопрос;)
    Я недавно, с месяц назад, как раз писал многопоточный аплоад, используя курл.

    Немного ябанутый, т.к вынут без изменения из системы:

    PHP:
    function mk_file(array $array_task_files$ftp){ //попытка мультипотоков отправки файлов
     
     
    global $realpath$ftp_site_id;
     
    sort ($array_task_files['full']);
     
    sort ($array_task_files['normal_file']);
     
    $array_temp_unlink = array();
     
    $count_files count($array_task_files['normal_file']);
     
    //$array_ftp = parse_url($ftp);
     
    for($i=0$i<$count_files$i=$i+10){
      
    $array_task = array();
      if((
    $count_files-$i)<10){
       
    $suc_num $count_files-$i;
      }else{
       
    $suc_num 10;
      }
      for(
    $ii=0$ii<$suc_num$ii++){
     
       
    $fp_new 'fp_'.$ii
     
       
    $name_file$array_task_files['full_real'][$i+$ii];
       $
    $fp_new fopen($name_file'r'); //открываем файл
     
       
    $array_task[$ii]['file_pach']= $array_task_files['normal_file'][$i+$ii];
       
    $array_task[$ii]['file_size']=filesize($name_file);
       
    $array_task[$ii]['file_name']=$name_file;
      }
      foreach (
    $array_task as $id=>$val){
       
    $new_ch 'ch'.$id;
       
    $fp_new 'fp_'.$id;
       $
    $new_ch curl_init();
     
       
    // set URL and other appropriate options
       
    curl_setopt($$new_ch,  CURLOPT_URL$ftp.$array_task[$id]['file_pach']);
       
    //curl_setopt($$new_ch, CURLOPT_HEADER, 1);
       //curl_setopt($ch, CURLOPT_NOBODY , 1);
     
       
    curl_setopt($$new_chCURLOPT_PUT1);
       
    curl_setopt($$new_chCURLOPT_UPLOAD1); // подготавливаем файл к «выгрузке»
       
    curl_setopt($$new_chCURLOPT_INFILE, $$fp_new); // Файл, из которого приходит ввод вашего трансфера
       //curl_setopt($ch, CURLOPT_FTPASCII, 1); // режим ASCII для FTP
     
       
    curl_setopt($$new_chCURLOPT_INFILESIZE$array_task[$id]['file_size']); //возвращаем трансфе вместо печати напрямую
     
       //
      
    }
      
    //create the multiple cURL handle
      
    $mh curl_multi_init();
      foreach (
    $array_task as $id=>$val){
       
    $new_ch 'ch'.$id;
       
    curl_multi_add_handle($mh,$$new_ch);
      }
      
    $running=null;
      do {
       
    curl_multi_exec($mh,$running);
      } while (
    $running 0);
      foreach (
    $array_task as $id=>$val){
       
    $new_ch 'ch'.$id;
       
    $fp_new 'fp_'.$id;
       if(!
    curl_error($$new_ch)){
        
    $fp_histori fopen$realpath."/temp/log_task.LOG""a");
        
    flock($fp_historiLOCK_EX);// запираем от греха
        
    fwrite($fp_histori'$array_spends[\''.$ftp_site_id.'\'][\'file\'][]= \''.$array_task[$id]['file_name'].'\';
        '
    );
        
    flock($fp_historiLOCK_UN); // отпираем файл
        
    fclose($fp_histori);
        
    //файл записан
       
    }
       
    curl_multi_remove_handle($mh,$$new_ch);
       
    fclose($$fp_new);
      }
      
    curl_multi_close($mh);
     
     }
     
     
    }
    Массив $array_task_files это массив со всеми файлами и паками
    PHP:
     
    Array
    (
        [
    pach] => Array
            (
                [
    0] => Все папки
            
    )
        [
    normal_file] => Array
            (
                [
    0] => патч на фтп сервере
            
    )
        [
    full_real] => Array
            (
                [
    0] => абсолютный путь загружаемого файла
            
    )
        [
    full] => Array
            (
                [
    0] => относительный путь загружаемого файла
    )
        [
    file_name] => Array
            (
                [
    0] => имя файла
            
    )
    )
     
     
    Вообще код строится на мультипоточности курла. Можешь поковырять, если нужно могу добавить комментарии.
     
  3. ewg777

    ewg777

    Регистр.:
    6 авг 2007
    Сообщения:
    763
    Симпатии:
    321
    Скрипт кончено не плохой, но ищу что-то более универсальное, без курл. ;)
     
  4. KillDead

    KillDead

    Регистр.:
    11 авг 2006
    Сообщения:
    890
    Симпатии:
    561
    Тогда можно заюзать сокеты. Вот класс, одновременно открывает несколько сокетов
    PHP:
    <? 
    class 
    HttpQueue 

        
    /** 
         * An array of URLs 
         * 
         * @access  private 
         * @var     array 
         */ 
        
    private $_urls = array();  

        
    /** 
         * An array of server sockets 
         * 
         * @access  private 
         * @var     array 
         */ 
        
    private $_sockets = array();  

        
    /** 
         * An array of server responses 
         * 
         * @access  private 
         * @var     array 
         */ 
        
    private $_response = array();  

        
    /** 
         * Socket timeout 
         * 
         * @access  private 
         * @var     integer 
         */ 
        
    private $_timeout 30;  

        
    /** 
         * An array of sockets which can be received 
         * 
         * @access  private 
         * @var     array 
         */ 
        
    private $_read = array();  

        
    /** 
         * An array of sockets which can be sended 
         * 
         * @access  private 
         * @var     array 
         */ 
        
    private $_write = array();  

        
    /** 
         * Adds an URL into a tasklist 
         * 
         * @access  public 
         * @param   string  $method 
         * @param   string  $url 
         * @return  void 
         */ 
        
    public function add($method$url
        { 
            
    $this->_urls[] = array(strtoupper($method), $this->_parseUrl($url)); 
        }  

        
    /** 
         * Parses requested URL and checks for all URL parts 
         * 
         * @access  private 
         * @param   string   $url 
         * @return  array 
         */ 
        
    private function _parseUrl($url
        { 
            
    $parts parse_url($url); 
            
    $parts['port'] = array_key_exists(’port’$parts) ? $parts['port'] : 80
            
    $parts['sock'] = sprintf(%s:%s’$parts['host'], $parts['port']); 
            
    $parts['request'] = sprintf(%s?%s’$parts['path'], $parts['query']); 
            return 
    $parts
        }  

        
    /** 
         * Starts fetch process 
         * 
         * @access  public 
         * @param   void 
         * @return  array 
         */ 
        
    public function fetch() 
        { 
            
    $this->_create(); 
            
    $this->_process(); 
            return 
    $this->toArray(); 
        }  

        
    /** 
         * Sets socket timeout (in seconds) 
         * 
         * @access  public 
         * @param   integer  $timeout 
         * @return  void 
         */ 
        
    public function setTimeout($timeout
        { 
            
    $this->_timeout $timeout
        }  

        
    /** 
         * Returns array of server responses 
         * 
         * @access  public 
         * @param   void 
         * @return  array 
         */ 
        
    public function toArray() 
        { 
            return 
    $this->_response
        }  

        
    /** 
         * Creates socket conenctions with hosts given in URL 
         * 
         * @access  private 
         * @param   void 
         * @return  void 
         */ 
        
    private function _create() 
        { 
            foreach (
    $this->_urls as $id => $connect) { 
                if (
    $socket = @stream_socket_client($connect[1]['sock'], $errno
                    
    $errstr$this->_timeout
                    
    STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT)  ) { 
                    
    $this->_sockets[$id] = $socket
                    
    $this->_response[$id]  = ‘processing’
                    continue; 
                }  

                
    $this->_response[$id] = “failed$errno $errstr”
            } 
        }  

        
    /** 
         * Process opened sockets 
         * 
         * @access  private 
         * @param   void 
         * @return  void 
         */ 
        
    private function _process() 
        { 
            while (
    count($this->_sockets)) { 
                
    $this->_read  $this->_sockets
                
    $this->_write $this->_sockets;  

                
    $select stream_select($this->_read$this->_write$e null
                                        
    $this->_timeout);  

                if (
    $select 0) { 
                    
    $this->_read(); 
                    
    $this->_write(); 
                }  

                else { 
                    foreach (
    $this->_sockets as $id => $s) { 
                        
    $this->_response[$id] = ‘Timed out’
                    }  

                    break; 
                } 
            } 
        }  

        
    /** 
         * Receives data from readable socket 
         * 
         * @access  private 
         * @param   void 
         * @return  void 
         */ 
        
    private function _read() 
        { 
            foreach (
    $this->_read as $fp) { 
                
    $id array_search($fp$this->_sockets); 
                
    $data fread($fp8192);  

                if (
    strlen($data) == 0) { 
                    if (
    $this->_response[$id] == ‘processing’) { 
                        
    $this->_response[$id] = ‘failed to connect’
                    }  

                    
    fclose($fp); 
                    unset(
    $this->_sockets[$id]); 
                }  

                else { 
                    
    $this->_response[$id].= $data
                } 
            } 
        }  

        
    /** 
         * Sends HTTP request into writeable socket 
         * 
         * @access  private 
         * @param   void 
         * @return  void 
         */ 
        
    private function _write() 
        { 
            foreach (
    $this->_write as $fp) { 
                
    $id array_search($fp$this->_sockets); 
                
    $method  $this->_urls[$id][0]; 
                
    $request $this->_urls[$id][1]['request']; 
                
    $host    $this->_urls[$id][1]['host'];  

                
    fputs($fp“$method $request HTTP/1.0rn”); 
                
    fputs($fp“Host$hostrnrn”);  

                
    $this->_response[$id] = 
            } 
        } 

    ?> 
    А вообще на php многопоточности нет, есть только симуляция.
     
  5. Juri

    Juri

    Заблокирован
    Регистр.:
    5 окт 2007
    Сообщения:
    1.065
    Симпатии:
    197
    а можно комментарии к скирпту с курл, заранее спасибо
     
Статус темы:
Закрыта.