Skip to main content

File events

File events split into two phases: upload (when the file enters the system) and serve (when a user downloads it). Three additional stats events fire during a serve and are consumed by the Stats registry.

Upload events

EventSignatureWhen
mc_dm_file_pre_upload(DownloadFile $file)Before processors run, after the upload has been received to a temp path.
mc_dm_file_post_upload(DownloadFile $file)After all processors have run and the row has been persisted.

Processors (hash, mime, magic-byte, decompression-bomb) run between these two events. A pre_upload listener that throws aborts the upload. A post_upload listener firing means the file passed every processor.

Serve events

EventSignatureWhen
mc_dm_file_pre_serve(DownloadFile $file, GateContext $context)Before gate evaluation.
mc_dm_file_post_serve(DownloadFile $file, GateContext $context)After bytes have been streamed.

pre_serve runs before any gate (see Gate registry). Listeners here can short-circuit by throwing. post_serve only fires on successful serves.

Stats events

These fire from Pub\Controller\Downloads around the file serve:

EventSignatureWhen
mc_dm_download_started(Download $download, Version $version, File $file)At the top of a serve, after gates pass.
mc_dm_download_completed(Download $download, Version $version, File $file)After bytes have been fully streamed (or, for external/magnet links, after handoff).
mc_dm_download_failed(Download $download, Version $version, ?File $file, string $reason)On serve error: gate fail, storage error, missing file row, client disconnect. $file is null when the failure happens before a specific file is resolved. $reason is a short identifier (e.g. missing_object, storage_unreadable).

The webhook payload for download_failed carries reason, file_id, and version_id as top-level fields alongside the Download entity. See Webhook payloads.

Example

public static function filePreServe(
\MC\DownloadsManager\Entity\DownloadFile $file,
\MC\DownloadsManager\Gate\GateContext $context
)
{
if ($context->visitor->is_banned)
{
throw new \XF\PrintableException(\XF::phraseDeferred('your_addon.banned_from_downloads'));
}
}