PluginProbe
Infinite Uploads – Offload, Optimize & Organize Your Media Library / 3.3.2
Infinite Uploads – Offload, Optimize & Organize Your Media Library v3.3.2
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 3.3.2, at infinite-uploads.php

321 lines 12.1 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.2
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.0
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.2' );
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 if ( ! defined( 'INFINITE_UPLOADS_HTTP_CACHE_CONTROL' ) ) {
94 define( 'INFINITE_UPLOADS_HTTP_CACHE_CONTROL', YEAR_IN_SECONDS );
95 }
96 //we cache the last object uploaded to cloud in memory so it can be processed without downloading again.
97 if ( ! defined( 'INFINITE_UPLOADS_STREAM_CACHE_MAX_BYTES' ) ) {
98 define( 'INFINITE_UPLOADS_STREAM_CACHE_MAX_BYTES', MB_IN_BYTES * 32 );
99 }
100
101 // Require Our custom AWS Autoloader file.
102
103 require_once dirname( __FILE__ ) . '/vendor/Aws3/aws-autoloader.php';
104
105 if ( ! infinite_uploads_check_requirements() ) {
106 return;
107 }
108
109 infinite_uploads_upgrade();
110
111 $instance = \ClikIT\InfiniteUploads\InfiniteUploads::get_instance();
112
113 require_once dirname( __FILE__ ) . '/functions.php';
114
115 $instance->setup();
116 }
117
118 function infinite_uploads_upgrade() {
119
120 // Network-wide table (infinite_uploads_files) — one option gates the whole network.
121 $installed = get_site_option( 'iup_installed' );
122 if ( INFINITE_UPLOADS_VERSION != $installed ) {
123 infinite_uploads_install();
124 }
125
126 // Per-site folder tables — each subsite tracks its own version independently.
127 $folders_installed = get_option( 'iup_folders_installed' );
128 if ( INFINITE_UPLOADS_VERSION != $folders_installed ) {
129 infinite_uploads_install_folders();
130 }
131
132 // One-time backfill: prior versions excluded /bb-plugin/cache/ entirely, so any
133 // images BB had already cropped before this release were never added to
134 // infinite_uploads_files. Schedule an async walk + queue so the existing
135 // iu_bb_cache_push handler can offload them. Idempotent — flag is set when done.
136 //
137 // is_main_site() guard: the flag is network-wide (get_site_option), but
138 // `infinite_uploads_upgrade()` runs on every plugins_loaded across every
139 // subsite. Without this guard, multiple subsite requests can each pass the
140 // `wp_next_scheduled` check before any of them actually schedule, racing to
141 // queue duplicate iu_bb_carveout_backfill events. Restricting to the main
142 // site collapses the race to a single scheduler.
143 if ( is_main_site() && ! get_site_option( 'iup_bb_carveout_backfilled' ) && ! wp_next_scheduled( 'iu_bb_carveout_backfill' ) ) {
144 wp_schedule_single_event( time() + 60, 'iu_bb_carveout_backfill' );
145 }
146 }
147
148 function infinite_uploads_install() {
149 global $wpdb;
150
151 //prevent race condition during upgrade by setting option before running potentially long query
152 if ( is_multisite() ) {
153 update_site_option( 'iup_installed', INFINITE_UPLOADS_VERSION );
154 } else {
155 update_option( 'iup_installed', INFINITE_UPLOADS_VERSION, true );
156 }
157
158 $charset_collate = $wpdb->get_charset_collate();
159
160 //191 is the maximum innodb default key length on utf8mb4
161 $sql = "CREATE TABLE {$wpdb->base_prefix}infinite_uploads_files (
162 `file` VARCHAR(255) NOT NULL,
163 `size` BIGINT UNSIGNED NOT NULL DEFAULT '0',
164 `modified` INT UNSIGNED NOT NULL,
165 `type` VARCHAR(20) NOT NULL,
166 `transferred` BIGINT UNSIGNED NOT NULL DEFAULT '0',
167 `synced` BOOLEAN NOT NULL DEFAULT '0',
168 `deleted` BOOLEAN NOT NULL DEFAULT '0',
169 `errors` INT UNSIGNED NOT NULL DEFAULT '0',
170 `transfer_status` TEXT NULL DEFAULT NULL,
171 PRIMARY KEY (`file`(191)),
172 KEY `type` (`type`),
173 KEY `synced` (`synced`),
174 KEY `deleted` (`deleted`)
175 ) {$charset_collate};";
176
177 if ( ! function_exists( 'dbDelta' ) ) {
178 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
179 }
180
181 dbDelta( $sql );
182
183 // Create per-site folder tables for the current site.
184 infinite_uploads_install_folders();
185 }
186
187 /**
188 * Create (or upgrade) the per-site media-folder tables for the current subsite.
189 *
190 * Uses $wpdb->prefix so each subsite gets its own tables, keeping folder
191 * assignments isolated to the site that owns the attachment posts.
192 * Gated by a per-site option so it runs independently on every subsite.
193 */
194 function infinite_uploads_install_folders() {
195 global $wpdb;
196
197 // Prevent race conditions by marking done before the potentially slow dbDelta.
198 update_option( 'iup_folders_installed', INFINITE_UPLOADS_VERSION, true );
199
200 $charset_collate = $wpdb->get_charset_collate();
201
202 // Media folders table.
203 $sql = "CREATE TABLE {$wpdb->prefix}infinite_uploads_media_folders (
204 id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
205 name VARCHAR(255) NOT NULL,
206 parent_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
207 sort_order INT UNSIGNED NOT NULL DEFAULT 0,
208 created_by BIGINT UNSIGNED NOT NULL DEFAULT 0,
209 created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
210 updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
211 color VARCHAR(20) NOT NULL DEFAULT '',
212 PRIMARY KEY (id),
213 KEY parent_id (parent_id),
214 KEY sort_order (sort_order)
215 ) {$charset_collate};";
216
217 // Media-to-folder relationship table.
218 $sql .= "\nCREATE TABLE {$wpdb->prefix}infinite_uploads_media_folder_relationships (
219 folder_id BIGINT UNSIGNED NOT NULL,
220 attachment_id BIGINT UNSIGNED NOT NULL,
221 PRIMARY KEY (folder_id, attachment_id),
222 KEY attachment_id (attachment_id)
223 ) {$charset_collate};";
224
225 if ( ! function_exists( 'dbDelta' ) ) {
226 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
227 }
228
229 dbDelta( $sql );
230 }
231
232 // Create folder tables for each new subsite when it is provisioned.
233 add_action( 'wp_initialize_site', function ( $new_site ) {
234 switch_to_blog( $new_site->blog_id );
235 infinite_uploads_install_folders();
236 restore_current_blog();
237 } );
238
239 /**
240 * Check whether the environment meets the plugin's requirements, like the minimum PHP version.
241 *
242 * @return bool True if the requirements are met, else false.
243 */
244 function infinite_uploads_check_requirements() {
245 global $wp_version;
246 $hook = is_multisite() ? 'network_admin_notices' : 'admin_notices';
247
248 if ( version_compare( PHP_VERSION, '5.5.0', '<' ) ) {
249 add_action( $hook, 'infinite_uploads_outdated_php_version_notice' );
250
251 return false;
252 }
253
254 if ( version_compare( $wp_version, '5.3.0', '<' ) ) {
255 add_action( $hook, 'infinite_uploads_outdated_wp_version_notice' );
256
257 return false;
258 }
259
260 return true;
261 }
262
263 /**
264 * Print an admin notice when the PHP version is not high enough.
265 *
266 * This has to be a named function for compatibility with PHP 5.2.
267 */
268 function infinite_uploads_outdated_php_version_notice() {
269 ?>
270 <div class="notice notice-warning is-dismissible"><p>
271 <?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 ); ?>
272 </p></div>
273 <?php
274 }
275
276 /**
277 * Print an admin notice when the WP version is not high enough.
278 *
279 * This has to be a named function for compatibility with PHP 5.2.
280 */
281 function infinite_uploads_outdated_wp_version_notice() {
282 global $wp_version;
283 ?>
284 <div class="notice notice-warning is-dismissible"><p>
285 <?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 ); ?>
286 </p></div>
287 <?php
288 }
289
290 /**
291 * Check if URL rewriting is enabled.
292 *
293 * @return bool
294 */
295 function infinite_uploads_enabled() {
296 return get_site_option( 'iup_enabled' );
297 }
298
299 /**
300 * Autoload callback.
301 *
302 * @param $class_name string Name of the class to load.
303 */
304 function infinite_uploads_autoload( $class_name ) {
305 /*
306 * Load plugin classes:
307 * - Class name: Infinite_Uploads_Image_Editor_Imagick.
308 * - File name: class-infinite-uploads-image-editor-imagick.php.
309 */
310 $class_file = 'class-' . strtolower( str_replace( '_', '-', $class_name ) ) . '.php';
311 $class_path = dirname( __FILE__ ) . '/inc/' . $class_file;
312
313 if ( file_exists( $class_path ) ) {
314 require $class_path;
315
316 return;
317 }
318 }
319
320 // spl_autoload_register( 'infinite_uploads_autoload' );
321