PageRenderTime 38ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/src/frapi/library/Zend/Service/Amazon/S3/Stream.php

https://github.com/Martin1982/IBMessagingWorkshopServer
PHP | 497 lines | 248 code | 50 blank | 199 comment | 36 complexity | 7ca668452c5062d5c12f865c4dc4b4f6 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-2010 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 20096 2010-01-06 02:05:09Z bkarwin $
  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-2010 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. }
  130. else {
  131. // Otherwise, just see if the file exists or not
  132. $info = $this->_getS3Client($path)->getInfo($name);
  133. if ($info) {
  134. $this->_objectName = $name;
  135. $this->_objectBuffer = null;
  136. $this->_objectSize = $info['size'];
  137. $this->_position = 0;
  138. $this->_writeBuffer = false;
  139. $this->_getS3Client($path);
  140. return true;
  141. }
  142. }
  143. return false;
  144. }
  145. /**
  146. * Close the stream
  147. *
  148. * @return void
  149. */
  150. public function stream_close()
  151. {
  152. $this->_objectName = null;
  153. $this->_objectBuffer = null;
  154. $this->_objectSize = 0;
  155. $this->_position = 0;
  156. $this->_writeBuffer = false;
  157. unset($this->_s3);
  158. }
  159. /**
  160. * Read from the stream
  161. *
  162. * @param integer $count
  163. * @return string
  164. */
  165. public function stream_read($count)
  166. {
  167. if (!$this->_objectName) {
  168. return false;
  169. }
  170. $range_start = $this->_position;
  171. $range_end = $this->_position+$count;
  172. // Only fetch more data from S3 if we haven't fetched any data yet (postion=0)
  173. // OR, the range end position is greater than the size of the current object
  174. // buffer AND if the range end position is less than or equal to the object's
  175. // size returned by S3
  176. if (($this->_position == 0) || (($range_end > strlen($this->_objectBuffer)) && ($range_end <= $this->_objectSize))) {
  177. $headers = array(
  178. 'Range' => "$range_start-$range_end"
  179. );
  180. $response = $this->_s3->_makeRequest('GET', $this->_objectName, null, $headers);
  181. if ($response->getStatus() == 200) {
  182. $this->_objectBuffer .= $response->getBody();
  183. }
  184. }
  185. $data = substr($this->_objectBuffer, $this->_position, $count);
  186. $this->_position += strlen($data);
  187. return $data;
  188. }
  189. /**
  190. * Write to the stream
  191. *
  192. * @param string $data
  193. * @return integer
  194. */
  195. public function stream_write($data)
  196. {
  197. if (!$this->_objectName) {
  198. return 0;
  199. }
  200. $len = strlen($data);
  201. $this->_objectBuffer .= $data;
  202. $this->_objectSize += $len;
  203. // TODO: handle current position for writing!
  204. return $len;
  205. }
  206. /**
  207. * End of the stream?
  208. *
  209. * @return boolean
  210. */
  211. public function stream_eof()
  212. {
  213. if (!$this->_objectName) {
  214. return true;
  215. }
  216. return ($this->_position >= $this->_objectSize);
  217. }
  218. /**
  219. * What is the current read/write position of the stream
  220. *
  221. * @return integer
  222. */
  223. public function stream_tell()
  224. {
  225. return $this->_position;
  226. }
  227. /**
  228. * Update the read/write position of the stream
  229. *
  230. * @param integer $offset
  231. * @param integer $whence
  232. * @return boolean
  233. */
  234. public function stream_seek($offset, $whence)
  235. {
  236. if (!$this->_objectName) {
  237. return false;
  238. }
  239. switch ($whence) {
  240. case SEEK_CUR:
  241. // Set position to current location plus $offset
  242. $new_pos = $this->_position + $offset;
  243. break;
  244. case SEEK_END:
  245. // Set position to end-of-file plus $offset
  246. $new_pos = $this->_objectSize + $offset;
  247. break;
  248. case SEEK_SET:
  249. default:
  250. // Set position equal to $offset
  251. $new_pos = $offset;
  252. break;
  253. }
  254. $ret = ($new_pos >= 0 && $new_pos <= $this->_objectSize);
  255. if ($ret) {
  256. $this->_position = $new_pos;
  257. }
  258. return $ret;
  259. }
  260. /**
  261. * Flush current cached stream data to storage
  262. *
  263. * @return boolean
  264. */
  265. public function stream_flush()
  266. {
  267. // If the stream wasn't opened for writing, just return false
  268. if (!$this->_writeBuffer) {
  269. return false;
  270. }
  271. $ret = $this->_s3->putObject($this->_objectName, $this->_objectBuffer);
  272. $this->_objectBuffer = null;
  273. return $ret;
  274. }
  275. /**
  276. * Returns data array of stream variables
  277. *
  278. * @return array
  279. */
  280. public function stream_stat()
  281. {
  282. if (!$this->_objectName) {
  283. return false;
  284. }
  285. $stat = array();
  286. $stat['dev'] = 0;
  287. $stat['ino'] = 0;
  288. $stat['mode'] = 0777;
  289. $stat['nlink'] = 0;
  290. $stat['uid'] = 0;
  291. $stat['gid'] = 0;
  292. $stat['rdev'] = 0;
  293. $stat['size'] = 0;
  294. $stat['atime'] = 0;
  295. $stat['mtime'] = 0;
  296. $stat['ctime'] = 0;
  297. $stat['blksize'] = 0;
  298. $stat['blocks'] = 0;
  299. if(($slash = strchr($this->_objectName, '/')) === false || $slash == strlen($this->_objectName)-1) {
  300. /* bucket */
  301. $stat['mode'] |= 040000;
  302. } else {
  303. $stat['mode'] |= 0100000;
  304. }
  305. $info = $this->_s3->getInfo($this->_objectName);
  306. if (!empty($info)) {
  307. $stat['size'] = $info['size'];
  308. $stat['atime'] = time();
  309. $stat['mtime'] = $info['mtime'];
  310. }
  311. return $stat;
  312. }
  313. /**
  314. * Attempt to delete the item
  315. *
  316. * @param string $path
  317. * @return boolean
  318. */
  319. public function unlink($path)
  320. {
  321. return $this->_getS3Client($path)->removeObject($this->_getNamePart($path));
  322. }
  323. /**
  324. * Attempt to rename the item
  325. *
  326. * @param string $path_from
  327. * @param string $path_to
  328. * @return boolean False
  329. */
  330. public function rename($path_from, $path_to)
  331. {
  332. // TODO: Renaming isn't supported, always return false
  333. return false;
  334. }
  335. /**
  336. * Create a new directory
  337. *
  338. * @param string $path
  339. * @param integer $mode
  340. * @param integer $options
  341. * @return boolean
  342. */
  343. public function mkdir($path, $mode, $options)
  344. {
  345. return $this->_getS3Client($path)->createBucket(parse_url($path, PHP_URL_HOST));
  346. }
  347. /**
  348. * Remove a directory
  349. *
  350. * @param string $path
  351. * @param integer $options
  352. * @return boolean
  353. */
  354. public function rmdir($path, $options)
  355. {
  356. return $this->_getS3Client($path)->removeBucket(parse_url($path, PHP_URL_HOST));
  357. }
  358. /**
  359. * Attempt to open a directory
  360. *
  361. * @param string $path
  362. * @param integer $options
  363. * @return boolean
  364. */
  365. public function dir_opendir($path, $options)
  366. {
  367. if (preg_match('@^([a-z0-9+.]|-)+://$@', $path)) {
  368. $this->_bucketList = $this->_getS3Client($path)->getBuckets();
  369. }
  370. else {
  371. $host = parse_url($path, PHP_URL_HOST);
  372. $this->_bucketList = $this->_getS3Client($path)->getObjectsByBucket($host);
  373. }
  374. return ($this->_bucketList !== false);
  375. }
  376. /**
  377. * Return array of URL variables
  378. *
  379. * @param string $path
  380. * @param integer $flags
  381. * @return array
  382. */
  383. public function url_stat($path, $flags)
  384. {
  385. $stat = array();
  386. $stat['dev'] = 0;
  387. $stat['ino'] = 0;
  388. $stat['mode'] = 0777;
  389. $stat['nlink'] = 0;
  390. $stat['uid'] = 0;
  391. $stat['gid'] = 0;
  392. $stat['rdev'] = 0;
  393. $stat['size'] = 0;
  394. $stat['atime'] = 0;
  395. $stat['mtime'] = 0;
  396. $stat['ctime'] = 0;
  397. $stat['blksize'] = 0;
  398. $stat['blocks'] = 0;
  399. $name = $this->_getNamePart($path);
  400. if(($slash = strchr($name, '/')) === false || $slash == strlen($name)-1) {
  401. /* bucket */
  402. $stat['mode'] |= 040000;
  403. } else {
  404. $stat['mode'] |= 0100000;
  405. }
  406. $info = $this->_getS3Client($path)->getInfo($name);
  407. if (!empty($info)) {
  408. $stat['size'] = $info['size'];
  409. $stat['atime'] = time();
  410. $stat['mtime'] = $info['mtime'];
  411. }
  412. return $stat;
  413. }
  414. /**
  415. * Return the next filename in the directory
  416. *
  417. * @return string
  418. */
  419. public function dir_readdir()
  420. {
  421. $object = current($this->_bucketList);
  422. if ($object !== false) {
  423. next($this->_bucketList);
  424. }
  425. return $object;
  426. }
  427. /**
  428. * Reset the directory pointer
  429. *
  430. * @return boolean True
  431. */
  432. public function dir_rewinddir()
  433. {
  434. reset($this->_bucketList);
  435. return true;
  436. }
  437. /**
  438. * Close a directory
  439. *
  440. * @return boolean True
  441. */
  442. public function dir_closedir()
  443. {
  444. $this->_bucketList = array();
  445. return true;
  446. }
  447. }