<?php

/**
 * Goweb Sitemanager 5 Framework
 *
 * @version    5.0.0
 * @category   Goweb
 * @package    Goweb_Ftp
 * @author     I&D <dev@goweb.pt>, Pedro Pinto <ppinto@goweb.pt>
 * @copyright  2009 (c) Goweb (http://www.goweb.pt)
 */

goweb::loadClass('Goweb_Ftp_Abstract');

if (!function_exists('ftp_connect')){
    throw new Goweb_Exception('Sem extensão ftp');
}

/**
 *
 * @version    5.0.0
 * @category   Goweb
 * @package    Goweb_Ftp
 * @author     I&D <dev@goweb.pt>, Pedro Pinto <ppinto@goweb.pt>
 * @copyright  2009 (c) Goweb (http://www.goweb.pt)
 */
class Goweb_Ftp_Native extends Goweb_Ftp_Abstract {
    
    /**
     * Efectuar a ligação ao servidor ftp
     *
     * @param String $host
     * @param int $port
     * @param int $timeout
     * @param boolean $ssl
     */
    protected function _connect($host, $port = 21, $timeout = 90, $ssl = false){
        if (!$ssl) {
            $this->_connection = @ftp_connect($host, $port, $timeout);
        } else {
            $this->_connection = @ftp_ssl_connect($host, $port, $timeout);
        }
    }
    
    /**
     * Efectuar o login no servidor ftp
     *
     * @param String $user
     * @param String $password
     */
    protected function _login($user = 'anonymous', $password = 'anonymous@goweb.pt'){
        if (!@ftp_login($this->_connection, $user, $password)) {
            $this->_error = self::ERROR_INVALID_LOGIN;
            $this->_close();
            throw new Goweb_Exception('Invalid user name or password');
        }
    }
    
    /**
     * Change directory
     *
     * @param string $path
     */
    protected function _chdir($path = false){
        if ($path) {
            if (!@ftp_chdir($this->_connection, $path)) {
                $this->_error = self::ERROR_INVALID_PATH;
                $this->_close();
                throw new Goweb_Exception('Invalid path');
            }
        }
    }
    
    /**
     * Usar modo passivo
     *
     * @param boolean $flag
     */
    protected function _passive($flag = true){
        if (!@ftp_pasv($this->_connection, $flag)) {
            $this->_error = self::ERROR_INVALID_MODE;
            $this->_close();
            throw new Goweb_Exception('Invalid file transfer mode');
        }
        $this->_passiveMode = $flag;
    }
    
    /**
     * Fechar ligação
     *
     * @return boolean
     */
    protected function _close(){
        return @ftp_close($this->_connection);
    }
    
    /**
     * Get current working directory
     *
     * @return string
     */
    protected function _pwd(){
        return @ftp_pwd($this->_connection);
    }

    /**
     * Change current working directory
     *
     * @param string $dir
     * @return boolean
     */
    protected function _cd($dir){
        return @ftp_chdir($this->_connection, $dir);
    }
    
    /**
     * Ler um ficheiro para uma string, ficheiro ou stream
     *
     * @param string $filename
     * @param string|resource|null $dest nome do ficheiro de destino, stream, ou se for null vai retornar o conteudo do ficheiro
     * @return string
     */
    protected function _read($filename, $dest=null){
        if (is_string($dest)) {
            $result = ftp_get($this->_connection, $dest, $filename, $this->_config['file_mode']);
        } else {
            if (is_resource($dest)) {
                $stream = $dest;
            } elseif (is_null($dest)) {
                $stream = tmpfile();
            } else {
                $this->_error = self::ERROR_INVALID_DESTINATION;
                return false;
            }

            $result = ftp_fget($this->_connection, $stream, $filename, $this->_config['file_mode']);

            if (is_null($dest)) {
                fseek($stream, 0);
                $result = '';
                for ($result = ''; $s = fread($stream, 4096); $result .= $s);
                fclose($stream);
            }
        }
        return $result;
    }
    
    /**
     * Gravar um ficheiro de uma string, outro ficheiro ou stream
     *
     * @param string $filename
     * @param string|resource $src filename, dados ou stream de origem
     * @return int|boolean
     */
    protected function _write($filename, $src, $mode=null){
        if (is_string($src) && is_readable($src)) {
            return @ftp_put($this->_connection, $filename, $src, $this->_config['file_mode']);
        } else {
            if (is_string($src)) {
                $stream = tmpfile();
                fputs($stream, $src);
                fseek($stream, 0);
            } elseif (is_resource($src)) {
                $stream = $src;
            } else {
                $this->_error = self::ERROR_INVALID_SOURCE;
                return false;
            }

            $result = ftp_fput($this->_connection, $filename, $stream, $this->_config['file_mode']);
            if (is_string($src)) {
                fclose($stream);
            }
            return $result;
        }
    }
    
    /**
     * Apagar um ficheiro
     *
     * @param string $filename
     * @return boolean
     */
    protected function _rm($filename){
        return @ftp_delete($this->_connection, $filename);
    }

        
    /**
     * Renomear ou mover um directório ou ficheiro
     *
     * @param string $src
     * @param string $dest
     * @return boolean
     */
    protected function _mv($src, $dest){
        return @ftp_rename($this->_connection, $src, $dest);
    }
    
    /**
     * Listar a directório corrente
     *
     * @return array
     */
    protected function _ls(){
        $ls = @ftp_nlist($this->_connection, '.');
        
        $list = array();
        foreach ($ls as $file) {
            if (!in_array($file, array('.', '..'))){
                $list[] = $file;
            }
        }

        return $list;
    }

    /**
     * Criar directório
     *
     * @param string $path
     * @return boolean
     */
    protected function _mkdir($dir){
        return @ftp_mkdir($this->_connection, $dir);
    }
    
    /**
     * Configurar permissões de ficheiro ou directório
     *
     * @param int $mode
     * @param string $dir
     * @return boolean
     */
    protected function _chmod($mode=0777, $dir){
        return @ftp_chmod($this->_connection, $mode, $dir);
    }

    /**
     * Verificar se um ficheiro existe,
     * e retorna o nome do mesmo(útil para wildcards, em que retorna o primeiro encontrado)
     *
     * @param String $filesearch
     * @return bool|String
     */
    protected function _fileExists($filesearch){

        if(empty($filesearch)) {
            $this->print_err('Por favor introduza o caminho para o ficheiro');
            return false;
        }

        $filelist = ftp_nlist($this->_connection, $filesearch);   

        if ( $filelist === false )
        {
            return false;
        }
        
        /**
         * Verificar se o ficheiro existe, mesmo para algumas respostas inválidas de alguns servidores FTP
         */
        if ( !count($filelist) || ftp_size($this->_connection, $filelist[0]) == -1 )
        {
            return false;
        }
        return $filelist[0];
    }

    /**
     * Obter conteudo de um ficheiro remoto sem efectuar a transferência, se possivel
     *
     * @param String $filename caminho para o ficheiro a efectuar a transferência
     * @return bool|String
     */
    protected function _getFileContents($filename){
        
        if (!$this->_fileExists($filename)){
            return false;
        }
        $url = 'ftp://' . $this->_config['username'] . ':' . $this->_config['password'] . '@' . $this->_config['host'];
        
        if ($this->_config['port'] != '21') {
            $url .= ':' . $this->_config['port'];
        }
        if (substr($filename,0,1) != '/') {
            $url .= '/';
        }
        $url .= $filename;
        
        if ($this->_passiveMode) {
            // O file_get_contents não funciona com active mode
            $stuff = file_get_contents($url);           
        }else{
            // Em active mode, transfere o ficheiro para a pasta cache
            $local = fopen(CACHE_PATH . '/' . $filename, 'w');
            $result = ftp_fget($this->_connection, $local,$filename, FTP_BINARY);
            $stuff = file_get_contents(CACHE_PATH . '/' . $filename);   
        }        
        return $stuff;        
    }
}