如何用PHP实现图片上传重命名并存路径到数据库?$_FILES失效排查
导致你功能异常的具体问题
- 表单属性拼写错误(最核心的根因)
你在form标签上写的是ectype="multipart/form-data",正确属性名是enctype="multipart/form-data"。这个属性是浏览器发送文件上传流的必要条件,拼写错误后,浏览器会用默认的表单编码提交请求,根本不会把你选择的图片文件传给PHP。这就是为什么if($_FILES)判断永远不触发——$_FILES数组在这个请求下根本不会携带任何文件数据。 - 图片字段的入库取值逻辑完全错位
你的代码中写$p_img = isset($_POST['p_img']) ? $_POST['p_img'] : null,但文件输入域的内容永远不会被PHP存入$_POST超全局数组。你本来的设计是把生成的自定义文件名存入数据库,但代码里从来没有把上传处理后的自定义路径赋值给$p_img变量,就算上传流程跑通,最后入库的图片字段值也和你生成的随机文件名没有关系,这也是你观察到“图片以原始文件名入库”的本质原因——整个上传流程的处理结果根本没接进入库逻辑。 - 上传校验的逻辑存在多处缺陷
- 用
if($_FILES)判断文件是否上传是无效的:哪怕用户没有选择任何文件,只要请求结构合法,$_FILES数组就会存在。正确的判断需要检查$_FILES['p_img']['error']的状态码; - 截取文件扩展名用
substr($_FILES["p_img"]["name"],-4,4)的兼容性很差:遇到.jpeg这类4字符以上的扩展名会截断错误,遇到.jpg这类3字符的扩展名会把文件名里的点一起截入,生成的文件名格式混乱; - 移动文件时使用
public_url()生成的可访问URL作为目标地址,但move_uploaded_file()需要的是服务器本地文件系统的物理路径,用URL当目标路径在绝大多数服务器配置下都会移动失败。
- 用
- 流程分支缺失错误处理
代码里没有给文件大小超标、类型不匹配、文件移动失败的场景设置中断逻辑,哪怕整个上传流程全部失败,后续的INSERT入库语句依然会照常执行,不会因为上传失败阻断业务流程。
修正后的可用代码
<?php // 定义上传目录的本地物理路径,自动创建不存在的目录并设置权限 $uploadDir = __DIR__ . '/uploads/product/'; if (!file_exists($uploadDir)) { mkdir($uploadDir, 0755, true); } if(isset($_POST['submit'])){ $p_img = null; // 初始化图片字段,避免上传失败时变量未定义 $uploadError = null; // 校验文件是否为有效上传请求 if (isset($_FILES['p_img']) && $_FILES['p_img']['error'] !== UPLOAD_ERR_NO_FILE) { $maxSize = 700000; $allowedTypes = ['image/jpeg', 'image/png']; $fileInfo = $_FILES['p_img']; // 校验文件大小 if ($fileInfo['size'] > $maxSize) { $uploadError = "dosya boyutu 700kb'dan yuksek olamaz..."; } // 校验文件类型 elseif (!in_array($fileInfo['type'], $allowedTypes)) { $uploadError = "Sadece JPG ve PNG formatinda yukleme yapilabilir..."; } // 校验文件是否为合法HTTP上传 elseif (!is_uploaded_file($fileInfo['tmp_name'])) { $uploadError = "Dosya yukleme hatasi olustu..."; } else { // 用pathinfo安全获取文件扩展名,避免截断错误 $ext = pathinfo($fileInfo['name'], PATHINFO_EXTENSION); // 生成不重复的自定义文件名 $newFileName = uniqid('prod_', true) . '.' . $ext; $targetPath = $uploadDir . $newFileName; // 移动临时文件到目标目录 if (move_uploaded_file($fileInfo['tmp_name'], $targetPath)) { // 存相对访问路径到数据库,避免硬编码域名 $p_img = '/uploads/product/' . $newFileName; } else { $uploadError = "Dosya tasima islemi basarisiz oldu..."; } } } // 上传出错直接输出提示,阻断后续入库流程 if ($uploadError) { echo "<h2>$uploadError</h2>"; exit; } // 读取其他普通表单字段 $p_name = isset($_POST['p_name']) ? trim($_POST['p_name']) : null; $p_barcode = isset($_POST['p_barcode']) ? trim($_POST['p_barcode']) : null; $p_price = isset($_POST['p_price']) ? trim($_POST['p_price']) : null; $p_stock = isset($_POST['p_stock']) ? trim($_POST['p_stock']) : null; $query = $db->prepare('INSERT INTO product SET p_name = ?, p_img = ?, p_barcode = ?, p_price = ?, p_stock = ? '); $result = $query->execute([ $p_name, $p_img, $p_barcode, $p_price, $p_stock ]); if($result) { echo 'Ürün başarıyla eklendi.'; } else { echo 'Ürün eklenemedi.'; } } ?>
<div class="product-list w-1/2"> <div class="product-list-area"> <!-- 修正拼写错误:ectype -> enctype --> <form action="" method="post" enctype="multipart/form-data"> <div class="input-group flex flex-wrap"> <div class="input-element w-full"> <label class="block" for="task-name">Ürün Görseli Ekle</label> <div class="file-input w-full"> <label class="block"> <input type="file" id="file" name="p_img"> <div class="file-input-box flex flex-col items-center justify-center"> <svg viewBox="0 0 24 24" stroke="currentColor" stroke-width="1" fill="none" stroke-linecap="round" stroke-linejoin="round"> <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect> <circle cx="8.5" cy="8.5" r="1.5"></circle> <polyline points="21 15 16 10 5 21"></polyline> </svg> <span class="block"><strong>Dosya ve Görsel yüklemek için </strong>tıklayın veya sürükleyin</span> <p>DOC, XLS, PNG, JPG maks. 10MB</p> </div> </label> </div> </div> <div class="input-element w-1/2"> <label class="block" for="p_name">Ürün Adı</label> <input type="text" name="p_name" placeholder=""> </div> <div class="input-element w-1/2"> <label class="block" for="p_barcode">Ürün Barkod</label> <input type="text" name="p_barcode" placeholder=""> </div> <div class="input-element w-1/2"> <label class="block" for="p_price">Ürün Fiyatı (Türk Lirası Olarak Giriniz)</label> <input type="text" name="p_price" placeholder=""> </div> <div class="input-element w-1/2"> <label class="block" for="p_stock">Ürün Stok</label> <input type="text" name="p_stock" placeholder=""> </div> <div class="input-element flex justify-end w-full"> <input type="hidden" name="submit" value="1"> <button type="submit" class="focus:outline-none">Ürün Ekle</button> </div> </div> </form> </div> </div>
内容的提问来源于stack exchange,提问作者Exciless_
相关产品推荐
相关产品推荐

