functions.php 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108
  1. <?php
  2. /**
  3. * All helper functions are bundled here
  4. */
  5. /**
  6. * Get the extension of an ElggFile
  7. *
  8. * @param ElggFile $file the file to check
  9. *
  10. * @return string
  11. */
  12. function file_tools_get_file_extension($file) {
  13. $result = '';
  14. if ($file->getSubtype() == 'file') {
  15. if ($filename = $file->getFilename()) {
  16. $exploded_filename = explode('.', $filename);
  17. $result = end($exploded_filename);
  18. }
  19. }
  20. return strtolower($result);
  21. }
  22. /**
  23. * Read a folder structure for a zip file
  24. *
  25. * @param ElggObject $folder the folder to read
  26. * @param string $prepend current prefix
  27. *
  28. * @return array
  29. */
  30. function file_tools_get_zip_structure($folder, $prepend) {
  31. $entries = array();
  32. if ($prepend) {
  33. $prepend .= '/';
  34. }
  35. if (!$folder) {
  36. $parent_guid = 0;
  37. } else {
  38. $parent_guid = $folder->getGUID();
  39. }
  40. $options = array(
  41. "type" => "object",
  42. "subtype" => FILE_TOOLS_SUBTYPE,
  43. "limit" => false,
  44. "metadata_name" => "parent_guid",
  45. "metadata_value" => $parent_guid,
  46. );
  47. // voor de hoogste map de sub bestanden nog ophalen
  48. if ($entities = elgg_get_entities_from_metadata($options)) {
  49. foreach ($entities as $subfolder) {
  50. $title = $prepend . $subfolder->title;
  51. $entries[] = array('directory' => $title, 'files' => file_tools_has_files($subfolder->getGUID()));
  52. $entries = array_merge($entries, file_tools_get_zip_structure($subfolder, $title));
  53. }
  54. }
  55. return $entries;
  56. }
  57. /**
  58. * Check if a folder has files
  59. *
  60. * @param ElggObject $folder the folder to check
  61. *
  62. * @return bool|array
  63. */
  64. function file_tools_has_files($folder) {
  65. $files_options = array(
  66. "type" => "object",
  67. "subtype" => "file",
  68. "limit" => false,
  69. //"container_guid" => get_loggedin_userid(),
  70. "relationship" => FILE_TOOLS_RELATIONSHIP,
  71. "relationship_guid" => $folder,
  72. "inverse_relationship" => false
  73. );
  74. $file_guids = array();
  75. if ($files = elgg_get_entities_from_relationship($files_options)) {
  76. foreach ($files as $file) {
  77. $file_guids[] = $file->getGUID();
  78. }
  79. return $file_guids;
  80. }
  81. return false;
  82. }
  83. /**
  84. * Get the folders in a container
  85. *
  86. * @param int $container_guid the container to check
  87. *
  88. * @return bool|ElggObject[]
  89. */
  90. function file_tools_get_folders($container_guid = 0) {
  91. $result = false;
  92. if (empty($container_guid)) {
  93. $container_guid = elgg_get_page_owner_guid();
  94. }
  95. if (!empty($container_guid)) {
  96. $options = array(
  97. "type" => "object",
  98. "subtype" => FILE_TOOLS_SUBTYPE,
  99. "container_guid" => $container_guid,
  100. "limit" => false
  101. );
  102. if ($folders = elgg_get_entities($options)) {
  103. $parents = array();
  104. foreach ($folders as $folder) {
  105. $parent_guid = (int) $folder->parent_guid;
  106. if (!empty($parent_guid)) {
  107. if ($temp = get_entity($parent_guid)) {
  108. if ($temp->getSubtype() != FILE_TOOLS_SUBTYPE) {
  109. $parent_guid = 0;
  110. }
  111. } else {
  112. $parent_guid = 0;
  113. }
  114. } else {
  115. $parent_guid = 0;
  116. }
  117. if (!array_key_exists($parent_guid, $parents)) {
  118. $parents[$parent_guid] = array();
  119. }
  120. $parents[$parent_guid][] = $folder;
  121. }
  122. $result = file_tools_sort_folders($parents, 0);
  123. }
  124. }
  125. return $result;
  126. }
  127. /**
  128. * Make folder select options
  129. *
  130. * @param array $folders folders to make the options for
  131. * @param int $depth current depth
  132. *
  133. * @return string
  134. */
  135. function file_tools_build_select_options($folders, $depth = 0) {
  136. $result = array();
  137. if (!empty($folders)) {
  138. foreach ($folders as $index => $level) {
  139. /**
  140. * $level contains
  141. * folder: the folder on this level
  142. * children: potential children
  143. *
  144. */
  145. if ($folder = elgg_extract("folder", $level)) {
  146. $result[$folder->getGUID()] = str_repeat("-", $depth) . $folder->title;
  147. }
  148. if ($childen = elgg_extract("children", $level)) {
  149. $result += file_tools_build_select_options($childen, $depth + 1);
  150. }
  151. }
  152. }
  153. return $result;
  154. }
  155. /**
  156. * Get folder selection options for widgets
  157. *
  158. * @param array $folder the folder to create for
  159. * @param string $internalname the name of the input field
  160. * @param array $selected the current selected values
  161. *
  162. * @return string
  163. */
  164. function file_tools_build_widget_options($folder, $internalname = "", $selected = array()) {
  165. $result = "";
  166. if (is_array($folder) && !array_key_exists("children", $folder)) {
  167. foreach ($folder as $folder_item) {
  168. $result .= "<ul>";
  169. $result .= file_tools_build_widget_options($folder_item, $internalname, $selected);
  170. $result .= "</ul>";
  171. }
  172. } else {
  173. $folder_item = $folder["folder"];
  174. $result .= "<li>";
  175. if (in_array($folder_item->getGUID(), $selected)) {
  176. $result .= "<input type='checkbox' name='" . $internalname . "' value='" . $folder_item->getGUID() . "' checked='checked'> " . $folder_item->title;
  177. } else {
  178. $result .= "<input type='checkbox' name='" . $internalname . "' value='" . $folder_item->getGUID() . "'> " . $folder_item->title;
  179. }
  180. if (!empty($folder["children"])) {
  181. $result .= file_tools_build_widget_options($folder["children"], $internalname, $selected);
  182. }
  183. $result .= "</li>";
  184. }
  185. return $result;
  186. }
  187. /**
  188. * Folder folders by their order
  189. *
  190. * @param array $folders the folders to sort
  191. * @param int $parent_guid the parent to sort for
  192. *
  193. * @return bool|array
  194. */
  195. function file_tools_sort_folders($folders, $parent_guid = 0) {
  196. $result = false;
  197. if (array_key_exists($parent_guid, $folders)) {
  198. $result = array();
  199. foreach ($folders[$parent_guid] as $subfolder) {
  200. $children = file_tools_sort_folders($folders, $subfolder->getGUID());
  201. $order = $subfolder->order;
  202. if (empty($order)) {
  203. $order = 0;
  204. }
  205. while (array_key_exists($order, $result)) {
  206. $order++;
  207. }
  208. $result[$order] = array(
  209. "folder" => $subfolder,
  210. "children" => $children
  211. );
  212. }
  213. ksort($result);
  214. }
  215. return $result;
  216. }
  217. /**
  218. * Get the subfolders of a folder
  219. *
  220. * @param ElggObject $folder the folder to get the subfolders for
  221. * @param bool $list output a list (default: false)
  222. *
  223. * @return bool|array|string
  224. */
  225. function file_tools_get_sub_folders($folder = false, $list = false) {
  226. $result = false;
  227. if (!empty($folder) && elgg_instanceof($folder, "object", FILE_TOOLS_SUBTYPE)) {
  228. $container_guid = $folder->getContainerGUID();
  229. $parent_guid = $folder->getGUID();
  230. } else {
  231. $container_guid = elgg_get_page_owner_guid();
  232. $parent_guid = 0;
  233. }
  234. $options = array(
  235. "type" => "object",
  236. "subtype" => FILE_TOOLS_SUBTYPE,
  237. "container_guid" => $container_guid,
  238. "limit" => false,
  239. "metadata_name" => "parent_guid",
  240. "metadata_value" => $parent_guid,
  241. "order_by_metadata" => array('name' => 'order', 'direction' => 'ASC', 'as' => 'integer'),
  242. "full_view" => false,
  243. "pagination" => false
  244. );
  245. if ($list) {
  246. $folders = elgg_list_entities_from_metadata($options);
  247. } else {
  248. $folders = elgg_get_entities_from_metadata($options);
  249. }
  250. if ($folders) {
  251. $result = $folders;
  252. }
  253. return $result;
  254. }
  255. /**
  256. * Create a folder menu
  257. *
  258. * @param array $folders the folders to create the menu for
  259. *
  260. * @return bool|ElggMenuItem[]
  261. */
  262. function file_tools_make_menu_items($folders) {
  263. $result = false;
  264. if (!empty($folders) && is_array($folders)) {
  265. $result = array();
  266. foreach ($folders as $index => $level) {
  267. if ($folder = elgg_extract("folder", $level)) {
  268. $folder_title = $folder->title;
  269. if (empty($folder_title)) {
  270. $folder_title = elgg_echo("untitled");
  271. }
  272. $folder_menu = ElggMenuItem::factory(array(
  273. "name" => "folder_" . $folder->getGUID(),
  274. "text" => $folder_title,
  275. "href" => "#" . $folder->getGUID(),
  276. "priority" => $folder->order
  277. ));
  278. if ($children = elgg_extract("children", $level)) {
  279. $folder_menu->setChildren(file_tools_make_menu_items($children));
  280. }
  281. $result[] = $folder_menu;
  282. }
  283. }
  284. }
  285. return $result;
  286. }
  287. /**
  288. * Recursivly change the access of subfolders (and files)
  289. *
  290. * @param ElggObject $folder the folder to change the access for
  291. * @param bool $change_files include files in this folder (default: false)
  292. *
  293. * @return void
  294. */
  295. function file_tools_change_children_access($folder, $change_files = false) {
  296. if (!empty($folder) && ($folder instanceof ElggObject)) {
  297. if ($folder->getSubtype() == FILE_TOOLS_SUBTYPE) {
  298. // get children folders
  299. $options = array(
  300. "type" => "object",
  301. "subtype" => FILE_TOOLS_SUBTYPE,
  302. "container_guid" => $folder->getContainerGUID(),
  303. "limit" => false,
  304. "metadata_name" => "parent_guid",
  305. "metadata_value" => $folder->getGUID()
  306. );
  307. if ($children = elgg_get_entities_from_metadata($options)) {
  308. foreach ($children as $child) {
  309. $child->access_id = $folder->access_id;
  310. $child->save();
  311. file_tools_change_children_access($child, $change_files);
  312. }
  313. }
  314. if ($change_files) {
  315. // change access on files in this folder
  316. file_tools_change_files_access($folder);
  317. }
  318. }
  319. }
  320. }
  321. /**
  322. * Change the access of all file in a folder
  323. *
  324. * @param ElggObject $folder the folder to change the file access for
  325. *
  326. * @return void
  327. */
  328. function file_tools_change_files_access($folder) {
  329. if (!empty($folder) && ($folder instanceof ElggObject)) {
  330. if ($folder->getSubtype() == FILE_TOOLS_SUBTYPE) {
  331. // change access on files in this folder
  332. $options = array(
  333. "type" => "object",
  334. "subtype" => "file",
  335. "container_guid" => $folder->getContainerGUID(),
  336. "limit" => false,
  337. "relationship" => FILE_TOOLS_RELATIONSHIP,
  338. "relationship_guid" => $folder->getGUID()
  339. );
  340. if ($files = elgg_get_entities_from_relationship($options)) {
  341. // need to unregister an event listener
  342. elgg_unregister_event_handler("update", "object", "file_tools_object_handler");
  343. foreach ($files as $file) {
  344. $file->access_id = $folder->access_id;
  345. $file->save();
  346. }
  347. }
  348. }
  349. }
  350. }
  351. /**
  352. * Get the allowed extensions for uploading
  353. *
  354. * @param bool $zip return zip upload dialog format
  355. *
  356. * @return bool|string
  357. */
  358. function file_tools_allowed_extensions($zip = false) {
  359. $allowed_extensions_settings = elgg_get_plugin_setting('allowed_extensions', 'file_tools');
  360. $allowed_extensions_settings = string_to_tag_array($allowed_extensions_settings);
  361. if (!empty($allowed_extensions_settings)) {
  362. $result = $allowed_extensions_settings;
  363. } else {
  364. $result = array('txt','jpg','jpeg','png','bmp','gif','pdf','doc','docx','xls','xlsx','ppt','pptx','odt','ods','odp');
  365. }
  366. if (!$zip) {
  367. return $result;
  368. }
  369. $result = implode(";*.", $result);
  370. return "*." . $result;
  371. }
  372. if (!function_exists("mime_content_type")) {
  373. // @codingStandardsIgnoreStart
  374. function mime_content_type($fn) {
  375. static $mime_magic_data;
  376. #-- fallback
  377. $type = false;
  378. #-- read in first 3K of given file
  379. if (is_dir($fn)) {
  380. return("httpd/unix-directory");
  381. } elseif (is_resource($fn) || ($fn = @fopen($fn, "rb"))) {
  382. $bin = fread($fn, $maxlen=3072);
  383. fclose($fn);
  384. } elseif (!file_exists($fn)) {
  385. return false;
  386. } else {
  387. return("application/octet-stream"); // give up
  388. }
  389. #-- use PECL::fileinfo when available
  390. if (function_exists("finfo_buffer")) {
  391. if (!isset($mime_magic_data)) {
  392. $mime_magic_data = finfo_open(MAGIC_MIME);
  393. }
  394. $type = finfo_buffer($bin);
  395. return($type);
  396. }
  397. #-- read in magic data, when called for the very first time
  398. if (!isset($mime_content_type)) {
  399. if ((file_exists($fn = ini_get("mime_magic.magicfile")))
  400. or (file_exists($fn = "/usr/share/misc/magic.mime"))
  401. or (file_exists($fn = "/etc/mime-magic")) ) {
  402. $mime_magic_data = array();
  403. #-- read in file
  404. $f = fopen($fn, "r");
  405. $fd = fread($f, 1<<20);
  406. fclose($f);
  407. $fd = str_replace(" ", "\t", $fd);
  408. #-- look at each entry
  409. foreach (explode("\n", $fd) as $line) {
  410. #-- skip empty lines
  411. if (!strlen($line) or ($line[0] == "#") or ($line[0] == "\n")) {
  412. continue;
  413. }
  414. #-- break into four fields at tabs
  415. $l = preg_split("/\t+/", $line);
  416. @list($pos, $typestr, $magic, $ct) = $l;
  417. #print_r($l);
  418. #-- ignore >continuing lines
  419. if ($pos[0] == ">") {
  420. continue;
  421. }
  422. #-- real mime type string?
  423. $ct = strtok($ct, " ");
  424. if (!strpos($ct, "/")) {
  425. continue;
  426. }
  427. #-- mask given?
  428. $mask = 0;
  429. if (strpos($typestr, "&")) {
  430. $typestr = strtok($typestr, "&");
  431. $mask = strtok(" ");
  432. if ($mask[0] == "0") {
  433. $mask = ($mask[1] == "x") ? hexdec(substr($mask, 2)) : octdec($mask);
  434. } else {
  435. $mask = (int)$mask;
  436. }
  437. }
  438. #-- strip prefixes
  439. if ($magic[0] == "=") {
  440. $magic = substr($magic, 1);
  441. }
  442. #-- convert type
  443. if ($typestr == "string") {
  444. $magic = stripcslashes($magic);
  445. $len = strlen($magic);
  446. if ($mask) {
  447. continue;
  448. }
  449. }
  450. #-- numeric values
  451. else {
  452. if ((ord($magic[0]) < 48) or (ord($magic[0]) > 57)) {
  453. #echo "\nmagicnumspec=$line\n";
  454. #var_dump($l);
  455. continue; #-- skip specials like >, x, <, ^, &
  456. }
  457. #-- convert string representation into int
  458. if ((strlen($magic) >= 4) && ($magic[1] == "x")) {
  459. $magic = hexdec(substr($magic, 2));
  460. } elseif ($magic[0]) {
  461. $magic = octdec($magic);
  462. } else {
  463. $magic = (int) $magic;
  464. if (!$magic) {
  465. continue;
  466. } // zero is not a good magic value anyhow
  467. }
  468. #-- different types
  469. switch ($typestr) {
  470. case "byte":
  471. $len = 1;
  472. break;
  473. case "beshort":
  474. $magic = ($magic >> 8) | (($magic & 0xFF) << 8);
  475. case "leshort":
  476. case "short":
  477. $len = 2;
  478. break;
  479. case "belong":
  480. $magic = (($magic >> 24) & 0xFF)
  481. | (($magic >> 8) & 0xFF00)
  482. | (($magic & 0xFF00) << 8)
  483. | (($magic & 0xFF) << 24);
  484. case "lelong":
  485. case "long":
  486. $len = 4;
  487. break;
  488. default:
  489. //date, ldate, ledate, leldate, beldate, lebelbe...
  490. continue;
  491. }
  492. }
  493. #-- add to list
  494. $mime_magic_data[] = array($pos, $len, $mask, $magic, trim($ct));
  495. }
  496. }
  497. #print_r($mime_magic_data);
  498. }
  499. #-- compare against each entry from the mime magic database
  500. foreach ($mime_magic_data as $def) {
  501. #-- entries are organized as follows
  502. list($pos, $len, $mask, $magic, $ct) = $def;
  503. #-- ignored entries (we only read first 3K of file for opt. speed)
  504. if ($pos >= $maxlen) {
  505. continue;
  506. }
  507. $slice = substr($bin, $pos, $len);
  508. #-- integer comparison value
  509. if ($mask) {
  510. $value = hexdec(bin2hex($slice));
  511. if (($value & $mask) == $magic) {
  512. $type = $ct;
  513. break;
  514. }
  515. }
  516. #-- string comparison
  517. else {
  518. if ($slice == $magic) {
  519. $type = $ct;
  520. break;
  521. }
  522. }
  523. } // foreach
  524. #-- built-in defaults
  525. if (!$type) {
  526. #-- some form of xml
  527. if (strpos($bin, "<"."?xml ") !== false) {
  528. return("text/xml");
  529. }
  530. #-- html
  531. elseif ((strpos($bin, "<html>") !== false) || (strpos($bin, "<HTML>") !== false)
  532. || strpos($bin, "<title>") || strpos($bin, "<TITLE>")
  533. || (strpos($bin, "<!--") !== false) || (strpos($bin, "<!DOCTYPE HTML ") !== false)) {
  534. $type = "text/html";
  535. }
  536. #-- mail msg
  537. elseif ((strpos($bin, "\nReceived: ") !== false) || strpos($bin, "\nSubject: ")
  538. || strpos($bin, "\nCc: ") || strpos($bin, "\nDate: ")) {
  539. $type = "message/rfc822";
  540. }
  541. #-- php scripts
  542. elseif (strpos($bin, "<"."?php") !== false) {
  543. return("application/x-httpd-php");
  544. }
  545. #-- plain text, C source or so
  546. elseif (strpos($bin, "function ") || strpos($bin, " and ")
  547. || strpos($bin, " the ") || strpos($bin, "The ")
  548. || (strpos($bin, "/*") !== false) || strpos($bin, "#include ")) {
  549. return("text/plain");
  550. }
  551. #-- final fallback
  552. else {
  553. $type = "application/octet-stream";
  554. }
  555. }
  556. #-- done
  557. return $type;
  558. }
  559. // @codingStandardsIgnoreEnd
  560. }
  561. /**
  562. * Check for unique folder names
  563. *
  564. * @param string $title the title to check
  565. * @param int $container_guid the container to limit the search to
  566. * @param int $parent_guid optional parent guid
  567. *
  568. * @return bool|ElggObject
  569. */
  570. function file_tools_check_foldertitle_exists($title, $container_guid, $parent_guid = 0) {
  571. $result = false;
  572. $entities_options = array(
  573. 'type' => 'object',
  574. 'subtype' => FILE_TOOLS_SUBTYPE,
  575. 'container_guid' => $container_guid,
  576. 'limit' => 1,
  577. 'joins' => array(
  578. "JOIN " . elgg_get_config("dbprefix") . "objects_entity oe ON e.guid = oe.guid"
  579. ),
  580. 'wheres' => array(
  581. "oe.title = '" . sanitise_string($title) . "'"
  582. ),
  583. "order_by_metadata" => array(
  584. "name" => "order",
  585. "direction" => "ASC",
  586. "as" => "integer"
  587. )
  588. );
  589. if (!empty($parent_guid)) {
  590. $entities_options["metadata_name_value_pairs"] = array("parent_guid" => $parent_guid);
  591. }
  592. if ($entities = elgg_get_entities_from_metadata($entities_options)) {
  593. $result = $entities[0];
  594. }
  595. return $result;
  596. }
  597. /**
  598. * Create folders from a zip file structure
  599. *
  600. * @param zip_entry $zip_entry the zip file entry
  601. * @param int $container_guid the container where the folders need to be created
  602. * @param int $parent_guid the parent folder
  603. *
  604. * @return void
  605. */
  606. function file_tools_create_folders($zip_entry, $container_guid, $parent_guid = 0) {
  607. $zip_entry_name = zip_entry_name($zip_entry);
  608. $filename = basename($zip_entry_name);
  609. if (substr($zip_entry_name, -1) != '/') {
  610. $zip_base = str_replace($filename, "", $zip_entry_name);
  611. } else {
  612. $zip_base = $zip_entry_name;
  613. }
  614. $zdir = substr($zip_base, 0, -1);
  615. if (!empty($zdir)) {
  616. $container_entity = get_entity($container_guid);
  617. $access_id = get_input("access_id", false);
  618. if ($access_id === false) {
  619. if ($parent_guid != 0) {
  620. $access_id = get_entity($parent_guid)->access_id;
  621. } else {
  622. if (elgg_instanceof($container_entity, "group")) {
  623. $access_id = $container_entity->group_acl;
  624. } else {
  625. $access_id = get_default_access($container_entity);
  626. }
  627. }
  628. }
  629. $sub_folders = explode("/", $zdir);
  630. if (count($sub_folders) == 1) {
  631. $entity = file_tools_check_foldertitle_exists($zdir, $container_guid, $parent_guid);
  632. if (!$entity) {
  633. $directory = new ElggObject();
  634. $directory->subtype = FILE_TOOLS_SUBTYPE;
  635. $directory->owner_guid = elgg_get_logged_in_user_guid();
  636. $directory->container_guid = $container_guid;
  637. $directory->access_id = $access_id;
  638. $directory->title = $zdir;
  639. $directory->parent_guid = $parent_guid;
  640. $order = elgg_get_entities_from_metadata(array(
  641. "type" => "object",
  642. "subtype" => FILE_TOOLS_SUBTYPE,
  643. "metadata_name_value_pairs" => array(
  644. "name" => "parent_guid",
  645. "value" => $parent_guid
  646. ),
  647. "count" => true
  648. ));
  649. $directory->order = $order;
  650. $directory->save();
  651. }
  652. } else {
  653. $parent = $parent_guid;
  654. foreach ($sub_folders as $folder) {
  655. if ($entity = file_tools_check_foldertitle_exists($folder, $container_guid, $parent)) {
  656. $parent = $entity->getGUID();
  657. } else {
  658. $directory = new ElggObject();
  659. $directory->subtype = FILE_TOOLS_SUBTYPE;
  660. $directory->owner_guid = elgg_get_logged_in_user_guid();
  661. $directory->container_guid = $container_guid;
  662. $directory->access_id = $access_id;
  663. $directory->title = $folder;
  664. $directory->parent_guid = $parent;
  665. $order = elgg_get_entities_from_metadata(array(
  666. "type" => "object",
  667. "subtype" => FILE_TOOLS_SUBTYPE,
  668. "metadata_name_value_pairs" => array(
  669. "name" => "parent_guid",
  670. "value" => $parent
  671. ),
  672. "count" => true
  673. ));
  674. $directory->order = $order;
  675. $parent = $directory->save();
  676. }
  677. }
  678. }
  679. }
  680. }
  681. /**
  682. * Unzip an uploaded zip file
  683. *
  684. * @param array $file the $_FILES information
  685. * @param int $container_guid the container to put the files/folders under
  686. * @param int $parent_guid the parrent folder
  687. *
  688. * @return bool
  689. */
  690. function file_tools_unzip($file, $container_guid, $parent_guid = 0) {
  691. $extracted = false;
  692. if (!empty($file) && !empty($container_guid)) {
  693. $allowed_extensions = file_tools_allowed_extensions();
  694. $zipfile = elgg_extract("tmp_name", $file);
  695. $container_entity = get_entity($container_guid);
  696. $access_id = get_input("access_id", false);
  697. if ($access_id === false) {
  698. if (!empty($parent_guid) && ($parent_folder = get_entity($parent_guid)) && elgg_instanceof($parent_folder, "object", FILE_TOOLS_SUBTYPE)) {
  699. $access_id = $parent_folder->access_id;
  700. } else {
  701. if (elgg_instanceof($container_entity, "group")) {
  702. $access_id = $container_entity->group_acl;
  703. } else {
  704. $access_id = get_default_access($container_entity);
  705. }
  706. }
  707. }
  708. // open the zip file
  709. $zip = zip_open($zipfile);
  710. while ($zip_entry = zip_read($zip)) {
  711. // open the zip entry
  712. zip_entry_open($zip, $zip_entry);
  713. // set some variables
  714. $zip_entry_name = zip_entry_name($zip_entry);
  715. $filename = basename($zip_entry_name);
  716. // check for folder structure
  717. if (strlen($zip_entry_name) != strlen($filename)) {
  718. // there is a folder structure, check it and create missing items
  719. file_tools_create_folders($zip_entry, $container_guid, $parent_guid);
  720. }
  721. // extract the folder structure from the zip entry
  722. $folder_array = explode("/", $zip_entry_name);
  723. $parent = $parent_guid;
  724. foreach ($folder_array as $folder) {
  725. $folder = utf8_encode($folder);
  726. if ($entity = file_tools_check_foldertitle_exists($folder, $container_guid, $parent)) {
  727. $parent = $entity->getGUID();
  728. } else {
  729. if ($folder == end($folder_array)) {
  730. $prefix = "file/";
  731. $extension_array = explode('.', $folder);
  732. $file_extension = end($extension_array);
  733. if (in_array(strtolower($file_extension), $allowed_extensions)) {
  734. $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
  735. // create the file
  736. $filehandler = new ElggFile();
  737. $filehandler->setFilename($prefix . $folder);
  738. $filehandler->title = $folder;
  739. $filehandler->originalfilename = $folder;
  740. $filehandler->owner_guid = elgg_get_logged_in_user_guid();
  741. $filehandler->container_guid = $container_guid;
  742. $filehandler->access_id = $access_id;
  743. $filehandler->open("write");
  744. $filehandler->write($buf);
  745. $filehandler->close();
  746. $mime_type = $filehandler->detectMimeType($filehandler->getFilenameOnFilestore());
  747. // hack for Microsoft zipped formats
  748. $info = pathinfo($folder);
  749. $office_formats = array("docx", "xlsx", "pptx");
  750. if ($mime_type == "application/zip" && in_array($info["extension"], $office_formats)) {
  751. switch ($info["extension"]) {
  752. case "docx":
  753. $mime_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
  754. break;
  755. case "xlsx":
  756. $mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
  757. break;
  758. case "pptx":
  759. $mime_type = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
  760. break;
  761. }
  762. }
  763. // check for bad ppt detection
  764. if ($mime_type == "application/vnd.ms-office" && $info["extension"] == "ppt") {
  765. $mime_type = "application/vnd.ms-powerpoint";
  766. }
  767. $simple_type = elgg_get_file_simple_type($mime_type);
  768. $filehandler->setMimeType($mime_type);
  769. $filehandler->simpletype = $simple_type;
  770. if ($simple_type == "image") {
  771. $filestorename = elgg_strtolower(time() . $folder);
  772. $thumb = new ElggFile();
  773. $thumb->owner_guid = elgg_get_logged_in_user_guid();
  774. $thumbnail = get_resized_image_from_existing_file($filehandler->getFilenameOnFilestore(), 60, 60, true);
  775. if ($thumbnail) {
  776. $thumb->setFilename($prefix . "thumb" . $filestorename);
  777. $thumb->open("write");
  778. $thumb->write($thumbnail);
  779. $thumb->close();
  780. $filehandler->thumbnail = $prefix . "thumb" . $filestorename;
  781. unset($thumbnail);
  782. }
  783. $thumbsmall = get_resized_image_from_existing_file($filehandler->getFilenameOnFilestore(), 153, 153, true);
  784. if ($thumbsmall) {
  785. $thumb->setFilename($prefix . "smallthumb" . $filestorename);
  786. $thumb->open("write");
  787. $thumb->write($thumbsmall);
  788. $thumb->close();
  789. $filehandler->smallthumb = $prefix . "smallthumb" . $filestorename;
  790. unset($thumbsmall);
  791. }
  792. $thumblarge = get_resized_image_from_existing_file($filehandler->getFilenameOnFilestore(), 600, 600, false);
  793. if ($thumblarge) {
  794. $thumb->setFilename($prefix . "largethumb" . $filestorename);
  795. $thumb->open("write");
  796. $thumb->write($thumblarge);
  797. $thumb->close();
  798. $filehandler->largethumb = $prefix . "largethumb" . $filestorename;
  799. unset($thumblarge);
  800. }
  801. unset($thumb);
  802. }
  803. set_input('folder_guid', $parent);
  804. $filehandler->save();
  805. $extracted = true;
  806. if (!empty($parent)) {
  807. add_entity_relationship($parent, FILE_TOOLS_RELATIONSHIP, $filehandler->getGUID());
  808. }
  809. }
  810. }
  811. }
  812. }
  813. zip_entry_close($zip_entry);
  814. }
  815. zip_close($zip);
  816. }
  817. return $extracted;
  818. }
  819. /**
  820. * Helper function to check if we use a folder structure
  821. * Result is cached to increase performance
  822. *
  823. * @return bool
  824. */
  825. function file_tools_use_folder_structure() {
  826. static $result;
  827. if (!isset($result)) {
  828. $result = false;
  829. // this plugin setting has a typo, should be use_folder_struture
  830. // @todo: update the plugin setting name
  831. if (elgg_get_plugin_setting("user_folder_structure", "file_tools") == "yes") {
  832. $result = true;
  833. }
  834. }
  835. return $result;
  836. }
  837. /**
  838. * Add a folder to a zip file
  839. *
  840. * @param ZipArchive &$zip_archive the zip file to add files/folder to
  841. * @param ElggObject $folder the folder to add
  842. * @param string $folder_path the path of the current folder
  843. *
  844. * @return void
  845. */
  846. function file_tools_add_folder_to_zip(ZipArchive &$zip_archive, ElggObject $folder, $folder_path = "") {
  847. if (!empty($zip_archive) && !empty($folder) && elgg_instanceof($folder, "object", FILE_TOOLS_SUBTYPE)) {
  848. $folder_title = elgg_get_friendly_title($folder->title);
  849. $zip_archive->addEmptyDir($folder_path . $folder_title);
  850. $folder_path .= $folder_title . DIRECTORY_SEPARATOR;
  851. $file_options = array(
  852. "type" => "object",
  853. "subtype" => "file",
  854. "limit" => false,
  855. "relationship" => FILE_TOOLS_RELATIONSHIP,
  856. "relationship_guid" => $folder->getGUID()
  857. );
  858. // add files from this folder to the zip
  859. if ($files = elgg_get_entities_from_relationship($file_options)) {
  860. foreach ($files as $file) {
  861. // check if the file exists
  862. if ($zip_archive->statName($folder_path . $file->originalfilename) === false) {
  863. // doesn't exist, so add
  864. $zip_archive->addFile($file->getFilenameOnFilestore(), $folder_path . $file->originalfilename);
  865. } else {
  866. // file name exists, so create a new one
  867. $ext_pos = strrpos($file->originalfilename, ".");
  868. $file_name = substr($file->originalfilename, 0, $ext_pos) . "_" . $file->getGUID() . substr($file->originalfilename, $ext_pos);
  869. $zip_archive->addFile($file->getFilenameOnFilestore(), $folder_path . $file_name);
  870. }
  871. }
  872. }
  873. // check if there are subfolders
  874. $folder_options = array(
  875. "type" => "object",
  876. "subtype" => FILE_TOOLS_SUBTYPE,
  877. "limit" => false,
  878. "metadata_name_value_pairs" => array("parent_guid" => $folder->getGUID())
  879. );
  880. if ($sub_folders = elgg_get_entities_from_metadata($folder_options)) {
  881. foreach ($sub_folders as $sub_folder) {
  882. file_tools_add_folder_to_zip($zip_archive, $sub_folder, $folder_path);
  883. }
  884. }
  885. }
  886. }
  887. /**
  888. * Get a readable byte count
  889. *
  890. * @return string
  891. */
  892. function file_tools_get_readable_file_size_limit() {
  893. $size_units = array("B", "KB", "MB", "GB", "TB", "PB");
  894. $i = 0;
  895. $file_size_limit = elgg_get_ini_setting_in_bytes("upload_max_filesize");
  896. while ($file_size_limit > 1024) {
  897. $i++;
  898. $file_size_limit /= 1024;
  899. }
  900. $result = $file_size_limit . $size_units[$i];
  901. return $result;
  902. }
  903. /**
  904. * Get the listing max length from the plugin settings
  905. *
  906. * @return int
  907. */
  908. function file_tools_get_list_length() {
  909. static $result;
  910. if (!isset($result)) {
  911. $result = 50;
  912. $setting = (int) elgg_get_plugin_setting("list_length", "file_tools");
  913. if ($setting < 0) {
  914. $result = false;
  915. } elseif ($setting > 0) {
  916. $result = $setting;
  917. }
  918. }
  919. return $result;
  920. }