Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 88
0.00% covered (danger)
0.00%
0 / 3
CRAP
n/a
0 / 0
wpcomsh_check_upload_size
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
90
wpcomsh_jetpack_upload_handler_can_upload
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
wpcomsh_allow_file_uploads_with_invalid_mime_types
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 1
702
1<?php
2/**
3 * Filters related to disk storage for WordPress on Atomic.
4 *
5 * @package wpcomsh
6 */
7
8/**
9 * Determine if uploaded file exceeds space quota.
10 * Modeled after core's check_upload_size() for multisite, but specific for WordPress on Atomic.
11 *
12 * @param array $file An element from the `$_FILES` array for a given file.
13 * @return array The `$_FILES` array element with 'error' key set if file exceeds quota. 'error' is empty otherwise.
14 */
15function wpcomsh_check_upload_size( $file ) {
16    if ( $file['error'] > 0 ) { // There's already an error.
17        return $file;
18    }
19
20    if ( defined( 'WP_IMPORTING' ) ) {
21        return $file;
22    }
23
24    $site_info = wpcomsh_get_at_site_info();
25    if ( empty( $site_info['space_used'] ) || empty( $site_info['space_quota'] ) ) {
26        return $file;
27    }
28
29    $space_available = $site_info['space_quota'] - $site_info['space_used'];
30    $file_size       = filesize( $file['tmp_name'] );
31
32    if ( $file_size >= $space_available ) {
33        $file['error'] = __( 'You have used your space quota. Please delete files before uploading.', 'wpcomsh' );
34    }
35
36    if ( $file['error'] > 0 && ! isset( $_POST['html-upload'] ) && ! wp_doing_ajax() ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
37        wp_die( esc_html( $file['error'] ), '', array( 'back_link' => true ) );
38    }
39
40    return $file;
41}
42add_filter( 'wp_handle_upload_prefilter', 'wpcomsh_check_upload_size' );
43
44/**
45 * Do not allow uploads from Calypso's media section if it would cause our
46 * disk usage to go over the quota.
47 *
48 * @param bool|WP_Error $allowed If false or WP_Error, blocks the upload. If true, allows the upload.
49 * @param array         $files   The $_FILES attempting to be uploaded.
50 *
51 * @return bool|WP_Error WP_Error when uploaded file would exceed upload space, $allowed when not.
52 */
53function wpcomsh_jetpack_upload_handler_can_upload( $allowed, $files ) {
54    $site_info = wpcomsh_get_at_site_info();
55
56    if ( empty( $site_info['space_used'] ) || empty( $site_info['space_quota'] ) ) {
57        return $allowed;
58    }
59
60    if ( ! empty( $files['media']['size'] ) ) {
61        $upload_size = array_sum( $files['media']['size'] );
62        if ( $site_info['space_used'] + $upload_size > $site_info['space_quota'] ) {
63            return new WP_Error( 'insufficient_space_available', 'Uploaded file is too large.' );
64        }
65    }
66
67    return $allowed;
68}
69add_filter( 'jetpack_upload_handler_can_upload', 'wpcomsh_jetpack_upload_handler_can_upload', 10, 2 );
70
71/**
72 * Allow the additional mime types that WPCOM already allows.
73 *
74 * @param array    $file_data {
75 *     Values for the extension, mime type, and corrected filename.
76 *
77 *     @type string|false $ext             File extension, or false if the file doesn't match a mime type.
78 *     @type string|false $type            File mime type, or false if the file doesn't match a mime type.
79 *     @type string|false $proper_filename File name with its correct extension, or false if it cannot be determined.
80 * }
81 * @param string   $file                      Full path to the file.
82 * @param string   $filename                  The name of the file (may differ from $file due to
83 *                                                $file being in a tmp directory).
84 * @param string[] $mimes                     Array of mime types keyed by their file extension regex.
85 */
86function wpcomsh_allow_file_uploads_with_invalid_mime_types( $file_data, $file, $filename, $mimes ) {
87    // Remove itself to avoid potential infinite loops
88    remove_filter( 'wp_check_filetype_and_ext', 'wpcomsh_allow_file_uploads_with_invalid_mime_types', 1000 );
89    if ( ! file_exists( $file ) ) {
90        return $file_data;
91    }
92
93    // If wp_check_filetype_and_ext already allows it or if the file does not,
94    // exist, don't bother doing the checks
95    if ( ! empty( $file_data['type'] ) ) {
96        return $file_data;
97    }
98
99    // Try to get the file type with the extension based check, bail if it fails
100    $file_type = wp_check_filetype( $filename, $mimes );
101    if ( empty( $file_type['type'] ) ) {
102        return $file_data;
103    }
104
105    $finfo     = finfo_open( FILEINFO_MIME_TYPE );
106    $real_mime = finfo_file( $finfo, $file );
107    // todo: remove when we are PHP 8.1+, as finfo_close() is noop in 8.1+ and deprecated in PHP 8.5+
108    if ( PHP_VERSION_ID < 80100 ) {
109        finfo_close( $finfo ); // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.finfo_closeDeprecated
110    }
111
112    if ( empty( $real_mime ) ) {
113        return $file_data;
114    }
115
116    $allowed = array();
117    switch ( strtolower( $file_type['ext'] ) ) {
118        case 'doc':
119        case 'docm':
120        case 'docx':
121            $allowed[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
122            $allowed[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml';
123            $allowed[] = $file_type['type'];
124            $allowed[] = 'application/cdfv2';
125            break;
126        case 'pot':
127        case 'pps':
128        case 'ppt':
129        case 'ppsm':
130        case 'ppsx':
131        case 'pptm':
132        case 'pptx':
133            $allowed[] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
134            $allowed[] = 'application/vnd.openxmlformats-officedocument.presentationml.slideshow';
135            $allowed[] = $file_type['type'];
136            $allowed[] = 'application/cdfv2';
137            break;
138        case 'xla':
139        case 'xls':
140        case 'xlt':
141        case 'xlw':
142        case 'xslb':
143        case 'xlsm':
144        case 'xlsx':
145            $allowed[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml';
146            $allowed[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
147            $allowed[] = $file_type['type'];
148            $allowed[] = 'application/cdfv2';
149            break;
150        case 'odt':
151            $allowed[] = 'application/vnd.oasis.opendocument.presentation';
152            $allowed[] = $file_type['type'];
153            $allowed[] = 'application/cdfv2';
154            break;
155    }
156
157    // Duplicate the mime types as a work around for https://bugs.php.net/bug.php?id=78028
158    $_allowed = array_map(
159        function ( $item ) {
160            return $item . $item;
161        },
162        $allowed
163    );
164    if ( in_array( strtolower( $real_mime ), $allowed, true ) || in_array( strtolower( $real_mime ), $_allowed, true ) ) {
165        $file_data['type'] = $file_type['type'];
166        $file_data['ext']  = $file_type['ext'];
167    }
168
169    return $file_data;
170}
171
172add_filter( 'wp_check_filetype_and_ext', 'wpcomsh_allow_file_uploads_with_invalid_mime_types', 1000, 4 );