Currently, ImageField::setUploadDir() only supports paths relative to kernel.project_dir.
Internally, the upload directory is normalized like this:
$relativeUploadDir = u($relativeUploadDir)
->trimStart(\DIRECTORY_SEPARATOR)
->ensureEnd(\DIRECTORY_SEPARATOR)
->toString();
$isStreamWrapper = filter_var($relativeUploadDir, \FILTER_VALIDATE_URL);
if (false !== $isStreamWrapper) {
$absoluteUploadDir = $relativeUploadDir;
} else {
$absoluteUploadDir = u($relativeUploadDir)
->ensureStart($this->projectDir.\DIRECTORY_SEPARATOR)
->toString();
}
Because of trimStart(DIRECTORY_SEPARATOR), it is currently impossible to pass a true absolute path like:
/mnt/data/article-assets
The only workaround is using:
relative ../../.. constructs
or use file:// to trick the uploader to use stream wrappers
Both are technically working but unintuitive and not officially documented.
Why this is problematic
- Many production setups store uploads outside of kernel.project_dir.
- Using ../ chains is fragile and unclear.
- Using file:// works but relies on URL detection instead of explicit filesystem support.
- The current behavior is surprising because setUploadDir() suggests a directory path, not necessarily a project-relative path.
Suggested improvement
Allow true absolute filesystem paths by detecting them explicitly:
if (str_starts_with($relativeUploadDir, DIRECTORY_SEPARATOR)) {
$absoluteUploadDir = $relativeUploadDir;
} elseif (false !== filter_var($relativeUploadDir, FILTER_VALIDATE_URL)) {
$absoluteUploadDir = $relativeUploadDir;
} else {
$absoluteUploadDir = $this->projectDir . DIRECTORY_SEPARATOR . $relativeUploadDir;
}
Even if the original intention was to prevent the user from uploading data to a system directory, this would be still possible using the current implementation by prepending file:// or a bunch of "../" to the path. But I think that is a problem that is out of scope anyway. Changing system files should not be possible due to permissions and the devs should not use user-generated paths without sanitazing anyway (if at all).
Currently, ImageField::setUploadDir() only supports paths relative to kernel.project_dir.
Internally, the upload directory is normalized like this:
Because of trimStart(DIRECTORY_SEPARATOR), it is currently impossible to pass a true absolute path like:
/mnt/data/article-assetsThe only workaround is using:
relative ../../.. constructs
or use file:// to trick the uploader to use stream wrappers
Both are technically working but unintuitive and not officially documented.
Why this is problematic
Suggested improvement
Allow true absolute filesystem paths by detecting them explicitly:
Even if the original intention was to prevent the user from uploading data to a system directory, this would be still possible using the current implementation by prepending file:// or a bunch of "../" to the path. But I think that is a problem that is out of scope anyway. Changing system files should not be possible due to permissions and the devs should not use user-generated paths without sanitazing anyway (if at all).