How to extract and store file attachments from Mailgun webhook in PHP

I’m working on a PHP application that receives webhook data from Mailgun when emails arrive. I need help figuring out how to properly extract file attachments from the incoming POST request and save them to my server.

Here’s what the attachment data structure looks like in the webhook payload:

$fileData1 = [
    'filename' => 'document.pdf',
    'type' => 'application/pdf', 
    'name' => 'file-1',
    'tempfile' => '/tmp/MailgunUpload20240315-1-abc123',
    'headers' => 'Content-Disposition: form-data; name="file-1"; filename="document.pdf"\r\nContent-Type: application/pdf\r\nContent-Length: 4521\r\n'
];

$fileData2 = [
    'filename' => 'notes_текст.txt',
    'type' => 'text/plain',
    'name' => 'file-2', 
    'tempfile' => '/tmp/MailgunUpload20240315-1-xyz789',
    'headers' => 'Content-Disposition: form-data; name="file-2"; filename="notes_текст.txt"\r\nContent-Type: text/plain\r\nContent-Length: 156\r\n'
];

$contentType = 'multipart/mixed; boundary="----WebKitFormBoundary7MA4YWxkTrZu0gW"';

What’s the best approach to handle these multipart attachments and move them from the temporary location to a permanent directory on my server?

I’ve worked with Mailgun webhooks before - skip the manual multipart parsing and just grab the attachment data from $_FILES. The webhook should already populate $_FILES with what you need. Use move_uploaded_file() to move it from temp storage to wherever you want it. Clean up the filename first though - I strip out special characters and add timestamps to prevent name conflicts. Also validate file types against a whitelist and check file sizes. Set proper permissions on your upload folder, and if you’re dealing with external files, consider virus scanning.

With Mailgun webhook attachments, I always check if the tempfile path exists with file_exists() before doing anything. Those temp files vanish fast depending on your server setup. I make a dedicated attachments folder with proper write permissions and create unique filenames by hashing the original name plus timestamp. Always validate the MIME type matches the file extension - I’ve seen the type field lie about what’s actually in the file. For non-ASCII filenames like Cyrillic, make sure your filesystem handles UTF-8 or convert to ASCII. Log failed moves too since temp file cleanup can mess with processing if there’s delays.