Changeset 27 for trunk

Show
Ignore:
Timestamp:
20.07.2005 22:33:40 (3 years ago)
Author:
m
Message:

Code cleanups

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/File/Bittorrent/MakeTorrent.php

    r26 r27  
    1515// | license@php.net so we can mail you a copy immediately.                 | 
    1616// +------------------------------------------------------------------------+ 
    17 // | Author: Justin Jones <j.nagash@gmail.com>                              | 
     17// | Authors                                                                | 
     18// |   Justin Jones <j.nagash@gmail.com>                                    | 
     19// |   Markus Tacker <m@tacker.org>                                         | 
    1820// +------------------------------------------------------------------------+ 
    1921// 
     
    2527 * from Bram Cohen's original BT client. 
    2628 * 
     29 * @author Justin Jones <j.nagash@gmail.com> 
     30 * @author Markus Tacker <m@tacker.org> 
     31 * @version $Id$ 
    2732 * @package File_Bittorrent 
    2833 * @category File 
     34 */ 
     35  
     36/** 
     37 * Include required classes 
     38 */ 
     39require_once 'PEAR.php'; 
     40require_once 'File/Bittorrent/Encode.php'; 
     41 
     42/** 
     43 * Provides a class for making .torrent files 
     44 * from a file or directory. Produces virtually 
     45 * identical torrent files as btmaketorrent.py 
     46 * from Bram Cohen's original BT client. 
    2947 * 
    30  * @author  Justin Jones <j.nagash@gmail.com> 
    31  * 
     48 * @author Justin Jones <j.nagash@gmail.com> 
     49 * @author Markus Tacker <m@tacker.org> 
    3250 * @version $Id$ 
    33  */ 
    34  
    35 /** 
    36  * Creates .torrent files 
    37  * 
    3851 * @package File_Bittorrent 
    3952 * @category File 
     
    4255{ 
    4356    /** 
    44      * Path to the file or directory to create the 
    45      * torrent from. 
    46      * 
    47      * @var string 
    48      */ 
    49     var $path = ''; 
    50  
    51     /** 
    52      * Whether or not $path is a file 
    53      * 
    54      * @var bool 
    55      */ 
    56     var $_isFile = false; 
    57  
    58     /** 
    59      * Where or not $path is a directory 
    60      * 
    61      * @var bool 
    62      */ 
    63     var $_isDir = false; 
    64  
    65     /** 
    66      * The .torrent info dictionary 
    67      * 
    68      * @var array 
    69      */ 
    70     var $info = array(); 
    71  
    72     /** 
    73      * The .torrent announce URL 
    74      * 
    75      * @var string 
    76      */ 
    77     var $announce = ''; 
    78  
    79     /** 
    80      * The .torrent announce_list extension 
    81      * 
    82      * @var array 
    83      */ 
    84     var $announce_list = array(); 
    85  
    86     /** 
    87      * The .torrent creation timestamp 
    88      * 
    89      * @var int 
    90      */ 
    91     var $creation_date = 0; 
    92  
    93     /** 
    94      * The .torrent comment 
    95      * 
    96      * @var string 
    97      */ 
    98     var $comment = ''; 
    99  
    100     /** 
    101      * The .torrent created by string 
    102      * 
    103      * @var string 
    104      */ 
    105     var $created_by = 'File_Bittorrent_MakeTorrent $Rev$'; 
    106  
    107     /** 
    108      * The .torrent suggested name (file/dir) 
    109      * 
    110      * @var string 
    111      */ 
    112     var $name = ''; 
    113  
    114     /** 
    115      * The .torrent packed piece data 
    116      * 
    117      * @var string 
    118      */ 
    119     var $pieces = ''; 
    120  
    121     /** 
    122      * The .torrent piece length 
    123      * The size of each piece in bytes. 
    124      * 
    125      * @var int 
    126      */ 
    127     var $piece_length = 524288; 
    128  
    129     /** 
    130      * The list of files (if this is 
    131      * a multi-file torrent) 
    132      * 
    133      * @var array 
    134      */ 
    135     var $files = array(); 
    136  
    137     /** 
    138      * The data gap used to join two 
    139      * files into the same piece 
    140      * 
    141      * @var mixed string if it contains data or boolean false 
    142      */ 
    143     var $data_gap = false; 
     57     * @var string Path to the file or directory to create the torrent from. 
     58     * @access private 
     59     */ 
     60    var $_path = ''; 
     61 
     62    /** 
     63     * @var bool Whether or not $path is a file 
     64     * @access private 
     65     */ 
     66    var $_is_file = false; 
     67 
     68    /** 
     69     * @var bool Where or not $path is a directory 
     70     */ 
     71    var $_is_dir = false; 
     72 
     73    /** 
     74     * @var string The .torrent announce URL 
     75     * @access private 
     76     */ 
     77    var $_announce = ''; 
     78 
     79    /** 
     80     * @var array The .torrent announce_list extension 
     81     * @access private 
     82     */ 
     83    var $_announce_list = array(); 
     84 
     85    /** 
     86     * @var string The .torrent comment 
     87     * @access private 
     88     */ 
     89    var $_comment = ''; 
     90 
     91    /** 
     92     * @var string The .torrent created by string 
     93     * @access private 
     94     */ 
     95    var $_created_by = 'File_Bittorrent_MakeTorrent $Rev$. http://pear.php.net/package/File_Bittorrent'; 
     96     
     97    /** 
     98     * @var string The .torrent suggested name (file/dir) 
     99     * @access private 
     100     */ 
     101    var $_name = ''; 
     102 
     103    /** 
     104     * @var string The .torrent packed piece data 
     105     * @access private 
     106     */ 
     107    var $_pieces = ''; 
     108 
     109    /** 
     110     * @var int The size of each piece in bytes. 
     111     * @access private 
     112     */ 
     113    var $_piece_length = 524288; 
     114 
     115    /** 
     116     * @var array The list of files (if this is a multi-file torrent) 
     117     * @access private 
     118     */ 
     119    var $_files = array(); 
     120 
     121    /** 
     122     * @var string|false The data gap used to join two files into the same piece. string if it contains data or false 
     123     * @access private 
     124     */ 
     125    var $_data_gap = false; 
     126     
     127    /** 
     128    * @var resource file pointer 
     129    * @access private 
     130    */ 
     131    var $_fp; 
    144132 
    145133    /** 
     
    150138     * 
    151139     * @param string Path to use 
    152      * @return voide 
    153      * @access public 
    154140     */ 
    155141    function File_Bittorrent_MakeTorrent($path) 
    156142    { 
    157         $this->path = $path; 
    158         if (is_dir($path)) { 
    159             $this->_isDir = true; 
    160             $this->name = basename($path); 
    161         } else if (is_file($path)) { 
    162             $this->_isFile = true; 
    163             $this->name = basename($path); 
    164         } else { 
    165             $this->path = ''; 
    166         } 
     143        $this->setPath($path); 
    167144    } 
    168145 
     
    172149     * 
    173150     * @param string announce url 
    174      * @return void 
    175      * @access public 
     151     * @return bool 
    176152     */ 
    177153    function setAnnounce($announce) 
    178154    { 
    179         $this->announce = strval($announce); 
     155        $this->_announce = strval($announce); 
     156        return true; 
    180157    } 
    181158 
     
    185162     * 
    186163     * @param array announce list 
    187      * @return void 
    188      * @access public 
     164     * @return bool 
    189165     */ 
    190166    function setAnnounceList($announce_list) 
    191167    { 
    192         if (is_array($announce_list)) 
    193         { 
    194             $this->announce_list = $announce_list; 
    195         } 
     168        if (!is_array($announce_list)) { 
     169            PEAR::raiseError(__CLASS__ . '::'. __FUNCTION__ . '() - No array given.'); 
     170            return false; 
     171        } 
     172        $this->_announce_list = $announce_list; 
     173        return true; 
    196174    } 
    197175 
     
    201179     * 
    202180     * @param string comment 
    203      * @return void 
    204      * @access public 
     181     * @return bool 
    205182     */ 
    206183    function setComment($comment) 
    207184    { 
    208         $this->comment = strval($comment); 
    209     } 
    210  
    211     /** 
    212      * Function to set the created by timestamp 
    213      * for the .torrent file. If you don't want 
    214      * to use the servers current timestamp 
    215      * 
    216      * @param int timestamp 
    217      * @return void 
    218      * @access public 
    219      */ 
    220     function setCreatedBy($created_by) 
    221     { 
    222         $this->created_by = strval($created_by); 
     185        $this->_comment = strval($comment); 
     186        return true; 
    223187    } 
    224188 
     
    229193     * 
    230194     * @param string path to file/dir 
    231      * @return void 
    232      * @access public 
     195     * @return bool 
    233196     */ 
    234197    function setPath($path) 
    235198    { 
    236         $this->path = $path; 
     199        $this->_path = $path; 
    237200        if (is_dir($path)) { 
    238             $this->_isDir = true; 
    239             $this->name = basename($path); 
     201            $this->_is_dir = true; 
     202            $this->_name = basename($path); 
    240203        } else if (is_file($path)) { 
    241             $this->_isFile = true; 
    242             $this->name = basename($path); 
     204            $this->_is_file = true; 
     205            $this->_name = basename($path); 
    243206        } else { 
    244             $this->path = ''; 
    245         } 
     207            $this->_path = ''; 
     208        } 
     209        return true; 
    246210    } 
    247211 
     
    252216     * 
    253217     * @param int piece length in kilobytes 
    254      * @return void 
    255      * @access public 
     218     * @return bool 
    256219     */ 
    257220    function setPieceLength($piece_length) 
    258221    { 
    259         if ($piece_length >= 32 && $piece_length <= 4096) { 
    260             $this->piece_length = $piece_length * 1024; 
    261         } 
     222        if ($piece_length < 32 or $piece_length > 4096) { 
     223            PEAR::raiseError(__CLASS__ . '::'. __FUNCTION__ . '() - Invalid piece lenth: "' . $piece_length . '"'); 
     224            return false; 
     225        } 
     226        $this->_piece_length = $piece_length * 1024; 
     227        return true; 
    262228    } 
    263229 
     
    268234     * 
    269235     * @return mixed false on failure or a string containing the metainfo 
    270      * @access public 
    271236     */ 
    272237    function buildTorrent() 
    273238    { 
    274         if ($this->_isFile) { 
    275             $info = $this->_addFile($this->path); 
    276             if ($info !== false) { 
    277                 $metainfo = $this->_encodeTorrent($info); 
    278                 return $metainfo; 
    279             } 
    280         } else if ($this->_isDir) { 
    281             $diradd_ok = $this->_addDir($this->path); 
    282             if ($diradd_ok !== false) { 
    283                 $metainfo = $this->_encodeTorrent(); 
    284                 return $metainfo; 
    285             } 
    286         } else { 
    287             return false; 
    288         } 
     239        if ($this->_is_file) { 
     240            if (!$info = $this->_addFile($this->_path)) { 
     241                return false; 
     242            } 
     243            if (!$metainfo = $this->_encodeTorrent($info)) { 
     244                return false; 
     245            }             
     246        } else if ($this->_is_dir) { 
     247            if (!$diradd_ok = $this->_addDir($this->_path)) { 
     248                return false; 
     249            } 
     250            $metainfo = $this->_encodeTorrent(); 
     251        } 
     252        return $metainfo; 
    289253    } 
    290254 
     
    299263    function _encodeTorrent($info = array()) 
    300264    { 
    301         require_once 'File/Bittorrent/Encode.php'; 
    302         $benc = new File_Bittorrent_Encode; 
    303  
    304265        $bencdata = array(); 
    305266        $bencdata['info'] = array(); 
    306         if ($this->_isFile) { 
     267        if ($this->_is_file) { 
    307268            $bencdata['info']['length'] = $info['length']; 
    308269            $bencdata['info']['md5sum'] = $info['md5sum']; 
    309         } else if ($this->_isDir) { 
    310             if ($this->data_gap !== false) { 
    311                 $this->pieces .= pack('H*', sha1($this->data_gap)); 
    312                 $this->data_gap = false; 
    313             } 
    314             $bencdata['info']['files'] = $this->files; 
     270        } else if ($this->_is_dir) { 
     271            if ($this->_data_gap !== false) { 
     272                $this->_pieces .= pack('H*', sha1($this->_data_gap)); 
     273                $this->_data_gap = false; 
     274            } 
     275            $bencdata['info']['files'] = $this->_files; 
    315276        } else { 
     277            PEAR::raiseError(__CLASS__ . '::'. __FUNCTION__ . '() - Use ' .  __CLASS__ . '::setPath() to define a file or directory.'); 
    316278            return false; 
    317279        } 
    318         $bencdata['info']['name'] = $this->name; 
    319         $bencdata['info']['piece length'] = $this->piece_length; 
    320         $bencdata['info']['pieces'] = $this->pieces; 
    321         $bencdata['announce'] = $this->announce; 
    322         //$bencdata['announce-list'] = array($this->announce) 
    323         $bencdata['creation date'] = time(); 
    324         $bencdata['comment'] = $this->comment; 
    325         $bencdata['created by'] = $this->created_by; 
    326         return $benc->encode_array($bencdata); 
     280        $bencdata['info']['name']         = $this->_name; 
     281        $bencdata['info']['piece length'] = $this->_piece_length; 
     282        $bencdata['info']['pieces']       = $this->_pieces; 
     283        $bencdata['announce']             = $this->_announce; 
     284        $bencdata['creation date']        = time(); 
     285        $bencdata['comment']              = $this->_comment; 
     286        $bencdata['created by']           = $this->_created_by; 
     287        // $bencdata['announce-list'] = array($this->_announce) 
     288        // Encode it 
     289        $Encoder = new File_Bittorrent_Encode; 
     290        return $Encoder->encode_array($bencdata); 
    327291    } 
    328292 
     
    333297     * @param string path to the file 
    334298     * @return mixed false on failure or file metainfo data 
    335     * @access private 
    336     */ 
     299    * @access private 
     300    */ 
    337301    function _addFile($file) 
    338302    { 
    339         $fp = &File_Bittorrent_MakeTorrent::_openfile($file); 
    340         if ($fp) { 
    341             $filelength = 0; 
    342             $md5sum = md5_file($file); 
    343             $piece_length = $this->piece_length; 
    344  
    345             while (!feof($fp)) { 
    346                 $data = ''; 
    347                 $datalength = 0; 
    348  
    349                 if ($this->_isDir && $this->data_gap !== false) { 
    350                     $data = $this->data_gap; 
    351                     $datalength = strlen($data); 
    352                     $this->data_gap = false; 
     303        if (!$this->_openFile($file)) return false; 
     304         
     305        $filelength = 0; 
     306        $md5sum = md5_file($file); 
     307 
     308        while (!feof($this->_fp)) { 
     309            $data = ''; 
     310            $datalength = 0; 
     311 
     312            if ($this->_is_dir && $this->_data_gap !== false) { 
     313                $data = $this->_data_gap; 
     314                $datalength = strlen($data); 
     315                $this->_data_gap = false; 
     316            } 
     317 
     318            while (!feof($this->_fp) && ($datalength < $this->_piece_length)) { 
     319                $readlength = 8192; 
     320                if (($datalength + 8192) > $this->_piece_length) { 
     321                    $readlength = $this->_piece_length - $datalength; 
    353322                } 
    354323 
    355                 while ( !feof($fp) && ($datalength < $piece_length) ) { 
    356                     $readlength = 8192; 
    357                     if ( ($datalength + 8192) > $piece_length ) { 
    358                         $readlength = $piece_length - $datalength; 
    359                     } 
    360  
    361                     $tmpdata = fread($fp, $readlength); 
    362                     $actual_readlength = strlen($tmpdata); 
    363                     $datalength += $actual_readlength; 
    364                     $filelength += $actual_readlength; 
    365  
    366                     $data .= $tmpdata; 
    367  
    368                     flush(); 
     324                $tmpdata = fread($this->_fp, $readlength); 
     325                $actual_readlength = strlen($tmpdata); 
     326                $datalength += $actual_readlength; 
     327                $filelength += $actual_readlength; 
     328 
     329                $data .= $tmpdata; 
     330 
     331                flush(); 
     332            } 
     333 
     334            // We've either reached the end of the file, or 
     335            // we have a whole piece, or both. 
     336            if ($datalength == $this->_piece_length) { 
     337                // We have a piece. 
     338                $this->_pieces .= pack('H*', sha1($data)); 
     339            } 
     340            if (($datalength != $this->_piece_length) && feof($this->_fp)) { 
     341                // We've reached the end of the file, and 
     342                // we dont have a whole piece. 
     343                if ($this->_is_dir) { 
     344                    $this->_data_gap = $data; 
     345                } else { 
     346                    $this->_pieces .= pack('H*', sha1($data)); 
    369347                } 
    370  
    371                 /* We've either reached the end of the file, or 
    372                  * we have a whole piece, or 
    373                  * both. 
    374                  */ 
    375                 if ($datalength == $piece_length) { 
    376                     // We have a piece. 
    377                     $this->pieces .= pack('H*', sha1($data)); 
    378                 } 
    379                 if ( ($datalength != $piece_length) && feof($fp) ) { 
    380                     // We've reached the end of the file, and 
    381                     // we dont have a whole piece. 
    382                     if ($this->_isDir) { 
    383                         $this->data_gap = $data; 
    384                     } else { 
    385                         $this->pieces .= pack('H*', sha1($data)); 
    386                     } 
    387                 } 
    388             } 
    389             // Close the file pointer. 
    390             File_Bittorrent_MakeTorrent::_closefile($fp); 
    391             $info = array( 
    392                     'length' => $filelength, 
    393                     'md5sum' => $md5sum 
    394                     ); 
    395             return $info; 
    396         } 
    397         return false; 
     348            } 
     349        } 
     350 
     351        // Close the file pointer. 
     352        $this->_closeFile(); 
     353        $info = array( 
     354            'length' => $filelength, 
     355            'md5sum' => $md5sum 
     356        ); 
     357        return $info; 
    398358    } 
    399359 
     
    418378                $filedata['path'][] = basename($file); 
    419379                $dirname = dirname($file); 
    420                 while ( basename($dirname) != $this->name ) { 
     380                while (basename($dirname) != $this->_name) { 
    421381                    $filedata['path'][] = basename($dirname); 
    422382                    $dirname = dirname($dirname); 
    423383                } 
    424384                $filedata['path'] = array_reverse($filedata['path'], false); 
    425                 $this->files[] = $filedata; 
     385                $this->_files[] = $filedata; 
    426386            } 
    427387        } 
     
    446406            if ($dh = opendir($current_dir)) { 
    447407                while ( ($file = readdir($dh)) !== false ) { 
    448                     if ($file !== '.' && $file !== '..') { 
    449                         $current_file = $current_dir . '/' . $file; 
    450  
    451                         if ( is_file($current_file) ) { 
    452                             $file_list[] = $current_dir . '/' . $file; 
    453                         } else if ( is_dir($current_file) ) { 
    454                             $stack[] = $current_file; 
    455                         } 
     408                    if ($file{0} =='.') continue; 
     409                    $current_file = $current_dir . '/' . $file; 
     410                    if (is_file($current_file)) { 
     411                        $file_list[] = $current_dir . '/' . $file; 
     412                    } else if (is_dir($current_file)) { 
     413                        $stack[] = $current_file; 
    456414                    } 
    457415                } 
     
    469427     * @access private 
    470428     */ 
    471     function _filesize($file) { 
     429    function _filesize($file) 
     430    { 
    472431        $size = @filesize($file); 
    473432        if ($size == 0) { 
    474             $size = exec('du -b "'.$file.'"'); 
     433            if (PHP_OS != 'Linux') return false;  
     434            $size = exec('du -b ' . escapeshellarg($file)); 
    475435        } 
    476436        return $size; 
     
    482442     * 
    483443     * @param string path to the file 
    484      * @return mixed file pointer or false 
    485      * @access private 
    486      */ 
    487     function &_openfile($file) { 
    488         $fsize = File_Bittorrent_MakeTorrent::_filesize($file); 
     444     * @return bool 
     445     * @access private 
     446     */ 
     447    function _openFile($file) 
     448    { 
     449        $fsize = $this->_filesize($file); 
    489450        if ($fsize <= 2*1024*1024*1024) { 
    490             $fp = fopen($file, 'r'); 
     451            if (!$this->_fp = fopen($file, 'r')) { 
     452                PEAR::raiseError(__CLASS__ . '::'. __FUNCTION__ . '() - Failed to open "' . $file . '"'); 
     453                return false; 
     454            } 
    491455            $this->_fopen = true; 
    492456        } else { 
    493             $fp = popen('cat "'.$file.'"', 'r'); 
     457            if (PHP_OS != 'Linux') { 
     458                PEAR::raiseError(__CLASS__ . '::'. __FUNCTION__ . '() - File size is greater than 2GB. This is only supported under Linux.'); 
     459                return false; 
     460            } 
     461            $this->_fp = popen('cat ' . escapeshellarg($file), 'r'); 
    494462            $this->_fopen = false; 
    495463        } 
    496         return $fp; 
     464        return true; 
    497465    } 
    498466 
     
    500468     * Internal function to close a file pointer 
    501469     * 
    502      * @param resource File Pointer 
    503      * @access private 
    504      */ 
    505     function _closefile(&$fp) 
    506     { 
    507         if ($this->_fopen == true) { 
    508             fclose($fp); 
    509         } else { 
    510             pclose($fp); 
     470     * @access private 
     471     */ 
     472    function _closeFile() 
     473    { 
     474        if ($this->_fopen) { 
     475            fclose($this->_fp); 
     476        } else { 
     477            pclose($this->_fp); 
    511478        } 
    512479    }