PageRenderTime 63ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/includes/filebox.php

https://github.com/klandestino/filebox
PHP | 2175 lines | 1444 code | 310 blank | 421 comment | 204 complexity | 6e926456c76cb8efaddfeca0b4fec9e7 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * Plugin main class
  4. */
  5. class Filebox {
  6. public $options = array();
  7. /**
  8. * Sets up this plugin main class
  9. * @return void
  10. */
  11. public static function __setup() {
  12. global $filebox;
  13. $filebox = new Filebox();
  14. }
  15. /**
  16. * Get options from wordpress
  17. * @uses get_option
  18. * return array
  19. */
  20. public static function get_options() {
  21. $default = array(
  22. 'group-tab' => __( 'File archive', 'filebox' ),
  23. 'topics-folder-name' => __( 'Imported forum attachments', 'filebox' ),
  24. 'topics-folder-desc' => __( '%s folder for imported forum attachments', 'filebox' ),
  25. 'mail-delay' => 15,
  26. 'remove-docs-from-library' => true,
  27. // Slugs
  28. // 1 year; 2 month
  29. 'slug-files' => 'documents/%1$s/%2$s',
  30. 'slug-folders' => 'documents/folders',
  31. 'folder-zip-folder' => 'document-archives',
  32. // On-site notifications
  33. // 1 filename/files; 2 folder; 3 group
  34. 'file-update-notify-single' => __( '%1$s updated in %2$s (%3$s)', 'filebox' ),
  35. 'file-update-notify-multi' => __( '%1$d files updated in %2$s (%3$s)', 'filebox' ),
  36. 'file-upload-notify-single' => __( '%1$s added in %2$s (%3$s)', 'filebox' ),
  37. 'file-upload-notify-multi' => __( '%1$d new files in %2$s (%3$s)', 'filebox' ),
  38. // Mail notifications
  39. // 1 blogname; 2 filename; 3 folder, 4 group
  40. 'file-update-mail-subject-single' => __( '[%1$s] One updated file in %4$s', 'filebox' ),
  41. 'file-upload-mail-subject-single' => __( '[%1$s] One new file in %4$s', 'filebox' ),
  42. // 1 filename; 2 folder; 3 group
  43. 'file-update-mail-message-line' => __( '%1$s updated in %2$s (%3$s)', 'filebox' ),
  44. 'file-upload-mail-message-line' => __( '%1$s added in %2$s (%3$s)', 'filebox' ),
  45. // 1 blogname; 2 files
  46. 'multiple-mail-messages-subject' => __( '[%1$s] %2$d uploaded files', 'filebox' ),
  47. // 1 messages
  48. 'mail-message-wrap' => __( '%1$s
  49. --------------------
  50. You are receiving this email because you\'re a member of these groups.
  51. Login and change you settings to unsubscribe from these emails.', 'filebox' )
  52. );
  53. $options = get_option( 'filebox', array() );
  54. foreach( $default as $i => $opt ) {
  55. if( ! array_key_exists( $i, $options ) ) {
  56. $options[ $i ] = $opt;
  57. }
  58. }
  59. return $options;
  60. }
  61. /**
  62. * Locates and loads a template by using Wordpress locate_template.
  63. * If no template is found, it loads a template from this plugins template
  64. * directory.
  65. * @uses locate_template
  66. * @param string $slug
  67. * @param string $name
  68. * @return void
  69. */
  70. public static function get_template( $slug, $name = '' ) {
  71. $template_names = array(
  72. $slug . '-' . $name . '.php',
  73. $slug . '.php'
  74. );
  75. $located = locate_template( $template_names );
  76. if ( empty( $located ) ) {
  77. foreach( $template_names as $name ) {
  78. if ( file_exists( FILEBOX_TEMPLATE_DIR . '/' . $name ) ) {
  79. load_template( FILEBOX_TEMPLATE_DIR . '/' . $name, false );
  80. return;
  81. }
  82. }
  83. } else {
  84. load_template( $located, false );
  85. }
  86. }
  87. /**
  88. * Sanitizes a filename to a slug
  89. * @param string $title
  90. * @return string
  91. */
  92. public static function sanitize_title( $title ) {
  93. $title = sanitize_file_name( $title );
  94. while( preg_match( '/(\.[^\s]+)$/', $title, $suffix ) ) {
  95. $title = substr( $title, 0, strrpos( $title, $suffix[ 1 ] ) );
  96. }
  97. return sanitize_title( $title );
  98. }
  99. /**
  100. * Class constructor
  101. */
  102. public function __construct() {
  103. $this->options = self::get_options();
  104. // Maybe create post type (if documents is non-existent)
  105. add_action( 'init', array( &$this, 'maybe_add_post_type' ) );
  106. // Maybe create taxonomy (if directories is non-existent)
  107. add_action( 'init', array( &$this, 'maybe_add_taxonomy' ) );
  108. // Add image sizes
  109. add_action( 'init', array( &$this, 'add_image_sizes' ) );
  110. // Add scripts and styles
  111. add_action( 'init', array( &$this, 'register_scripts' ) );
  112. // enqueue scripts and styles
  113. add_action( 'wp_enqueue_scripts', array( &$this, 'enqueue_scripts' ) );
  114. // Action for fetching forum attachments
  115. add_action( 'bbp_new_topic', array( &$this, 'handle_new_forum_topic' ), 1000, 4 );
  116. add_action( 'bbp_new_reply', array( &$this, 'handle_new_forum_reply' ), 1000, 5 );
  117. /**
  118. * Upload directories
  119. */
  120. // Fix upload directory
  121. add_filter( 'upload_dir', array( &$this, 'get_upload_dir' ) );
  122. // Security action for documents so non-members can't view group files
  123. add_filter( 'template_include', array( &$this, 'load_file' ) );
  124. // Fix thumbnail issue if wp-document-revisions is installed
  125. add_filter( 'template_include', array( &$this, 'load_thumbnail' ) );
  126. // Set correct folder zip url
  127. add_filter( 'template_include', array( &$this, 'load_folder_zip' ) );
  128. /**
  129. * Permissions
  130. */
  131. // User permissions to read uploaded files revisions
  132. add_filter( 'user_has_cap', array( &$this, 'user_has_cap' ), 10, 3 );
  133. // Admins shall not see documents attachments in media library
  134. add_filter( 'posts_where', array( &$this, 'set_sql_where_limit_for_docs' ) );
  135. /**
  136. * Add action for ajax-calls
  137. */
  138. // List all files and folders
  139. add_action( 'wp_ajax_filebox_list', array( &$this, 'list_files_and_folders' ) );
  140. /**
  141. * File actions
  142. */
  143. // Upload file
  144. add_action( 'wp_ajax_filebox_upload_file', array( &$this, 'upload_file' ) );
  145. // Move file to folder
  146. add_action( 'wp_ajax_filebox_move_file', array( &$this, 'move_file' ) );
  147. // Rename file
  148. add_action( 'wp_ajax_filebox_rename_file', array( &$this, 'rename_file' ) );
  149. // File history
  150. add_action( 'wp_ajax_filebox_history_file', array( &$this, 'history_file' ) );
  151. // Trash file
  152. add_action( 'wp_ajax_filebox_trash_file', array( &$this, 'trash_file' ) );
  153. // Reset file
  154. add_action( 'wp_ajax_filebox_reset_file', array( &$this, 'reset_file' ) );
  155. // Reset file
  156. add_action( 'wp_ajax_filebox_delete_file', array( &$this, 'delete_file' ) );
  157. // Generate zip
  158. add_action( 'wp_ajax_filebox_generate_zip', array( &$this, 'generate_folder_zip' ) );
  159. /**
  160. * Folder actions
  161. */
  162. // Add new folder
  163. add_action( 'wp_ajax_filebox_add_folder', array( &$this, 'add_folder' ) );
  164. // Move folder
  165. add_action( 'wp_ajax_filebox_move_folder', array( &$this, 'move_folder' ) );
  166. // Rename folder
  167. add_action( 'wp_ajax_filebox_rename_folder', array( &$this, 'rename_folder' ) );
  168. // Delete folder
  169. add_action( 'wp_ajax_filebox_delete_folder', array( &$this, 'delete_folder' ) );
  170. }
  171. /**
  172. * Adds post type if it doesn't already exist.
  173. * Uses document as post-type so it will work with
  174. * wp-document-revisions
  175. * @uses register_post_type
  176. * @return void
  177. */
  178. public function maybe_add_post_type() {
  179. if( ! post_type_exists( 'document' ) ) {
  180. register_post_type( 'document', array(
  181. 'labels' => array(
  182. 'name' => _x( 'Documents', 'post type general name', 'filebox' ),
  183. 'singular_name' => _x( 'Document', 'post type singular name', 'filebox' )
  184. ),
  185. 'public' => true,
  186. 'has_archive' => true,
  187. 'hierarchical' => false,
  188. 'supports' => array(
  189. 'title',
  190. 'author',
  191. 'revisions',
  192. 'excerpt',
  193. 'custom-fields'
  194. )
  195. ) );
  196. }
  197. }
  198. /**
  199. * Adds taxonomy if it doesn't exist.
  200. * Taxonomy is used to simulate directories and commit messages
  201. * @uses register_taxonomy
  202. * @return void
  203. */
  204. public function maybe_add_taxonomy() {
  205. //if( ! taxonomy_exists( 'fileboxfolders' ) ) {
  206. register_taxonomy( 'fileboxfolders', array( 'document', 'revision' ), array(
  207. 'labels' => array(
  208. 'name' => __( 'Folders', 'filebox' ),
  209. 'singular_name' => __( 'Folder', 'filebox' )
  210. ),
  211. 'hierarchical' => true,
  212. 'public' => true,
  213. 'show_ui' => true,
  214. 'show_admin_column' => true,
  215. 'show_in_nav_menus' => false,
  216. 'rewrite' => false,
  217. 'query_var' => true,
  218. 'show_tagcloud' => false
  219. ) );
  220. //}
  221. // Commit messages
  222. //if( ! taxonomy_exists( 'fileboxcommits' ) ) {
  223. register_taxonomy( 'fileboxcommits', array( 'document', 'revision' ), array(
  224. 'labels' => array(
  225. 'name' => __( 'Revision comments', 'filebox' ),
  226. 'singular_name' => __( 'Revision comment', 'filebox' )
  227. ),
  228. 'hierarchical' => false,
  229. 'public' => true,
  230. 'show_ui' => true,
  231. 'show_admin_column' => true,
  232. 'show_in_nav_menus' => false,
  233. 'rewrite' => false,
  234. 'query_var' => true,
  235. 'show_tagcloud' => false
  236. ) );
  237. //}
  238. }
  239. public function add_image_sizes() {
  240. add_image_size( 'filebox-thumbnail', 46, 60, true );
  241. }
  242. /**
  243. * Register scripts and styles
  244. * @return void
  245. */
  246. public function register_scripts() {
  247. // Filebox general javascript methods
  248. wp_register_script(
  249. 'filebox',
  250. FILEBOX_PLUGIN_URL . 'js/filebox.js',
  251. array( 'jquery' )
  252. );
  253. wp_localize_script( 'filebox', 'filebox', array(
  254. 'confirm_folder_delete' => __( "You're about to delete this folder and you can not undo this. Do you want to continue?", 'filebox' ),
  255. 'confirm_file_trash' => __( "You're about to trash this file and you can undo this. Do you want to continue?", 'filebox' ),
  256. 'confirm_file_delete' => __( "You're about to delete this file permanently and you can not undo this. Do you want to continue?", 'filebox' ),
  257. 'required_error_message' => __( '%s is required', 'filebox' ),
  258. 'unknown_size' => __( 'Unknown size', 'filebox' )
  259. ) );
  260. // General style
  261. wp_register_style(
  262. 'filebox',
  263. FILEBOX_PLUGIN_URL . 'css/filebox.css'
  264. );
  265. }
  266. /**
  267. * Enqueue scripts and css
  268. * @return void
  269. */
  270. public function enqueue_scripts() {
  271. if( bp_is_group() ) {
  272. // Media upload scripts
  273. add_thickbox();
  274. wp_enqueue_script( 'media-upload' );
  275. // Filebox general javascript methods
  276. wp_enqueue_script( 'filebox' );
  277. // General css
  278. wp_enqueue_style( 'filebox' );
  279. }
  280. }
  281. /**
  282. * Get upload directory
  283. * @param array $params
  284. * return array
  285. */
  286. public function get_upload_dir( $params ) {
  287. //
  288. return $params;
  289. }
  290. /**
  291. * Is a loaded post is a document from a group, then apply security check
  292. * @param string $template;
  293. * @return string
  294. */
  295. public function load_file( $template ) {
  296. global $post, $wp, $wp_query;
  297. if( is_object( $post ) ) {
  298. if( property_exists( $post, 'post_type' ) && property_exists( $post, 'ID' ) ) {
  299. if( $post->post_type == 'document' ) {
  300. $folder_id = $this->get_folder_by_file( $post->ID );
  301. if( $folder_id ) {
  302. if( ! $this->is_allowed( $folder_id ) ) {
  303. $post->post_type = '';
  304. $wp_query->posts = array();
  305. $wp_query->queried_object = null;
  306. $wp->handle_404();
  307. return get_404_template();
  308. }
  309. }
  310. }
  311. }
  312. }
  313. return $template;
  314. }
  315. /**
  316. * If WP Document Revisions is installed, thumbnail urls
  317. * are rewritten to something uncompatible. Therefore,
  318. * we'll check the request path and translate it to an
  319. * image if there is any.
  320. * @param string $template
  321. * @return string
  322. */
  323. public function load_thumbnail( $template ) {
  324. global $post;
  325. if( ! $post && strpos( $_SERVER[ 'REQUEST_URI' ], '/documents/' ) === 0 ) {
  326. $dir = wp_upload_dir();
  327. $filename = $dir[ 'basedir'] . urldecode( substr( $_SERVER[ 'REQUEST_URI' ], 10 ) );
  328. if( is_file( $filename ) ) {
  329. status_header( 200 );
  330. $mime = wp_check_filetype( $filename );
  331. if( $mime[ 'type' ] === false && function_exists( 'mime_content_type' ) ) {
  332. $mime[ 'type' ] = mime_content_type( $filename );
  333. }
  334. if( $mime[ 'type' ] ) {
  335. $mimetype = $mime[ 'type' ];
  336. } else {
  337. $mimetype = 'image/' . substr( $filename, strrpos( $filename, '.' ) + 1 );
  338. }
  339. $last_modified = gmdate( 'D, d M Y H:i:s', filemtime( $filename ) );
  340. $etag = '"' . md5( $last_modified ) . '"';
  341. header( 'Content-Type: ' . $mimetype );
  342. header( 'Content-Length: ' . filesize( $filename ) );
  343. header( "Last-Modified: $last_modified GMT" );
  344. header( 'ETag: ' . $etag );
  345. header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 100000000 ) . ' GMT' );
  346. ob_clean();
  347. flush();
  348. @set_time_limit( 0 );
  349. readfile( $filename );
  350. exit;
  351. }
  352. }
  353. return $template;
  354. }
  355. /**
  356. * Serves folder zip files
  357. * @param string $template
  358. * return string
  359. */
  360. public function load_folder_zip( $template ) {
  361. global $post;
  362. if( ! $post && strpos( $_SERVER[ 'REQUEST_URI' ], $this->options[ 'slug-folders' ] ) ) {
  363. $folder = null;
  364. if( preg_match( '/\/([0-9]+)\/[^\.]+\.zip$/', $_SERVER[ 'REQUEST_URI' ], $folder_id ) ) {
  365. $folder = get_term( $folder_id[ 1 ], 'fileboxfolders' );
  366. }
  367. if( $folder ) {
  368. if( $this->is_allowed( $folder->term_id ) ) {
  369. $upload = wp_upload_dir();
  370. $filename = $this->get_folder_zip_path( $folder->term_id );
  371. if( is_file( $filename ) ) {
  372. status_header( 200 );
  373. $mime = wp_check_filetype( $filename );
  374. if( $mime[ 'type' ] === false && function_exists( 'mime_content_type' ) ) {
  375. $mime[ 'type' ] = mime_content_type( $filename );
  376. }
  377. $mimetype = $mime[ 'type' ];
  378. $last_modified = gmdate( 'D, d M Y H:i:s', filemtime( $filename ) );
  379. $etag = '"' . md5( $last_modified ) . '"';
  380. header( 'Content-Type: ' . $mimetype );
  381. header( 'Content-Length: ' . filesize( $filename ) );
  382. header( "Last-Modified: $last_modified GMT" );
  383. header( 'ETag: ' . $etag );
  384. header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 100000000 ) . ' GMT' );
  385. ob_clean();
  386. flush();
  387. @set_time_limit( 0 );
  388. readfile( $filename );
  389. exit;
  390. }
  391. }
  392. }
  393. }
  394. return $template;
  395. }
  396. /**
  397. * Checks for user permissions
  398. * @param array $all_caps All capabilities
  399. * @param array $caps Required capabilities
  400. * @param array $args Requested objects
  401. * @return array
  402. */
  403. public function user_has_cap( $all_caps, $caps, $args ) {
  404. if( in_array( 'read_document_revisions', $caps ) ) {
  405. $all_caps[ 'read_document_revisions' ] = true;
  406. }
  407. return $all_caps;
  408. }
  409. /**
  410. * Limits attachments to not include documents in media library
  411. * @param string $where
  412. * return string
  413. */
  414. public function set_sql_where_limit_for_docs( $where ) {
  415. global $wpdb;
  416. if(
  417. $this->options[ 'remove-docs-from-library' ]
  418. && (
  419. strpos( $_SERVER[ 'REQUEST_URI' ], 'wp-admin/upload.php' )
  420. || (
  421. strpos( $_SERVER[ 'REQUEST_URI' ], 'wp-admin/admin-ajax.php' )
  422. && $_POST[ 'action' ] == 'query-attachments'
  423. )
  424. )
  425. ) {
  426. $where .= sprintf(
  427. ' AND ( SELECT COUNT( * ) FROM `%1$s` AS docs_parent WHERE docs_parent.post_type = "document" AND docs_parent.ID = `%1$s`.post_parent ) = 0',
  428. $wpdb->posts
  429. );
  430. }
  431. return $where;
  432. }
  433. /**
  434. * Gets a group name
  435. * @using groups_get_group
  436. * @return string
  437. */
  438. public function get_group_name( $group_id ) {
  439. $group = groups_get_group( array( 'group_id' => $group_id ) );
  440. if ( ! $group ) return false;
  441. return $group->name;
  442. }
  443. /**
  444. * Get group id by file
  445. * @param int $file_id
  446. * @return int
  447. */
  448. public function get_group_by_file( $file_id ) {
  449. return $this->get_group_by_folder( $this->get_folder_by_file( $file_id ) );
  450. }
  451. /**
  452. * Get group id by folder
  453. * @param int $folder_id
  454. * @return int
  455. */
  456. public function get_group_by_folder( $folder_id ) {
  457. global $bp, $wpdb;
  458. $parents = $this->get_folder_ancestors( $folder_id );
  459. if( count( $parents ) ) {
  460. $folder_id = $parents[ 0 ]->term_id;
  461. }
  462. $group_id = $wpdb->get_var( $wpdb->prepare(
  463. 'SELECT `group_id` FROM `'. $bp->groups->table_name_groupmeta . '` WHERE `meta_key` = "filebox_group_folder" AND `meta_value` = %d LIMIT 0,1',
  464. $folder_id
  465. ) );
  466. return $group_id;
  467. }
  468. /**
  469. * Get group folder.
  470. * Creates group folder if it does not exist.
  471. * @param int $group_id
  472. * @return int Return false if there is no group folder and we did not succeed in creating one.
  473. */
  474. public function get_group_folder( $group_id ) {
  475. $group_name = $this->get_group_name( $group_id );
  476. if( $group_name === false ) return false;
  477. $folder_id = groups_get_groupmeta( $group_id, 'filebox_group_folder' );
  478. if( is_numeric( $folder_id ) && $folder_id ) {
  479. $folder = get_term( $folder_id, 'fileboxfolders' );
  480. if( $folder ) {
  481. if( $folder->name != $group_name ) {
  482. wp_update_term( $folder_id, array(
  483. 'name' => $group_name
  484. ) );
  485. }
  486. return $folder_id;
  487. }
  488. }
  489. /**
  490. * If folder been found, it's already returned.
  491. * Therefore we're at this point sure there are
  492. * no folder for specified group.
  493. */
  494. // Check if there's already a term with group name
  495. $folder_name = $group_name;
  496. $folder = get_term_by( 'name', $folder_name, 'fileboxfolders' );
  497. $folder_id = 0;
  498. if( $folder ) {
  499. // Is there any group using this term?
  500. if( $this->get_group_by_folder( $folder->term_id ) ) {
  501. // Then create another folder name
  502. while( term_exists( $folder_name, 'fileboxfolders' ) ) {
  503. if( preg_match( '/-([0-9]+)$/', $folder_name, $match ) ) {
  504. $folder_name = preg_replace( '/-[0-9]+$/', '-' . ( ( ( int ) $match[ 1 ] ) + 1 ), $folder_name );
  505. } else {
  506. $folder_name .= '-1';
  507. }
  508. }
  509. } else {
  510. $folder_id = $folder->term_id;
  511. }
  512. }
  513. if( ! $folder_id ) {
  514. $folder = wp_insert_term( $folder_name, 'fileboxfolders', array(
  515. 'description' => sprintf( __( '%s group folder', 'filebox' ), $group_name )
  516. ) );
  517. if( is_array( $folder ) ) {
  518. $folder_id = $folder[ 'term_id' ];
  519. }
  520. }
  521. if( $folder_id ) {
  522. groups_update_groupmeta( $group_id, 'filebox_group_folder', $folder_id );
  523. return $folder_id;
  524. } else {
  525. return false;
  526. }
  527. }
  528. /**
  529. * Gets a folder id for forum attachments
  530. * Creates folder if it doesn't exist.
  531. * @param int $group_id
  532. * @return int
  533. */
  534. public function get_topics_folder( $group_id ) {
  535. $parent = $this->get_group_folder( $group_id );
  536. if( ! $parent ) return false;
  537. $folder_id = groups_get_groupmeta( $group_id, 'filebox_topics_folder' );
  538. if( is_numeric( $folder_id ) && $folder_id ) {
  539. $folder = get_term( ( int ) $folder_id, 'fileboxfolders' );
  540. if( $folder ) {
  541. if( $folder->name != $this->options[ 'topics-folder-name' ] ) {
  542. wp_update_term( $folder_id, 'fileboxfolders', array(
  543. 'name' => $this->options[ 'topics-folder-name' ],
  544. 'description' => sprintf( $this->options[ 'topics-folder-desc' ], $this->get_group_name( $group_id ) )
  545. ) );
  546. }
  547. return $folder_id;
  548. }
  549. }
  550. /**
  551. * If folder been found, it's already returned.
  552. * Therefore we're at this point sure there are
  553. * no folder for specified group.
  554. */
  555. $folder = wp_insert_term(
  556. $this->options[ 'topics-folder-name' ],
  557. 'fileboxfolders',
  558. array(
  559. 'parent' => $parent,
  560. 'description' => sprintf( $this->options[ 'topics-folder-desc' ], $this->get_group_name( $group_id ) )
  561. )
  562. );
  563. if( is_array( $folder ) ) {
  564. $folder_id = $folder[ 'term_id' ];
  565. // So we now what folder belongs to where
  566. groups_update_groupmeta( $group_id, 'filebox_topics_folder', $folder_id );
  567. // Fetch all forum attachments
  568. $this->index_group_forum_attachments( $group_id );
  569. }
  570. return $folder_id;
  571. }
  572. /**
  573. * Gets a folder
  574. * @using get_term
  575. * @param int $folder_id
  576. * @return object
  577. */
  578. public function get_folder( $folder_id ) {
  579. $folder = get_term( $folder_id, 'fileboxfolders' );
  580. if( $folder ) {
  581. $folder->zip = $this->get_folder_zip( $folder_id );
  582. }
  583. return $folder;
  584. }
  585. /**
  586. * Gets a folder name
  587. * @return string
  588. */
  589. public function get_folder_name( $folder_id ) {
  590. $folder = $this->get_folder( $folder_id );
  591. if( $folder ) {
  592. return $folder->name;
  593. }
  594. return 'Error';
  595. }
  596. /**
  597. * Gets a folders URL
  598. * @param $folder_id
  599. * @return string
  600. */
  601. public function get_folder_url( $folder_id ) {
  602. $url = bp_get_group_permalink( groups_get_group( array( 'group_id' => $this->get_group_by_folder( $folder_id ) ) ) );
  603. $url .= 'filebox';
  604. $folders = array_merge(
  605. $this->get_folder_ancestors( $folder_id ),
  606. array( $this->get_folder( $folder_id ) )
  607. );
  608. array_shift( $folders );
  609. foreach( $folders as $folder ) {
  610. $url .= '/' . $folder->slug;
  611. }
  612. return $url;
  613. }
  614. /**
  615. * Get all folders by group
  616. * @param int $group_id
  617. * @return array
  618. */
  619. public function get_all_folders( $group_id ) {
  620. $result = array( $this->get_folder( $this->get_group_folder( $group_id ) ) );
  621. if( $result[ 0 ] ) {
  622. $result = array_merge( $result, get_terms( 'fileboxfolders', array(
  623. 'child_of' => $result[ 0 ]->term_id,
  624. 'hide_empty' => false,
  625. 'pad_counts' => true
  626. ) ) );
  627. }
  628. return $result;
  629. }
  630. /**
  631. * Get all subfolders by folder
  632. * @param int $folder_id
  633. * @return array
  634. */
  635. public function get_subfolders( $folder_id ) {
  636. $response = array();
  637. $folders = get_terms( 'fileboxfolders', array(
  638. 'parent' => $folder_id,
  639. 'hide_empty' => false,
  640. 'pad_counts' => true,
  641. 'orderby' => 'name',
  642. 'order' => 'ASC'
  643. ) );
  644. foreach( $folders as $folder ) {
  645. $folder->childs = count( get_terms( 'fileboxfolders', array(
  646. 'parent' => $folder->term_id,
  647. 'hide_empty' => false
  648. ) ) );
  649. $folder->zip = $this->get_folder_zip( $folder->term_id );
  650. $response[ $folder->term_id ] = $folder;
  651. }
  652. return $response;
  653. }
  654. /**
  655. * Get folder id by file
  656. * @param int $file_id
  657. * @return int
  658. */
  659. public function get_folder_by_file( $file_id ) {
  660. $folder = wp_get_object_terms( $file_id, 'fileboxfolders', array( 'fields' => 'ids' ) );
  661. if( is_array( $folder ) ) {
  662. return reset( $folder );
  663. } else {
  664. return $folder;
  665. }
  666. }
  667. /**
  668. * If specified folder is group root folder
  669. * @param int $folder_id
  670. * @return int
  671. */
  672. public function is_root_folder( $folder_id ) {
  673. $group_id = $this->get_group_by_folder( $folder_id );
  674. $root_id = $this->get_group_folder( $group_id );
  675. return( $group_id == $root_id );
  676. }
  677. /**
  678. * Get folder ancestors
  679. * @param int $folder_id
  680. * @return array
  681. */
  682. public function get_folder_ancestors( $folder_id ) {
  683. $result = array();
  684. $folder = get_term( $folder_id, 'fileboxfolders' );
  685. if( $folder ) {
  686. while( $folder->parent ) {
  687. $folder = get_term( $folder->parent, 'fileboxfolders' );
  688. if( $folder ) {
  689. $result = array_merge( array( $folder ), $result );
  690. } else {
  691. $folder = ( object ) array( 'parent' => 0 );
  692. }
  693. }
  694. }
  695. return $result;
  696. }
  697. /**
  698. * Get folder parent
  699. * @param int $folder_id
  700. * @return int
  701. */
  702. public function get_parent_folder( $folder_id ) {
  703. $folder = get_term( $folder_id, 'fileboxfolders' );
  704. if( $folder ) {
  705. return $folder->parent;
  706. } else {
  707. return false;
  708. }
  709. }
  710. /**
  711. * Get file by id
  712. * @param int $file_id
  713. * @return object
  714. */
  715. public function get_file( $file_id ) {
  716. $file = get_post( $file_id );
  717. if( $file ) {
  718. $file->user = get_userdata( $file->post_author );
  719. $file->attachments = get_children( array(
  720. 'post_parent' => $file_id,
  721. 'post_type' => 'attachment'
  722. ) );
  723. return $file;
  724. }
  725. return null;
  726. }
  727. /**
  728. * Get all files from specified folder
  729. * @param int $folder_id
  730. * @param boolean $include_children Get all childs
  731. * @return array
  732. */
  733. public function get_files( $folder_id, $include_children = false ) {
  734. $results = array();
  735. $files = new WP_Query( array(
  736. 'post_type' => array( 'document' ),
  737. 'tax_query' => array(
  738. array(
  739. 'taxonomy' => 'fileboxfolders',
  740. 'fields' => 'id',
  741. 'terms' => $folder_id,
  742. 'include_children' => $include_children
  743. )
  744. ),
  745. 'posts_per_page' => -1,
  746. 'orderby' => 'title',
  747. 'order' => 'ASC'
  748. ) );
  749. while( $files->have_posts() ) {
  750. $files->the_post();
  751. $files->post->user = get_userdata( $files->post->post_author );
  752. $files->post->attachments = get_children( array(
  753. 'post_parent' => $files->post->ID,
  754. 'post_type' => 'attachment'
  755. ) );
  756. $results[ $files->post->ID ] = $files->post;
  757. }
  758. wp_reset_postdata();
  759. return $results;
  760. }
  761. /**
  762. * Gets a file URL
  763. * @uses wp_get_attachment_url
  764. * @param int $file_id Post ID
  765. * @return string Post attachment URL
  766. */
  767. public function get_file_url( $file_id ) {
  768. $attachments = get_children( array( 'parent' => $file_id, 'post_type' => 'attachment' ) );
  769. if( is_array( $attachments ) ) {
  770. return wp_get_attachment_url( reset( $attachments )->ID );
  771. } else {
  772. return '';
  773. }
  774. }
  775. /**
  776. * Get trash count
  777. * @param int $group_id
  778. * @return int
  779. */
  780. public function trash_count( $group_id ) {
  781. $files = new WP_Query( array(
  782. 'post_type' => array( 'document' ),
  783. 'post_status' => 'trash',
  784. 'tax_query' => array(
  785. array(
  786. 'taxonomy' => 'fileboxfolders',
  787. 'fields' => 'id',
  788. 'terms' => $this->get_group_folder( $group_id ),
  789. 'include_children' => true
  790. )
  791. ),
  792. 'posts_per_page' => -1
  793. ) );
  794. return $files->found_posts;
  795. }
  796. /**
  797. * Get all files from trash
  798. * @param int $group_id
  799. * @return array
  800. */
  801. public function get_trash( $group_id ) {
  802. $results = array();
  803. $files = new WP_Query( array(
  804. 'post_type' => array( 'document' ),
  805. 'post_status' => 'trash',
  806. 'tax_query' => array(
  807. array(
  808. 'taxonomy' => 'fileboxfolders',
  809. 'fields' => 'id',
  810. 'terms' => $this->get_group_folder( $group_id ),
  811. 'include_children' => true
  812. )
  813. ),
  814. 'posts_per_page' => -1
  815. ) );
  816. while( $files->have_posts() ) {
  817. $files->the_post();
  818. $files->post->attachments = get_children( array(
  819. 'post_parent' => $files->post->ID,
  820. 'post_type' => 'attachment'
  821. ) );
  822. $results[ $files->post->ID ] = $files->post;
  823. }
  824. wp_reset_postdata();
  825. return $results;
  826. }
  827. /**
  828. * Get attachments by post id
  829. * @param int $post_id
  830. * @return array
  831. */
  832. public function get_attachments( $post_id ) {
  833. $result = array();
  834. $query = new WP_Query( array(
  835. 'post_type' => 'attachment',
  836. 'post_status' => 'inherit',
  837. 'post_parent' => $post_id,
  838. ) );
  839. while( $query->have_posts() ) {
  840. $query->the_post();
  841. $result[] = $query->post;
  842. }
  843. wp_reset_postdata();
  844. return $result;
  845. }
  846. /**
  847. * Returns true if current user is allowed to upload
  848. * or modify anything in specified folder.
  849. * @param int $folder_id
  850. * @param int $user_id optional
  851. * @param boolean $make_changes optional If user is about to make changes
  852. * @return boolean
  853. */
  854. public function is_allowed( $folder_id, $user_id = 0, $make_changes = false ) {
  855. if( ! $user_id ) {
  856. $user_id = get_current_user_id();
  857. }
  858. if( is_super_admin( $user_id ) ) {
  859. return true;
  860. }
  861. $group_id = $this->get_group_by_folder( $folder_id );
  862. if( $group_id ) {
  863. if(
  864. groups_is_user_admin( $user_id, $group_id )
  865. || groups_is_user_mod( $user_id, $group_id )
  866. || groups_is_user_member( $user_id, $group_id )
  867. ) {
  868. if( $make_changes ) {
  869. $options = groups_get_groupmeta( $group_id, 'filebox' );
  870. if( is_array( $options ) ) {
  871. if( array_key_exists( 'permissions', $options ) ) {
  872. if(
  873. $options[ 'permissions' ] == 'admin'
  874. && ! groups_is_user_admin( $user_id, $group_id )
  875. ) {
  876. return false;
  877. } elseif(
  878. $options[ 'permissions' ] == 'mods'
  879. && ! groups_is_user_admin( $user_id, $group_id )
  880. && ! groups_is_user_mod( $user_id, $group_id )
  881. ) {
  882. return false;
  883. }
  884. }
  885. }
  886. }
  887. return true;
  888. }
  889. }
  890. return false;
  891. }
  892. /**
  893. * Handles the action for a new forum topic
  894. * @param int $topic_id
  895. * @param int $forum_id
  896. * @param string $anonymous_data ???
  897. * @param int $topic_author author user id
  898. * @return void
  899. */
  900. public function handle_new_forum_topic( $topic_id, $forum_id, $anonymous_data = '', $topic_author ) {
  901. $groups = get_post_meta( $forum_id, '_bbp_group_ids', array() );
  902. foreach( $groups as $group_ids ) {
  903. if( ! is_array( $group_ids ) ) {
  904. $group_ids = array( $group_ids );
  905. }
  906. foreach( $group_ids as $group_id ) {
  907. $this->index_group_forum_attachments( $group_id );
  908. }
  909. }
  910. }
  911. /**
  912. * Handles the action for a new forum reply
  913. * @param int $reply_id
  914. * @param int $topic_id
  915. * @param int $forum_id
  916. * @param string $anonymous_data ???
  917. * @param int $topic_author author user id
  918. * @return void
  919. */
  920. public function handle_new_forum_reply( $reply_id, $topic_id, $forum_id, $anonymous_data = '', $topic_author ) {
  921. $groups = get_post_meta( $forum_id, '_bbp_group_ids', array() );
  922. foreach( $groups as $group_ids ) {
  923. if( ! is_array( $group_ids ) ) {
  924. $group_ids = array( $group_ids );
  925. }
  926. foreach( $group_ids as $group_id ) {
  927. $this->index_group_forum_attachments( $group_id );
  928. }
  929. }
  930. }
  931. /**
  932. * Finds attachments in Buddypress group forum threads
  933. * and store a way to find them in a folder linked to
  934. * specified group
  935. * @param int $group_id
  936. */
  937. public function index_group_forum_attachments( $group_id ) {
  938. global $wpdb, $bbdb;
  939. do_action( 'bbpress_init' );
  940. $group_folder = $this->get_group_folder( $group_id );
  941. $topics_folder = $this->get_topics_folder( $group_id );
  942. $forum_id = groups_get_groupmeta( $group_id, 'forum_id' );
  943. if( is_array( $forum_id ) ) {
  944. $forum_id = reset( $forum_id );
  945. }
  946. if( $forum_id ) {
  947. $topic_query = new WP_Query( array(
  948. 'post_type' => bbp_get_topic_post_type(),
  949. 'post_parent' => $forum_id,
  950. 'posts_per_page' => -1,
  951. 'post_status' => join( ',', array( bbp_get_public_status_id(), bbp_get_closed_status_id() ) ),
  952. ) );
  953. while( $topic_query->have_posts() ) {
  954. $topic_query->the_post();
  955. $topic_id = bbp_get_topic_id( $topic_query->post->ID );
  956. $attachments = $this->get_attachments( $topic_id );
  957. $reply_query = new WP_Query( array(
  958. 'post_type' => bbp_get_reply_post_type(),
  959. 'post_parent' => $topic_id,
  960. 'posts_per_page' => -1
  961. ) );
  962. while( $reply_query->have_posts() ) {
  963. $reply_query->the_post();
  964. $reply_id = bbp_get_reply_id( $reply_query->post->ID );
  965. $attachments = array_merge( $attachments, $this->get_attachments( $reply_id ) );
  966. }
  967. wp_reset_postdata();
  968. foreach( $attachments as $attachment ) {
  969. $post_query = new WP_Query( array(
  970. 'post_type' => 'document',
  971. 'meta_key' => 'filebox_forum_imported',
  972. 'meta_value' => $attachment->ID
  973. ) );
  974. if( ! $post_query->have_posts() ) {
  975. $filename = get_attached_file( $attachment->ID );
  976. if( $filename && is_file( $filename ) ) {
  977. $finfo = new finfo( FILEINFO_MIME );
  978. $type = $finfo->file( $filename );
  979. if( strpos( $type, ';' ) ) {
  980. $type = substr( $type, 0, strpos( $type, ';' ) );
  981. }
  982. $file = $this->upload_file( array(
  983. 'folder_id' => $topics_folder,
  984. 'file_upload' => array(
  985. 'name' => substr( $filename, strrpos( $filename, '/' ) + 1 ),
  986. 'tmp_name' => $filename,
  987. 'type' => $type
  988. ),
  989. 'comment' => __( 'Imported from group forum', 'filebox' ),
  990. 'user_id' => $attachment->post_author
  991. ), ARRAY_A );
  992. if( $file[ 'file_id' ] ) {
  993. update_post_meta( $file[ 'file_id' ], 'filebox_forum_imported', $attachment->ID );
  994. }
  995. }
  996. }
  997. wp_reset_postdata();
  998. }
  999. }
  1000. }
  1001. }
  1002. /**
  1003. * Returns zip info-data
  1004. * $zip->url, $zip->size
  1005. * @param int $folder_id
  1006. * @return object
  1007. */
  1008. public function get_folder_zip( $folder_id ) {
  1009. $upload = wp_upload_dir();
  1010. $folder = get_term( $folder_id, 'fileboxfolders' );
  1011. if( $folder ) {
  1012. $filename = $this->get_folder_zip_path( $folder_id );
  1013. if( is_file( $filename ) ) {
  1014. $zip = new stdClass();
  1015. $zip->url = sprintf( '%s/%s.zip',
  1016. home_url( sprintf( '/%s/%s',
  1017. $this->options[ 'slug-folders' ],
  1018. $folder_id
  1019. ) ),
  1020. $folder->slug
  1021. );
  1022. $zip->size = filesize( $filename );
  1023. return $zip;
  1024. }
  1025. }
  1026. return null;
  1027. }
  1028. /**
  1029. * Returns a local path to specified folder zip
  1030. * @param int $folder_id
  1031. * return atring
  1032. */
  1033. public function get_folder_zip_path( $folder_id ) {
  1034. $upload = wp_upload_dir();
  1035. $path = sprintf( '%s/%s',
  1036. $upload[ 'basedir' ],
  1037. $this->options[ 'folder-zip-folder' ]
  1038. );
  1039. if( ! is_dir( $path ) ) {
  1040. mkdir( $path );
  1041. }
  1042. $path = sprintf( '%s/%s.zip', $path, $folder_id );
  1043. return $path;
  1044. }
  1045. /**
  1046. * Generates a zip stored in uploads folder with all files attached to
  1047. * specified term.
  1048. * DONT CALL THIS FUNCTION DIRECTLY. USE generate_folder_zip_async INSTEAD.
  1049. * This function touches a lock-file that ensures no duplicates. Altough,
  1050. * $force will override this.
  1051. * @param array|int $args Argument array or the folder id
  1052. * @param boolean $force Override lock
  1053. * @return void
  1054. */
  1055. public function generate_folder_zip( $args, $force = false ) {
  1056. set_time_limit( 0 );
  1057. $now = time();
  1058. if( is_numeric( $args ) ) {
  1059. $folder_id = $args;
  1060. } else {
  1061. $args = $this->get_ajax_arguments( $args, array(
  1062. 'folder_id' => 0,
  1063. 'force' => false
  1064. ), 'generate_folder_zip' );
  1065. $folder_id = $args[ 'folder_id' ];
  1066. $force = $args[ 'force' ];
  1067. }
  1068. if( $folder_id && ( ! $this->generate_folder_zip_exists( $folder_id ) || $force ) ) {
  1069. $lock = preg_replace(
  1070. '/\.zip$/',
  1071. '.lock',
  1072. $this->get_folder_zip_path( $folder_id )
  1073. );
  1074. touch( $lock );
  1075. $zip = new ZipArchive();
  1076. $filename = preg_replace(
  1077. '/\.lock$/',
  1078. sprintf( '.%s.zip', $now ),
  1079. $lock
  1080. );
  1081. if( $zip->open( $filename, ZIPARCHIVE::CREATE ) ) {
  1082. $this->generate_folder_zip_files( $zip, $folder_id, '', $force );
  1083. }
  1084. $zip->close();
  1085. if( file_exists( $filename ) ) {
  1086. $target = $this->get_folder_zip_path( $folder_id );
  1087. if( file_exists( $target ) ) {
  1088. unlink( $target );
  1089. }
  1090. symlink( $filename, $target );
  1091. }
  1092. if( file_exists( $lock ) ) {
  1093. unlink( $lock );
  1094. }
  1095. foreach( glob( preg_match(
  1096. '/\.zip$/', '.*.zip', $this->get_folder_zip_path( $folder_id )
  1097. ) ) as $symlink ) {
  1098. if( preg_match( '/\.([0-9]+)\.zip$/', $symlink, $time ) ) {
  1099. $time = ( int ) $time[ 0 ];
  1100. if( $time - 86400 < $now && $symlink != $filename ) {
  1101. unlink( $symlink );
  1102. }
  1103. }
  1104. }
  1105. }
  1106. }
  1107. /**
  1108. * Checks of a generated folder zip file exists or a lock.
  1109. * @param int $folder_id
  1110. * @return boolean
  1111. */
  1112. public function generate_folder_zip_exists( $folder_id ) {
  1113. $filename = $this->get_folder_zip_path( $folder_id );
  1114. $files = glob( preg_replace(
  1115. '/\.zip$/',
  1116. '.*.zip',
  1117. $filename
  1118. ) );
  1119. $files = array_merge( $files, glob( preg_replace(
  1120. '/\.zip$/',
  1121. '.lock',
  1122. $filename
  1123. ) ) );
  1124. return( is_array( $files ) && count( $files ) );
  1125. }
  1126. /**
  1127. * Starts an async call to the generate_folder_zip via an ajax request.
  1128. * @param int $folder_id
  1129. * @param boolean $force If a zip is already being created, a true here will
  1130. * force a new creation.
  1131. * @return void
  1132. */
  1133. public function generate_folder_zip_async( $folder_id, $force = false ) {
  1134. if( ! $this->generate_folder_zip_exists( $folder_id ) || $force ) {
  1135. $nonce = wp_create_nonce( 'generate_folder_zip' );
  1136. $cookies = array();
  1137. foreach( $_COOKIE as $key => $val ) {
  1138. $cookies[] = sprintf( '%s=%s', $key, urlencode( $val ) );
  1139. }
  1140. exec( sprintf(
  1141. 'curl -b "%s" -d "action=filebox_generate_zip" -d "security=%s" -d "folder_id=%s" -d "force=%s" "%s" > /dev/null 2>&1 &',
  1142. implode( ';', $cookies ),
  1143. $nonce,
  1144. $folder_id,
  1145. $force,
  1146. admin_url( 'admin-ajax.php' )
  1147. ) );
  1148. }
  1149. }
  1150. /**
  1151. * Adds folders and folders' files in specified zip
  1152. * @param object $zip
  1153. * @param int $folder_id
  1154. * @return void
  1155. */
  1156. public function generate_folder_zip_files( $zip, $folder_id, $current_zip_dir = '', $force = false ) {
  1157. $folder_name = sanitize_title( sanitize_file_name( $this->get_folder_name( $folder_id ) ) );
  1158. $files = $this->get_files( $folder_id );
  1159. $subfolders = $this->get_subfolders( $folder_id );
  1160. if( $folder_name && ( count( $subfolders ) || count( $files ) ) ) {
  1161. $folder_name = $current_zip_dir . $folder_name;
  1162. $zip->addEmptyDir( $folder_name );
  1163. foreach( $files as $file ) {
  1164. if( is_array( $file->attachments ) ) {
  1165. $attachment = reset( $file->attachments );
  1166. if( is_object( $attachment ) ) {
  1167. $filename = get_attached_file( $attachment->ID );
  1168. $zip->addFile( $filename, sprintf( '%s/%s.%s',
  1169. $folder_name,
  1170. self::sanitize_title( $file->post_title ),
  1171. substr( $filename, strpos( $filename, '.' ) + 1 )
  1172. ) );
  1173. }
  1174. }
  1175. }
  1176. foreach( $subfolders as $subfolder ) {
  1177. $this->generate_folder_zip( $subfolder->term_id, $force );
  1178. $this->generate_folder_zip_files( $zip, $subfolder->term_id, $folder_name . '/', $force );
  1179. }
  1180. }
  1181. }
  1182. /**
  1183. * Sets message-term and folder-term on latest revision
  1184. * @param int $file_id
  1185. * @param string $message
  1186. * @return void
  1187. */
  1188. public function record_change( $file_id, $message ) {
  1189. $revisions = get_children( array(
  1190. 'post_parent' => $file_id,
  1191. 'post_type' => 'revision',
  1192. 'post_status' => 'inherit',
  1193. 'numberposts' => 1,
  1194. 'orderby' => 'post_date',
  1195. 'order' => 'DESC'
  1196. ) );
  1197. if( is_array( $revisions ) ) {
  1198. $terms = wp_get_object_terms( $file_id, array( 'fileboxcommits', 'fileboxfolders' ) );
  1199. if( is_array( $terms ) ) {
  1200. foreach( $terms as $term ) {
  1201. wp_set_object_terms( reset( $revisions )->ID, ( int ) $term->term_id, $term->taxonomy );
  1202. }
  1203. }
  1204. }
  1205. wp_set_object_terms( $file_id, $message, 'fileboxcommits' );
  1206. update_post_meta( $file_id, '_edit_last', get_current_user_id() );
  1207. }
  1208. // ---------------------
  1209. // AJAX FRIENDLY METHODS
  1210. // ---------------------
  1211. /**
  1212. * Get an ajax-friendly argument array.
  1213. * It will also check for nonce if arguments are fetched from an post request.
  1214. * @param array $args
  1215. * @param array $defaults
  1216. * @param string $nonce The nonce to check if this is an ajax-request
  1217. * @return array
  1218. */
  1219. public function get_ajax_arguments( $args, $defaults, $nonce = '' ) {
  1220. $using_nonce = false;
  1221. if( ! is_array( $args ) ) {
  1222. $args = array();
  1223. }
  1224. foreach( $defaults as $arg => $default ) {
  1225. if( ! array_key_exists( $arg, $args ) ) {
  1226. if( array_key_exists( $arg, $_POST ) ) {
  1227. $args[ $arg ] = $_POST[ $arg ];
  1228. $using_nonce = true;
  1229. } else {
  1230. $args[ $arg ] = $default;
  1231. }
  1232. }
  1233. }
  1234. if( $using_nonce ) {
  1235. check_ajax_referer( $nonce, 'security', true );
  1236. }
  1237. return $args;
  1238. }
  1239. /**
  1240. * Get an ajax-friendly return
  1241. * @param string $output ARRAY_A, STRING prints json and NULL is NULL
  1242. * @return array|void
  1243. */
  1244. public function get_ajax_output( $output, $response = STRING ) {
  1245. if( $output == ARRAY_A ) {
  1246. return $response;
  1247. } elseif( $output == STRING ) {
  1248. echo json_encode( $response );
  1249. exit;
  1250. }
  1251. }
  1252. /**
  1253. * Get a list of all files and folders.
  1254. * $args can be filtered by filebox_list_files_and_folders_args filter.
  1255. * $response can be filtered by filebox_list_files_and_folders_response filter.
  1256. * @param int|string|array $args array( folder_id => folder id, group_id => group id, folder_slug => string ) Uses $_POST as fallback.
  1257. * @param boolean $show_all Show all files and folders
  1258. * @param $output ARRAY_A, STRING prints json and NULL is void
  1259. * @return array|void
  1260. */
  1261. public function list_files_and_folders( $args = null, $output = STRING ) {
  1262. $response = array(
  1263. 'meta' => array(),
  1264. 'folders' => array(),
  1265. 'files' => array()
  1266. );
  1267. if( is_numeric( $args ) ) {
  1268. $args = array( 'folder_id' => ( int ) $args );
  1269. } elseif( ! is_array( $args ) ) {
  1270. $args = array();
  1271. }
  1272. $args = $this->get_ajax_arguments( $args, array(
  1273. 'folder_id' => 0,
  1274. 'group_id' => 0,
  1275. 'folder_slug' => ''
  1276. ), 'list_files_and_folders' );
  1277. if( ! is_array( $args[ 'folder_slug' ] ) ) {
  1278. $args[ 'folder_slug' ] = array( $args[ 'folder_slug' ] );
  1279. }
  1280. $args = apply_filters( 'filebox_list_files_and_folders_args', $args );
  1281. if( $args[ 'group_id' ] ) {
  1282. $group_folder_id = $this->get_group_folder( $args[ 'group_id' ] );
  1283. $topic_folder_id = $this->get_topics_folder( $args[ 'group_id' ] );
  1284. if( ! empty( $args[ 'folder_slug' ] ) && ! $args[ 'folder_id' ] ) {
  1285. $folder_id = $group_folder_id;
  1286. foreach( $args[ 'folder_slug' ] as $slug ) {
  1287. $folder_id = get_terms( 'fileboxfolders', array(
  1288. 'fields' => 'ids',
  1289. 'slug' => $slug,
  1290. 'parent' => $folder_id,
  1291. 'hide_empty' => false
  1292. ) );
  1293. if( is_array( $folder_id ) ) {
  1294. $folder_id = reset( $folder_id );
  1295. }
  1296. }
  1297. $args[ 'folder_id' ] = $folder_id;
  1298. } elseif( $args[ 'folder_id' ] ) {
  1299. $ancestors = $this->get_folder_ancestors( $args[ 'folder_id' ] );
  1300. if( ! in_array( $group_folder_id, $ancestors ) ) {
  1301. $args[ 'folder_id' ] = 0;
  1302. }
  1303. } else {
  1304. $args[ 'folder_id' ] = $group_folder_id;
  1305. }
  1306. if( $args[ 'folder_id' ] ) {
  1307. $this->generate_folder_zip_async( $args[ 'folder_id' ] );
  1308. $response[ 'folders' ] = $this->get_subfolders( $args[ 'folder_id' ] );
  1309. $response[ 'files' ] = $this->get_files( $args[ 'folder_id' ] );
  1310. $response[ 'meta' ] = array(
  1311. 'id' => $args[ 'folder_id' ],
  1312. 'current' => $this->get_folder( $args[ 'folder_id' ] ),
  1313. 'breadcrumbs' => $this->get_folder_ancestors( $args[ 'folder_id' ] )
  1314. );
  1315. do_action( 'filebox_list_files_and_folders', $response[ 'meta' ][ 'current' ] );
  1316. } elseif( $args[ 'folder_slug' ][ 0 ] == 'trash' ) {
  1317. $response[ 'files' ] = $this->get_trash( $args[ 'group_id' ] );
  1318. $response[ 'meta' ] = array(
  1319. 'id' => 0,
  1320. 'trash' => true,
  1321. 'current' => $this->get_folder( $group_folder_id )
  1322. );
  1323. }
  1324. }
  1325. $response = apply_filters( 'filebox_list_files_and_folders_response', $response, $args );
  1326. return $this->get_ajax_output( $output, $response );
  1327. }
  1328. // --------------------------
  1329. // FILE AJAX FRIENDLY METHODS
  1330. // --------------------------
  1331. /**
  1332. * Upload file
  1333. * Requires an uploaded file in $_FILES if not defined in $args.
  1334. * $args can be filtered by filebox_upload_file_args filter.
  1335. * $response can be filtered by filebox_upload_file_response filter.
  1336. * Action filebox_upload_file will be executed just after file has been saved.
  1337. * @param array $args array( folder_id => int, file_id => int, comment (optional) => string, file_upload (optional) => array( name => string, tmp_name => string, type => string ) )
  1338. * @param string $output ARRAY_A, STRING prints json, NULL is void
  1339. * @return array|void
  1340. */
  1341. public function upload_file( $args = null, $output = STRING ) {
  1342. $response = array(
  1343. 'file_id' => 0
  1344. );
  1345. $args = $this->get_ajax_arguments( $args, array(
  1346. 'folder_id' => 0,
  1347. 'file_id' => 0
  1348. ), 'upload_file' );
  1349. $args = apply_filters( 'filebox_upload_file_args', $args );
  1350. if( $args[ 'file_id' ] ) {
  1351. $doc = $this->get_file( $args[ 'file_id' ] );
  1352. } else {
  1353. $doc = null;
  1354. }
  1355. if(
  1356. (
  1357. term_exists( ( int ) $args[ 'folder_id' ], 'fileboxfolders' )
  1358. || $doc
  1359. ) && (
  1360. array_key_exists( 'file_upload', $_FILES )
  1361. || array_key_exists( 'file_upload', $args )
  1362. )
  1363. ) {
  1364. if( array_key_exists( 'file_upload', $args ) ) {
  1365. $file = $args[ 'file_upload' ];
  1366. } else {
  1367. $file = $_FILES[ 'file_upload' ];
  1368. }
  1369. $upload = wp_upload_bits( $file[ 'name' ], null, file_get_contents( $file[ 'tmp_name' ] ) );
  1370. if( $upload[ 'error' ] ) {
  1371. $response[ 'error' ] = strip_tags( $upload[ 'error' ] );
  1372. } else {
  1373. if( $doc ) {
  1374. $file_id = $doc->ID;
  1375. } else {
  1376. $file_id = wp_insert_post( array(
  1377. 'post_title' => $file[ 'name' ],
  1378. 'post_name' => self::sanitize_title( $file[ 'name' ] ),
  1379. 'post_content' => '',
  1380. 'post_type' => 'document',
  1381. 'post_status' => 'publish',
  1382. 'post_author' => array_key_exists( 'user_id', $args ) ? $args[ 'user_id' ] : get_current_user_id()
  1383. ) );
  1384. }
  1385. wp_set_object_terms(
  1386. $file_id,
  1387. ( int ) $args[ 'folder_id' ],
  1388. 'fileboxfolders'
  1389. );
  1390. $attach_id = wp_insert_attachment( array(
  1391. 'guid' => $upload[ 'url' ],
  1392. 'post_mime_type' => $file[ 'type' ],
  1393. 'post_title' => $file[ 'name' ],
  1394. 'post_content' => '',
  1395. 'post_status' => 'inherit',
  1396. 'post_author' => array_key_exists( 'user_id', $args ) ? $args[ 'user_id' ] : get_current_user_id()
  1397. ), $upload[ 'file' ], $file_id );
  1398. wp_update_post( array(
  1399. 'ID' => $file_id,
  1400. 'post_content' => $attach_id,
  1401. 'post_author' => array_key_exists( 'user_id', $args ) ? $args[ 'user_id' ] : get_current_user_id()
  1402. ) );
  1403. // check if this is the first time the file has been uploaded, if so add term "Uploaded new file", else add term "Updated file"
  1404. if ( ! $doc ) :
  1405. $this->record_change(
  1406. $file_id,
  1407. array_key_exists( 'comment', $args )
  1408. ? $args[ 'comment' ]
  1409. : __( 'Uploaded new file', 'filebox' )
  1410. );
  1411. else :
  1412. $this->record_change(
  1413. $file_id,
  1414. array_key_exists( 'comment', $args )
  1415. ? $args[ 'comment' ]
  1416. : __( 'Updated file', 'filebox' )
  1417. );
  1418. endif;
  1419. require_once( ABSPATH . 'wp-admin/includes/image.php');
  1420. $attach_data = wp_generate_attachment_metadata(
  1421. $attach_id,
  1422. $upload[ 'file' ]
  1423. );
  1424. wp_update_attachment_metadata( $attach_id, $attach_data );
  1425. $response[ 'file_id' ] = $file_id;
  1426. $response[ 'file_name' ] = $file[ 'name' ];
  1427. $group_id = $this->get_group_by_folder( $args[ 'folder_id' ] );
  1428. $group_folder_id = $this->get_group_folder( $group_id );
  1429. $this->generate_folder_zip_async( $group_folder_id, true );
  1430. do_action(
  1431. 'filebox_file_upload',
  1432. $this->get_file( $file_id ),
  1433. $this->get_folder( $args[ 'folder_id' ] ),
  1434. groups_get_group( array( 'group_id' => $group_id ) ),
  1435. $doc ? true : false
  1436. );
  1437. }
  1438. } else {
  1439. $response[ 'error' ] = __( 'Wrong arguments. Could not save file.', 'filebox' );
  1440. }
  1441. $response = apply_filters( 'filebox_upload_file_response', $response, $args );
  1442. return $this->get_ajax_output( $output, $response );
  1443. }
  1444. /**
  1445. * Move file to specified dir.
  1446. * $args can be filtered by filebox_move_file_args filter.
  1447. * $response can be filtered by filebox_upload_file_response filter.
  1448. * Action filebox_move_file is executed when file has been moved.
  1449. * @param array $args array( file_id => int, folder_id => int )
  1450. * @param string $output ARRAY_A, STRING prints json, NULL is void
  1451. * @return array|void
  1452. */
  1453. public function move_file( $args = null, $output = STRING ) {
  1454. $response = array(
  1455. 'file_id' => 0,
  1456. 'folder_id' => 0
  1457. );
  1458. $args = $this->get_ajax_arguments( $args, array(
  1459. 'file_id' => 0,
  1460. 'folder_id' => 0
  1461. ), 'move_file' );
  1462. $args = apply_filters( 'filebox_move_file_args', $args );
  1463. if(
  1464. get_post( $args[ 'file_id' ] )
  1465. && term_exists( ( int ) $args[ 'folder_id' ], 'fileboxfolders' )
  1466. ) {
  1467. if( wp_update_post( array( 'ID' => $args[ 'file_id' ] ) ) ) {
  1468. $this->record_change(
  1469. $args[ 'file_id' ],
  1470. __( 'Moved to folder', 'filebox' )
  1471. );
  1472. $old_folder_id = $this->get_folder_by_file( $args[ 'file_id' ] );
  1473. if( wp_set_object_terms(
  1474. $args[ 'file_id' ],
  1475. ( int ) $args[ 'folder_id' ],
  1476. 'fileboxfolders'
  1477. ) ) {
  1478. $group_id = $this->get_group_by_folder( $args[ 'folder_id' ] );
  1479. $group_folder_id = $this->get_group_folder( $group_id );
  1480. $this->generate_folder_zip_async( $group_folder_id, true );
  1481. do_action(
  1482. 'filebox_move_file',
  1483. $this->get_file( $args[ 'file_id' ] ),
  1484. $this->get_folder( $args[ 'folder_id' ] ),
  1485. $old_folder_id,
  1486. groups_get_group( array( 'group_id' => $group_id ) )
  1487. );
  1488. $response = $args;
  1489. } else {
  1490. $response[ 'error' ] = __( 'Error when trying to move file.', 'filebox' );
  1491. }
  1492. } else {
  1493. $response[ 'error' ] = __( 'Error when trying to move file. Either you\'re moving an non-existing file or the folder doesn\'t exist.', 'filebox' );
  1494. }
  1495. } else {
  1496. $response[ 'error' ] = __( 'Wrong arguments. Could not move file.', 'filebox' );
  1497. }
  1498. $response = apply_filters( 'filebox_move_file_response', $response, $args );
  1499. return $this->get_ajax_output( $output, $response );
  1500. }
  1501. /**
  1502. * Renames a file.
  1503. * $args can be filtered by filebox_rename_file_args filter.
  1504. * $response can be filtered by filebox_rename_file_response filter.
  1505. * Action filebox_rename_file is executed when file has been renamed.
  1506. * @param array $args array( 'file_id' => int, file_name => string )
  1507. * @param string $output ARRAY_A, STRING prints json, NULL is void
  1508. * @return array|void
  1509. */
  1510. public function rename_file( $args = null, $output = STRING ) {
  1511. $response = array(
  1512. 'file_id' => 0,
  1513. 'file_name' => '',
  1514. 'file_description' => ''
  1515. );
  1516. $args = $this->get_ajax_arguments( $args, array(
  1517. 'file_id' => 0,
  1518. 'file_name' => '',
  1519. 'file_description' => ''
  1520. ), 'rename_file' );
  1521. $args = apply_filters( 'filebox_rename_file_args', $args );
  1522. $file = get_post( $args[ 'file_id' ] );
  1523. if( $file && ! empty( $args[ 'file_name' ] ) ) {
  1524. if( wp_update_post( array(
  1525. 'ID' => $file->ID,
  1526. 'post_title' => $args[ 'file_name' ],
  1527. 'post_excerpt' => $args[ 'file_description' ]
  1528. ) ) ) {
  1529. $this->record_change( $file->ID, __( 'Renamed file', 'filebox' ) );
  1530. $group_id = $this->get_group_by_file( $args[ 'file_id' ] );
  1531. $group_folder_id = $this->get_group_folder( $group_id );
  1532. $this->generate_folder_zip_async( $group_folder_id, true );
  1533. do_action(
  1534. 'filebox_rename_file',
  1535. $this->get_file( $file->ID ),
  1536. $this->get_folder_by_file( $file->ID ),
  1537. groups_get_group( array( 'group_id' => $group_id ) )
  1538. );
  1539. $response = $args;
  1540. } else {
  1541. $response[ 'error' ] = __( 'Error when trying to rename file.', 'filebox' );
  1542. }
  1543. } else {
  1544. $response[ 'error' ] = __( 'Error when trying to rename file. Either you\'re trying to rename a non-existing file. Or the new name is empty.', 'filebox' );
  1545. }
  1546. $response = apply_filters( 'filebox_rename_file_response', $response, $args );
  1547. return $this->get_ajax_output( $output, $response );
  1548. }
  1549. /**
  1550. * Get revision history for file
  1551. * @param array $args array( file_id => int )
  1552. * @param string $output ARRAY_A, STRING prints json, NULL is void
  1553. * @return array|void
  1554. */
  1555. public function history_file( $args = null, $output = STRING ) {
  1556. $response = array(
  1557. 'file_history' => array()
  1558. );
  1559. $args = $this->get_ajax_arguments( $args, array(
  1560. 'file_id' => 0
  1561. ), 'history_file' );
  1562. if( $args[ 'file_id' ] ) {
  1563. $file = $this->get_file( $args[ 'file_id' ] );
  1564. $folder = wp_get_post_terms( $args[ 'file_id' ], 'fileboxfolders' );
  1565. $workflow = wp_get_post_terms( $args[ 'file_id' ], 'fileboxcommits' );
  1566. if( $file && $

Large files files are truncated, but you can click here to view the full file