PageRenderTime 68ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/application/libraries/Zend/Service/Amazon/S3/Stream.php

https://bitbucket.org/masnug/grc276-blog-laravel
PHP | 503 lines | 253 code | 50 blank | 200 comment | 35 complexity | f521bf413039265a5d4fa563f0c8e84f MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Service
  17. * @subpackage Amazon_S3
  18. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Stream.php 23775 2011-03-01 17:25:24Z ralph $
  21. */
  22. /**
  23. * @see Zend_Service_Amazon_S3
  24. */
  25. require_once 'Zend/Service/Amazon/S3.php';
  26. /**
  27. * Amazon S3 PHP stream wrapper
  28. *
  29. * @category Zend
  30. * @package Zend_Service
  31. * @subpackage Amazon_S3
  32. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. */
  35. class Zend_Service_Amazon_S3_Stream
  36. {
  37. /**
  38. * @var boolean Write the buffer on fflush()?
  39. */
  40. private $_writeBuffer = false;
  41. /**
  42. * @var integer Current read/write position
  43. */
  44. private $_position = 0;
  45. /**
  46. * @var integer Total size of the object as returned by S3 (Content-length)
  47. */
  48. private $_objectSize = 0;
  49. /**
  50. * @var string File name to interact with
  51. */
  52. private $_objectName = null;
  53. /**
  54. * @var string Current read/write buffer
  55. */
  56. private $_objectBuffer = null;
  57. /**
  58. * @var array Available buckets
  59. */
  60. private $_bucketList = array();
  61. /**
  62. * @var Zend_Service_Amazon_S3
  63. */
  64. private $_s3 = null;
  65. /**
  66. * Retrieve client for this stream type
  67. *
  68. * @param string $path
  69. * @return Zend_Service_Amazon_S3
  70. */
  71. protected function _getS3Client($path)
  72. {
  73. if ($this->_s3 === null) {
  74. $url = explode(':', $path);
  75. if (!$url) {
  76. /**
  77. * @see Zend_Service_Amazon_S3_Exception
  78. */
  79. require_once 'Zend/Service/Amazon/S3/Exception.php';
  80. throw new Zend_Service_Amazon_S3_Exception("Unable to parse URL $path");
  81. }
  82. $this->_s3 = Zend_Service_Amazon_S3::getWrapperClient($url[0]);
  83. if (!$this->_s3) {
  84. /**
  85. * @see Zend_Service_Amazon_S3_Exception
  86. */
  87. require_once 'Zend/Service/Amazon/S3/Exception.php';
  88. throw new Zend_Service_Amazon_S3_Exception("Unknown client for wrapper {$url[0]}");
  89. }
  90. }
  91. return $this->_s3;
  92. }
  93. /**
  94. * Extract object name from URL
  95. *
  96. * @param string $path
  97. * @return string
  98. */
  99. protected function _getNamePart($path)
  100. {
  101. $url = parse_url($path);
  102. if ($url['host']) {
  103. return !empty($url['path']) ? $url['host'].$url['path'] : $url['host'];
  104. }
  105. return '';
  106. }
  107. /**
  108. * Open the stream
  109. *
  110. * @param string $path
  111. * @param string $mode
  112. * @param integer $options
  113. * @param string $opened_path
  114. * @return boolean
  115. */
  116. public function stream_open($path, $mode, $options, $opened_path)
  117. {
  118. $name = $this->_getNamePart($path);
  119. // If we open the file for writing, just return true. Create the object
  120. // on fflush call
  121. if (strpbrk($mode, 'wax')) {
  122. $this->_objectName = $name;
  123. $this->_objectBuffer = null;
  124. $this->_objectSize = 0;
  125. $this->_position = 0;
  126. $this->_writeBuffer = true;
  127. $this->_getS3Client($path);
  128. return true;
  129. } else {
  130. // Otherwise, just see if the file exists or not
  131. $info = $this->_getS3Client($path)->getInfo($name);
  132. if ($info) {
  133. $this->_objectName = $name;
  134. $this->_objectBuffer = null;
  135. $this->_objectSize = $info['size'];
  136. $this->_position = 0;
  137. $this->_writeBuffer = false;
  138. $this->_getS3Client($path);
  139. return true;
  140. }
  141. }
  142. return false;
  143. }
  144. /**
  145. * Close the stream
  146. *
  147. * @return void
  148. */
  149. public function stream_close()
  150. {
  151. $this->_objectName = null;
  152. $this->_objectBuffer = null;
  153. $this->_objectSize = 0;
  154. $this->_position = 0;
  155. $this->_writeBuffer = false;
  156. unset($this->_s3);
  157. }
  158. /**
  159. * Read from the stream
  160. *
  161. * http://bugs.php.net/21641 - stream_read() is always passed PHP's
  162. * internal read buffer size (8192) no matter what is passed as $count
  163. * parameter to fread().
  164. *
  165. * @param integer $count
  166. * @return string
  167. */
  168. public function stream_read($count)
  169. {
  170. if (!$this->_objectName) {
  171. return false;
  172. }
  173. // make sure that count doesn't exceed object size
  174. if ($count + $this->_position > $this->_objectSize) {
  175. $count = $this->_objectSize - $this->_position;
  176. }
  177. $range_start = $this->_position;
  178. $range_end = $this->_position + $count - 1;
  179. // Only fetch more data from S3 if we haven't fetched any data yet (postion=0)
  180. // OR, the range end position plus 1 is greater than the size of the current
  181. // object buffer
  182. if ($this->_objectBuffer === null || $range_end >= strlen($this->_objectBuffer)) {
  183. $headers = array(
  184. 'Range' => "bytes=$range_start-$range_end"
  185. );
  186. $response = $this->_s3->_makeRequest('GET', $this->_objectName, null, $headers);
  187. if ($response->getStatus() == 206) { // 206 Partial Content
  188. $this->_objectBuffer .= $response->getBody();
  189. }
  190. }
  191. $data = substr($this->_objectBuffer, $this->_position, $count);
  192. $this->_position += strlen($data);
  193. return $data;
  194. }
  195. /**
  196. * Write to the stream
  197. *
  198. * @param string $data
  199. * @return integer
  200. */
  201. public function stream_write($data)
  202. {
  203. if (!$this->_objectName) {
  204. return 0;
  205. }
  206. $len = strlen($data);
  207. $this->_objectBuffer .= $data;
  208. $this->_objectSize += $len;
  209. // TODO: handle current position for writing!
  210. return $len;
  211. }
  212. /**
  213. * End of the stream?
  214. *
  215. * @return boolean
  216. */
  217. public function stream_eof()
  218. {
  219. if (!$this->_objectName) {
  220. return true;
  221. }
  222. return ($this->_position >= $this->_objectSize);
  223. }
  224. /**
  225. * What is the current read/write position of the stream
  226. *
  227. * @return integer
  228. */
  229. public function stream_tell()
  230. {
  231. return $this->_position;
  232. }
  233. /**
  234. * Update the read/write position of the stream
  235. *
  236. * @param integer $offset
  237. * @param integer $whence
  238. * @return boolean
  239. */
  240. public function stream_seek($offset, $whence)
  241. {
  242. if (!$this->_objectName) {
  243. return false;
  244. }
  245. switch ($whence) {
  246. case SEEK_CUR:
  247. // Set position to current location plus $offset
  248. $new_pos = $this->_position + $offset;
  249. break;
  250. case SEEK_END:
  251. // Set position to end-of-file plus $offset
  252. $new_pos = $this->_objectSize + $offset;
  253. break;
  254. case SEEK_SET:
  255. default:
  256. // Set position equal to $offset
  257. $new_pos = $offset;
  258. break;
  259. }
  260. $ret = ($new_pos >= 0 && $new_pos <= $this->_objectSize);
  261. if ($ret) {
  262. $this->_position = $new_pos;
  263. }
  264. return $ret;
  265. }
  266. /**
  267. * Flush current cached stream data to storage
  268. *
  269. * @return boolean
  270. */
  271. public function stream_flush()
  272. {
  273. // If the stream wasn't opened for writing, just return false
  274. if (!$this->_writeBuffer) {
  275. return false;
  276. }
  277. $ret = $this->_s3->putObject($this->_objectName, $this->_objectBuffer);
  278. $this->_objectBuffer = null;
  279. return $ret;
  280. }
  281. /**
  282. * Returns data array of stream variables
  283. *
  284. * @return array
  285. */
  286. public function stream_stat()
  287. {
  288. if (!$this->_objectName) {
  289. return false;
  290. }
  291. $stat = array();
  292. $stat['dev'] = 0;
  293. $stat['ino'] = 0;
  294. $stat['mode'] = 0777;
  295. $stat['nlink'] = 0;
  296. $stat['uid'] = 0;
  297. $stat['gid'] = 0;
  298. $stat['rdev'] = 0;
  299. $stat['size'] = 0;
  300. $stat['atime'] = 0;
  301. $stat['mtime'] = 0;
  302. $stat['ctime'] = 0;
  303. $stat['blksize'] = 0;
  304. $stat['blocks'] = 0;
  305. if(($slash = strchr($this->_objectName, '/')) === false || $slash == strlen($this->_objectName)-1) {
  306. /* bucket */
  307. $stat['mode'] |= 040000;
  308. } else {
  309. $stat['mode'] |= 0100000;
  310. }
  311. $info = $this->_s3->getInfo($this->_objectName);
  312. if (!empty($info)) {
  313. $stat['size'] = $info['size'];
  314. $stat['atime'] = time();
  315. $stat['mtime'] = $info['mtime'];
  316. }
  317. return $stat;
  318. }
  319. /**
  320. * Attempt to delete the item
  321. *
  322. * @param string $path
  323. * @return boolean
  324. */
  325. public function unlink($path)
  326. {
  327. return $this->_getS3Client($path)->removeObject($this->_getNamePart($path));
  328. }
  329. /**
  330. * Attempt to rename the item
  331. *
  332. * @param string $path_from
  333. * @param string $path_to
  334. * @return boolean False
  335. */
  336. public function rename($path_from, $path_to)
  337. {
  338. // TODO: Renaming isn't supported, always return false
  339. return false;
  340. }
  341. /**
  342. * Create a new directory
  343. *
  344. * @param string $path
  345. * @param integer $mode
  346. * @param integer $options
  347. * @return boolean
  348. */
  349. public function mkdir($path, $mode, $options)
  350. {
  351. return $this->_getS3Client($path)->createBucket(parse_url($path, PHP_URL_HOST));
  352. }
  353. /**
  354. * Remove a directory
  355. *
  356. * @param string $path
  357. * @param integer $options
  358. * @return boolean
  359. */
  360. public function rmdir($path, $options)
  361. {
  362. return $this->_getS3Client($path)->removeBucket(parse_url($path, PHP_URL_HOST));
  363. }
  364. /**
  365. * Attempt to open a directory
  366. *
  367. * @param string $path
  368. * @param integer $options
  369. * @return boolean
  370. */
  371. public function dir_opendir($path, $options)
  372. {
  373. if (preg_match('@^([a-z0-9+.]|-)+://$@', $path)) {
  374. $this->_bucketList = $this->_getS3Client($path)->getBuckets();
  375. }
  376. else {
  377. $host = parse_url($path, PHP_URL_HOST);
  378. $this->_bucketList = $this->_getS3Client($path)->getObjectsByBucket($host);
  379. }
  380. return ($this->_bucketList !== false);
  381. }
  382. /**
  383. * Return array of URL variables
  384. *
  385. * @param string $path
  386. * @param integer $flags
  387. * @return array
  388. */
  389. public function url_stat($path, $flags)
  390. {
  391. $stat = array();
  392. $stat['dev'] = 0;
  393. $stat['ino'] = 0;
  394. $stat['mode'] = 0777;
  395. $stat['nlink'] = 0;
  396. $stat['uid'] = 0;
  397. $stat['gid'] = 0;
  398. $stat['rdev'] = 0;
  399. $stat['size'] = 0;
  400. $stat['atime'] = 0;
  401. $stat['mtime'] = 0;
  402. $stat['ctime'] = 0;
  403. $stat['blksize'] = 0;
  404. $stat['blocks'] = 0;
  405. $name = $this->_getNamePart($path);
  406. if(($slash = strchr($name, '/')) === false || $slash == strlen($name)-1) {
  407. /* bucket */
  408. $stat['mode'] |= 040000;
  409. } else {
  410. $stat['mode'] |= 0100000;
  411. }
  412. $info = $this->_getS3Client($path)->getInfo($name);
  413. if (!empty($info)) {
  414. $stat['size'] = $info['size'];
  415. $stat['atime'] = time();
  416. $stat['mtime'] = $info['mtime'];
  417. }
  418. return $stat;
  419. }
  420. /**
  421. * Return the next filename in the directory
  422. *
  423. * @return string
  424. */
  425. public function dir_readdir()
  426. {
  427. $object = current($this->_bucketList);
  428. if ($object !== false) {
  429. next($this->_bucketList);
  430. }
  431. return $object;
  432. }
  433. /**
  434. * Reset the directory pointer
  435. *
  436. * @return boolean True
  437. */
  438. public function dir_rewinddir()
  439. {
  440. reset($this->_bucketList);
  441. return true;
  442. }
  443. /**
  444. * Close a directory
  445. *
  446. * @return boolean True
  447. */
  448. public function dir_closedir()
  449. {
  450. $this->_bucketList = array();
  451. return true;
  452. }
  453. }