Viewing file: Stream.php (12.35 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category Zend * @package Zend_Service * @subpackage Amazon_S3 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @version $Id: Stream.php 18951 2009-11-12 16:26:19Z alexander $ */
/** * @see Zend_Service_Amazon_S3 */ require_once 'Zend/Service/Amazon/S3.php';
/** * Amazon S3 PHP stream wrapper * * @category Zend * @package Zend_Service * @subpackage Amazon_S3 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Service_Amazon_S3_Stream { /** * @var boolean Write the buffer on fflush()? */ private $_writeBuffer = false;
/** * @var integer Current read/write position */ private $_position = 0;
/** * @var integer Total size of the object as returned by S3 (Content-length) */ private $_objectSize = 0;
/** * @var string File name to interact with */ private $_objectName = null;
/** * @var string Current read/write buffer */ private $_objectBuffer = null;
/** * @var array Available buckets */ private $_bucketList = array();
/** * @var Zend_Service_Amazon_S3 */ private $_s3 = null;
/** * Retrieve client for this stream type * * @param string $path * @return Zend_Service_Amazon_S3 */ protected function _getS3Client($path) { if ($this->_s3 === null) { $url = explode(':', $path);
if (!$url) { /** * @see Zend_Service_Amazon_S3_Exception */ require_once 'Zend/Service/Amazon/S3/Exception.php'; throw new Zend_Service_Amazon_S3_Exception("Unable to parse URL $path"); }
$this->_s3 = Zend_Service_Amazon_S3::getWrapperClient($url[0]); if (!$this->_s3) { /** * @see Zend_Service_Amazon_S3_Exception */ require_once 'Zend/Service/Amazon/S3/Exception.php'; throw new Zend_Service_Amazon_S3_Exception("Unknown client for wrapper {$url[0]}"); } }
return $this->_s3; }
/** * Extract object name from URL * * @param string $path * @return string */ protected function _getNamePart($path) { $url = parse_url($path); if ($url['host']) { return !empty($url['path']) ? $url['host'].$url['path'] : $url['host']; }
return ''; } /** * Open the stream * * @param string $path * @param string $mode * @param integer $options * @param string $opened_path * @return boolean */ public function stream_open($path, $mode, $options, $opened_path) { $name = $this->_getNamePart($path); // If we open the file for writing, just return true. Create the object // on fflush call if (strpbrk($mode, 'wax')) { $this->_objectName = $name; $this->_objectBuffer = null; $this->_objectSize = 0; $this->_position = 0; $this->_writeBuffer = true; $this->_getS3Client($path); return true; } else { // Otherwise, just see if the file exists or not $info = $this->_getS3Client($path)->getInfo($name); if ($info) { $this->_objectName = $name; $this->_objectBuffer = null; $this->_objectSize = $info['size']; $this->_position = 0; $this->_writeBuffer = false; $this->_getS3Client($path); return true; } } return false; }
/** * Close the stream * * @return void */ public function stream_close() { $this->_objectName = null; $this->_objectBuffer = null; $this->_objectSize = 0; $this->_position = 0; $this->_writeBuffer = false; unset($this->_s3); }
/** * Read from the stream * * @param integer $count * @return string */ public function stream_read($count) { if (!$this->_objectName) { return false; }
$range_start = $this->_position; $range_end = $this->_position+$count;
// Only fetch more data from S3 if we haven't fetched any data yet (postion=0) // OR, the range end position is greater than the size of the current object // buffer AND if the range end position is less than or equal to the object's // size returned by S3 if (($this->_position == 0) || (($range_end > strlen($this->_objectBuffer)) && ($range_end <= $this->_objectSize))) {
$headers = array( 'Range' => "$range_start-$range_end" );
$response = $this->_s3->_makeRequest('GET', $this->_objectName, null, $headers);
if ($response->getStatus() == 200) { $this->_objectBuffer .= $response->getBody(); } }
$data = substr($this->_objectBuffer, $this->_position, $count); $this->_position += strlen($data); return $data; }
/** * Write to the stream * * @param string $data * @return integer */ public function stream_write($data) { if (!$this->_objectName) { return 0; } $len = strlen($data); $this->_objectBuffer .= $data; $this->_objectSize += $len; // TODO: handle current position for writing! return $len; }
/** * End of the stream? * * @return boolean */ public function stream_eof() { if (!$this->_objectName) { return true; }
return ($this->_position >= $this->_objectSize); }
/** * What is the current read/write position of the stream * * @return integer */ public function stream_tell() { return $this->_position; }
/** * Update the read/write position of the stream * * @param integer $offset * @param integer $whence * @return boolean */ public function stream_seek($offset, $whence) { if (!$this->_objectName) { return false; }
switch ($whence) { case SEEK_CUR: // Set position to current location plus $offset $new_pos = $this->_position + $offset; break; case SEEK_END: // Set position to end-of-file plus $offset $new_pos = $this->_objectSize + $offset; break; case SEEK_SET: default: // Set position equal to $offset $new_pos = $offset; break; } $ret = ($new_pos >= 0 && $new_pos <= $this->_objectSize); if ($ret) { $this->_position = $new_pos; } return $ret; }
/** * Flush current cached stream data to storage * * @return boolean */ public function stream_flush() { // If the stream wasn't opened for writing, just return false if (!$this->_writeBuffer) { return false; }
$ret = $this->_s3->putObject($this->_objectName, $this->_objectBuffer);
$this->_objectBuffer = null;
return $ret; }
/** * Returns data array of stream variables * * @return array */ public function stream_stat() { if (!$this->_objectName) { return false; }
$stat = array(); $stat['dev'] = 0; $stat['ino'] = 0; $stat['mode'] = 0777; $stat['nlink'] = 0; $stat['uid'] = 0; $stat['gid'] = 0; $stat['rdev'] = 0; $stat['size'] = 0; $stat['atime'] = 0; $stat['mtime'] = 0; $stat['ctime'] = 0; $stat['blksize'] = 0; $stat['blocks'] = 0;
if(($slash = strchr($this->_objectName, '/')) === false || $slash == strlen($this->_objectName)-1) { /* bucket */ $stat['mode'] |= 040000; } else { $stat['mode'] |= 0100000; } $info = $this->_s3->getInfo($this->_objectName); if (!empty($info)) { $stat['size'] = $info['size']; $stat['atime'] = time(); $stat['mtime'] = $info['mtime']; }
return $stat; }
/** * Attempt to delete the item * * @param string $path * @return boolean */ public function unlink($path) { return $this->_getS3Client($path)->removeObject($this->_getNamePart($path)); }
/** * Attempt to rename the item * * @param string $path_from * @param string $path_to * @return boolean False */ public function rename($path_from, $path_to) { // TODO: Renaming isn't supported, always return false return false; }
/** * Create a new directory * * @param string $path * @param integer $mode * @param integer $options * @return boolean */ public function mkdir($path, $mode, $options) { return $this->_getS3Client($path)->createBucket(parse_url($path, PHP_URL_HOST)); }
/** * Remove a directory * * @param string $path * @param integer $options * @return boolean */ public function rmdir($path, $options) { return $this->_getS3Client($path)->removeBucket(parse_url($path, PHP_URL_HOST)); }
/** * Attempt to open a directory * * @param string $path * @param integer $options * @return boolean */ public function dir_opendir($path, $options) {
if (preg_match('@^([a-z0-9+.]|-)+://$@', $path)) { $this->_bucketList = $this->_getS3Client($path)->getBuckets(); } else { $url = parse_url($path); $this->_bucketList = $this->_getS3Client($path)->getObjectsByBucket($url["host"]); }
return ($this->_bucketList !== false); }
/** * Return array of URL variables * * @param string $path * @param integer $flags * @return array */ public function url_stat($path, $flags) { $stat = array(); $stat['dev'] = 0; $stat['ino'] = 0; $stat['mode'] = 0777; $stat['nlink'] = 0; $stat['uid'] = 0; $stat['gid'] = 0; $stat['rdev'] = 0; $stat['size'] = 0; $stat['atime'] = 0; $stat['mtime'] = 0; $stat['ctime'] = 0; $stat['blksize'] = 0; $stat['blocks'] = 0;
$name = $this->_getNamePart($path); if(($slash = strchr($name, '/')) === false || $slash == strlen($name)-1) { /* bucket */ $stat['mode'] |= 040000; } else { $stat['mode'] |= 0100000; } $info = $this->_getS3Client($path)->getInfo($name);
if (!empty($info)) { $stat['size'] = $info['size']; $stat['atime'] = time(); $stat['mtime'] = $info['mtime']; }
return $stat; }
/** * Return the next filename in the directory * * @return string */ public function dir_readdir() { $object = current($this->_bucketList); if ($object !== false) { next($this->_bucketList); } return $object; }
/** * Reset the directory pointer * * @return boolean True */ public function dir_rewinddir() { reset($this->_bucketList); return true; }
/** * Close a directory * * @return boolean True */ public function dir_closedir() { $this->_bucketList = array(); return true; } }
|