File & Image Uploads
change_type() field types for file and image uploads, plus gallery() for a multi-image, drag-to-reorder field.
Plain file uploads
public function change_type(string $field, string $type, string $length = '', array $extra = []): self
change_type($field, 'file', '', $extra) turns a field into a file dropzone. Its $extra options:
| Option | Type | Default | Description |
|---|---|---|---|
not_rename | bool | false | Keep the uploaded file's original name instead of a generated safe one. The name is still sanitized (path separators/traversal stripped) even with this on - it just isn't randomized. |
preview | false|true|'download'|'modal'|'edit' | false | What clicking the file name does. false/'download' - a plain download link. true/'modal' - opens an in-app preview modal (an iframe onto the file) with a Download button alongside. 'edit' - opens that row's own edit form instead, useful when the field's real purpose is "the record this file is attached to". |
$xcrud->change_type('simple_upload', 'file', '', ['not_rename' => true, 'preview' => 'modal']);
Image uploads
change_type($field, 'image', '', $extra) adds resize/crop/watermark/thumbnail processing on top of a plain upload:
| Option | Type | Default | Description |
|---|---|---|---|
width / height | int | - | Auto resize target. Both + crop=true fills the exact box (aspect ratio preserved, excess cropped); either alone, or both without crop, fits within the box (aspect ratio preserved, no cropping). |
crop | bool | false | See above - fills the box instead of just fitting within it. |
manual_crop | bool | false | Shows an interactive drag-to-crop UI (Cropper.js) right after picking a file, before it's saved. Combines with width/height/crop rather than replacing them - manual_crop controls what gets kept, the others still apply to the cropped result afterward. |
ratio | float | - | With manual_crop, locks the crop box to this width/height ratio (e.g. 0.5 = always twice as tall as wide) instead of letting the visitor pick any rectangle. |
watermark | string | - | Path to a PNG, relative to the project root, overlaid onto the saved image. |
watermark_position | [x%, y%] | [95, 95] | Where the watermark's top-left corner lands, as a percentage of the image's own width/height. |
thumbs | array | [] | Named additional derived images saved alongside the main one - each item: width/height/crop/marker (filename suffix)/folder/watermark. Each thumb is independently resized from the original, not chained off each other. |
// Fits within 200x200, no cropping
$xcrud->change_type('auto_resize', 'image', '', ['width' => 200, 'height' => 200]);
// Fills 200x200 exactly, excess cropped
$xcrud->change_type('auto_crop', 'image', '', ['width' => 200, 'height' => 200, 'crop' => true]);
// Interactive drag-to-crop, then resized to 200x200
$xcrud->change_type('manual_crop_2', 'image', '', ['width' => 200, 'height' => 200, 'manual_crop' => true]);
// Two derived thumbnails, one watermarked, one cropped into a subfolder
$xcrud->change_type('image_with_thumbs', 'image', '', [
'thumbs' => [
['width' => 300, 'marker' => '_th', 'watermark' => 'assets/watermark.png'],
['width' => 100, 'height' => 100, 'crop' => true, 'folder' => 'thumbs'],
],
]);
Upload storage configuration
These live in XcrudConfig, not per-field:
| Setting | Type | Default | Description |
|---|---|---|---|
$uploadDir | string | 'media/' | Where uploaded files are actually written. |
$uploadMaxSize | int | 10 MB (10 * 1024 * 1024) | Max upload size in bytes, enforced application-side on top of PHP's own upload_max_filesize. |
$uploadAllowedImageExt | array | ['jpg', 'jpeg', 'png', 'gif', 'webp'] | Allowed extensions for image fields. |
$uploadAllowedFileExt | array | a curated list of common document/archive types | Allowed extensions for plain file fields. Add to this list only for genuinely safe types you actually need. |
See the XcrudConfig Reference for every other setting.
gallery(): a multi-image field
public function gallery(string $field, string $childTable, array $options = []): self
Unlike change_type('image'), gallery() is a drag-drop field for many images at once, each saved as its own row in $childTable - not a column on the current table. $field here is a virtual name, so it does not go in ->columns(). $childTable must itself be a real, reachable table with at minimum an auto-increment id, the foreign-key column named in fk, a filename column, a name column (a per-image caption), a size column, and a sort_order column that drag-to-reorder persists into.
| Option | Type | Default | Description |
|---|---|---|---|
fk | string | required | The child table's own foreign-key column referencing this table's primary key. |
folder | string | field name | Subdirectory of $uploadDir this gallery's images are saved into. |
layout | 'grid'|'list' | 'grid' | 'grid' - a wrapping grid of square thumbnails. 'list' - one row per image with a thumbnail, editable caption, file size, and Preview/Remove buttons. Drag-to-reorder works identically either way. |
width / height / crop / watermark / watermark_position / thumbs | - | - | Same meaning as change_type('image')'s own options, applied to every image uploaded into this gallery independently. |
max_files | int | - | Caps how many images this gallery can hold in total; further uploads are rejected once reached. |
$xcrud->gallery('gallery', 'uploads_gallery', [
'fk' => 'upload_id',
'width' => 1600,
'height' => 1600,
]);
A brand new, never-saved row has no id yet for gallery images to reference - the field shows a disabled "save this record first" placeholder until the row actually exists.