PluginProbe
UpdraftCentral Dashboard / trunk
UpdraftCentral Dashboard vtrunk
0.8.33 0.7.2 0.7.3 0.7.4 0.8.0 0.8.1 0.8.10 0.8.11 0.8.12 0.8.13 0.8.14 0.8.15 0.8.16 0.8.17 0.8.18 0.8.19 0.8.2 0.8.20 0.8.21 0.8.22 0.8.23 0.8.24 0.8.25 0.8.26 0.8.27 All 51 releases
updraftcentral / classes / class-uploader.php

class-uploader.php in UpdraftCentral Dashboard trunk, at classes/class-uploader.php

243 lines 8.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) die('Access denied.');
3
4 if (!class_exists('UpdraftCentral_Uploader')) :
5
6 /**
7 * Handles file upload process initiated by plupload which sends the data directly to the
8 * remote website. Intended to be shared and used by the "plugin" and "theme" modules.
9 */
10 class UpdraftCentral_Uploader {
11
12 protected static $_instance = null;
13
14 /**
15 * Creates an instance of this class. Singleton Pattern
16 *
17 * @return object Instance of this class
18 */
19 public static function instance() {
20 if (empty(self::$_instance)) {
21 self::$_instance = new self();
22 }
23
24 return self::$_instance;
25 }
26
27 /**
28 * Sends the uploaded data to the remote website
29 *
30 * @param integer $site_id The ID of the remote site where the data is to be sent
31 * @param array $data The data to send
32 * @param string $module Indicates whether this request is intended for the 'plugin' or 'theme' module
33 * @return array
34 */
35 private function send_upload_request($site_id, $data, $module) {
36
37 $user = UpdraftCentral()->user;
38
39 $user_id = get_current_user_id();
40 if (empty($user)) $user = UpdraftCentral()->get_user_object($user_id);
41
42 if (!empty($user) && is_a($user, 'UpdraftCentral_User')) {
43 $remote_params = array(
44 'site_id' => $site_id,
45 'data' => array(
46 'command' => $module.'.upload_'.$module,
47 'data' => $data
48 )
49 );
50
51 $remote_response = $user->send_remote_command($remote_params);
52 if (!empty($remote_response) && 'ok' == $remote_response['responsetype']) {
53 $response = $remote_response['rpc_response']['response'];
54 $data = $remote_response['rpc_response']['data'];
55
56 if ('rpcok' === $response) {
57 return $data;
58 } else {
59 $data['error'] = true;
60 if (is_null($data['data'])) $data['data'] = array();
61
62 return $data;
63 }
64 }
65
66 // If proccess gets to this line it would mean that we have encountered
67 // an issue other than the expected response (like fatal error, etc.). So, it would be
68 // helpful if we pass back the original response to the caller for easier debugging if need be.
69 return $remote_response;
70 }
71 }
72
73 /**
74 * Retrieves a PHP error message associated with the error code. These error messages
75 * are the ones raised when an upload error has occured using PHP.
76 *
77 * @param integer $code The error code returned by $_FILES
78 * @return string
79 */
80 private function get_upload_error_message($code) {
81
82 // $_FILES error code may return as string. Thus, we're going to
83 // cast it into int before proceeding with the check.
84 switch ((int) $code) {
85 case 1:
86 $message = __('The uploaded file exceeds the upload_max_filesize directive set in your UpdraftCentral dashboard\'s php.ini file.', 'updraftcentral');
87 break;
88 case 2:
89 $message = __('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.', 'updraftcentral');
90 break;
91 case 3:
92 $message = __('The uploaded file was only partially uploaded.', 'updraftcentral');
93 break;
94 case 4:
95 $message = __('No file was uploaded.', 'updraftcentral');
96 break;
97 case 6:
98 $message = __('Missing a temporary folder that is needed to upload files to your UpdraftCentral dashboard.', 'updraftcentral');
99 break;
100 case 7:
101 $message = __('Failed to write file to disk.', 'updraftcentral').' '.__("Make sure you have sufficient permission to upload files to your UpdraftCentral dashboard's file system.", 'updraftcentral');
102 break;
103 case 8:
104 $message = __('Your UpdraftCentral dashboard\'s PHP extension stopped the file upload.', 'updraftcentral');
105 break;
106 default:
107 $message = __('The file was not uploaded successfully.', 'updraftcentral').' '.__('Please try again.', 'updraftcentral');
108 break;
109 }
110
111 return $message;
112 }
113
114 /**
115 * Retrieves the Plupload configuration
116 *
117 * @param string $module Indicates whether the current request is intended for the 'plugin' or 'theme' module
118 * @return string
119 */
120 public function get_plupload_config($module) {
121
122 $chunk_size = min(wp_max_upload_size()-1024, 1024*1024*2-1024);
123 $plupload_init = array(
124 'runtimes' => 'html5,flash,silverlight,html4',
125 'browse_button' => 'plupload-browse-button',
126 'container' => 'plupload-upload-ui',
127 'drop_element' => 'drag-drop-area',
128 'file_data_name' => 'async-upload',
129 'multiple_queues' => false,
130 'max_file_count' => 1,
131 'max_file_size' => '100Gb',
132 'chunk_size' => $chunk_size.'b',
133 'url' => admin_url('admin-ajax.php'),
134 'filters' => array(array('title' => __('Allowed Files'), 'extensions' => 'zip')),
135 'multipart' => true,
136 'multi_selection' => false,
137 'urlstream_upload' => true,
138 // additional post data to send to our ajax hook
139 'multipart_params' => array(
140 '_ajax_nonce' => wp_create_nonce('updraftcentral-uploader-'.$module),
141 'action' => $module.'_uploader_action'
142 )
143 );
144
145 // WP 3.9 updated to plupload 2.0 - https://core.trac.wordpress.org/ticket/25663
146 if (is_file(ABSPATH.WPINC.'/js/plupload/Moxie.swf')) {
147 $plupload_init['flash_swf_url'] = includes_url('js/plupload/Moxie.swf');
148 } else {
149 $plupload_init['flash_swf_url'] = includes_url('js/plupload/plupload.flash.swf');
150 }
151
152 if (is_file(ABSPATH.WPINC.'/js/plupload/Moxie.xap')) {
153 $plupload_init['silverlight_xap_url'] = includes_url('js/plupload/Moxie.xap');
154 } else {
155 $plupload_init['silverlight_xap_url'] = includes_url('js/plupload/plupload.silverlight.swf');
156 }
157
158 // plupload_config
159 return json_encode($plupload_init);
160 }
161
162 /**
163 * Process the upload request originating from the plupload client and send
164 * the uploaded data directly to the remote website.
165 *
166 * @param string $module Indicates whether the current request is intended for the 'plugin' or 'theme' module
167 * @return string
168 */
169 public function plupload_action($module) {
170
171 // Verify the nonce submitted
172 $post = wp_unslash($_POST);
173 $ajax_nonce = !empty($post['_ajax_nonce']) ? sanitize_text_field($post['_ajax_nonce']) : '';
174 if (empty($ajax_nonce) || !wp_verify_nonce($ajax_nonce, 'updraftcentral-uploader-'.$module)) {
175 echo json_encode(array('e' => sprintf(__('Error: %s', 'updraftcentral'), __('Nonce verification failed.', 'updraftcentral'))));
176 exit;
177 }
178
179 // "tmp_name" field of the $_FILES array is auto-generated by PHP, not a user input.
180 // It contains the temporary location/path of the uploaded file. Adding "wp_unslash" will
181 // break this upload feature on a Windows System thus, we added the phpcs:ignore
182 // annotation here.
183 $tmp_name = isset($_FILES['async-upload']['tmp_name']) ? sanitize_text_field($_FILES['async-upload']['tmp_name']) : '';// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash - this value is not slashed
184 $filename = isset($post['name']) ? sanitize_file_name(basename($post['name'])) : '';
185
186 if (isset($_FILES['async-upload']['error']) && UPLOAD_ERR_OK == sanitize_text_field(wp_unslash($_FILES['async-upload']['error'])) && is_uploaded_file($tmp_name)) {
187 if (isset($post['chunk']) && 0 === (int) $post['chunk']) {
188 $validate = wp_check_filetype_and_ext($tmp_name, $filename);
189 } else {
190 $validate = wp_check_filetype($filename);
191 }
192
193 if (!empty($validate['ext']) && 'zip' === $validate['ext']) {
194 $filename = (isset($validate['proper_filename']) && false !== $validate['proper_filename']) ? $validate['proper_filename'] : $filename;
195 $args = array('filename' => $filename);
196
197 // Check to see if the current upload was split in chunks
198 if (isset($post['chunks'])) {
199 // Handling upload in chunks
200 $chunks = sanitize_text_field($post['chunks']);
201 if (1 < (int) $chunks) {
202 $args['chunks'] = $chunks;
203 if (isset($post['chunk'])) {
204 $args['chunk'] = sanitize_text_field($post['chunk']);
205 }
206 }
207 }
208
209 $args['data'] = base64_encode(file_get_contents($tmp_name));
210 $args['activate'] = isset($post['activate']) ? sanitize_text_field($post['activate']) : '';
211
212 $response_data = array();
213 if (isset($post['sites'])) {
214 $sites = json_decode(base64_decode(sanitize_text_field($post['sites'])), true);
215
216 foreach ($sites as $site) {
217 $args['filesystem_credentials'] = $site['filesystem_credentials'];
218 $response_data[] = array(
219 'site_id' => $site['id'],
220 'site_description' => $site['description'],
221 'response' => $this->send_upload_request($site['id'], $args, $module)
222 );
223 }
224 }
225
226 echo json_encode($response_data);
227 exit;
228 } else {
229 // Not a valid zip file...
230 echo json_encode(array('e' => sprintf(__('Error: %s', 'updraftcentral'), __('This file does not appear to be a zip file.', 'updraftcentral'))));
231 exit;
232 }
233 } else {
234 // An error has occured while processing the upload request
235 $error_message = $this->get_upload_error_message(sanitize_text_field(wp_unslash($_FILES['async-upload']['error'])));
236 echo json_encode(array('e' => sprintf(__('Error: %s', 'updraftcentral'), $error_message)));
237 exit;
238 }
239 }
240 }
241
242 endif;
243