File indexing completed on 2024-12-29 05:28:04
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Service_WindowsAzure_Storage 0017 * @subpackage Blob 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://todo name_todo 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * @category Zend 0025 * @package Zend_Service_WindowsAzure_Storage 0026 * @subpackage Blob 0027 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0028 * @license http://framework.zend.com/license/new-bsd New BSD License 0029 */ 0030 class Zend_Service_WindowsAzure_Storage_Blob_Stream 0031 { 0032 /** 0033 * Current file name 0034 * 0035 * @var string 0036 */ 0037 protected $_fileName = null; 0038 0039 /** 0040 * Temporary file name 0041 * 0042 * @var string 0043 */ 0044 protected $_temporaryFileName = null; 0045 0046 /** 0047 * Temporary file handle 0048 * 0049 * @var resource 0050 */ 0051 protected $_temporaryFileHandle = null; 0052 0053 /** 0054 * Blob storage client 0055 * 0056 * @var Zend_Service_WindowsAzure_Storage_Blob 0057 */ 0058 protected $_storageClient = null; 0059 0060 /** 0061 * Write mode? 0062 * 0063 * @var boolean 0064 */ 0065 protected $_writeMode = false; 0066 0067 /** 0068 * List of blobs 0069 * 0070 * @var array 0071 */ 0072 protected $_blobs = null; 0073 0074 /** 0075 * Retrieve storage client for this stream type 0076 * 0077 * @param string $path 0078 * @return Zend_Service_WindowsAzure_Storage_Blob 0079 */ 0080 protected function _getStorageClient($path = '') 0081 { 0082 if (is_null($this->_storageClient)) { 0083 $url = explode(':', $path); 0084 if (!$url) { 0085 throw new Zend_Service_WindowsAzure_Exception('Could not parse path "' . $path . '".'); 0086 } 0087 0088 $this->_storageClient = Zend_Service_WindowsAzure_Storage_Blob::getWrapperClient($url[0]); 0089 if (!$this->_storageClient) { 0090 throw new Zend_Service_WindowsAzure_Exception('No storage client registered for stream type "' . $url[0] . '://".'); 0091 } 0092 } 0093 0094 return $this->_storageClient; 0095 } 0096 0097 /** 0098 * Extract container name 0099 * 0100 * @param string $path 0101 * @return string 0102 */ 0103 protected function _getContainerName($path) 0104 { 0105 $url = parse_url($path); 0106 if ($url['host']) { 0107 return $url['host']; 0108 } 0109 0110 return ''; 0111 } 0112 0113 /** 0114 * Extract file name 0115 * 0116 * @param string $path 0117 * @return string 0118 */ 0119 protected function _getFileName($path) 0120 { 0121 $url = parse_url($path); 0122 if ($url['host']) { 0123 $fileName = isset($url['path']) ? $url['path'] : $url['host']; 0124 if (strpos($fileName, '/') === 0) { 0125 $fileName = substr($fileName, 1); 0126 } 0127 return $fileName; 0128 } 0129 0130 return ''; 0131 } 0132 0133 /** 0134 * Open the stream 0135 * 0136 * @param string $path 0137 * @param string $mode 0138 * @param integer $options 0139 * @param string $opened_path 0140 * @return boolean 0141 */ 0142 public function stream_open($path, $mode, $options, &$opened_path) 0143 { 0144 $this->_fileName = $path; 0145 $this->_temporaryFileName = tempnam(sys_get_temp_dir(), 'azure'); 0146 0147 // Check the file can be opened 0148 $fh = @fopen($this->_temporaryFileName, $mode); 0149 if ($fh === false) { 0150 return false; 0151 } 0152 fclose($fh); 0153 0154 // Write mode? 0155 if (strpbrk($mode, 'wax+')) { 0156 $this->_writeMode = true; 0157 } else { 0158 $this->_writeMode = false; 0159 } 0160 0161 // If read/append, fetch the file 0162 if (!$this->_writeMode || strpbrk($mode, 'ra+')) { 0163 $this->_getStorageClient($this->_fileName)->getBlob( 0164 $this->_getContainerName($this->_fileName), 0165 $this->_getFileName($this->_fileName), 0166 $this->_temporaryFileName 0167 ); 0168 } 0169 0170 // Open temporary file handle 0171 $this->_temporaryFileHandle = fopen($this->_temporaryFileName, $mode); 0172 0173 // Ok! 0174 return true; 0175 } 0176 0177 /** 0178 * Close the stream 0179 * 0180 * @return void 0181 */ 0182 public function stream_close() 0183 { 0184 @fclose($this->_temporaryFileHandle); 0185 0186 // Upload the file? 0187 if ($this->_writeMode) { 0188 // Make sure the container exists 0189 $containerExists = $this->_getStorageClient($this->_fileName)->containerExists( 0190 $this->_getContainerName($this->_fileName) 0191 ); 0192 if (!$containerExists) { 0193 $this->_getStorageClient($this->_fileName)->createContainer( 0194 $this->_getContainerName($this->_fileName) 0195 ); 0196 } 0197 0198 // Upload the file 0199 try { 0200 $this->_getStorageClient($this->_fileName)->putBlob( 0201 $this->_getContainerName($this->_fileName), 0202 $this->_getFileName($this->_fileName), 0203 $this->_temporaryFileName 0204 ); 0205 } catch (Zend_Service_WindowsAzure_Exception $ex) { 0206 @unlink($this->_temporaryFileName); 0207 unset($this->_storageClient); 0208 0209 throw $ex; 0210 } 0211 } 0212 0213 @unlink($this->_temporaryFileName); 0214 unset($this->_storageClient); 0215 } 0216 0217 /** 0218 * Read from the stream 0219 * 0220 * @param integer $count 0221 * @return string 0222 */ 0223 public function stream_read($count) 0224 { 0225 if (!$this->_temporaryFileHandle) { 0226 return false; 0227 } 0228 0229 return fread($this->_temporaryFileHandle, $count); 0230 } 0231 0232 /** 0233 * Write to the stream 0234 * 0235 * @param string $data 0236 * @return integer 0237 */ 0238 public function stream_write($data) 0239 { 0240 if (!$this->_temporaryFileHandle) { 0241 return 0; 0242 } 0243 0244 $len = strlen($data); 0245 fwrite($this->_temporaryFileHandle, $data, $len); 0246 return $len; 0247 } 0248 0249 /** 0250 * End of the stream? 0251 * 0252 * @return boolean 0253 */ 0254 public function stream_eof() 0255 { 0256 if (!$this->_temporaryFileHandle) { 0257 return true; 0258 } 0259 0260 return feof($this->_temporaryFileHandle); 0261 } 0262 0263 /** 0264 * What is the current read/write position of the stream? 0265 * 0266 * @return integer 0267 */ 0268 public function stream_tell() 0269 { 0270 return ftell($this->_temporaryFileHandle); 0271 } 0272 0273 /** 0274 * Update the read/write position of the stream 0275 * 0276 * @param integer $offset 0277 * @param integer $whence 0278 * @return boolean 0279 */ 0280 public function stream_seek($offset, $whence) 0281 { 0282 if (!$this->_temporaryFileHandle) { 0283 return false; 0284 } 0285 0286 return (fseek($this->_temporaryFileHandle, $offset, $whence) === 0); 0287 } 0288 0289 /** 0290 * Flush current cached stream data to storage 0291 * 0292 * @return boolean 0293 */ 0294 public function stream_flush() 0295 { 0296 $result = fflush($this->_temporaryFileHandle); 0297 0298 // Upload the file? 0299 if ($this->_writeMode) { 0300 // Make sure the container exists 0301 $containerExists = $this->_getStorageClient($this->_fileName)->containerExists( 0302 $this->_getContainerName($this->_fileName) 0303 ); 0304 if (!$containerExists) { 0305 $this->_getStorageClient($this->_fileName)->createContainer( 0306 $this->_getContainerName($this->_fileName) 0307 ); 0308 } 0309 0310 // Upload the file 0311 try { 0312 $this->_getStorageClient($this->_fileName)->putBlob( 0313 $this->_getContainerName($this->_fileName), 0314 $this->_getFileName($this->_fileName), 0315 $this->_temporaryFileName 0316 ); 0317 } catch (Zend_Service_WindowsAzure_Exception $ex) { 0318 @unlink($this->_temporaryFileName); 0319 unset($this->_storageClient); 0320 0321 throw $ex; 0322 } 0323 } 0324 0325 return $result; 0326 } 0327 0328 /** 0329 * Returns data array of stream variables 0330 * 0331 * @return array 0332 */ 0333 public function stream_stat() 0334 { 0335 if (!$this->_temporaryFileHandle) { 0336 return false; 0337 } 0338 0339 return $this->url_stat($this->_fileName, 0); 0340 } 0341 0342 /** 0343 * Attempt to delete the item 0344 * 0345 * @param string $path 0346 * @return boolean 0347 */ 0348 public function unlink($path) 0349 { 0350 $this->_getStorageClient($path)->deleteBlob( 0351 $this->_getContainerName($path), 0352 $this->_getFileName($path) 0353 ); 0354 0355 // Clear the stat cache for this path. 0356 clearstatcache(true, $path); 0357 return true; 0358 } 0359 0360 /** 0361 * Attempt to rename the item 0362 * 0363 * @param string $path_from 0364 * @param string $path_to 0365 * @return boolean False 0366 */ 0367 public function rename($path_from, $path_to) 0368 { 0369 if ($this->_getContainerName($path_from) != $this->_getContainerName($path_to)) { 0370 throw new Zend_Service_WindowsAzure_Exception('Container name can not be changed.'); 0371 } 0372 0373 if ($this->_getFileName($path_from) == $this->_getContainerName($path_to)) { 0374 return true; 0375 } 0376 0377 $this->_getStorageClient($path_from)->copyBlob( 0378 $this->_getContainerName($path_from), 0379 $this->_getFileName($path_from), 0380 $this->_getContainerName($path_to), 0381 $this->_getFileName($path_to) 0382 ); 0383 $this->_getStorageClient($path_from)->deleteBlob( 0384 $this->_getContainerName($path_from), 0385 $this->_getFileName($path_from) 0386 ); 0387 0388 // Clear the stat cache for the affected paths. 0389 clearstatcache(true, $path_from); 0390 clearstatcache(true, $path_to); 0391 return true; 0392 } 0393 0394 /** 0395 * Return array of URL variables 0396 * 0397 * @param string $path 0398 * @param integer $flags 0399 * @return array 0400 */ 0401 public function url_stat($path, $flags) 0402 { 0403 $stat = array(); 0404 $stat['dev'] = 0; 0405 $stat['ino'] = 0; 0406 $stat['mode'] = 0; 0407 $stat['nlink'] = 0; 0408 $stat['uid'] = 0; 0409 $stat['gid'] = 0; 0410 $stat['rdev'] = 0; 0411 $stat['size'] = 0; 0412 $stat['atime'] = 0; 0413 $stat['mtime'] = 0; 0414 $stat['ctime'] = 0; 0415 $stat['blksize'] = 0; 0416 $stat['blocks'] = 0; 0417 0418 $info = null; 0419 try { 0420 $info = $this->_getStorageClient($path)->getBlobInstance( 0421 $this->_getContainerName($path), 0422 $this->_getFileName($path) 0423 ); 0424 $stat['size'] = $info->Size; 0425 0426 // Set the modification time and last modified to the Last-Modified header. 0427 $lastmodified = strtotime($info->LastModified); 0428 $stat['mtime'] = $lastmodified; 0429 $stat['ctime'] = $lastmodified; 0430 0431 // Entry is a regular file. 0432 $stat['mode'] = 0100000; 0433 0434 return array_values($stat) + $stat; 0435 } catch (Zend_Service_WindowsAzure_Exception $ex) { 0436 // Unexisting file... 0437 return false; 0438 } 0439 } 0440 0441 /** 0442 * Create a new directory 0443 * 0444 * @param string $path 0445 * @param integer $mode 0446 * @param integer $options 0447 * @return boolean 0448 */ 0449 public function mkdir($path, $mode, $options) 0450 { 0451 if ($this->_getContainerName($path) == $this->_getFileName($path)) { 0452 // Create container 0453 try { 0454 $this->_getStorageClient($path)->createContainer( 0455 $this->_getContainerName($path) 0456 ); 0457 return true; 0458 } catch (Zend_Service_WindowsAzure_Exception $ex) { 0459 return false; 0460 } 0461 } else { 0462 throw new Zend_Service_WindowsAzure_Exception('mkdir() with multiple levels is not supported on Windows Azure Blob Storage.'); 0463 } 0464 } 0465 0466 /** 0467 * Remove a directory 0468 * 0469 * @param string $path 0470 * @param integer $options 0471 * @return boolean 0472 */ 0473 public function rmdir($path, $options) 0474 { 0475 if ($this->_getContainerName($path) == $this->_getFileName($path)) { 0476 // Clear the stat cache so that affected paths are refreshed. 0477 clearstatcache(); 0478 0479 // Delete container 0480 try { 0481 $this->_getStorageClient($path)->deleteContainer( 0482 $this->_getContainerName($path) 0483 ); 0484 return true; 0485 } catch (Zend_Service_WindowsAzure_Exception $ex) { 0486 return false; 0487 } 0488 } else { 0489 throw new Zend_Service_WindowsAzure_Exception('rmdir() with multiple levels is not supported on Windows Azure Blob Storage.'); 0490 } 0491 } 0492 0493 /** 0494 * Attempt to open a directory 0495 * 0496 * @param string $path 0497 * @param integer $options 0498 * @return boolean 0499 */ 0500 public function dir_opendir($path, $options) 0501 { 0502 $this->_blobs = $this->_getStorageClient($path)->listBlobs( 0503 $this->_getContainerName($path) 0504 ); 0505 return is_array($this->_blobs); 0506 } 0507 0508 /** 0509 * Return the next filename in the directory 0510 * 0511 * @return string 0512 */ 0513 public function dir_readdir() 0514 { 0515 $object = current($this->_blobs); 0516 if ($object !== false) { 0517 next($this->_blobs); 0518 return $object->Name; 0519 } 0520 return false; 0521 } 0522 0523 /** 0524 * Reset the directory pointer 0525 * 0526 * @return boolean True 0527 */ 0528 public function dir_rewinddir() 0529 { 0530 reset($this->_blobs); 0531 return true; 0532 } 0533 0534 /** 0535 * Close a directory 0536 * 0537 * @return boolean True 0538 */ 0539 public function dir_closedir() 0540 { 0541 $this->_blobs = null; 0542 return true; 0543 } 0544 }