Skip to content

Working with uploaded files

On most platforms, media files uploaded to a WordPress site are stored in a filesystem local to the site’s web server. On the VIP Platform, media files uploaded or imported to a WordPress environment are stored on the VIP File System, which is an external object store. A WordPress site’s /wp-content/uploads/ directory is mapped to this external object store. This design provides better security and allows VIP’s CDN to more easily scale access to a site’s media.

The VIP File System is read-only but several different methods exist to programmatically access and interact with media files stored on the VIP File System.

Limitations

  • Because the VIP File System uses an object store, it lacks a true directory structure.
  • Communication with the VIP File System occurs over HTTP. At a minimum, every filesystem-related operation takes 200 milliseconds to process. As a result, file operations such as file_exists() and file_get_contents() should be used at a minimum to prevent a negative impact to page load time. 
  • Media can only be uploaded to a path within /uploads/. Only paths to files that begin with /wp-content/uploads/ are possible; other paths will not work.
  • Permissions-related operations (e.g., chmod(), chown()) will not work as expected and should not be used.
  • The system /tmp directory should be used to perform operations on temporary files and other local file operations such as extracting and working with ZIP files.
  • Some themes and plugins expect to have write permissions, or that media files are stored locally, and may not work as expected with the VIP File System.
  • All file names are treated as case-insensitive.
  • A limit of 2000 modifications are permitted for overwriting and versioning any particular file path.

PHP Stream Wrapper

A custom PHP Stream Wrapper has been integrated into the VIP File System to allow for more complex interactions. This allows most filesystem functions (e.g. fopen(), fwrite(), file_put_contents()) to automatically work with media uploads within the /wp-content/uploads/ path. Most open, read, and write file-related operations are supported by the PHP Stream Wrapper, including copy(), rename(), and unlink().

Because the VIP File System uses an object store, it lacks a true directory structure. As a result:

  • Most operations on directories will not work as expected.
  • Directory traversal operations will not work because there are technically no true directories to traverse.
  • Some directory-related operations like mkdir() will return true because directories are automatically created by the Filesystem API.
  • PHP directory functions such as rmdir() will not work as expected.
  • scandir(), list_files(), glob(),  and opendir()  will not work as expected, and will instead return either an empty array or false and trigger a PHP Warning.
  • is_dir() will not work as expected if it is called against a file lacking an extension; it will return true.
  • Because directories are created automatically, it is not necessary to add logic in code to check if a directory exists. If file_exists() is used in code to check if a directory exists, it will always return true for paths within /wp-content/uploads/.

WordPress filesystem functions

To generate correct, writeable paths use the WordPress function wp_get_upload_dir() or wp_upload_dir(). Hard-coding a path like /wp-content/uploads/... will not work.

For simple file uploads use media_handle_sideload(), media_sideload_image(), or wp_upload_bits().

WP_Filesystem API

To use the WP_Filesystem API, the following code must be added to a site’s codebase usually within the /themes directory, /plugins directory, or /client-mu-plugins directory:

	global $wp_filesystem;
	
	if ( ! is_a( $wp_filesystem, 'WP_Filesystem_Base') ) {
		$creds = request_filesystem_credentials( site_url() );
		wp_filesystem( $creds );
	}

Note

Because the VIP File System lacks a true directory structure, most WP_Filesystem operations related to directories will not work as expected.

Code examples

In this code example, a file is uploaded to /uploads/csv/:

$csv_content = '1,hello,admin';

$upload_dir = wp_get_upload_dir()['basedir'];

$file_path = $upload_dir . '/csv/updated.csv';

file_put_contents( $file_path, $csv_content );

// The file will now be accessible at https://example-com.go-vip.net/wp-content/uploads/csv/updated.csv

In this code example, a file is uploaded to /uploads/csv/ using the WP_Filesystem API:

$csv_content = '1,hello,admin';
$upload_dir = wp_get_upload_dir()['basedir'];
$file_path = $upload_dir . '/csv/updated.csv';

global $wp_filesystem;
if ( ! is_a( $wp_filesystem, 'WP_Filesystem_Base') ) {
	$creds = request_filesystem_credentials( site_url() );
	wp_filesystem( $creds );
}
$wp_filesystem->put_contents(
	$file_path,
	$csv_content
);

In this code example, a CSV file that was previously uploaded to WordPress is retrieved, parsed, and stored in a variable:

$csv_attachment = get_attached_file( 1234 );

$csv_file = file( $csv_attachment );

$csv_content = array_map( 'str_getcsv', $csv_file );

Last updated: February 09, 2024

Relevant to

  • WordPress