Folders and files
A folder in S5W is not only a way to group files but a set of rules for them: who sees them, how long they live and how they are cached. Recipes for folders, finding files and changing their place and name.
Folders
Create a folder with rules
use Flytachi\Winter\SDK\S5w\Enum\Retention;
$folders = $s5w->folders();
$folders->create('avatars', public: true); // open to all, kept forever
$folders->create('tmp-exports', retention: Retention::WEEK); // private, files live a week| Rule | What it means for the files inside |
|---|---|
public: true |
served at publicUrl without a key — for site images, avatars, public downloads |
public: false (default) |
only with a key, through privateUrl |
retention |
deleted by themselves a set time after each file was created — from a day to a year |
A folder name is 1 to 100 characters: letters, digits, space, ., _, -; it starts with a
letter or a digit. There is no nesting — one level. A taken name gives ConflictException.
Create only if missing
For code that runs many times (application start, a migration), ensure() is handier:
$folder = $s5w->folders()->ensure('avatars', public: true);ensure() looks the folder up first and, if it exists, returns it as it is — the given
settings are not applied to an existing folder. If it is missing, it is created with them.
Find a folder
$folders->get('avatars'); // Folder or NotFoundException
$folders->find('avatars'); // Folder or null
$folders->exists('avatars'); // boolA name may contain spaces and non-Latin letters — the SDK encodes it in the address itself.
Change a folder
$folders->update('avatars', public: false); // only the visibility
$folders->update('tmp-exports', retention: Retention::DAY); // only the retention
$folders->rename('avatars', 'userpics'); // only the nameupdate() changes only what you pass; the rest stays. The server takes the folder as a whole, so
when not everything is passed, the SDK reads the current folder first — two requests instead of one.
Changes reach the files
Changing the visibility rewrites the flag on every file in the folder. Changing the retention
recomputes each file’s expiry from its creation date: going from YEAR to DAY deletes files
older than a day on the next sweep (it runs every five minutes).
Cache
The Cache-Control header the server delivers the folder’s files with is set separately:
use Flytachi\Winter\SDK\S5w\Enum\CacheVisibility;
$folders->setCache('avatars', 86400, CacheVisibility::SHARED); // public, max-age=86400
$folders->setCache('avatars', null, CacheVisibility::PRIVATE); // private, max-age from the bucket
$folders->resetCache('avatars'); // everything from the bucketnull in a parameter means “take the bucket’s”. setCache() always sends both values. How the
server picks the header — in the S5W documentation.
List folders
$page = $folders->list(page: 1, limit: 25, search: 'user');
foreach ($folders->all() as $folder) {
echo "{$folder->name} — {$folder->retention->name}\n";
}Delete a folder
$folders->delete('tmp-exports');Together with its files
A folder is deleted together with every file inside, with no confirmation and no way back. There is no “move the files to the root” mode.
Finding files
A list with filters
use Flytachi\Winter\SDK\S5w\Enum\FileSort;
use Flytachi\Winter\SDK\S5w\Enum\SortDirection;
$page = $s5w->files()->list(
page: 1,
limit: 25,
search: 'invoice', // part of the name, case-insensitive
folder: 'docs', // one folder
sort: FileSort::SIZE,
direction: SortDirection::DESC,
);
echo "Found {$page->total}, page {$page->current} of {$page->pages}\n";
foreach ($page as $file) {
echo "{$file->name} {$file->content->size}\n";
}The folder: parameter picks where to look:
| Value | Where it looks |
|---|---|
not passed (null) |
the whole bucket |
'docs' or a Folder |
one folder |
Folder::ROOT |
only the files outside any folder (the root) |
use Flytachi\Winter\SDK\S5w\Entity\Folder;
$s5w->files()->list(folder: Folder::ROOT); // the root onlyA missing folder in the filter is ValidationException, not an empty list.
Sorting:
FileSort |
Order |
|---|---|
CREATED (default) |
by upload time |
NAME |
by name |
TYPE |
by MIME type, then name |
SIZE |
by size, then name |
The direction is SortDirection::DESC (default, newest and largest first) or ASC.
Sorting by name is case-sensitive
The server sorts names byte by byte: capitals come before lower case — Banana.txt,
Report.md, apple.txt.
Walk every file
list() returns one page. To go through all of them there is all() — a generator that fetches
the next page itself when the current one runs out:
$total = 0;
foreach ($s5w->files()->all(folder: 'backups') as $file) {
$total += $file->content->size;
}
echo "{$total} bytes in backups\n";Pages are taken 100 files at a time (the server’s maximum), so most folders are one request. It
takes the same filters as list(), except the page number.
Don't change the selection while walking it
The server pages by number. Deleting or moving files inside a foreach over all() shifts the
following pages, and some files get skipped. Collect the list first —
iterator_to_array($files->all(…), false) — then change.
One file
$file = $s5w->files()->get('FXOkqegbdrNRWQgc'); // File or NotFoundException
$file = $s5w->files()->find($id); // File or null
$s5w->files()->exists($id); // boolA string that cannot be an id (not 16 characters of A-Za-z0-9_-) is rejected by the SDK
itself, with no request: find() returns null. Handy when the id comes from a page address.
To check the shape up front use File::isValidId($id).
Changing files
Rename
$file = $s5w->files()->rename($file, 'Q4 report.pdf');The file stays in its folder and its id does not change — every link keeps working. The name is
stored as given: the server neither checks nor adds an extension. If the folder already has that
name — ConflictException.
Move
$file = $s5w->files()->move($file, 'archive'); // into a folder by name
$file = $s5w->files()->move($file, $archiveFolder); // into a Folder
$file = $s5w->files()->move($file, Folder::ROOT); // into the rootThe destination is required: move($file) and move($file, null) are PHP errors before any
request. The name stays. After the move the file takes the new folder’s rules:
| Where to | What changes for the file |
|---|---|
| a public folder | becomes public, gets a publicUrl |
| a private folder | becomes private, publicUrl = null |
| a folder with a retention | the expiry counts from the file’s creation date |
| the root | becomes public |
The root makes a file public
Moving a private file into the root opens it to everyone at publicUrl, without a key. That is
why the root can only be given explicitly — Folder::ROOT or ''.
Rename and move at once
$file = $s5w->files()->update($file, 'Q4-final.pdf', 'archive');update() sets the name and the folder in one request and reads nothing first. Both values are
required.
How it differs from rename() and move():
rename() / move() |
update() |
|
|---|---|---|
| requests | 2 (read + change) | 1 |
| what you pass | only what changes | the name and the folder |
| if someone changed the file between the read and the write | the change may roll back to what was read | no: the result is exactly what you passed |
Take update() when both values are known or both changes must happen atomically.
Delete
$s5w->files()->delete($file); // or delete($id)The file disappears from every delivery address at once; temporary links to it start answering
404. Deleting again is NotFoundException: deletion is not idempotent, so on a retry after a
broken connection 404 means “already deleted”. If another file has the same content
(deduplication), that one is unaffected.
See also
FoldersandFiles— every method and parameterFolder,File,Page— entity fields- Folders on the server and files on the server