Aim
To design a form that uploads an image and displays it on the page using PHP.
Theory
The upload pipeline is the same as Practical 21 — a method="post" form with enctype="multipart/form-data", the file arriving in $_FILES["img"] (keys name, type, tmp_name, error, size) and move_uploaded_file() claiming it from PHP's quarantine directory. What is new is that the file must actually be an image, and must land somewhere the browser can fetch it from.
Validation: $_FILES["img"]["type"] is whatever the client claims — a forged request can label a PHP shell as image/png, so it must never be trusted. Reliable checks read the actual bytes: getimagesize() returns real dimensions and MIME type (or false for non-images), and finfo sniffs magic numbers. Production code adds an extension whitelist (jpg, png, gif, webp). The form's accept='image/*' merely filters the file picker — a convenience, not security.
Display: an <img src="..."> is fetched by the browser as a URL, so the stored file must live under the document root — conventionally an uploads/ folder inside the site — for <img src='uploads/photo.png'> to resolve. A filesystem path outside htdocs is not served by Apache.
Requirements
- XAMPP/WAMP with Apache and PHP 8.x (or PHP CLI for the simulated run)
- Code editor (VS Code); browser (Chrome/Edge)
Procedure
- Start Apache from the XAMPP Control Panel.
- Save the snippet as
p22_upload_image.phpinC:\xampp\htdocs\wbplab. For the picture to actually render, point$imageDirat a folder inside the site (e.g.DIR . "/uploads") so the emittedsrcis web-reachable; the temp-dir default exists to keep the demo portable for the compiler. - Open
http://localhost/wbplab/p22_upload_image.php, choose an image (the picker is pre-filtered to image types) and click Upload Image. - Or run
php p22_upload_image.php— the compiler/CLI branch generates a sample PNG file and prints the display logic instead of rendering a form.
Explanation of the Code
$imageDirissys_get_temp_dir()pluswbp_images, created withmkdir()if missing.- CLI branch: the long base64 string is a complete 1×1 transparent PNG;
base64_decode()restores its raw bytes andfile_put_contents()writesdemo.png— an "upload" without a browser — then the path and an<img>usage hint are printed. - Web branch: on a POST with
$_FILES["img"]set,basename()sanitises the client filename andmove_uploaded_file()moves the quarantinedtmp_nameto$target. - On success the script echoes an
<img>tag:htmlspecialchars($target)escapes the path used assrc(a crafted filename could otherwise break out of the attribute — XSS),width='200'scales the preview andaltsupplies fallback text. - The echoed form uses
accept='image/*' required— both client-side conveniences; a hardened version would also callgetimagesize()before accepting the file.
Expected Output
In the browser the page shows a file input and an Upload Image button. After a successful upload it prints Image uploaded successfully. followed by the <img> tag; the picture itself displays once $imageDir points under the document root — with the temp-dir default the browser cannot reach that path, so only the alt text Uploaded Image shows. A failed move prints Image upload failed.. From the CLI/compiler it prints Sample image created at: with the temp path of demo.png, then the hint In web mode, uploaded image can be shown using <img src='uploads/file.png'>.
🎯 Viva Questions
- Why is
$_FILES["img"]["type"]unsafe for validation? It is supplied by the client and trivially forged — any file can claim to beimage/png. - How do you reliably verify an upload is an image? Read the bytes:
getimagesize()returns real dimensions/MIME orfalse, or usefinfomagic-number sniffing. - **What does
accept='image/'actually do?* It only filters the browser's file picker — UI convenience, not server-side security. - Why must uploaded images live under the document root to display?
<img src>is a URL the browser fetches through Apache; paths outsidehtdocsare not served. - Why wrap the path in
htmlspecialchars()inside the<img>tag? A malicious filename could inject markup or script through the attribute — output escaping prevents XSS. - Which function moves the file out of quarantine, and what does it verify?
move_uploaded_file(); it checks the source is a genuine HTTP upload before moving it.
CO Mapping
CO1, CO2