PluginProbe
Upload Larger Plugins / 1.5
Upload Larger Plugins v1.5
2.1 trunk 1.0 1.1 1.2 1.3 1.4 1.4.1 1.5 1.6 1.7 1.8 2.0
upload-larger-plugins / upload-larger-plugins.php

upload-larger-plugins.php in Upload Larger Plugins 1.5, at upload-larger-plugins.php

414 lines 14.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Upload Larger Plugins
4 Version: 1.5
5 Plugin URI: https://wordpress.org/plugins/upload-larger-plugins
6 Description: Allow plugins larger than the PHP-defined limit to be uploaded.
7 Author: David Anderson
8 Donate: https://david.dw-perspective.org.uk/donate
9 Author URI: https://david.dw-perspective.org.uk
10 License: MIT
11 */
12
13 if (!defined('ABSPATH')) die('No direct access');
14
15 // Globals
16 define('UPLOADLARGERPLUGINS_VERSION', '1.5');
17 define('UPLOADLARGERPLUGINS_SLUG', "upload-larger-plugins");
18 define('UPLOADLARGERPLUGINS_DIR', dirname(realpath(__FILE__)));
19 define('UPLOADLARGERPLUGINS_URL', plugins_url('', __FILE__));
20
21 $simba_upload_larger_plugins = new Simba_Upload_Larger_Plugins();
22
23 class Simba_Upload_Larger_Plugins {
24
25 private $upload_dir;
26 private $upload_basedir;
27
28 /**
29 * Plugin constructor
30 */
31 public function __construct() {
32 //add_filter('plugin_action_links', array($this, 'action_links'), 10, 2 );
33 add_action('install_plugins_upload', array($this, 'install_plugins_upload'), 9, 1);
34 add_action('install_plugins_pre_upload', array($this, 'install_plugins_pre_upload'));
35 add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
36 add_action('plugins_loaded', array($this, 'load_translations'));
37 add_action('admin_head', array($this, 'admin_head'));
38 add_action('wp_ajax_ulp_plupload_action', array($this, 'ulp_plupload_action'));
39 add_action('admin_init', array($this, 'admin_init'));
40 // This filter only exists on WP 3.7+. We used to use it then... but then WP 4.6.1 broke our method, so we've reverted to the pre-WP-3.7 method
41 // add_filter('upgrader_pre_download', array($this, 'upgrader_pre_download'), 10, 3);
42 // This action allows us to tweak the link URL on WP 5.5+'s
43 add_filter('install_plugin_overwrite_actions', array($this, 'install_plugin_overwrite_actions'));
44 }
45
46 /**
47 * Called by the WP filter install_plugin_overwrite_actions (WP 5.5+)
48 *
49 * @param Array $install_actions Array of plugin action links.
50 *
51 * @return Array - modified array
52 */
53 public function install_plugin_overwrite_actions($install_actions) {
54
55 if (!empty($install_actions['overwrite_plugin']) && false !== strpos($install_actions['overwrite_plugin'], 'action=upload-plugin&amp;')) {
56
57 if (!empty($_GET['plugincksha1']) && !empty($_GET['overridebd']) && !empty($_GET['package']) && current_user_can('install_plugins')) {
58
59 // WP 5.5 already uses "package=0"; so we have to replace that with the proper name that will work with our upload directory
60 $install_actions['overwrite_plugin'] = str_replace('action=upload-plugin&amp;', 'action=upload-plugin&amp;plugincksha1='.urlencode($_GET['plugincksha1']).'&amp;overridebd='.urlencode($_GET['overridebd']).'&amp;package='.urlencode($_GET['package']).'&amp;', $install_actions['overwrite_plugin']);
61
62 $install_actions['overwrite_plugin'] = str_replace('package=0&amp;', '', $install_actions['overwrite_plugin']);
63 }
64
65 }
66
67 // error_log(print_r($install_actions, true));
68
69 return $install_actions;
70 }
71
72 /**
73 * Called by the WP action admin_init. Used to continue when a completed upload from our widget has occurred.
74 */
75 public function admin_init() {
76
77 // Check if parameters present indicate our action
78 if (empty($_GET['plugincksha1']) || empty($_GET['overridebd']) || !isset($_GET['package']) || !current_user_can('install_plugins')) return;
79
80 /*
81 Old note:
82
83 The rest of the code's purpose is to work-around the lack of the upgrader_pre_download filter before WP 3.7
84 The below would work on >= 3.7 too; but there, we use a more elegant/direct method.
85
86 New situation:
87 WP 4.6.1 - https://build.trac.wordpress.org/changeset/38466 - introduced a change which prevents upgrader_pre_download from working. So, this way is back.
88 */
89
90 // require(ABSPATH.WPINC.'/version.php');
91 // if (version_compare($wp_version, '3.7', '>=')) return;
92
93 $package = (isset($_GET['fpackage']) && is_numeric($_GET['package'])) ? stripslashes($_GET['fpackage']) : stripslashes($_GET['package']);
94
95 $upgrader = new stdClass;
96 $upgrader->strings = array('download_failed' => __('Error when trying to find uploaded file', 'uploadlargerplugins'));
97 $try_file = $this->upgrader_pre_download(false, $package, $upgrader);
98
99 // The File_Upload_Upgrader object eventually gets constructed with this (where $urlholder = 'package', and $uploads = wp_upload_dir())
100 //File_Upload_Upgrader::filename = $_GET[$urlholder];
101 //File_Upload_Upgrader::package = $uploads['basedir'] . '/' . $this->filename;
102
103 if (!(($uploads = wp_upload_dir()) && false === $uploads['error'])) return;
104
105 if (is_string($try_file) && file_exists($try_file)) {
106 $upload_dir = untrailingslashit(get_temp_dir());
107 // if (!is_writable($upload_dir)) return;
108 $this->upload_basedir = $upload_dir;
109 add_filter('upload_dir', array($this, 'upload_dir'));
110 add_action('upgrader_process_complete', array($this, 'upgrader_process_complete'));
111 }
112 }
113
114 // Only hooked on WP < 3.7
115 public function upgrader_process_complete() {
116 remove_filter('upload_dir', array($this, 'upload_dir'));
117 }
118
119 public function upgrader_pre_download($result, $package, $upgrader) {
120
121 if (empty($_GET['plugincksha1']) || empty($_GET['overridebd'])) return $result;
122 $upload_dir = untrailingslashit(get_temp_dir());
123
124 // Sanity checks
125 if ($upload_dir != $_GET['overridebd']) return new WP_Error('download_failed', $upgrader->strings['download_failed']);
126 $try_file = $upload_dir.'/'.basename($package);
127
128 if (!file_exists($try_file) || sha1_file($try_file) != $_GET['plugincksha1']) return new WP_Error('download_failed', $upgrader->strings['download_failed']);
129
130 return $try_file;
131 }
132
133 /**
134 * @return Boolean
135 */
136 private function is_our_page_and_authorised() {
137 if (!current_user_can('install_plugins')) return false;
138
139 require(ABSPATH.WPINC.'/version.php');
140
141 global $pagenow;
142 // On WP 4.6, there is no longer an upload 'tab' - it's a slide-down instead
143
144 return ($pagenow != 'plugin-install.php' || (version_compare($wp_version, '4.5.9999', '<') && (!isset($_REQUEST['tab']) || 'upload' != $_REQUEST['tab']))) ? false : true;
145
146 }
147
148 /**
149 * Runs upon the WP action admin_enqueue_scripts
150 */
151 public function admin_enqueue_scripts() {
152
153 if (!$this->is_our_page_and_authorised()) return;
154
155 wp_enqueue_script('ulp-admin-ui', UPLOADLARGERPLUGINS_URL.'/admin.js', array('jquery', 'plupload-all'), '1');
156
157 wp_localize_script('ulp-admin-ui', 'ulplion', array(
158 'notarchive' => __('This file does not appear to be a zip file.', 'uploadlargerplugins'),
159 'notarchive2' => '<p>'.__('This file does not appear to be a zip file.', 'uploadlargerplugins').'</p>',
160 'uploaderror' => __('Upload error:','uploadlargerplugins'),
161 'makesure' => __('(make sure that you were trying to upload a zip file','uploadlargerplugins'),
162 'uploaderr' => __('Upload error', 'uploadlargerplugins'),
163 'jsonnotunderstood' => __('Error: the server sent us a response (JSON) which we did not understand.', 'uploadlargerplugins'),
164 'error' => __('Error:','uploadlargerplugins')
165 ));
166
167 }
168
169 /**
170 * Runs upon the WP action plugins_loaded
171 */
172 public function load_translations() {
173 // Tell WordPress where to find the translations
174 load_plugin_textdomain('uploadlargerplugins', false, basename(dirname(__FILE__)).'/languages/');
175 }
176
177 public function upload_dir($uploads) {
178 if (!empty($this->upload_dir)) $uploads['path'] = $this->upload_dir;
179 if (!empty($this->upload_basedir)) $uploads['basedir'] = $this->upload_basedir;
180 return $uploads;
181 }
182
183 /**
184 * Runs upon the AJAX event ulp_plupload_action
185 */
186 public function ulp_plupload_action() {
187
188 @set_time_limit(900);
189
190 if (!current_user_can('install_plugins')) return;
191 check_ajax_referer('uploadlargerplugins-uploader');
192
193 $upload_dir = untrailingslashit(get_temp_dir());
194 if (!is_writable($upload_dir)) exit;
195 $this->upload_dir = $upload_dir;
196
197 add_filter('upload_dir', array($this, 'upload_dir'));
198 // handle file upload
199
200 $farray = array('test_form' => true, 'action' => 'ulp_plupload_action');
201
202 $farray['test_type'] = false;
203 $farray['ext'] = 'zip';
204 $farray['type'] = 'application/zip';
205
206 // if (isset($_POST['chunks'])) {
207 //
208 // } else {
209 // # Over-write - that's OK.
210 // $farray['unique_filename_callback'] = array($this, 'unique_filename_callback');
211 // }
212
213 $status = wp_handle_upload(
214 $_FILES['async-upload'],
215 $farray
216 );
217 remove_filter('upload_dir', array($this, 'upload_dir'));
218
219 if (isset($status['error'])) {
220 echo json_encode(array('e' => $status['error']));
221 exit;
222 }
223
224 // Should be a no-op
225 $name = basename($_POST['name']);
226
227 // If this was the chunk, then we should instead be concatenating onto the final file
228 if (isset($_POST['chunks']) && isset($_POST['chunk']) && preg_match('/^[0-9]+$/',$_POST['chunk'])) {
229 # A random element is added, because otherwise it is theoretically possible for another user to upload into a shared temporary directory in between the upload and install, and over-write
230 $final_file = $name;
231 rename($status['file'], $upload_dir.'/'.$final_file.'.'.$_POST['chunk'].'.zip.tmp');
232 $status['file'] = $upload_dir.'/'.$final_file.'.'.$_POST['chunk'].'.zip.tmp';
233
234 // Final chunk? If so, then stich it all back together
235 if ($_POST['chunk'] == $_POST['chunks']-1) {
236 if ($wh = fopen($upload_dir.'/'.$final_file, 'wb')) {
237 for ($i=0 ; $i<$_POST['chunks']; $i++) {
238 $rf = $upload_dir.'/'.$final_file.'.'.$i.'.zip.tmp';
239 if ($rh = fopen($rf, 'rb')) {
240 while ($line = fread($rh, 32768)) fwrite($wh, $line);
241 fclose($rh);
242 @unlink($rf);
243 }
244 }
245 fclose($wh);
246 $status['file'] = $upload_dir.'/'.$final_file;
247 }
248 }
249
250 }
251
252 $response = array();
253 if (!isset($_POST['chunks']) || (isset($_POST['chunk']) && $_POST['chunk'] == $_POST['chunks']-1)) {
254 $file = basename($status['file']);
255 if (!preg_match('/\.zip$/i', $file, $matches)) {
256 @unlink($status['file']);
257 echo json_encode(array('e' => sprintf(__('Error: %s', 'uploadlargerplugins'), __('This file does not appear to be a zip file.', 'uploadlargerplugins'))));
258 exit;
259 }
260 }
261
262 // send the redirect URL
263 $response['m'] = admin_url('update.php?action=upload-plugin&overridebd='.urlencode(dirname($status['file'])).'&plugincksha1='.sha1_file($status['file']).'&_wpnonce='.wp_create_nonce( 'plugin-upload' ).'&package='.urlencode(basename($status['file'])));
264 echo json_encode($response);
265 exit;
266 }
267
268 /**
269 * Runs upon the WP action admin_head
270 */
271 public function admin_head() {
272
273 if (!$this->is_our_page_and_authorised()) return;
274
275 $chunk_size = min(wp_max_upload_size()-1024, 1024*1024*2-1024);
276
277 # The multiple_queues argument is ignored in plupload 2.x (WP3.9+) - https://make.wordpress.org/core/2014/04/11/plupload-2-x-in-wordpress-3-9/
278 # max_file_size is also in filters as of plupload 2.x, but in its default position is still supported for backwards-compatibility. Likewise, our use of filters.extensions below is supported by a backwards-compatibility option (the current way is filters.mime-types.extensions
279
280 $plupload_init = array(
281 'runtimes' => 'html5,flash,silverlight,html4',
282 'browse_button' => 'plupload-browse-button',
283 'container' => 'plupload-upload-ui',
284 'drop_element' => 'drag-drop-area',
285 'file_data_name' => 'async-upload',
286 'multiple_queues' => false,
287 'max_file_count' => 1,
288 'max_file_size' => '100Gb',
289 'chunk_size' => $chunk_size.'b',
290 'url' => admin_url('admin-ajax.php'),
291 'filters' => array(array('title' => __('Allowed Files'), 'extensions' => 'zip')),
292 'multipart' => true,
293 'multi_selection' => false,
294 'urlstream_upload' => true,
295 // additional post data to send to our ajax hook
296 'multipart_params' => array(
297 '_ajax_nonce' => wp_create_nonce('uploadlargerplugins-uploader'),
298 'action' => 'ulp_plupload_action'
299 )
300 );
301 // 'flash_swf_url' => includes_url('js/plupload/plupload.flash.swf'),
302 // 'silverlight_xap_url' => includes_url('js/plupload/plupload.silverlight.xap'),
303
304 # WP 3.9 updated to plupload 2.0 - https://core.trac.wordpress.org/ticket/25663
305 if (is_file(ABSPATH.'wp-includes/js/plupload/Moxie.swf')) {
306 $plupload_init['flash_swf_url'] = includes_url('js/plupload/Moxie.swf');
307 } else {
308 $plupload_init['flash_swf_url'] = includes_url('js/plupload/plupload.flash.swf');
309 }
310
311 if (is_file(ABSPATH.'wp-includes/js/plupload/Moxie.xap')) {
312 $plupload_init['silverlight_xap_url'] = includes_url('js/plupload/Moxie.xap');
313 } else {
314 $plupload_init['silverlight_xap_url'] = includes_url('js/plupload/plupload.silverlight.swf');
315 }
316
317 ?><script type="text/javascript">
318 var ulp_plupload_config=<?php echo json_encode($plupload_init); ?>;
319 </script>
320 <style type="text/css">
321 .drag-drop #drag-drop-area {
322 border: 4px dashed #ddd;
323 height: 200px;
324 }
325 #filelist {
326 width: 100%;
327 }
328 #filelist .file {
329 padding: 5px;
330 background: #ececec;
331 border: solid 1px #ccc;
332 margin: 4px 0;
333 }
334 #filelist .fileprogress {
335 width: 0%;
336 background: #f6a828;
337 height: 5px;
338 }
339 </style>
340 <?php
341
342 }
343
344 public function install_plugins_pre_upload() {
345 // Unhook the default uploader (works on WP < 4.6 only)
346 remove_action('install_plugins_upload', 'install_plugins_upload');
347 }
348
349 public function install_plugins_upload( $page = 1 ) {
350 ?>
351
352 <div class="upload-plugin">
353
354 <?php
355
356 require(ABSPATH.WPINC.'/version.php');
357
358 if (version_compare($wp_version, '4.5.9999', '<')) { ?>
359
360 <!-- Upload form from Upload Larger Plugins -->
361 <h4><?php _e('Install a plugin in .zip format'); ?></h4>
362
363 <?php } ?>
364
365 <p class="install-help" style="text-align:left; margin-bottom: 6px;">
366 <?php _e('If you have a plugin in a .zip format, you may install it by uploading it here.'); ?>
367 </p>
368
369 <?php
370
371 if (version_compare($wp_version, '3.3', '<')) {
372 echo '<em>'.sprintf(__('This feature requires %s version %s or later', 'uploadlargerplugins'), 'WordPress', '3.3').'</em>';
373 } else {
374 ?>
375 <div id="plupload-upload-ui" class="drag-drop" style="width: 70%;">
376 <div id="drag-drop-area">
377 <div class="drag-drop-inside">
378 <p class="drag-drop-info"><?php _e('Drop plugin zip here', 'uploadlargerplugins'); ?></p>
379 <p><?php _ex('or', 'Uploader: Drop plugin zip here - or - Select File'); ?></p>
380 <p class="drag-drop-buttons"><input id="plupload-browse-button" type="button" value="<?php echo esc_attr(__('Select File', 'uploadlargerplugins')); ?>" class="button" /></p>
381 </div>
382 </div>
383 <div id="filelist">
384 </div>
385 </div>
386 <?php
387 }
388 ?>
389
390 </div>
391
392 <?php
393 /*
394 <div style="display:none;">
395 <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url('update.php?action=upload-plugin'); ?>">
396 <?php wp_nonce_field( 'plugin-upload'); ?>
397 <input type="file" id="pluginzip" name="pluginzip" />
398 <?php submit_button( __( 'Install Now' ), 'button', 'install-plugin-submit', false ); ?>
399 </form>
400 </div>
401 */
402 }
403
404 public function action_links($links, $file) {
405 if ($file == UPLOADLARGERPLUGINS_SLUG."/".basename(__FILE__)) {
406 array_unshift( $links,
407 '<a href="options-general.php?page=upload_larger_plugins">'.__('Settings', 'uploadlargerplugins').'</a>'
408 );
409 }
410 return $links;
411 }
412
413 }
414