GravityKit\GravityMigrate\Media\MediaPaths
The rules deciding which uploaded file a bundle may carry, what it is called inside the
archive, and how many of them fit.
Every method here is static and pure: no database, no filesystem, no WordPress. These are the decisions an untrusted bundle is refused by -- a path that climbs out of the media root, an entry meta value that is not the shape its field type promises, a manifest naming a file the archive never carried -- and each stays exercisable without a WordPress install.
Since: %ver%
Source: src/Media/MediaPaths.php:21
Details
- Kind:
class - Namespace:
GravityKit\GravityMigrate\Media
Methods
| Method | Description |
|---|---|
relative_to() | The path of an absolute file relative to a base directory, or null if it is not under it. |
relative_from_url() | Turns a file URL into its path relative to the uploads URL it should sit under. |
is_safe_relative_path() | Whether a manifest entry is safe to write inside the media root. |
extension_of() | The extension of a filename, or '' when it does not end in a plain one. |
has_allowed_extension() | Whether a filename's extension is one a bundle may write. |
has_masked_extension() | Whether a name hides a refused extension behind an allowed one. |
media_types_only() | Narrows a WordPress mime map to the types a bundle's files may actually be. |
file_urls_from_meta_value() | The file URLs a single entry meta value names, given the type of the field that wrote it. |
url_from_post_image_value() | The URL half of a post_image value. |
replace_post_image_url() | Rebuilds a post_image value around a new URL, keeping its title, caption and alt text. |
image_choice_urls() | The image URLs an Image Choice field's choices point at. |
select_within_budget() | Fills a size budget from a list of sized files, in the order given. |
Method Reference
relative_to()
public static function relative_to( string $absolute_path, string $base_dir ): ?string
The path of an absolute file relative to a base directory, or null if it is not under it.
A prefix test, not a substring replace. The obvious implementation --
str_replace( $base, '', $path ) -- rewrites a base that appears anywhere in the string
and returns the untouched path when it appears nowhere, so a file outside the uploads
directory comes back looking exactly like a file inside it.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$absolute_path | string | Absolute path to a file. | |
$base_dir | string | Absolute path to the directory it should sit under. |
Returns
string|null— Relative path with no leading slash, or null when it is not under $base_dir.
Since: %ver%
Source: src/Media/MediaPaths.php:142
relative_from_url()
public static function relative_from_url( string $file_url, string $uploads_url ): ?string
Turns a file URL into its path relative to the uploads URL it should sit under.
The URL comes out of exported entry meta, so it is another site's data: a URL that merely mentions the uploads URL somewhere in a query string is not a file in it.
The scheme is the one part allowed to differ. A site that moved to https keeps http://
in every entry written before the move, and wp_upload_dir() answers with the scheme the
site serves on TODAY -- so on ordinary data a strict comparison matches nothing, and an
export asked for its files packages none of them. Host and path are still compared in
full, and both sides lose their scheme together, so a file on another host stays refused.
A differing HOST is deliberately not tolerated. www.example.com and example.com are
usually one site and a CDN hostname usually fronts the same uploads directory, but this
function cannot tell either of those from a stored URL pointing at a genuinely different
site, and the cost of guessing wrong is packaging somebody else's files.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$file_url | string | The stored file URL. | |
$uploads_url | string | The source site's uploads base URL. |
Returns
string|null— Relative path, or null when the URL does not name a file under $uploads_url.
Since: %ver%
Source: src/Media/MediaPaths.php:179
is_safe_relative_path()
public static function is_safe_relative_path( string $relative_path ): bool
Whether a manifest entry is safe to write inside the media root.
Refuses anything that is not a plain relative path to an allowed file type: an absolute
path, a Windows drive, a .. segment, a byte that terminates a C string, or an extension
on the denylist. Checked on the way into the archive AND on the way out of it, because
only the second of those runs against an archive somebody else built.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$relative_path | string | Path relative to the uploads directory. |
Returns
bool
Since: %ver%
Source: src/Media/MediaPaths.php:248
extension_of()
public static function extension_of( string $path ): string
The extension of a filename, or '' when it does not end in a plain one.
Deliberately NOT pathinfo( $path, PATHINFO_EXTENSION ), which returns everything after
the last dot whatever it contains -- so a name whose tail is a denied extension plus
trailing junk reports an extension no denylist holds, while the filesystem can still
resolve it back to the denied one (Win32 strips a trailing space; an NTFS alternate data
stream suffix is not part of the name). Anchoring to [A-Za-z0-9]+ at the very end means
a name that is not cleanly extensioned has no extension at all, and is refused rather than
waved through.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$path | string | A path or filename. |
Returns
string— Lowercased extension, or '' when there is not a clean one.
Since: %ver%
Source: src/Media/MediaPaths.php:318
has_allowed_extension()
public static function has_allowed_extension( string $path ): bool
Whether a filename's extension is one a bundle may write.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$path | string | A path or filename. |
Returns
bool
Since: %ver%
Source: src/Media/MediaPaths.php:338
has_masked_extension()
public static function has_masked_extension( string $path ): bool
Whether a name hides a refused extension behind an allowed one.
An extension check reads the LAST extension, so a name whose interior extension is a
denied one still passes as an image. Apache's mod_mime assigns a handler from ANY extension
in the name, so such a file is handled by that handler while every last-extension check
calls it media. sanitize_file_name() does not close it -- core leaves a two-part name
untouched (if ( count( $parts ) <= 2 ) in wp-includes/formatting.php), so the underscore
it would add never arrives.
Only interior extensions are judged, and only against the same rule the last one faces, so
a name that is merely dotted stays allowed: an export is named for the site it came from,
and gk-migrate-www.example.com-2026-01-01-1.zip carries three dots by design.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$path | string | A path or filename. |
Returns
bool
Since: %ver%
Source: src/Media/MediaPaths.php:389
media_types_only()
public static function media_types_only( array $mimes ): array
Narrows a WordPress mime map to the types a bundle's files may actually be.
get_allowed_mime_types() answers "what will this site accept from a logged-in author",
and for an administrator on single-site that answer includes text/html and
application/javascript: core strips those two keys only if ( empty( $unfiltered ) ),
and both staging and import run inside the importing administrator's own request. A
migration bundle has no reason to carry markup, so the packaged-file gate asks a
different question -- what a file-upload field collects -- and this is where it is asked.
Narrowing, not replacing: a type the site itself refuses is still refused, because the
caller passes the site's own map in. Each alternation is filtered separately, so
jpg|jpeg|jpe survives intact while htm|html disappears entirely.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$mimes | array | Extension pattern => mime type, as WordPress reports it. |
Returns
array— The same shape, carrying only media types with allowed extensions.
Since: %ver%
Source: src/Media/MediaPaths.php:431
file_urls_from_meta_value()
public static function file_urls_from_meta_value( string $meta_value, string $field_type ): array
The file URLs a single entry meta value names, given the type of the field that wrote it.
Three storage shapes, one per field type:
fileupload: one URL, or a JSON array of them for a multi-file field.post_image:URL|:|title|:|caption|:|description|:|alt.signature: a bare filename resolved against{uploads}/gravity_forms/signatures/.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$meta_value | string | The stored value. | |
$field_type | string | One of \self::UPLOAD_FIELD_TYPES(). |
Returns
string[]— Zero or more URLs, in the order the value names them.
Since: %ver%
Source: src/Media/MediaPaths.php:503
url_from_post_image_value()
public static function url_from_post_image_value( string $meta_value ): ?string
The URL half of a post_image value.
The value is URL|:|title|:|caption|:|description|:|alt, and an image field left empty
still stores the separators, so an empty first part is a field with no image rather than
a malformed one.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$meta_value | string | The stored value. |
Returns
string|null
Since: %ver%
Source: src/Media/MediaPaths.php:553
replace_post_image_url()
public static function replace_post_image_url( string $meta_value, string $new_url ): string
Rebuilds a post_image value around a new URL, keeping its title, caption and alt text.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$meta_value | string | The stored value. | |
$new_url | string | The URL the image now lives at. |
Returns
string
Since: %ver%
Source: src/Media/MediaPaths.php:570
image_choice_urls()
public static function image_choice_urls( array $display_meta ): array
The image URLs an Image Choice field's choices point at.
Unlike every other type here this is form data, not entry data: the images belong to the form's field definition, so a form with no entries at all still carries them.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$display_meta | array | A form's decoded display_meta. |
Returns
string[]
Since: %ver%
Source: src/Media/MediaPaths.php:588
select_within_budget()
public static function select_within_budget( array $files, int $budget ): array
Fills a size budget from a list of sized files, in the order given.
The caller orders the list newest-entry-first, so a bundle that cannot carry everything carries the most recent uploads rather than an arbitrary slice. A single file larger than the whole budget is skipped and the walk continues, rather than stopping: one 90 MB video must not cost the operator the two hundred small images behind it.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
$files | array | List of [ 'path' => string, 'size' => int ], most wanted first. | |
$budget | int | Maximum total bytes to include. Zero or less includes nothing. |
Returns
array{included:string,excluded:string,included_size:int,excluded_size:int}
Since: %ver%
Source: src/Media/MediaPaths.php:635