Improve user experience when downloading archives#59049
Improve user experience when downloading archives#59049salmart-dev wants to merge 7 commits intomasterfrom
Conversation
a9a469d to
6e8ee13
Compare
b8e07ba to
fbdef2a
Compare
d90be1a to
ccc00aa
Compare
|
so only admin configured, no user option if first failed? |
We could add this option later, right? We need this to work on 29 too 🙈 |
| } | ||
|
|
||
| $byteCounter = new StreamByteCounter(); | ||
| $wrapped = stream_filter_append($stream, 'count.bytes', STREAM_FILTER_READ, ['counter' => $byteCounter]); |
There was a problem hiding this comment.
There is already the CountWrapper that can be used to track how many bytes get read from a stream.
There was a problem hiding this comment.
Dropped the ByteCountFilter and switched to CountWrapper 👍
|
It might make the code clearer if the error reporting code in the inner logic was always active, and only have the outer logic conditionally throw/abort or generate the error report. |
|
The overall logic looks good |
There was a problem hiding this comment.
Embedding missing_files.json is a meaningful improvement over silently producing corrupted/incomplete archives (never good).
- The UX concern that a “successful” download (archive) with missing files is still too easy to misunderstand/overlook remains.
missing_files.jsonis better than nothing, but many users will not inspect it. I don't have a good answer here. - The opt-in flag seems like a good idea, but less certain upon reflection. If we need a toggle for straightforward (from the end-user perspective) functionality like this it may be a sign the implementation and design still needs further refinement before we commit (or, alternatively,we should drop the flag and accept it as the new default behavior!)
- Admittedly, sometimes the best we can do is improve the UX until the next "go around". ;-)
For cases known ahead of time (e.g. filtered/blocked files), it may still be worth considering an additional visible signal that the archive is incomplete.
| } | ||
|
|
||
| if (!($streamMetadata['eof'] ?? true) || $readFileSize != $expectedFileSize) { | ||
| return $this->l10n->t('Read %d out of %d bytes from storage. This means the connection may have been closed due to a network/storage error.', [$expectedFileSize, $readFileSize]); |
There was a problem hiding this comment.
| return $this->l10n->t('Read %d out of %d bytes from storage. This means the connection may have been closed due to a network/storage error.', [$expectedFileSize, $readFileSize]); | |
| return $this->l10n->t('Read %d out of %d bytes from storage. This means the connection may have been closed due to a network/storage error.', [$readFileSize, $expectedFileSize]); |
There was a problem hiding this comment.
nice catch! addressed 👍
| // opening failed, log the failure as reason for the missing file | ||
| if ($this->reportMissingFiles) { | ||
| $exceptionClass = get_class($e); | ||
| return $this->l10n->t('Error while opening the file: %s', [$exceptionClass]); |
There was a problem hiding this comment.
Not sure about reporting the class name here. May be useful to admin/support (but then it should be logged not shown), but it is not end-user friendly. Maybe even just use the below (from stream === false check) for now?
There was a problem hiding this comment.
This code has been changed, now the error is logged when the exception is not re-thrown.
| $this->reportMissingFiles = $this->config->getSystemValueBool('archive_report_missing_files', false); | ||
|
|
||
| if ($this->reportMissingFiles) { | ||
| stream_filter_register('count.bytes', ByteCounterFilter::class); |
There was a problem hiding this comment.
guard? / return value is currently ignored
There was a problem hiding this comment.
Also this has changed, now using another wrapper and the return value is checked not to be false 👍
…wnload folder with non-downloadable files Signed-off-by: Kostiantyn Miakshyn <molodchick@gmail.com>
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
e5b982a to
df9c1be
Compare
Makes sense: I removed all |
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
Took over some of the changes from #57335, thanks @Koc
Summary
This PR adds an alternative working mode to the
ZipFolderPlugin.By setting the new
archive_report_missing_filestotrue(defaultfalse) inconfig.phpadministrators can allow users to download partial archives when those contain a file that is blocked or missing/corrupted files.The users will be informed of this via the addition of a
missing_files.jsoninside the archive itself, giving the user some minimal information about why the files are missing.Why is this needed
The
ZipFolderPlugincurrently halts the streaming of an archive for download due to various factors, such as storage issues with a file, temporary database problems, or a lost network connection. Because the plugin streams without acontent-lengthheader, the user receives an incomplete archive without any warning. In some cases, this issue only becomes apparent when attempting to open a file in the archive and discovering that the entire archive is corrupted.What changes
missing_files.jsoncontaining an entry for the blocked filemissing_files.jsonreporting the issuemissing_files.jsonreporting the reasonNote: this will need to be backported down to stable29
TODO
deepdiver/zipstreamerto avoid slow tests due to loss of precisionChecklist
3. to review, feature component)stable32)AI (if applicable)