1: <?php
2: /**
3: * This code is licensed under AGPLv3 license or Afterlogic Software License
4: * if commercial version of the product was purchased.
5: * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
6: */
7:
8: namespace Aurora\Modules\FilesZipFolder;
9:
10: /**
11: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
12: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
13: * @copyright Copyright (c) 2023, Afterlogic Corp.
14: *
15: * @package Modules
16: */
17: class Module extends \Aurora\System\Module\AbstractModule
18: {
19: /***** private functions *****/
20: /**
21: * Initializes FilesZipFolder Module.
22: *
23: * @ignore
24: */
25: public function init()
26: {
27: $this->subscribeEvent('Files::GetFile', array($this, 'onGetFile'), 50);
28: // $this->subscribeEvent('Files::GetItems::before', array($this, 'onBeforeGetItems'), 500);
29: $this->subscribeEvent('Files::GetItems', array($this, 'onGetItems'), 50);
30: $this->subscribeEvent('Files::CreateFolder::before', array($this, 'onBeforeCreateFolder'), 50);
31: $this->subscribeEvent('Files::CreateFile', array($this, 'onCreateFile'), 50);
32: $this->subscribeEvent('Files::Delete::after', array($this, 'onAfterDelete'), 50);
33: $this->subscribeEvent('Files::Rename::after', array($this, 'onAfterRename'), 50);
34: $this->subscribeEvent('Files::Move::before', array($this, 'onBeforeMove'), 50);
35: $this->subscribeEvent('Files::Copy::before', array($this, 'onBeforeCopy'), 50);
36: $this->subscribeEvent('Files::GetFileInfo::after', array($this, 'onAfterGetFileInfo'), 500);
37: $this->subscribeEvent('Files::PopulateFileItem::after', array($this, 'onAfterPopulateFileItem'));
38: }
39:
40: /**
41: * Returns directory name for the specified path.
42: *
43: * @param string $sPath Path to the file.
44: * @return string
45: */
46: protected function getDirName($sPath)
47: {
48: $sPath = \dirname($sPath);
49: return \str_replace(DIRECTORY_SEPARATOR, '/', $sPath);
50: }
51:
52: /**
53: * Returns base name for the specified path.
54: *
55: * @param string $sPath Path to the file.
56: * @return string
57: */
58: protected function getBaseName($sPath)
59: {
60: $aPath = \explode('/', $sPath);
61: return \end($aPath);
62: }
63:
64: /**
65: * Populates file info.
66: *
67: * @param string $sType Service type.
68: * @param \Dropbox\Client $oClient DropBox client.
69: * @param array $aData Array contains information about file.
70: * @return \Aurora\Modules\Files\Classes\FileItem|false
71: */
72: protected function populateFileInfo($sType, $oClient, $aData)
73: {
74: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
75:
76: $mResult = false;
77: if ($aData && \is_array($aData)) {
78: $sPath = \ltrim($this->getDirName($aData['path']), '/');
79:
80: // $oSocial = $this->GetSocial($oAccount);
81: $mResult /*@var $mResult \Aurora\Modules\Files\Classes\FileItem */ = new \Aurora\Modules\Files\Classes\FileItem();
82: // $mResult->IsExternal = true;
83: $mResult->TypeStr = $sType;
84: $mResult->IsFolder = $aData['is_dir'];
85: $mResult->Id = $this->getBaseName($aData['path']);
86: $mResult->Name = $mResult->Id;
87: $mResult->Path = !empty($sPath) ? '/'.$sPath : $sPath;
88: $mResult->Size = $aData['bytes'];
89: // $bResult->Owner = $oSocial->Name;
90: $mResult->LastModified = \date_timestamp_get($oClient->parseDateTime($aData['modified']));
91: $mResult->Shared = isset($aData['shared']) ? $aData['shared'] : false;
92: $mResult->FullPath = $mResult->Name !== '' ? $mResult->Path . '/' . $mResult->Name : $mResult->Path ;
93:
94: if (!$mResult->IsFolder && $aData['thumb_exists']) {
95: $mResult->Thumb = true;
96: }
97: }
98: return $mResult;
99: }
100:
101: public function getItemHash($oItem)
102: {
103: return \Aurora\System\Api::EncodeKeyValues(array(
104: 'UserId' => \Aurora\System\Api::getAuthenticatedUserId(),
105: 'Type' => $oItem->TypeStr,
106: 'Path' => $oItem->FullPath,
107: 'Name' => $oItem->Name
108: ));
109: }
110:
111: /**
112: * Writes to the $mResult variable open file source if $sType is DropBox account type.
113: *
114: * @ignore
115: * @param int $iUserId Identifier of the authenticated user.
116: * @param string $sType Service type.
117: * @param string $sPath File path.
118: * @param string $sName File name.
119: * @param boolean $bThumb **true** if thumbnail is expected.
120: * @param mixed $mResult
121: */
122: public function onGetFile($aArgs, &$mResult)
123: {
124: $sPath = $aArgs['Path'];
125: if (\strpos($sPath, '$ZIP:')) {
126: list($sPath, $sIndex) = \explode('$ZIP:', $sPath);
127: }
128: $aPathInfo = \pathinfo($sPath);
129: if (isset($aPathInfo['extension']) && $aPathInfo['extension'] === 'zip') {
130: $aArgs['Id'] = \basename($sPath);
131: $aArgs['Path'] = \dirname($sPath) === '\\' ? '' : \dirname($sPath);
132: $oFileInfo = false;
133: \Aurora\System\Api::GetModuleManager()->broadcastEvent(
134: 'Files',
135: 'GetFileInfo::after',
136: $aArgs,
137: $oFileInfo
138: );
139:
140: if ($oFileInfo && class_exists('ZipArchive')) {
141: $za = new \ZipArchive();
142: $za->open($oFileInfo->RealPath);
143: $mResult = $za->getStream($sIndex);
144: if (\is_resource($mResult)) {
145: $aArgs['Name'] = \basename($sIndex);
146: return true;
147: }
148: }
149: }
150: }
151:
152: /**
153: * Writes to $aData variable list of DropBox files if $aData['Type'] is DropBox account type.
154: *
155: * @ignore
156: * @param array $aData Is passed by reference.
157: */
158: public function onGetItems($aArgs, &$mResult)
159: {
160: if (isset($aArgs['Path'])) {
161: $sPath = $aArgs['Path'];
162: $sIndex = '';
163: if (\strpos($sPath, '$ZIP:')) {
164: list($sPath, $sIndex) = \explode('$ZIP:', $sPath);
165: }
166: $aPathInfo = \pathinfo($sPath);
167: if (isset($aPathInfo['extension']) && $aPathInfo['extension'] === 'zip') {
168: $aGetFileInfoArgs = array(
169: 'Id' => \basename($sPath),
170: 'Name' => \basename($sPath),
171: 'Path' => \trim(\dirname($sPath), '\\'),
172: 'UserId' => $aArgs['UserId'],
173: 'Type' => $aArgs['Type']
174: );
175: $oFileInfo = false;
176: \Aurora\System\Api::GetModuleManager()->broadcastEvent(
177: 'Files',
178: 'GetFileInfo::after',
179: $aGetFileInfoArgs,
180: $oFileInfo
181: );
182:
183: if ($oFileInfo && class_exists('ZipArchive')) {
184: $za = new \ZipArchive();
185: $za->open($oFileInfo->RealPath);
186:
187: $mResult = array();
188: $aItems = array();
189: for ($i = 0; $i < $za->numFiles; $i++) {
190: $aStat = $za->statIndex($i);
191: $sStatName = $aStat['name'];
192: if (!empty($sStatName) && !empty($sIndex)) {
193: if (strpos($sStatName, $sIndex) === 0) {
194: $sStatName = \substr($sStatName, \strlen($sIndex));
195: } else {
196: $sStatName = '';
197: }
198: }
199: if (!empty($sStatName)) {
200: $oItem /*@var $oItem \Aurora\Modules\Files\Classes\FileItem */ = new \Aurora\Modules\Files\Classes\FileItem();
201: $oItem->Id = $aStat['name'];
202: $oItem->Path = $sPath;
203: $oItem->TypeStr = $aArgs['Type'];
204: $oItem->FullPath = $oItem->Path . '$ZIP:' . $oItem->Id;
205: if ($aStat['size'] === 0) {
206: $oItem->IsFolder = true;
207: } else {
208: $oItem->Size = $aStat['size'];
209: }
210: $oItem->ContentType = \MailSo\Base\Utils::MimeContentType($oItem->Id);
211:
212: $aPath = \explode('/', $sStatName);
213: $sName = $aPath[0];
214:
215: if (!isset($aItems[$sName])) {
216: $oItem->Name = $sName;
217: $aItems[$sName] = $oItem;
218: }
219:
220: if ($oItem->IsFolder) {
221: $oItem->AddAction([
222: 'list' => []
223: ]);
224: } else {
225: $oItem->AddAction([
226: 'view' => [
227: 'url' => '?download-file/' . $this->getItemHash($oItem) .'/view'
228: ]
229: ]);
230: $oItem->AddAction([
231: 'download' => [
232: 'url' => '?download-file/' . $this->getItemHash($oItem)
233: ]
234: ]);
235:
236: $sMimeType = \MailSo\Base\Utils::MimeContentType($sName);
237: $oSettings =& \Aurora\System\Api::GetSettings();
238: $iThumbnailLimit = ((int) $oSettings->GetValue('ThumbnailMaxFileSizeMb', 5)) * 1024 * 1024;
239: if ($oSettings->GetValue('AllowThumbnail', true) &&
240: $oItem->Size < $iThumbnailLimit && \Aurora\System\Utils::IsGDImageMimeTypeSuppoted($sMimeType, $sName)) {
241: $oItem->Thumb = true;
242: $oItem->ThumbnailUrl = '?download-file/' . $this->getItemHash($oItem) .'/thumb';
243: }
244: }
245: }
246: }
247: $mResult = \array_values($aItems);
248: }
249: return true;
250: }
251: }
252: }
253:
254: /**
255: * Creates folder if $aData['Type'] is DropBox account type.
256: *
257: * @ignore
258: * @param array $aData Is passed by reference.
259: */
260: public function onBeforeCreateFolder($aArgs, &$mResult)
261: {
262: }
263:
264: /**
265: * Creates file if $aData['Type'] is DropBox account type.
266: *
267: * @ignore
268: * @param array $aData
269: */
270: public function onCreateFile($aArgs, &$Result)
271: {
272: }
273:
274: /**
275: * Deletes file if $aData['Type'] is DropBox account type.
276: *
277: * @ignore
278: * @param array $aData
279: */
280: public function onAfterDelete($aArgs, &$mResult)
281: {
282: $bResult = false;
283:
284: foreach ($aArgs['Items'] as $aItem) {
285: $sPath = $aItem['Path'];
286: $aPathInfo = \pathinfo($sPath);
287: if (isset($aPathInfo['extension']) && $aPathInfo['extension'] === 'zip') {
288: $sName = $aItem['Name'];
289: $aGetFileInfoArgs = $aArgs;
290: $aGetFileInfoArgs['Name'] = \basename($sPath);
291: $aGetFileInfoArgs['Path'] = \dirname($sPath);
292: $oFileInfo = false;
293: \Aurora\System\Api::GetModuleManager()->broadcastEvent(
294: 'Files',
295: 'GetFileInfo::after',
296: $aGetFileInfoArgs,
297: $oFileInfo
298: );
299: if ($oFileInfo && class_exists('ZipArchive')) {
300: $za = new \ZipArchive();
301: $za->open($oFileInfo->RealPath);
302: $mResult = $za->deleteName($sName);
303: $bResult = $mResult;
304: }
305: }
306: }
307: return $bResult;
308: }
309:
310: /**
311: * Renames file if $aData['Type'] is DropBox account type.
312: *
313: * @ignore
314: * @param array $aData
315: */
316: public function onAfterRename($aArgs, &$mResult)
317: {
318: $sPath = $aArgs['Path'];
319: $aPathInfo = \pathinfo($sPath);
320: if (isset($aPathInfo['extension']) && $aPathInfo['extension'] === 'zip') {
321: $sName = $aArgs['Name'];
322: $sNewName = $aArgs['NewName'];
323: $aArgs['Name'] = \basename($sPath);
324: $aArgs['Path'] = \dirname($sPath);
325: $oFileInfo = false;
326: \Aurora\System\Api::GetModuleManager()->broadcastEvent(
327: 'Files',
328: 'GetFileInfo::after',
329: $aArgs,
330: $oFileInfo
331: );
332: if ($oFileInfo && class_exists('ZipArchive')) {
333: $za = new \ZipArchive();
334: $za->open($oFileInfo->RealPath);
335: $sFileDir = \dirname($sName);
336: if ($sFileDir !== '.') {
337: $sNewFullPath = $sFileDir . $sNewName;
338: } else {
339: $sNewFullPath = $sNewName;
340: }
341: $mResult = $za->renameName($sName, $sNewFullPath);
342: $za->close();
343: }
344: return $mResult;
345: }
346: }
347:
348: /**
349: * Moves file if $aData['Type'] is DropBox account type.
350: *
351: * @ignore
352: * @param array $aData
353: */
354: public function onBeforeMove($aArgs, &$mResult)
355: {
356: $sPath = $aArgs['FromPath'];
357: $aPathInfo = \pathinfo($sPath);
358: if (isset($aPathInfo['extension']) && $aPathInfo['extension'] === 'zip') {
359: $sFileName = $aArgs['Name'];
360: $aArgs['Name'] = \basename($sPath);
361: $aArgs['Path'] = \dirname($sPath);
362: $oFileInfo = false;
363: \Aurora\System\Api::GetModuleManager()->broadcastEvent(
364: 'Files',
365: 'GetFileInfo::after',
366: $aArgs,
367: $oFileInfo
368: );
369: if ($oFileInfo && class_exists('ZipArchive')) {
370: $za = new \ZipArchive();
371: $za->open($oFileInfo->RealPath);
372: }
373: }
374: }
375:
376: /**
377: * Copies file if $aData['Type'] is DropBox account type.
378: *
379: * @ignore
380: * @param array $aData
381: */
382: public function onBeforeCopy($aArgs, &$mResult)
383: {
384: }
385:
386: /**
387: * @ignore
388: * @todo not used
389: * @param object $oAccount
390: * @param string $sType
391: * @param string $sPath
392: * @param string $sName
393: * @param mixed $mResult
394: * @param boolean $bBreak
395: */
396: public function onAfterGetFileInfo($aArgs, &$mResult)
397: {
398: }
399:
400: /**
401: * @ignore
402: * @todo not used
403: * @param object $oItem
404: * @return boolean
405: */
406: public function onAfterPopulateFileItem($oItem, &$mResult)
407: {
408: if (isset($mResult)) {
409: $aPathInfo = \pathinfo($mResult->Name);
410: if (class_exists('ZipArchive') && isset($aPathInfo['extension']) && $aPathInfo['extension'] === 'zip') {
411: $mResult->UnshiftAction(array(
412: 'list' => array()
413: ));
414: }
415: }
416:
417: return false;
418: }
419: /***** private functions *****/
420: }
421: