PluginProbe
Infinite Uploads – Offload, Optimize & Organize Your Media Library / trunk
Infinite Uploads – Offload, Optimize & Organize Your Media Library vtrunk
3.3.4 3.3.3 3.3.2 3.3.1 3.3.0 3.2.6 3.2.5 3.2.4 3.2.3 trunk 1.0 1.0.1 1.0.2 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 2.0 2.0.1 2.0.10 2.0.2 2.0.4 All 48 releases
infinite-uploads / infinite-uploads.php

infinite-uploads.php in Infinite Uploads – Offload, Optimize & Organize Your Media Library trunk, at infinite-uploads.php

326 lines 12.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * Plugin Name: Infinite Uploads
4 * Description: Infinitely scalable cloud storage and delivery for your videos and uploads made easy! Upload directly to cloud storage and manage your files right from the WordPress Media Library.
5 * Version: 3.3.4
6 * Author: Infinite Uploads
7 * Author URI: https://infiniteuploads.com/?utm_source=iup_plugin&utm_medium=plugin&utm_campaign=iup_plugin&utm_content=meta
8 * Text Domain: infinite-uploads
9 * Requires at least: 6.0
10 * Tested up to: 7.1
11 * Requires PHP: 8.0
12 * License: GPLv2
13 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
14 * Network: true
15 *
16 * Inspired by AWS PHP SDK stream wrapper code from the S3 Uploads plugin by Human Made https://github.com/humanmade/S3-Uploads.
17 *
18 * Copyright 2021-2026 ClikIT, LLC
19 */
20
21 define( 'INFINITE_UPLOADS_VERSION', '3.3.4' );
22
23 // Composer-generated autoload files (vendor/autoload.php,
24 // vendor/composer/autoload_*.php, vendor/composer/installed.*) are NOT
25 // committed to git — they must be regenerated per-environment by running
26 // `composer install --no-dev` from the plugin directory. Historically these
27 // files WERE committed with dev references baked in, which fataled on live
28 // (`require '.../mockery/library/helpers.php'` — dev-only, absent on prod).
29 // If they're missing on this install, halt the plugin gracefully with an
30 // admin notice instead of a hard fatal on the first autoloaded class access.
31 if ( ! file_exists( __DIR__ . '/vendor/composer/autoload_real.php' ) ) {
32 add_action( 'admin_notices', 'infinite_uploads_missing_autoload_notice' );
33 add_action( 'network_admin_notices', 'infinite_uploads_missing_autoload_notice' );
34
35 function infinite_uploads_missing_autoload_notice() {
36 echo '<div class="notice notice-error"><p><strong>Infinite Uploads:</strong> '
37 . esc_html__( 'Composer dependencies are not installed. Run ', 'infinite-uploads' )
38 . '<code>composer install --no-dev</code>'
39 . esc_html__( ' from the plugin directory, or replace this checkout with the release ZIP from wordpress.org.', 'infinite-uploads' )
40 . '</p></div>';
41 }
42
43 return;
44 }
45
46 require_once __DIR__ . '/vendor/autoload.php';
47
48 // Load action scheduler.
49 require_once dirname( __FILE__ ) . '/libs/action-scheduler/action-scheduler.php';
50
51 if ( defined( 'WP_CLI' ) && WP_CLI ) {
52 \WP_CLI::add_command( 'infinite-uploads', '\ClikIT\InfiniteUploads\InfiniteUploadsWPCLICommand' );
53 }
54
55 //require_once 'inc/class-infinite-uploads-wp-mail.php';
56 register_activation_hook( __FILE__, 'infinite_uploads_install' );
57
58 add_action( 'plugins_loaded', 'infinite_uploads_init' );
59
60 function infinite_uploads_init() {
61 //how much to try uploading/downloading per ajax loop (we want as much as possible without exceeding (php timeout - ajax_timeout) to avoid 504s
62 if ( ! defined( 'INFINITE_UPLOADS_SYNC_MAX_BYTES' ) ) {
63 define( 'INFINITE_UPLOADS_SYNC_MAX_BYTES', MB_IN_BYTES * 12 );
64 }
65 //This is the maximum to transfer in parallel within the INFINITE_UPLOADS_SYNC_MAX_BYTES size.
66 if ( ! defined( 'INFINITE_UPLOADS_SYNC_CONCURRENCY' ) ) {
67 define( 'INFINITE_UPLOADS_SYNC_CONCURRENCY', 15 );
68 }
69 if ( ! defined( 'INFINITE_UPLOADS_SYNC_MULTIPART_CONCURRENCY' ) ) {
70 define( 'INFINITE_UPLOADS_SYNC_MULTIPART_CONCURRENCY', 5 );
71 }
72 if ( ! defined( 'INFINITE_UPLOADS_SYNC_PER_LOOP' ) ) {
73 define( 'INFINITE_UPLOADS_SYNC_PER_LOOP', 1000 );
74 }
75 // Page size for the continuous-iterator sync/download Generators —
76 // how many rows each DB refresh pulls when the current page exhausts.
77 if ( ! defined( 'INFINITE_UPLOADS_SYNC_ITERATOR_PAGE_SIZE' ) ) {
78 define( 'INFINITE_UPLOADS_SYNC_ITERATOR_PAGE_SIZE', 200 );
79 }
80 // Rolling window of recently-yielded file names carried as a NOT IN
81 // clause on each page refresh, to keep a still-in-flight file from
82 // being re-yielded when the fresh (errors=0) pool starts running out.
83 // The Transfer manager holds at most INFINITE_UPLOADS_SYNC_CONCURRENCY
84 // (default 15) files in-flight, so 100 is roughly 6x headroom. A
85 // yielded file older than the window that (a) succeeded is already
86 // excluded by the SELECT's `synced = 0` predicate, or (b) failed
87 // sits behind errors=0 rows in the ORDER BY tail and only reappears
88 // after the fresh pool drains below the page size — same
89 // intra-request retry semantics as the pre-refactor code.
90 if ( ! defined( 'INFINITE_UPLOADS_SYNC_ITERATOR_INFLIGHT_WINDOW' ) ) {
91 define( 'INFINITE_UPLOADS_SYNC_ITERATOR_INFLIGHT_WINDOW', 100 );
92 }
93 // Per-level cap on the exclusion tree. See prepare_directory_tree()
94 // docblock and the `infinite_uploads_exclude_tree_max_nodes` filter.
95 if ( ! defined( 'INFINITE_UPLOADS_EXCLUDE_TREE_MAX_NODES' ) ) {
96 define( 'INFINITE_UPLOADS_EXCLUDE_TREE_MAX_NODES', 2000 );
97 }
98 if ( ! defined( 'INFINITE_UPLOADS_HTTP_CACHE_CONTROL' ) ) {
99 define( 'INFINITE_UPLOADS_HTTP_CACHE_CONTROL', YEAR_IN_SECONDS );
100 }
101 //we cache the last object uploaded to cloud in memory so it can be processed without downloading again.
102 if ( ! defined( 'INFINITE_UPLOADS_STREAM_CACHE_MAX_BYTES' ) ) {
103 define( 'INFINITE_UPLOADS_STREAM_CACHE_MAX_BYTES', MB_IN_BYTES * 32 );
104 }
105
106 // Require Our custom AWS Autoloader file.
107
108 require_once dirname( __FILE__ ) . '/vendor/Aws3/aws-autoloader.php';
109
110 if ( ! infinite_uploads_check_requirements() ) {
111 return;
112 }
113
114 infinite_uploads_upgrade();
115
116 $instance = \ClikIT\InfiniteUploads\InfiniteUploads::get_instance();
117
118 require_once dirname( __FILE__ ) . '/functions.php';
119
120 $instance->setup();
121 }
122
123 function infinite_uploads_upgrade() {
124
125 // Network-wide table (infinite_uploads_files) — one option gates the whole network.
126 $installed = get_site_option( 'iup_installed' );
127 if ( INFINITE_UPLOADS_VERSION != $installed ) {
128 infinite_uploads_install();
129 }
130
131 // Per-site folder tables — each subsite tracks its own version independently.
132 $folders_installed = get_option( 'iup_folders_installed' );
133 if ( INFINITE_UPLOADS_VERSION != $folders_installed ) {
134 infinite_uploads_install_folders();
135 }
136
137 // One-time backfill: prior versions excluded /bb-plugin/cache/ entirely, so any
138 // images BB had already cropped before this release were never added to
139 // infinite_uploads_files. Schedule an async walk + queue so the existing
140 // iu_bb_cache_push handler can offload them. Idempotent — flag is set when done.
141 //
142 // is_main_site() guard: the flag is network-wide (get_site_option), but
143 // `infinite_uploads_upgrade()` runs on every plugins_loaded across every
144 // subsite. Without this guard, multiple subsite requests can each pass the
145 // `wp_next_scheduled` check before any of them actually schedule, racing to
146 // queue duplicate iu_bb_carveout_backfill events. Restricting to the main
147 // site collapses the race to a single scheduler.
148 if ( is_main_site() && ! get_site_option( 'iup_bb_carveout_backfilled' ) && ! wp_next_scheduled( 'iu_bb_carveout_backfill' ) ) {
149 wp_schedule_single_event( time() + 60, 'iu_bb_carveout_backfill' );
150 }
151 }
152
153 function infinite_uploads_install() {
154 global $wpdb;
155
156 //prevent race condition during upgrade by setting option before running potentially long query
157 if ( is_multisite() ) {
158 update_site_option( 'iup_installed', INFINITE_UPLOADS_VERSION );
159 } else {
160 update_option( 'iup_installed', INFINITE_UPLOADS_VERSION, true );
161 }
162
163 $charset_collate = $wpdb->get_charset_collate();
164
165 //191 is the maximum innodb default key length on utf8mb4
166 $sql = "CREATE TABLE {$wpdb->base_prefix}infinite_uploads_files (
167 `file` VARCHAR(255) NOT NULL,
168 `size` BIGINT UNSIGNED NOT NULL DEFAULT '0',
169 `modified` INT UNSIGNED NOT NULL,
170 `type` VARCHAR(20) NOT NULL,
171 `transferred` BIGINT UNSIGNED NOT NULL DEFAULT '0',
172 `synced` BOOLEAN NOT NULL DEFAULT '0',
173 `deleted` BOOLEAN NOT NULL DEFAULT '0',
174 `errors` INT UNSIGNED NOT NULL DEFAULT '0',
175 `transfer_status` TEXT NULL DEFAULT NULL,
176 PRIMARY KEY (`file`(191)),
177 KEY `type` (`type`),
178 KEY `synced` (`synced`),
179 KEY `deleted` (`deleted`)
180 ) {$charset_collate};";
181
182 if ( ! function_exists( 'dbDelta' ) ) {
183 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
184 }
185
186 dbDelta( $sql );
187
188 // Create per-site folder tables for the current site.
189 infinite_uploads_install_folders();
190 }
191
192 /**
193 * Create (or upgrade) the per-site media-folder tables for the current subsite.
194 *
195 * Uses $wpdb->prefix so each subsite gets its own tables, keeping folder
196 * assignments isolated to the site that owns the attachment posts.
197 * Gated by a per-site option so it runs independently on every subsite.
198 */
199 function infinite_uploads_install_folders() {
200 global $wpdb;
201
202 // Prevent race conditions by marking done before the potentially slow dbDelta.
203 update_option( 'iup_folders_installed', INFINITE_UPLOADS_VERSION, true );
204
205 $charset_collate = $wpdb->get_charset_collate();
206
207 // Media folders table.
208 $sql = "CREATE TABLE {$wpdb->prefix}infinite_uploads_media_folders (
209 id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
210 name VARCHAR(255) NOT NULL,
211 parent_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
212 sort_order INT UNSIGNED NOT NULL DEFAULT 0,
213 created_by BIGINT UNSIGNED NOT NULL DEFAULT 0,
214 created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
215 updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
216 color VARCHAR(20) NOT NULL DEFAULT '',
217 PRIMARY KEY (id),
218 KEY parent_id (parent_id),
219 KEY sort_order (sort_order)
220 ) {$charset_collate};";
221
222 // Media-to-folder relationship table.
223 $sql .= "\nCREATE TABLE {$wpdb->prefix}infinite_uploads_media_folder_relationships (
224 folder_id BIGINT UNSIGNED NOT NULL,
225 attachment_id BIGINT UNSIGNED NOT NULL,
226 PRIMARY KEY (folder_id, attachment_id),
227 KEY attachment_id (attachment_id)
228 ) {$charset_collate};";
229
230 if ( ! function_exists( 'dbDelta' ) ) {
231 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
232 }
233
234 dbDelta( $sql );
235 }
236
237 // Create folder tables for each new subsite when it is provisioned.
238 add_action( 'wp_initialize_site', function ( $new_site ) {
239 switch_to_blog( $new_site->blog_id );
240 infinite_uploads_install_folders();
241 restore_current_blog();
242 } );
243
244 /**
245 * Check whether the environment meets the plugin's requirements, like the minimum PHP version.
246 *
247 * @return bool True if the requirements are met, else false.
248 */
249 function infinite_uploads_check_requirements() {
250 global $wp_version;
251 $hook = is_multisite() ? 'network_admin_notices' : 'admin_notices';
252
253 if ( version_compare( PHP_VERSION, '5.5.0', '<' ) ) {
254 add_action( $hook, 'infinite_uploads_outdated_php_version_notice' );
255
256 return false;
257 }
258
259 if ( version_compare( $wp_version, '5.3.0', '<' ) ) {
260 add_action( $hook, 'infinite_uploads_outdated_wp_version_notice' );
261
262 return false;
263 }
264
265 return true;
266 }
267
268 /**
269 * Print an admin notice when the PHP version is not high enough.
270 *
271 * This has to be a named function for compatibility with PHP 5.2.
272 */
273 function infinite_uploads_outdated_php_version_notice() {
274 ?>
275 <div class="notice notice-warning is-dismissible"><p>
276 <?php printf( esc_html__( 'The Infinite Uploads plugin requires PHP version 5.5.0 or higher. Your server is running PHP version %s.', 'infinite-uploads' ), PHP_VERSION ); ?>
277 </p></div>
278 <?php
279 }
280
281 /**
282 * Print an admin notice when the WP version is not high enough.
283 *
284 * This has to be a named function for compatibility with PHP 5.2.
285 */
286 function infinite_uploads_outdated_wp_version_notice() {
287 global $wp_version;
288 ?>
289 <div class="notice notice-warning is-dismissible"><p>
290 <?php printf( esc_html__( 'The Infinite Uploads plugin requires WordPress version 5.3 or higher. Your server is running WordPress version %s.', 'infinite-uploads' ), $wp_version ); ?>
291 </p></div>
292 <?php
293 }
294
295 /**
296 * Check if URL rewriting is enabled.
297 *
298 * @return bool
299 */
300 function infinite_uploads_enabled() {
301 return get_site_option( 'iup_enabled' );
302 }
303
304 /**
305 * Autoload callback.
306 *
307 * @param $class_name string Name of the class to load.
308 */
309 function infinite_uploads_autoload( $class_name ) {
310 /*
311 * Load plugin classes:
312 * - Class name: Infinite_Uploads_Image_Editor_Imagick.
313 * - File name: class-infinite-uploads-image-editor-imagick.php.
314 */
315 $class_file = 'class-' . strtolower( str_replace( '_', '-', $class_name ) ) . '.php';
316 $class_path = dirname( __FILE__ ) . '/inc/' . $class_file;
317
318 if ( file_exists( $class_path ) ) {
319 require $class_path;
320
321 return;
322 }
323 }
324
325 // spl_autoload_register( 'infinite_uploads_autoload' );
326