php代码不执行不产生任何异常
2019-09-04 站长 站长日志
php代码不执行不产生任何异常
最近遇到一个比较奇怪的问题,下面这段拉取远程图片的代码,readfile部分不执行,也不抛出任何异常。php.ini中display_errors=On,error_reporting= E_ALL也配置了,甚至代码中使用
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 'on');
都没有用,这到底是什么原因呢?
/** * 拉取远程图片 * @return mixed */ private function saveRemote() { $imgUrl = htmlspecialchars($this->fileField); $imgUrl = str_replace("&", "&", $imgUrl); //http开头验证 if (strpos($imgUrl, "http") !== 0) { $this->stateInfo = $this->getStateInfo("ERROR_HTTP_LINK"); return; } preg_match('/(^https*://[^:/]+)/', $imgUrl, $matches); $host_with_protocol = count($matches) > 1 ? $matches[1] : ''; // 判断是否是合法 url if (!filter_var($host_with_protocol, FILTER_VALIDATE_URL)) { $this->stateInfo = $this->getStateInfo("INVALID_URL"); return; } preg_match('/^https*://(.+)/', $host_with_protocol, $matches); $host_without_protocol = count($matches) > 1 ? $matches[1] : ''; // 此时提取出来的可能是 ip 也有可能是域名,先获取 ip $ip = gethostbyname($host_without_protocol); // 判断是否是私有 ip if(!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) { $this->stateInfo = $this->getStateInfo("INVALID_IP"); return; } //获取请求头并检测死链 $heads = get_headers($imgUrl, 1); if (!(stristr($heads[0], "200") && stristr($heads[0], "OK"))) { $this->stateInfo = $this->getStateInfo("ERROR_DEAD_LINK"); return; } //格式验证(扩展名验证和Content-Type验证) $fileType = strtolower(strrchr($imgUrl, '.')); if (strpos($fileType, "?")){ $fileType = strstr($fileType, "?", true); } if (!isset($heads['Content-Type']) || !stristr($heads['Content-Type'], "image")) { $this->stateInfo = $this->getStateInfo("ERROR_HTTP_CONTENTTYPE"); return; }else{ if (count($this->config['allowFiles']) > 0){ if (!in_array($fileType, $this->config['allowFiles'])){ //$this->stateInfo = $this->getStateInfo("ERROR_HTTP_ALLOWFILES").$heads['Content-Type']; //image/webp return; } } } //打开输出缓冲区并获取远程图片 ob_start(); $context = stream_context_create( array('http' => array( 'follow_location' => false // don't follow redirects )) ); readfile($imgUrl, false, $context); $img = ob_get_contents(); ob_end_clean(); $imgUrl2 = $imgUrl; if (strpos($imgUrl, "?")){ $imgUrl2 = substr($imgUrl, 0, strripos($imgUrl, "?")); } preg_match("/[/]([^/]*)[.]?[^./]*$/", $imgUrl2, $m); $this->oriName = $m ? $m[1]:""; $this->fileSize = strlen($img); $this->fileType = $this->getFileExt(); $this->fullName = $this->getFullName(); $this->filePath = $this->getFilePath(); $this->fileName = $this->getFileName(); $dirname = dirname($this->filePath); //检查文件大小是否超出限制 if (!$this->checkSize()) { $this->stateInfo = $this->getStateInfo("ERROR_SIZE_EXCEED"); return; } //创建目录失败 if (!file_exists($dirname) && !mkdir($dirname, 0777, true)) { $this->stateInfo = $this->getStateInfo("ERROR_CREATE_DIR"); return; } else if (!is_writeable($dirname)) { $this->stateInfo = $this->getStateInfo("ERROR_DIR_NOT_WRITEABLE"); return; } //移动文件 if (!(file_put_contents($this->filePath, $img) && file_exists($this->filePath))) { //移动失败 $this->stateInfo = $this->getStateInfo("ERROR_WRITE_CONTENT"); } else { //移动成功 $this->stateInfo = $this->stateMap[0]; } }
没有执行的代码段:
//打开输出缓冲区并获取远程图片 ob_start(); $context = stream_context_create( array('http' => array( 'follow_location' => false // don't follow redirects )) ); readfile($imgUrl, false, $context); $img = ob_get_contents(); ob_end_clean();
关键并不是所有情况都不执行,而是拉取微信公众号的图片时存在这一问题。
比如:https://mmbiz.qpic.cn/mmbiz_jpg/icpB1HHeTK319UXVXSXIUnYRDYTX95lJzLp0c6xMLnicL6icjFvDHzGiby5KbEz0CXDJOSOb2ia35rlOVxbYDvklhbw/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1
而改用以下代码是可以拉取成功的:
function mkdirs($dir, $mode = 0777) { if (is_dir($dir) || @mkdir($dir, $mode)) return TRUE; if (!mkdirs(dirname($dir), $mode)) return FALSE; return @mkdir($dir, $mode); } function download123($url, $path = 'images/') { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); $file = curl_exec($ch); curl_close($ch); $filename = pathinfo($url, PATHINFO_BASENAME); if (stripos($filename, "?")){ $filename = strstr($filename, "?", true); } if (!stripos($filename, ".")){ $filename = $filename.".jpeg"; } mkdirs($filename); $resource = fopen($path . $filename, 'a'); echo "<br>4"; fwrite($resource, $file); fclose($resource); echo "<br>5<br>"; }
注:mkdirs 函数有问题,没有对传入路径的文件名进行处理。