Entities
The objects the SDK turns server answers into. They are all immutable (readonly) and describe
the state at the moment of the answer; to see the new state, use what the changing method
returned, or read the object again.
General
Dates are DateTimeImmutable with the server’s time zone.
Enums are PHP enum objects (Retention::WEEK), not numbers. See
Options & enums.
JSON. Every entity implements JsonSerializable and a toArray() method, so it can go
straight into a response: ResponseEntity::ok($file). In JSON, dates are ISO 8601 strings
(2026-11-07T14:54:51+00:00), enums are names ("WEEK"), nested objects are arrays.
json_encode($folder);
// {"name":"avatars","public":true,"retention":"NONE",
// "cache":{"maxAge":null,"visibility":null},
// "createdAt":"2026-11-07T14:54:51+00:00","updatedAt":"2026-11-07T14:54:51+00:00"}Answer checks. If the server’s answer lacks a field or has the wrong type in it, the SDK
throws ResponseException with the path to the field — e.g.
S5W v1/check: bytes.quota must be int, got string.
File
A file in the bucket.
| Field | Type | Description |
|---|---|---|
id |
string |
16 characters of A-Za-z0-9_-; addresses the file everywhere. The server calls it a slug. Does not change on rename or move |
name |
string |
the name; unique within the folder |
folder |
?string |
the folder’s name; null — the bucket root |
content |
FileContent |
size, type, extension, hash |
public |
bool |
whether it is served at publicUrl without a key; follows the folder |
deduplicated |
bool |
these bytes were already in the bucket — no disk space spent |
processed |
?Processing |
the image processing report; only in the answer to an upload, null when read |
expiresAt |
?DateTimeImmutable |
when the folder’s retention deletes the file; null — it is not deleted by itself |
privateUrl |
string |
the /p/{id} address — serves the file with any key in the Authorization header |
publicUrl |
?string |
the /o/{bucketId}/{id} address — no key; null while the file is not public |
createdAt |
DateTimeImmutable |
when uploaded |
updatedAt |
DateTimeImmutable |
when changed (name, folder) |
The addresses are built from the server’s PUBLIC_BASE_URL — see S5W configuration.
File::ID_PATTERN, File::isValidId()
The id format: /^[A-Za-z0-9_-]{16}$/. The method checks only the shape, not whether the file
exists — handy to drop junk from a page address before any request.
public const string ID_PATTERN = '/^[A-Za-z0-9_-]{16}$/';
public static function isValidId(string $id): boolFile::isValidId('FXOkqegbdrNRWQgc'); // true
File::isValidId('../etc/passwd'); // falseFileContent
The file’s bytes. Two files with the same content point at the same bytes.
| Field | Type | Description |
|---|---|---|
size |
int |
size in bytes |
mime |
string |
MIME type, detected by the server from the content |
extension |
string |
the extension matching the type; may be empty |
hash |
string |
SHA-256 of the content, 64 lowercase characters |
Processing
What the server did with an image at upload.
| Field | Type | Description |
|---|---|---|
applied |
bool |
whether processing happened |
reason |
?string |
why it didn’t: no options, nothing to do, animated, output is larger than source; null if it did |
operations |
list<string> |
what was done, e.g. ["resize:400x267", "encode:webp@80"] |
source |
?ImageInfo |
the original image; null if nothing was done |
result |
?ImageInfo |
the result; null if nothing was done |
Methods
saved(): int — bytes saved: source->size - result->size. Negative if the result is heavier;
0 if nothing was done.
ImageInfo
| Field | Type | Description |
|---|---|---|
width |
int |
width, pixels |
height |
int |
height, pixels |
size |
int |
size, bytes |
mime |
string |
MIME type |
Folder
A folder. One level, no nesting; the name is unique within the bucket.
| Field | Type | Description |
|---|---|---|
name |
string |
the name |
public |
bool |
the files inside are served without a key |
retention |
Retention |
how long the files live |
cache |
CachePolicy |
the folder’s cache policy |
createdAt |
DateTimeImmutable |
when created |
updatedAt |
DateTimeImmutable |
when changed |
Folder::ROOT
The bucket root, wherever a folder is expected.
public const string ROOT = '/';/ can never be a real folder’s name, so there is no confusion. Where it applies:
| Method | What Folder::ROOT means |
|---|---|
files()->list(), files()->all() |
only the files outside any folder |
files()->move(), files()->update() |
move into the root (the file becomes public) |
files()->upload(), uploads()->send() and the other uploads |
upload into the root — the same as null |
CachePolicy
A cache override at the folder level. Every null field is inherited from the bucket.
| Field | Type | Description |
|---|---|---|
maxAge |
?int |
max-age, seconds |
visibility |
?CacheVisibility |
who may cache |
Methods
isInherited(): bool — true if both fields are null: the folder overrides nothing.
Page
One page of a list. Mirrors the server’s { meta, data } format.
| Field | Type | Description |
|---|---|---|
items |
list<T> |
this page’s items (File or Folder) |
current |
int |
the page number, from 1 |
size |
int |
the page size the server applied |
total |
int |
how many items match in total, across all pages |
pages |
int |
how many pages in total |
previous |
?int |
the previous page’s number, or null |
next |
?int |
the next page’s number, or null |
Methods
hasNext(): bool — whether there is a next page.
isEmpty(): bool — whether this page is empty.
count($page) — how many items are on this page (Countable). Not to be confused with total.
foreach ($page as $item) — walks this page’s items (IteratorAggregate).
map(callable $fn): Page — a new page where every item went through $fn; the meta is kept.
Handy to turn entities into your own DTOs.
toArray() / jsonSerialize() — { meta: { current, size, total, pages, previous, next }, data: [...] }.
$page = $s5w->files()->list(limit: 10);
count($page); // 10 — on this page
$page->total; // 134 — in total
$page->hasNext(); // true
$names = $page->map(fn(File $f) => $f->name);
json_encode($names); // {"meta":{…},"data":["a.txt","b.txt",…]}previous past the last page
Ask for a page beyond the last one and the server returns an empty list, but previous equals
current - 1 — e.g. 998 with pages = 1. For navigation rely on pages.
UploadSession
The state of a chunked upload. Every uploads() call returns a new session carrying the server’s
current offset.
| Field | Type | Description |
|---|---|---|
id |
string |
the session’s UUID; an empty string if deduplication kicked in |
name |
string |
the name declared at the start |
size |
int |
the declared size, bytes |
offset |
int |
how many bytes are already on the server — the next chunk starts here |
chunkSize |
int |
the chunk size the server asks for; 0 on deduplication |
expiresAt |
?DateTimeImmutable |
when the session is removed if no chunk arrives; null on deduplication |
file |
?File |
the ready file, if the content was already in the bucket |
Methods
isDeduplicated(): bool — the content was in the bucket, the file is ready, nothing to send.
isComplete(): bool — every byte is on the server (offset >= size), ready to assemble.
remaining(): int — how many bytes are left to send.
KeyInfo
The answer of check(): what is behind the key.
| Field | Type | Description |
|---|---|---|
bucket |
BucketRef |
the key’s bucket |
access |
TokenAccess |
the access level |
expiresAt |
?DateTimeImmutable |
when the key expires; null — never |
storage |
Storage |
space in the bucket |
Methods
expiresBefore(DateTimeInterface $at = now): bool — whether the key will have expired by $at.
if ($s5w->check()->expiresBefore(new DateTimeImmutable('+7 days'))) {
$logger->warning('The S5W key expires within a week');
}BucketRef
| Field | Type | Description |
|---|---|---|
id |
string |
the bucket’s UUID; the {bucketId} in public addresses /o/{bucketId}/{id} |
name |
string |
the bucket’s name |
Storage
Space in the bucket, in bytes.
| Field | Type | Description |
|---|---|---|
quota |
int |
the quota |
used |
int |
used |
free |
int |
free |
Methods
fits(int $bytes): bool — whether $bytes more would fit.
usage(): float — the used share, from 0.0 to 1.0.