upload-interop / interface
Requires
- php: >=8.4
Requires (Dev)
- pds/composer-script-names: ^1.0
- pds/skeleton: ^1.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
This package is not auto-updated.
Last update: 2025-04-25 17:39:05 UTC
README
Upload-Interop publishes a standard set of interoperable upload structure interfaces for PHP 8.4+. It reflects, refines, and reconciles the common practices identified within several pre-existing projects.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174).
This package attempts to adhere to the Package Development Standards approach to naming and versioning.
Interfaces
Upload-Interop defines these interfaces:
- UploadStruct represents an individual upload.
- UploadStructFactory affords creating an UploadStruct instance.
- UploadFilesParser affords parsing
$_FILES
to create anuploads_array
of UploadStruct instances.
Upload-Interop also defines an UploadTypeAliases interface with PHPStan types to aid static analysis.
UploadStruct
The UploadStruct interface affords reading the $_FILES
values for a single uploaded file. It defines these properties:
-
string $tmp_name { get; }
- Corresponds to the
'tmp_name'
key in afiles_item_array
.
- Corresponds to the
-
int $error { get; }
- Corresponds to the
'error'
key in afiles_item_array
.
- Corresponds to the
-
?string $name { get; }
- Corresponds to the
'name'
key in afiles_item_array
.
- Corresponds to the
-
?string $full_path { get; }
- Corresponds to the
'full_path'
key in afiles_item_array
.
- Corresponds to the
-
?string $type { get; }
- Corresponds to the
'type'
key in afiles_item_array
.
- Corresponds to the
-
?int $size { get; }
- Corresponds to the
'size'
key in afiles_item_array
.
- Corresponds to the
Notes:
-
The properties are in
snake_case
, notcamelCase
. This maintains a direct 1:1 correspondence between the native$_FILES
array keys and the UploadStruct properties. -
There are no affordances for operating on the uploaded file itself. Reading from, writing to, moving, copying, renaming, etc. an uploaded file are application-specific concerns, independent from any specific UploadStruct implementation.
UploadStructFactory
The UploadStructFactory interface affords creating an UploadStruct instance:
-
public function newUpload( string $tmp_name, int $error, ?string $name = null, ?string $full_path = null, ?string $type = null, ?int $size = null, ) : UploadStruct;
UploadFilesParser
The UploadStructFactory interface affords parsing $_FILES
to create an uploads_array
of UploadStruct instances:
-
public function parseUploadFiles(files_array $files) : uploads_array;
The uploads_array
index structure returned from parseUploadFiles()
MUST correspond to the structure in which the $files
were indexed; cf. README-FILES.md.
UploadTypeAliases
The UploadTypeAliases interface provides these custom PHPStan types to aid static analysis:
-
files_array
:array<array-key, files_item_array|files_group_array|files_array>
recursively up to 16 dimensions. -
files_group_array
:array{ tmp_name:string[], error:int[], name?:string[], full_path?:string[], type?:string[], size?:int[], }
-
files_item_array
:array{ tmp_name:string, error:int, name?:string, full_path?:string, type?:string, size?:int, }
-
uploads_array
:array<array-key, UploadStruct|uploads_array>
recursively up to 16 dimensions.
Notes:
- The
files_*
types are defined from the$_FILES
structure. Cf. https://www.php.net/manual/en/features.file-upload.post-method.php.
Implementations
Implementations advertised as readonly or immutable MUST be deeply readonly or immutable; they MUST NOT encapsulate any references, resources, mutable objects, objects or arrays encapsulating references or resources or mutable objects, and so on.
Implementations MAY define additional class members not defined in these interfaces; implementations advertised as readonly or immutable MUST make those additional class members deeply readonly or immutable.
Notes:
-
Reflection does not invalidate advertisements of readonly or immutable implementations. The ability of a consumer to use Reflection to mutate an implementation advertised as readonly or immutable does not constitute a failure to comply with Upload-Interop.
-
Reference implementations are available at https://github.com/upload-interop/impl.
Q & A
Why a separate Upload-Interop?
Whereas the key structures of $_GET, $_POST, etc. data structures are completely undefined, the terminating $_FILES
data structure is well-defined. However, one wants to be able to pass that data structure (or a representation of it) into presentation-independent application or domain logic. As such, one would prefer something that is not tied to a particular presentation format.
For example, embedding the Upload-Interop structures in a server-side request interop standard HTTP could reasonably be considered as tying the structures to HTTP presentation. That in turn would make it theoretically unsuitable for application or domain use.
Thus, Upload-Interop being separated from a particular presentation format gives philosophical cover to using UploadStruct instances and the various UploadTypeAliases in application or domain logic, much the same way there is cover for using DateTime or SimpleXml instances in application or domain logic.
Why is there no UploadCollection ?
Insofar as $_GET
and $_POST
user inputs are arbitrarily structured from interaction to interaction, $_FILES
is likewise arbitrarily structured (but for the terminating files_array_item
). An uploads_array
is a representation of that arbitrary structure.
As with other user inputs, it is an application-specific concern to map those arbitrary structures to more well-defined ones, such as domain-specific collections.