← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

move_uploaded_file()

PHP OWASP A5:2021 PHP 4.0+ Intermediate
debt(d5/e1/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep and psalm as tools, and the code_pattern describes rename() or copy() used instead of move_uploaded_file() — this is catchable by SAST tools like semgrep but not by a default linter or compiler, placing it squarely at d5.

e1 Effort Remediation debt — work required to fix once spotted

Closest to 'one-line patch or single-call swap' (e1). The quick_fix explicitly states: replace rename() or copy() with move_uploaded_file(). That is a direct single-call substitution, making this e1.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The applies_to context is web-only PHP file upload handling — this pattern is isolated to upload endpoints. It doesn't shape the whole codebase, just the upload handling component. Additional mistakes (MIME validation, webroot placement) add some localised tax but remain contained.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap (contradicts how a similar concept works elsewhere)' (t7). The misconception field states developers believe copy() and move_uploaded_file() are interchangeable — a highly plausible mistake since copy() and rename() perform the same filesystem operation in virtually all other contexts. The critical HTTP POST validation check is invisible and unique to move_uploaded_file(), making this a serious trap that contradicts normal file-manipulation expectations.

About DEBT scoring →

Also Known As

move_uploaded_file() PHP file upload upload handling

TL;DR

PHP's function for safely relocating an uploaded file from the temporary directory to its final destination.

Explanation

move_uploaded_file() verifies that the file is a legitimate HTTP upload (using is_uploaded_file() internally) before moving it, preventing path manipulation attacks that attempt to move arbitrary files. It must be combined with strict validation of the file type (via mime_content_type() or finfo), a sanitised filename (never trust $_FILES['name']), a destination outside the web root or with execute permissions disabled, and a size limit check. Relying on client-supplied Content-Type or file extension alone is insufficient.

Common Misconception

copy() and move_uploaded_file() are interchangeable for handling uploads. move_uploaded_file() performs an additional security check verifying the file was actually uploaded via HTTP POST — using copy() or rename() bypasses this check, enabling path injection attacks.

Why It Matters

move_uploaded_file() validates that the file was actually uploaded via HTTP POST before moving it — this prevents local file manipulation attacks that file_rename() or copy() would be vulnerable to.

Common Mistakes

  • Using rename() or copy() instead of move_uploaded_file() — they do not verify the file came from an upload.
  • Not validating the file type and size before calling move_uploaded_file().
  • Moving files to a web-accessible directory without disabling script execution in that directory.
  • Using the original filename from $_FILES['name'] — sanitise it; attacker controls this value.

Code Examples

✗ Vulnerable
// Moving to a predictable path with user-supplied filename
copy($_FILES['upload']['tmp_name'], '/uploads/' . $_FILES['upload']['name']);
✓ Fixed
// Validate, generate a safe filename, use move_uploaded_file
$upload = $_FILES['avatar'];

// 1. Check it's actually an uploaded file
if (!is_uploaded_file($upload['tmp_name'])) { abort(400); }

// 2. Validate MIME type via finfo (not the browser-supplied type)
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mime  = $finfo->file($upload['tmp_name']);
if (!in_array($mime, ['image/jpeg', 'image/png', 'image/webp'], true)) { abort(415); }

// 3. Generate a random filename — never trust the original
$ext      = ['image/jpeg'=>'jpg','image/png'=>'png','image/webp'=>'webp'][$mime];
$filename = bin2hex(random_bytes(16)) . '.' . $ext;

// 4. Move — only move_uploaded_file is safe for uploaded files
move_uploaded_file($upload['tmp_name'], '/var/uploads/' . $filename);

Added 15 Mar 2026
Edited 22 Mar 2026
Views 128
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 4 pings F 1 ping S 0 pings S 1 ping M 0 pings T 1 ping W 1 ping T 1 ping F 1 ping S 0 pings S 0 pings M 0 pings T 1 ping W 1 ping T 2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Amazonbot 15 PetalBot 10 Google 8 Ahrefs 8 Perplexity 7 ChatGPT 6 Scrapy 4 Brave Search 4 SEMrush 4 Sogou 3 Bing 3 Applebot 2 Meta AI 1 Twitter/X 1 Unknown AI 1
crawler 73 crawler_json 4
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
PHP php A server-side scripting language that generates web pages and APIs — the code runs on the server, and only its output (usually HTML or JSON) reaches the browser.

PHP is often the first server-side language people meet, and understanding its execution model — script starts fresh on every request, no memory between requests — explains most of how the web backend works: sessions, databases, and caching all exist to bridge that per-request amnesia.

💡 Start with PHP 8.x, declare(strict_types=1), and PDO — skip any tutorial that mentions mysql_query().

Ask Codex about PHP →
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Always use move_uploaded_file() not rename() or copy() for uploaded files — it validates that the file actually came from HTTP upload and was not tampered with
📦 Applies To
PHP 4.0+ web
🔗 Prerequisites
🔍 Detection Hints
rename() or copy() used to move uploaded files instead of move_uploaded_file(); no MIME type validation before move; destination inside webroot
Auto-detectable: ✓ Yes semgrep psalm
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Function Tests: Update
CWE-434 CWE-73


✓ schema.org compliant