<?php

/**
* This class extends of HTTP_Request_Listener and used by HTTP_Sync
* for download and save safely without corrupt of existing file
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt.  If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category   HTTP
* @package    HTTP_Sync
* @author     Ildar N. Shaimordanov <ildar-sh@mail.ru>
* @license    http://www.php.net/license/3_0.txt  PHP License 3.0
*/

require_once 'HTTP/Request/Listener.php';

// {{{

class HTTP_Sync_Download extends HTTP_Request_Listener
{

    
// {{{

    /*
    * Handle for the target file
    * @var int
    */
    
var $_fp false;

    
// }}}
    // {{{

    /*
    * Name of the target file
    * @var string
    */
    
var $_target false;

    
// }}}
    // {{{

    /*
    * Name of the temporary file
    * @var string
    */
    
var $_tmp false;

    
// }}}
    // {{{

    /*
    * Number of bytes received so far
    * @var int
    */
    
var $_size 0;

    
// }}}
    // {{{

    /*
    * Constructor
    *
    * Creates the listener
    *
    * @param   string $target The filename (including path) where the remote source would be saved
    *
    * @access  public
    */
    
function HTTP_Sync_Download($target=false)
    {
        
$this->HTTP_Request_Listener();
        
$this->_target $target;
    }

    
// }}}
    // {{{

    /*
    * Stores the target filename
    * and opens the temporary file for downloading
    *
    * @param   string $target Target filename
    *
    * @result  void
    *
    * @throws  PEAR_Error
    * @access  public
    */
    
function setTarget($target)
    {
        if ( empty(
$target) ) {
            return;
        }
        
$this->_target $target;

        require_once 
'System.php';
        
$this->_tmp System::mktemp();
        
$this->_fp = @fopen($this->_tmp'wb');
        if ( 
$this->_fp ) {
            @
flock($this->_fpLOCK_EX);
            return;
        }
        
$this->raiseError('Cannot open temp ' $this->_tmp);
    }

    
// }}}
    // {{{

    /*
    * This method is called when Listener is notified of an event
    *
    * @param   object $subject An object the listener is attached to
    * @param   string $event Event name
    * @param   mixed $data Additional data
    *
    * @result  void
    *
    * @access  public
    */
    
function update(&$subject$event$data null)
    {
        switch (
$event) {
        case 
'sentRequest':

            
// Try target from URL
            
$url_target basename($subject->_url->path);
            if ( empty(
$this->_target) && ! empty($url_target) ) {
                
$this->_target $url_target;
            }

            break;

        case 
'gotHeaders':

            
// Try target from response
            
if (
                (isset(
$data['content-disposition']) && preg_match('/filename="([^"]+)"/'$data['content-disposition'], $matches))
                || 
                (isset(
$data['content-type']) && preg_match('/name="([^"]+)"/'$data['content-type'], $matches)) 
            ) {
                
$this->_target basename($matches[1]);
            }
            
$this->setTarget($this->_target);
            
$this->_size 0;

            break;

        case 
'tick':
        case 
'gzTick':

            if ( 
$this->_fp ) {
                
$this->_size += strlen($data);
                @
fwrite($this->_fp$data);
            }

            break;

        case 
'gotBody':

            if ( 
$this->_fp ) {
                @
flock($this->_fpLOCK_UN);
                @
fclose($this->_fp);

                
$result = @copy($this->_tmp$this->_target);
                if ( ! 
$result ) {
                    
$this->raiseError('Cannot save ' $this->_target);
                }
            }

            break;

        default:

            
$this->raiseError('Unhandled event ' $event);

        } 
// switch
    
}

    
// }}}
    // {{{

    
function raiseError($message)
    {
        include_once 
'PEAR.php';
        return 
PEAR::raiseError(__CLASS__ ' ' $message);
    }

    
// }}}

}

// }}}

?>