Post by scandic » Wed Mar 25, 2009 9:58 pm

To make things easier with cloud hosting services it might be good to implement the FTP functionality for all changes to the filesystem. Also direct support of memcache for query and template cache would be very helpful. If you need a cluster for testing I can provide you with an account on my own cluster including global memcached instance.

New member

Posts

Joined
Sun Jul 08, 2007 2:48 am
Location - Frankfurt, Germany

Post by openmind » Wed Dec 14, 2011 3:02 am

Well i develop a class that wrapper the ftp into a new scheme, you just only need to add the word cdn: in front of your paths in the config file:

Code: Select all

<?php defined('VERSION') OR die('Direct Access Denied!');

/**
* CDN is a new wrapper
*
* @version 0.01
*/

class CDN
{

	/*
	* @protected
	*/
	static protected $instance = NULL;
	static protected $pasv = TRUE;
	static protected $timeout = 90;

	/*
	* @private
	*/
	private $pos = 0;
	private $file = NULL;
	private $mode = NULL;
	private $wrap = NULL;
	private $eof = FALSE;
	private $seek = FALSE;


	/** 
	* resource context 
	* 
	* @var resource 
	*/ 
	public $context = NULL; 

    /** 
     * Nothing to do 
     * 
     */ 
    public function __construct(){}

    /** 
     * Connect to server
	 *
	 * @param  string path full path with server connection
	 * @return string path server path
	 */ 
	protected function connect($path)
	{
		// Parse wrapper
		$url = parse_url($path);

		// Instanciate
		if (self::$instance === NULL)
		{

			// Set values
 			if (empty($url['host'])) $url['host'] = 'localhost';
 			if (empty($url['port'])) $url['port'] = 21;
 			if ( ! isset($url['user'])) $url['user'] = 'anonimous';
 			if ( ! isset($url['pass'])) $url['pass'] = '';

			// Connect to server
			self::$instance = ftp_connect($url['host'],$url['port'],self::$timeout);
		
			// Set user and pass
			ftp_login(self::$instance,$url['user'],$url['pass']);

			// Set pasive mode
			ftp_pasv(self::$instance,self::$pasv);
		}

		return str_replace(array('\\',':','//'),'/',$url['path']);
	}
	
    /** 
     * Connect to server
	 *
	 * @param void
	 */ 
	public function __destruct()
	{
		if (is_resource(self::$instance))
		{
			// Close Connection
			ftp_close(self::$instance);
		}
	}


    /** 
     * 
     * 
     * @return bool 
     */ 
    public function dir_closedir() {}

    /** 
     * Enter description here... 
     * 
     * @param string $path 
     * @param int $options 
     * @return bool 
     */ 
    public function dir_opendir($path , $options) { }

    /** 
     * Enter description here... 
     * 
     * @return string 
     */ 
    public function dir_readdir(){}

    /** 
     * Enter description here... 
     * 
     * @return bool 
     */ 
    public function dir_rewinddir() {}

    /** 
     * Create a directory
     * 
     * @param string $path 
     * @param int $mode 
     * @param int $options 
     * @return bool 
     */ 
    public function mkdir($path , $mode = 0777, $options = FALSE)
	{
		// Connect and remove connection from path
		$path = $this->connect($path);
		
		// Directory
		$directory = '/';

		// Create a recursive directory
		if ($options)
		{
			// Explode directory
			foreach (explode('/',$path) as $path)
			{
				if (empty($path)) continue;

				if ( ! @ftp_chdir(self::$instance,$directory))
				{
					if ( ! @ftp_mkdir(self::$instance,$path))
					{
						return FALSE;
					}

					// If not 0777 change mode
					if ($mode !== 0777)
					{
						ftp_chmod(self::$instance,$mode,$path);
					}
				}

				// Add path
				$directory .= '/'.$path;
			}
		}
		else
		{
			// Set root
			@ftp_chdir(self::$instance,$directory);

			// Set full directory
			$directory = $path;

			// Change directory
			@ftp_mkdir(self::$instance,$directory);

			// If not 0777 change mode
			if ($mode !== 0777)
			{
				ftp_chmod(self::$instance,$mode,$path);
			}
		}

		return $directory;
	}

    /** 
     * Rename a file
     * 
     * @param string $from 
     * @param string $to 
     * @return bool 
     */ 
    public function rename($from , $to)
	{
		// Connect and remove connection from path
		$path = $this->connect($path);

		return ftp_rename(self::$instance,$from,$to);
	}

    /** 
     * Remove directory 
     * 
     * @param string $path 
     * @param int $options 
     * @return bool 
     */ 
    public function rmdir($path , $options = NULL)
	{
	 	// Connect and remove connection from path
		$path = $this->connect($path);

		// Set root
		@ftp_chdir(self::$instance,'/');

		return @ftp_rmdir(self::$instance,$path);
	}

    /** 
     * Enter description here... 
     * 
     * @return bool 
     */ 
    public function stream_eof()
	{
		return $this->eof; 
	}

    /** 
     * Close file handle 
     * 
     * @return bool 
     */ 
    public function stream_close()
	{
		// Close handle
		return fclose($this->handle);
	}


    /** 
     * Not Supported
     * 
     * @param mode $operation 
     * @return bool 
     */ 
    public function stream_lock($operation)
	{
		return TRUE; 
	} 

    /** 
     * Open a file
     * 
     * @param string $path 
     * @param string $mode 
     * @param int $options 
     * @param string &$opened_path 
     * @return bool 
     */ 
    public function stream_open($path , $mode , $options , &$opened_path)
	{
		// Set mode
		$this->mode = (stripos($mode,'b') !== FALSE) ? FTP_BINARY : FTP_ASCII;

		// Set wrapper
		$this->wrap = $path;

	 	// Connect and remove connection from path
		$this->file = $this->connect($path);

		// Set position
		$this->pos = 0;

		// Set Handle at memory
		$this->handle = fopen('php://memory','rb+');

		// Return status
		return TRUE;
	} 

    /** 
     * Read a file from ftp
     * 
     * @param void
     * @return boolean 
     */ 
	private function read()
	{
		if ( ! $this->pos)
		{
			// Get entire content
			return ftp_fget(self::$instance,$this->handle,$this->file,$this->mode);
		}
	}
	
    /** 
     * Read a file
     * 
     * @param int $count 
     * @return string 
     */ 
    public function stream_read($count = 0)
	{
		// Load file to filehandle
		$this->read();

		if ( ! $this->seek)
		{
			// Set handle
			fseek($this->handle,$this->pos,0);
		}

		// Initialize content
		$content = FALSE;

		// Select read function
		if ($count === 0)
		{
			$content = fgets($this->handle);
		}
		else
		{
			$content = fread($this->handle,$count);
		}

		// Update pointer
		$this->pos = ftell($this->handle);

		// Update EOF
		$this->eof = feof($this->handle);

		// Get Content
		return $content;
	}

    /** 
     * Set the pointer
     * 
     * @param int $offset 
     * @param int $whence = SEEK_SET 
     * @return bool 
     */ 
    public function stream_seek($offset , $whence = SEEK_SET)
	{
		if ($this->pos)
		{
			// Set manual seek
			$this->seek = TRUE;

			// Set handle
			return fseek($this->handle,$offset,$whence);
		}

		return TRUE;
	}

    /** 
     * Unimplemented 
     * 
     * @param int $option 
     * @param int $arg1 
     * @param int $arg2 
     * @return bool 
     */ 
    public function stream_set_option($option , $arg1 , $arg2)
	{
		return TRUE; 
	}

    /** 
     * Get stat of a stream
     * 
     * @return array 
     */ 
    public function stream_stat()
	{
		 return $this->url_stat($this->wrap);
	}

    /** 
     * Get actual position of the context variable 
     * 
     * @return int 
     */ 
    public function stream_tell()
	{
		return $this->pos; 
	}

    /** 
     * Write a stream
     * 
     * @param string $data 
     * @return int 
     */ 
    public function stream_write($data = '')
	{
		if ( ! $this->seek)
		{
			// Set handle
			fseek($this->handle,$this->pos,0);
		}

		fwrite($this->handle,$data);
		
		if ( ! $this->seek)
		{
			// Set handle
			fseek($this->handle,$this->pos,0);
		}

		if (ftp_fput(self::$instance,$this->file,$this->handle,$this->mode,$this->pos))
		{
			return ($this->pos += ftell($this->handle));
		}

		return 0;	 
	}

    /** 
     * Delete a file
     * 
     * @param string $path 
     * @return bool 
     */ 
    public function unlink($path)
	{
		// Connect and remove connection from path
		$path = $this->connect($path);
	
		// Delete and return boolean
		return ftp_delete(self::$instance,$path); 
	}

    /** 
     * Get Stat of a given remote file 
     * 
     * @param string $path 
     * @param int $flags 
     * @return array 
     */ 
    public function url_stat($path = NULL, $flags = NULL)
    {
		// Connect and remove connection from path
		$path = $this->connect($path);

		if ($flags === 7)
		{
			return ftp_size(self::$instance,$path);
		}
		elseif ($flags === 8 OR $flags === 9 OR $flags === 10)
		{
			return strtotime(ftp_mdtm(self::$instance,$path));
		}

		// name
		$name = basename($path);

		// Directory
		$directory = dirname($path);

		// Get list
		$file = preg_grep('@'.preg_quote($name,'@').'\s*$@',(array) ftp_rawlist(self::$instance,$directory));

		// Check if ok
		if ( ! empty($file) AND is_array($file))
		{
			$file = array_shift($file);
		}
		else
		{
			$file = '';
		}

		// Parse modes
		if (preg_match("@([-dl][rwxst-]+)\s+([0-9]*)\s+(\S+)\s+(\S+)\s+([0-9]+)@", $file, $match))
		{

			$mode = 0;
			if ($match[1]{1} == 'r') $mode += 0400; 
			if ($match[1]{2} == 'w') $mode += 0200; 
			if ($match[1]{3} == 'x')
		    {
				$mode += 0100; 
			}
			elseif ($match[1]{3} == 's')
		    {
				$mode += 04100; 
		    }
			elseif ($match[1]{3} == 'S')
		    {
				$mode += 04000; 
			}

			if ($match[1]{4} == 'r') $mode += 040; 
			if ($match[1]{5} == 'w') $mode += 020; 
			if ($match[1]{6} == 'x')
		    {
				$mode += 010; 
			}
			elseif ($match[1]{6} == 's')
		    {
				$mode += 02010;
			}
			elseif ($match[1]{6} == 'S')
		    {
				$mode += 02000;
		    }
			
			if ($match[1]{7} == 'r') $mode += 04; 
			if ($match[1]{8} == 'w') $mode += 02; 
			if ($match[1]{9} == 'x')
		    {
				$mode += 01; 
			}
			elseif ($match[1]{9} == 't')
		    {
				$mode += 01001;
			}
			elseif ($match[1]{9} == 'T')
		    {
				$mode += 01000; 
			}
			// Not used!
            $type = (int) strpos("-dl", $match[1]{0});

			// Set place holder
			$time = time();

			if ($flags === NULL)
			{
				// Get Time
				$time = strtotime(ftp_mdtm(self::$instance,$path));
			}

			// Fill array
			$data = array
			(
				'dev' => 1,
				'ino' => 1,
				'mode' => $mode,
				'nlink' => 1,
				'uid' => $match[2],
				'gid' => $match[2],
				'rdev' => 1,
				'size' => $match[5],
				'atime' => $time,
				'mtime' => $time,
				'ctime' => $time,
				'blksize' => 1,
				'blocks' => 1,

				// Old version
				0 => 1,
				1 => 1,
				2 => $mode,
				3 => 1,
				4 => $match[2],
				5 => $match[2],
				6 => 1,
				7 => $match[5],
				8 => $time,
				9 => $time,
				10 => $time,
				11 => 1,
				12 => 1
			);

			return $flags !== NULL AND isset($data[$flags]) ? $data[$flags] : $data;
		}

		return 0;
	}
}

// Register Wrapper
stream_wrapper_register('cdn','CDN');
It's functional but i never finished the url_stat function something is not returning the right value, so if someone want to check is welcome, otherwise you can use the ftp scheme in your config file and it will work too, but instead hold a "persistent" conection it will connect and disconnect every time which turn it in unuseful.

In my opinion you should disable the image function that use daniel or cache some flags about your remote image because opencart always check the images file before render the page.

New member

Posts

Joined
Tue Jan 05, 2010 7:52 am
Who is online

Users browsing this forum: No registered users and 99 guests