PHP上传入库报120秒最大执行时间超限致命错误排查
问题根因
你遇到的Fatal Error:Maximum execution time of 120 seconds is exceeded超时是代码逻辑错误触发死循环导致的,和服务器本身性能、大文件上传没有直接关系,具体问题点如下:
- 核心死循环诱因:参数绑定逻辑存在设计缺陷
你传入SQL参数绑定方法的$paramValue是带字符串键(:title/:descrip/:image)的关联数组,但bindQueryParams方法中用数字下标$i遍历数组取值。当PHP访问关联数组中不存在的数字索引时,会自动创建对应空元素,导致数组长度count($paramArray)随循环持续增长,循环变量$i永远无法满足终止条件,代码无限循环直到触发120秒的执行时间上限。你在addVideo开头写的ini_set('max_execution_time', 0)未生效,大概率是PHP开启了安全模式,该模式下脚本级别的执行时间配置修改会被拦截。 - 重复执行SQL语句
你自定义的prepare方法内部已经调用了$stmt->execute()执行SQL,但在addVideo方法中,调用完prepare后又额外调用了一次execute方法,重复执行插入逻辑不仅浪费资源,还会导致脏数据。 - 无效死代码
prepare方法中return $stmt之后写的header("location: ../header.php")永远不会执行,return语句会直接终止函数运行,后续代码全部属于无效逻辑。 - 逻辑顺序颠倒
你当前代码是先执行数据库插入操作,再校验标题等参数是否为空,会导致大量空数据写入数据表。 - 表单配置缺失
上传表单没有添加enctype="multipart/form-data"属性,文件上传功能完全不生效,$_FILES数组取不到上传的文件信息。 - 上传逻辑不完整
代码仅获取了上传文件的原始文件名,没有调用move_uploaded_file()把临时文件落地到存储目录,PHP会在请求结束后自动清理临时目录的上传文件。
修复方案
按以下步骤调整代码即可解决问题:
- 修复参数绑定的死循环问题
在bindQueryParams方法中,先将传入的关联数组通过array_values()转为顺序索引数组,再进行遍历,避免不存在的数字下标触发数组自动扩容:
public function bindQueryParams($stmt, $paramType, $paramArray = array()) { ini_set('memory_limit', '-1'); // 转为纯索引数组,消除死循环隐患 $paramArray = array_values($paramArray); $paramValueReference[] = &$paramType; for ($i = 0; $i < count($paramArray); $i++) { $paramValueReference[] = &$paramArray[$i]; } call_user_func_array(array( $stmt, 'bind_param' ), $paramValueReference); }
- 调整业务逻辑顺序,移除重复执行
把参数校验逻辑放到数据库操作之前,删除重复的execute调用,将跳转逻辑移到return语句之前:
public function addVideo(){ ini_set('max_execution_time', 0); // 先取参数、做校验 $title = $_POST["title"] ? trim($_POST["title"]) : ""; $descrip = $_POST["descrip"] ? trim($_POST["descrip"]) : ""; $image = $_FILES["image"]["name"] ? $_FILES["image"]["name"] : ""; if(empty($title)) { $response["status"] = "error"; $response["message"] = "Please enter a title"; return $response; } if(empty($image)) { $response["status"] = "error"; $response["message"] = "Please upload a valid file"; return $response; } $sql = "INSERT INTO vidup (title, descrip, image) VALUES (?, ?, ?)"; $paramType = "sss"; // 按占位符顺序传索引数组,不要用字符串键 $paramValue = array($title, $descrip, $image); // 仅调用一次prepare(内部已包含execute逻辑) $stmt = $this->ds->prepare($sql, $paramType, $paramValue); if($stmt) { // 补全文件落地逻辑,把临时文件移到你的存储目录 // move_uploaded_file($_FILES["image"]["tmp_name"], "你的存储路径/".$image); $response["status"] = "success"; $response["message"] = "Upload success"; // 跳转逻辑放到方法最后,不要写在return后面 header("location: ../upload_success.php"); return $response; } $response["status"] = "error"; $response["message"] = "Database insert failed"; return $response; }
- 补全表单的必要属性
给form标签加上enctype="multipart/form-data",否则文件上传无法生效:
<form method="POST" enctype="multipart/form-data"> <label>Name your video!</label> <input type="text" name="title" placeholder="Title" required> <label>Description</label> <input type="text" name="descrip" placeholder="Tell the viewers about your video" required> <label>Upload your file</label> <input type="file" name="image" required> <button type="submit" name="addVideo">UPLOAD</button> </form>
- 清理prepare方法中的死代码
把prepare方法里return后面的无效header逻辑删掉,避免后续维护产生误解:
public function prepare($query, $paramType, $paramArray) { $stmt = $this->conn->prepare($query); $this->bindQueryParams($stmt, $paramType, $paramArray); $stmt->execute(); return $stmt; }
额外提示:如果是公网业务,不要直接用用户上传的原始文件名存文件,容易产生重名覆盖、路径穿越等安全问题,建议生成随机文件名存储。
内容的提问来源于stack exchange,提问作者Super David Gangster
相关产品推荐
相关产品推荐

