PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Cloud/StorageService/Adapter/WindowsAzure.php

https://github.com/necrogami/zf2
PHP | 448 lines | 253 code | 47 blank | 148 comment | 30 complexity | ac6f7ccba99bbcb473539d4f2d5cf6c0 MD5 | raw file
  1. <?php
  2. /**
  3. * LICENSE
  4. *
  5. * This source file is subject to the new BSD license that is bundled
  6. * with this package in the file LICENSE.txt.
  7. * It is also available through the world-wide-web at this URL:
  8. * http://framework.zend.com/license/new-bsd
  9. * If you did not receive a copy of the license and are unable to
  10. * obtain it through the world-wide-web, please send an email
  11. * to license@zend.com so we can send you a copy immediately.
  12. *
  13. * @category Zend
  14. * @package Zend_Cloud_StorageService
  15. * @subpackage Adapter
  16. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  17. * @license http://framework.zend.com/license/new-bsd New BSD License
  18. */
  19. namespace Zend\Cloud\StorageService\Adapter;
  20. use Traversable;
  21. use Zend\Stdlib\ArrayUtils;
  22. use Zend\Cloud\StorageService\Adapter;
  23. use Zend\Cloud\StorageService\Exception;
  24. use Zend\Service\WindowsAzure\Exception as WindowsAzureException;
  25. use Zend\Service\WindowsAzure\Storage\Storage;
  26. use Zend\Service\WindowsAzure\Storage\Blob\Blob;
  27. /**
  28. *
  29. * Windows Azure Blob Service abstraction
  30. *
  31. * @category Zend
  32. * @package Zend_Cloud_StorageService
  33. * @subpackage Adapter
  34. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  35. * @license http://framework.zend.com/license/new-bsd New BSD License
  36. */
  37. class WindowsAzure implements AdapterInterface
  38. {
  39. const ACCOUNT_NAME = 'storage_accountname';
  40. const ACCOUNT_KEY = 'storage_accountkey';
  41. const HOST = "storage_host";
  42. const PROXY_HOST = "storage_proxy_host";
  43. const PROXY_PORT = "storage_proxy_port";
  44. const PROXY_CREDENTIALS = "storage_proxy_credentials";
  45. const CONTAINER = "storage_container";
  46. const RETURN_TYPE = 'return_type';
  47. const RETURN_PATHNAME = 'return_path';
  48. const RETURN_OPENMODE = 'return_openmode';
  49. /** return types for fetch */
  50. const RETURN_PATH = 1; // return filename
  51. const RETURN_STRING = 2; // return data as string
  52. const RETURN_STREAM = 3; // return PHP stream
  53. /** return types for list */
  54. const RETURN_LIST = 1; // return native list
  55. const RETURN_NAMES = 2; // return only names
  56. const DEFAULT_HOST = Storage::URL_CLOUD_BLOB;
  57. /**
  58. * Storage container to operate on
  59. *
  60. * @var string
  61. */
  62. protected $_container;
  63. /**
  64. * Storage client
  65. *
  66. * @var \Zend\Service\WindowsAzure\Storage\Blob\Blob
  67. */
  68. protected $_storageClient = null;
  69. /**
  70. * Creates a new \Zend\Cloud\Storage\WindowsAzure instance
  71. *
  72. * @param array|Traversable $options Options for the \Zend\Cloud\Storage\WindowsAzure instance
  73. */
  74. public function __construct($options = array())
  75. {
  76. if ($options instanceof Traversable) {
  77. $options = ArrayUtils::iteratorToArray($options);
  78. }
  79. if (!is_array($options)) {
  80. throw new Exception\InvalidArgumentException('Invalid options provided');
  81. }
  82. // Build \Zend\Service\WindowsAzure\Storage\Blob instance
  83. if (!isset($options[self::HOST])) {
  84. $host = self::DEFAULT_HOST;
  85. } else {
  86. $host = $options[self::HOST];
  87. }
  88. if (!isset($options[self::ACCOUNT_NAME])) {
  89. throw new Exception\InvalidArgumentException('No Windows Azure account name provided.');
  90. }
  91. if (!isset($options[self::ACCOUNT_KEY])) {
  92. throw new Exception\InvalidArgumentException('No Windows Azure account key provided.');
  93. }
  94. $this->_storageClient = new Blob($host,
  95. $options[self::ACCOUNT_NAME], $options[self::ACCOUNT_KEY]);
  96. // Parse other options
  97. if (!empty($options[self::PROXY_HOST])) {
  98. $proxyHost = $options[self::PROXY_HOST];
  99. $proxyPort = isset($options[self::PROXY_PORT]) ? $options[self::PROXY_PORT] : 8080;
  100. $proxyCredentials = isset($options[self::PROXY_CREDENTIALS]) ? $options[self::PROXY_CREDENTIALS] : '';
  101. $this->_storageClient->setProxy(true, $proxyHost, $proxyPort, $proxyCredentials);
  102. }
  103. if (isset($options[self::HTTP_ADAPTER])) {
  104. $this->_storageClient->setHttpClientChannel($options[self::HTTP_ADAPTER]);
  105. }
  106. // Set container
  107. $this->_container = $options[self::CONTAINER];
  108. // Make sure the container exists
  109. if (!$this->_storageClient->containerExists($this->_container)) {
  110. $this->_storageClient->createContainer($this->_container);
  111. }
  112. }
  113. /**
  114. * Get an item from the storage service.
  115. *
  116. * @param string $path
  117. * @param array $options
  118. * @return mixed
  119. */
  120. public function fetchItem($path, $options = null)
  121. {
  122. // Options
  123. $returnType = self::RETURN_STRING;
  124. $returnPath = tempnam('', 'azr');
  125. $openMode = 'r';
  126. // Parse options
  127. if (is_array($options)) {
  128. if (isset($options[self::RETURN_TYPE])) {
  129. $returnType = $options[self::RETURN_TYPE];
  130. }
  131. if (isset($options[self::RETURN_PATHNAME])) {
  132. $returnPath = $options[self::RETURN_PATHNAME];
  133. }
  134. if (isset($options[self::RETURN_OPENMODE])) {
  135. $openMode = $options[self::RETURN_OPENMODE];
  136. }
  137. }
  138. // Fetch the blob
  139. try {
  140. $this->_storageClient->getBlob(
  141. $this->_container,
  142. $path,
  143. $returnPath
  144. );
  145. } catch (WindowsAzureException\ExceptionInterface $e) {
  146. if (strpos($e->getMessage(), "does not exist") !== false) {
  147. return false;
  148. }
  149. throw new Exception\RuntimeException('Error on fetch: '.$e->getMessage(), $e->getCode(), $e);
  150. }
  151. // Return value
  152. if ($returnType == self::RETURN_PATH) {
  153. return $returnPath;
  154. }
  155. if ($returnType == self::RETURN_STRING) {
  156. return file_get_contents($returnPath);
  157. }
  158. if ($returnType == self::RETURN_STREAM) {
  159. return fopen($returnPath, $openMode);
  160. }
  161. }
  162. /**
  163. * Store an item in the storage service.
  164. * WARNING: This operation overwrites any item that is located at
  165. * $destinationPath.
  166. * @param string $destinationPath
  167. * @param mixed $data
  168. * @param array $options
  169. * @return boolean
  170. */
  171. public function storeItem($destinationPath, $data, $options = null)
  172. {
  173. // Create a temporary file that will be uploaded
  174. $temporaryFilePath = '';
  175. $removeTemporaryFilePath = false;
  176. if (is_resource($data)) {
  177. $temporaryFilePath = tempnam('', 'azr');
  178. $fpDestination = fopen($temporaryFilePath, 'w');
  179. $fpSource = $data;
  180. rewind($fpSource);
  181. while (!feof($fpSource)) {
  182. fwrite($fpDestination, fread($fpSource, 8192));
  183. }
  184. fclose($fpDestination);
  185. $removeTemporaryFilePath = true;
  186. } elseif (file_exists($data)) {
  187. $temporaryFilePath = $data;
  188. $removeTemporaryFilePath = false;
  189. } else {
  190. $temporaryFilePath = tempnam('', 'azr');
  191. file_put_contents($temporaryFilePath, $data);
  192. $removeTemporaryFilePath = true;
  193. }
  194. try {
  195. // Upload data
  196. $this->_storageClient->putBlob(
  197. $this->_container,
  198. $destinationPath,
  199. $temporaryFilePath
  200. );
  201. } catch(WindowsAzureException\ExceptionInterface $e) {
  202. @unlink($temporaryFilePath);
  203. throw new Exception\RuntimeException('Error on store: '.$e->getMessage(), $e->getCode(), $e);
  204. }
  205. if ($removeTemporaryFilePath) {
  206. @unlink($temporaryFilePath);
  207. }
  208. }
  209. /**
  210. * Delete an item in the storage service.
  211. *
  212. * @param string $path
  213. * @param array $options
  214. * @return void
  215. */
  216. public function deleteItem($path, $options = null)
  217. {
  218. try {
  219. $this->_storageClient->deleteBlob(
  220. $this->_container,
  221. $path
  222. );
  223. } catch (WindowsAzureException\ExceptionInterface $e) {
  224. throw new Exception\RuntimeException('Error on delete: '.$e->getMessage(), $e->getCode(), $e);
  225. }
  226. }
  227. /**
  228. * Copy an item in the storage service to a given path.
  229. *
  230. * @param string $sourcePath
  231. * @param string $destinationPath
  232. * @param array $options
  233. * @return void
  234. */
  235. public function copyItem($sourcePath, $destinationPath, $options = null)
  236. {
  237. try {
  238. $this->_storageClient->copyBlob(
  239. $this->_container,
  240. $sourcePath,
  241. $this->_container,
  242. $destinationPath
  243. );
  244. } catch (WindowsAzureException\ExceptionInterface $e) {
  245. throw new Exception\RuntimeException('Error on copy: '.$e->getMessage(), $e->getCode(), $e);
  246. }
  247. }
  248. /**
  249. * Move an item in the storage service to a given path.
  250. *
  251. * @param string $sourcePath
  252. * @param string $destinationPath
  253. * @param array $options
  254. * @return void
  255. */
  256. public function moveItem($sourcePath, $destinationPath, $options = null)
  257. {
  258. try {
  259. $this->_storageClient->copyBlob(
  260. $this->_container,
  261. $sourcePath,
  262. $this->_container,
  263. $destinationPath
  264. );
  265. $this->_storageClient->deleteBlob(
  266. $this->_container,
  267. $sourcePath
  268. );
  269. } catch (WindowsAzureException\ExceptionInterface $e) {
  270. throw new Exception\RunTimeException('Error on move: '.$e->getMessage(), $e->getCode(), $e);
  271. }
  272. }
  273. /**
  274. * Rename an item in the storage service to a given name.
  275. *
  276. *
  277. * @param string $path
  278. * @param string $name
  279. * @param array $options
  280. * @return void
  281. */
  282. public function renameItem($path, $name, $options = null)
  283. {
  284. return $this->moveItem($path, $name, $options);
  285. }
  286. /**
  287. * List items in the given directory in the storage service
  288. *
  289. * The $path must be a directory
  290. *
  291. *
  292. * @param string $path Must be a directory
  293. * @param array $options
  294. * @return array A list of item names
  295. */
  296. public function listItems($path, $options = null)
  297. {
  298. // Options
  299. $returnType = self::RETURN_NAMES; // 1: return list of paths, 2: return raw output from underlying provider
  300. // Parse options
  301. if (is_array($options)&& isset($options[self::RETURN_TYPE])) {
  302. $returnType = $options[self::RETURN_TYPE];
  303. }
  304. try {
  305. // Fetch list
  306. $blobList = $this->_storageClient->listBlobs(
  307. $this->_container,
  308. $path
  309. );
  310. } catch (WindowsAzureException\ExceptionInterface $e) {
  311. throw new Exception\RuntimeException('Error on list: '.$e->getMessage(), $e->getCode(), $e);
  312. }
  313. // Return
  314. if ($returnType == self::RETURN_LIST) {
  315. return $blobList;
  316. }
  317. $returnValue = array();
  318. foreach ($blobList as $blob) {
  319. $returnValue[] = $blob->Name;
  320. }
  321. return $returnValue;
  322. }
  323. /**
  324. * Get a key/value array of metadata for the given path.
  325. *
  326. * @param string $path
  327. * @param array $options
  328. * @return array
  329. */
  330. public function fetchMetadata($path, $options = null)
  331. {
  332. try {
  333. return $this->_storageClient->getBlobMetaData(
  334. $this->_container,
  335. $path
  336. );
  337. } catch (WindowsAzureException\ExceptionInterface $e) {
  338. if (strpos($e->getMessage(), "could not be accessed") !== false) {
  339. return false;
  340. }
  341. throw new Exception\RuntimeException('Error on fetch: '.$e->getMessage(), $e->getCode(), $e);
  342. }
  343. }
  344. /**
  345. * Store a key/value array of metadata at the given path.
  346. * WARNING: This operation overwrites any metadata that is located at
  347. * $destinationPath.
  348. *
  349. * @param string $destinationPath
  350. * @param array $options
  351. * @return void
  352. */
  353. public function storeMetadata($destinationPath, $metadata, $options = null)
  354. {
  355. try {
  356. $this->_storageClient->setBlobMetadata($this->_container, $destinationPath, $metadata);
  357. } catch (WindowsAzureException\ExceptionInterface $e) {
  358. if (strpos($e->getMessage(), "could not be accessed") === false) {
  359. throw new Exception\RuntimeException('Error on store metadata: '.$e->getMessage(), $e->getCode(), $e);
  360. }
  361. }
  362. }
  363. /**
  364. * Delete a key/value array of metadata at the given path.
  365. *
  366. * @param string $path
  367. * @param array $options
  368. * @return void
  369. */
  370. public function deleteMetadata($path, $options = null)
  371. {
  372. try {
  373. $this->_storageClient->setBlobMetadata($this->_container, $destinationPath, array());
  374. } catch (WindowsAzureException\ExceptionInterface $e) {
  375. if (strpos($e->getMessage(), "could not be accessed") === false) {
  376. throw new Exception\RuntimeException('Error on delete metadata: '.$e->getMessage(), $e->getCode(), $e);
  377. }
  378. }
  379. }
  380. /**
  381. * Delete container
  382. *
  383. * @return void
  384. */
  385. public function deleteContainer()
  386. {
  387. try {
  388. $this->_storageClient->deleteContainer($this->_container);
  389. } catch (WindowsAzureException\ExceptionInterface $e) {
  390. throw new Exception\RuntimeException('Error on delete: '.$e->getMessage(), $e->getCode(), $e);
  391. }
  392. }
  393. /**
  394. * Get the concrete adapter.
  395. * @return \Zend\Service\WindowsAzure\Storage\Blob\Blob
  396. */
  397. public function getClient()
  398. {
  399. return $this->_storageClient;
  400. }
  401. }