BxDolStorageS3.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaCore UNA Core
  7. * @{
  8. */
  9. if (!defined('CURL_SSLVERSION_TLSv1'))
  10. define('CURL_SSLVERSION_TLSv1', 1);
  11. require_once(BX_DIRECTORY_PATH_PLUGINS . 'amazon-s3/S3.php');
  12. /**
  13. * File storage in Amazon S3.
  14. * @see BxDolStorage
  15. */
  16. class BxDolStorageS3 extends BxDolStorage
  17. {
  18. protected $_s3;
  19. protected $_sBucket;
  20. protected $_sDomain;
  21. protected $_bSSL;
  22. protected $_bReducedRedundancy;
  23. /**
  24. * constructor
  25. */
  26. public function __construct($aObject)
  27. {
  28. parent::__construct($aObject);
  29. $sAccessKey = getParam('sys_storage_s3_access_key');
  30. $sSecretKey = getParam('sys_storage_s3_secret_key');
  31. $this->_s3 = new S3($sAccessKey, $sSecretKey);
  32. $this->_sBucket = getParam('sys_storage_s3_bucket');
  33. $this->_sDomain = getParam('sys_storage_s3_domain');
  34. $this->_bSSL = (isset($this->_aParams['ssl']) && $this->_aParams['ssl']) || (!isset($this->_aParams['ssl']) && strncmp(BX_DOL_URL_ROOT, 'https://', 8) === 0) ? true : false;
  35. $this->_bReducedRedundancy = isset($this->_aParams['reduced_redundancy']) && $this->_aParams['reduced_redundancy'] ? true : false;
  36. }
  37. /**
  38. * Get file url.
  39. * @param $iFileId file
  40. * @return file url
  41. */
  42. public function getFileUrlById($iFileId)
  43. {
  44. $aFile = $this->_oDb->getFileById($iFileId);
  45. if (!$aFile)
  46. return false;
  47. if ($aFile['private']) {
  48. $sFileLocation = $this->getObjectBaseDir($aFile['private']) . $aFile['path'];
  49. if ($this->_sDomain)
  50. return $this->_s3->getAuthenticatedURL($this->_sDomain, $sFileLocation, $this->_aObject['token_life'], true, $this->_bSSL);
  51. else
  52. return $this->_s3->getAuthenticatedURL($this->_sBucket, $sFileLocation, $this->_aObject['token_life'], false, $this->_bSSL);
  53. }
  54. return $this->getObjectBaseUrl($aFile['private']) . $aFile['path'];
  55. }
  56. /**
  57. * Start file fownloading by remote id. If file is private then token is checked.
  58. */
  59. public function download ($sRemoteId, $sToken = false)
  60. {
  61. $this->setErrorCode(BX_DOL_STORAGE_ERR_OK);
  62. $aFile = $this->_oDb->getFileByRemoteId($sRemoteId);
  63. if (!$aFile) {
  64. $this->setErrorCode(BX_DOL_STORAGE_ERR_FILE_NOT_FOUND);
  65. return false;
  66. }
  67. if ($aFile['private'] && !$this->_oDb->isTokenValid($aFile['id'], $sToken)) {
  68. $this->setErrorCode(BX_DOL_STORAGE_ERR_PERMISSION_DENIED);
  69. return false;
  70. }
  71. $sUrl = $this->getFileUrlById($aFile['id']);
  72. header("Location: " . $sUrl);
  73. return parent::download($aFile);
  74. }
  75. /**
  76. * Set file private or public.
  77. */
  78. public function setFilePrivate($iFileId, $isPrivate = true)
  79. {
  80. $aFile = $this->_oDb->getFileById($iFileId);
  81. $sFileLocation = $this->getObjectBaseDir($aFile['private']) . $aFile['path'];
  82. if (($aACP = $this->_s3->getAccessControlPolicy($this->_sBucket, $sFileLocation)) === false) {
  83. $this->setErrorCode(BX_DOL_STORAGE_ERR_ENGINE_GET);
  84. return false;
  85. }
  86. if (!is_array($aACP['acl']) || !$aACP['acl']) {
  87. $this->setErrorCode(BX_DOL_STORAGE_ERR_ENGINE_GET);
  88. return false;
  89. }
  90. // check current permissions
  91. $aNewACP = $aACP;
  92. unset($aNewACP['acl']);
  93. $aNewACP['acl'] = array();
  94. $aGroupPublic = false;
  95. $aGroupPrivate = false;
  96. foreach ($aACP['acl'] as $r) {
  97. if ('Group' == $r['type']) {
  98. if (isset($r['uri']) && $r['uri'] == 'http://acs.amazonaws.com/groups/global/AllUsers')
  99. $aGroupPublic = $r;
  100. elseif (isset($r['uri']) && $r['uri'] == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers')
  101. $aGroupPrivate = $r;
  102. else
  103. $aNewACP['acl'][] = $r;
  104. } else {
  105. $aNewACP['acl'][] = $r;
  106. }
  107. }
  108. // determine permissions changing
  109. $aGroupAdd = false;
  110. if ($isPrivate && (!$aGroupPrivate || $aGroupPublic)) {
  111. // make private
  112. $aGroupAdd = array (
  113. 'type' => 'Group',
  114. 'uri' => 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers',
  115. 'permission' => 'READ',
  116. );
  117. } elseif (!$isPrivate && ($aGroupPrivate || !$aGroupPublic)) {
  118. // make public
  119. $aGroupAdd = array (
  120. 'type' => 'Group',
  121. 'uri' => 'http://acs.amazonaws.com/groups/global/AllUsers',
  122. 'permission' => 'READ',
  123. );
  124. }
  125. // change permission if necessary
  126. if ($aGroupAdd) {
  127. $aNewACP['acl'][] = $aGroupAdd;
  128. if (!$this->_s3->setAccessControlPolicy($this->_sBucket, $sFileLocation, $aNewACP)) {
  129. $this->setErrorCode(BX_DOL_STORAGE_ERR_ENGINE_GET);
  130. return false;
  131. }
  132. }
  133. return parent::setFilePrivate($iFileId, $isPrivate);
  134. }
  135. // ----------------
  136. protected function addFileToEngine($sTmpFile, $sLocalId, $sName, $isPrivate, $iProfileId)
  137. {
  138. $sMimeType = $this->getMimeTypeByFileName($sName);
  139. $sExt = $this->getFileExt($sName);
  140. $sPath = $this->genPath($sLocalId, $this->_aObject['levels']);
  141. $sRemoteNamePath = $sPath . $sLocalId . ($sExt ? '.' . $sExt : '');
  142. $aMetaHeaders = array();
  143. $aRequestHeaders = array (
  144. "Content-Type" => $sMimeType,
  145. );
  146. if ($this->_iCacheControl > 0) {
  147. $aRequestHeaders = array_merge ($aRequestHeaders, array (
  148. "Cache-Control" => "max-age=" . ($isPrivate && $this->_iCacheControl > $this->_aObject['token_life'] ? $this->_aObject['token_life'] : $this->_iCacheControl),
  149. ));
  150. }
  151. $sStorageClass = $this->_bReducedRedundancy ? S3::STORAGE_CLASS_RRS : S3::STORAGE_CLASS_STANDARD;
  152. $sACL = $isPrivate ? S3::ACL_AUTHENTICATED_READ : S3::ACL_PUBLIC_READ;
  153. $aInputFile = $this->_s3->inputFile($sTmpFile);
  154. if (!$this->_s3->putObject($aInputFile, $this->_sBucket, $this->getObjectBaseDir($isPrivate) . $sRemoteNamePath, $sACL, $aMetaHeaders, $aRequestHeaders, $sStorageClass)) {
  155. $this->setErrorCode(BX_DOL_STORAGE_ERR_ENGINE_ADD);
  156. return false;
  157. }
  158. return true;
  159. }
  160. protected function deleteFileFromEngine($sFilePath, $isPrivate)
  161. {
  162. $sFileLocation = $this->getObjectBaseDir($isPrivate) . $sFilePath;
  163. if (!$this->_s3->deleteObject($this->_sBucket, $sFileLocation)) {
  164. $this->setErrorCode(BX_DOL_STORAGE_ERR_UNLINK);
  165. return false;
  166. }
  167. return true;
  168. }
  169. protected function genRemoteNamePath ($sPath, $sLocalId, $sExt)
  170. {
  171. return $sPath . $sLocalId . ($sExt ? '.' . $sExt : '');
  172. }
  173. protected function getObjectBaseDir ($isPrivate = false)
  174. {
  175. return $this->_aObject['object'] . '/';
  176. }
  177. protected function getObjectBaseUrl ($isPrivate = false)
  178. {
  179. $sProto = $this->_bSSL ? 'https://' : 'http://';
  180. return $sProto . $this->_sBucket . '.s3.amazonaws.com/' . $this->getObjectBaseDir($isPrivate);
  181. }
  182. }
  183. /** @} */