国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

709 lignes
19KB

  1. <?php if(!defined('DEDEINC')) exit("Request Error!");
  2. /**
  3. * 织梦HTTP下载类
  4. *
  5. * @version $Id: dedehttpdown.class.php 1 11:42 2010年7月6日Z tianya $
  6. * @package DedeCMS.Libraries
  7. * @copyright Copyright (c) 2007 - 2019, DesDev, Inc.
  8. * @license http://help.dedecms.com/usersguide/license.html
  9. * @link http://www.dedecms.com
  10. */
  11. @set_time_limit(0);
  12. class DedeHttpDown
  13. {
  14. var $m_ch = '';
  15. var $m_url = '';
  16. var $m_urlpath = '';
  17. var $m_scheme = 'http';
  18. var $m_host = '';
  19. var $m_port = '80';
  20. var $m_user = '';
  21. var $m_pass = '';
  22. var $m_path = '/';
  23. var $m_query = '';
  24. var $m_fp = '';
  25. var $m_error = '';
  26. var $m_httphead = array();
  27. var $m_html = '';
  28. var $m_puthead = array();
  29. var $m_cookies = '';
  30. var $BaseUrlPath = '';
  31. var $HomeUrl = '';
  32. var $reTry = 0;
  33. var $JumpCount = 0;
  34. /**
  35. * 初始化系统
  36. *
  37. * @access public
  38. * @param string $url 需要下载的地址
  39. * @return string
  40. */
  41. function PrivateInit($url)
  42. {
  43. if($url=='') {
  44. return ;
  45. }
  46. $urls = '';
  47. $urls = @parse_url($url);
  48. $this->m_url = $url;
  49. if(is_array($urls))
  50. {
  51. $this->m_host = $urls["host"];
  52. if(!empty($urls["scheme"]))
  53. {
  54. $this->m_scheme = $urls["scheme"];
  55. }
  56. if(!empty($urls["user"]))
  57. {
  58. $this->m_user = $urls["user"];
  59. }
  60. if(!empty($urls["pass"]))
  61. {
  62. $this->m_pass = $urls["pass"];
  63. }
  64. if(!empty($urls["port"]))
  65. {
  66. $this->m_port = $urls["port"];
  67. }
  68. if(!empty($urls["path"]))
  69. {
  70. $this->m_path = $urls["path"];
  71. }
  72. $this->m_urlpath = $this->m_path;
  73. if(!empty($urls["query"]))
  74. {
  75. $this->m_query = $urls["query"];
  76. $this->m_urlpath .= "?".$this->m_query;
  77. }
  78. $this->HomeUrl = $urls["host"];
  79. $this->BaseUrlPath = $this->HomeUrl.$urls["path"];
  80. $this->BaseUrlPath = preg_replace("/\/([^\/]*)\.(.*)$/","/",$this->BaseUrlPath);
  81. $this->BaseUrlPath = preg_replace("/\/$/","",$this->BaseUrlPath);
  82. }
  83. }
  84. /**
  85. * 重设各参数
  86. *
  87. * @access public
  88. * @return void
  89. */
  90. function ResetAny()
  91. {
  92. $this->m_ch = "";
  93. $this->m_url = "";
  94. $this->m_urlpath = "";
  95. $this->m_scheme = "http";
  96. $this->m_host = "";
  97. $this->m_port = "80";
  98. $this->m_user = "";
  99. $this->m_pass = "";
  100. $this->m_path = "/";
  101. $this->m_query = "";
  102. $this->m_cookies = "";
  103. $this->m_error = "";
  104. }
  105. /**
  106. * 打开指定网址
  107. *
  108. * @access public
  109. * @param string $url 地址
  110. * @param string $requestType 请求类型
  111. * @return string
  112. */
  113. function OpenUrl($url,$requestType="GET")
  114. {
  115. $this->ResetAny();
  116. $this->JumpCount = 0;
  117. $this->m_httphead = Array() ;
  118. $this->m_html = '';
  119. $this->reTry = 0;
  120. $this->Close();
  121. //初始化系统
  122. $this->PrivateInit($url);
  123. $this->PrivateStartSession($requestType);
  124. }
  125. /**
  126. * 转到303重定向网址
  127. *
  128. * @access public
  129. * @param string $url 地址
  130. * @return string
  131. */
  132. function JumpOpenUrl($url)
  133. {
  134. $this->ResetAny();
  135. $this->JumpCount++;
  136. $this->m_httphead = Array() ;
  137. $this->m_html = "";
  138. $this->Close();
  139. //初始化系统
  140. $this->PrivateInit($url);
  141. $this->PrivateStartSession('GET');
  142. }
  143. /**
  144. * 获得某操作错误的原因
  145. *
  146. * @access public
  147. * @return void
  148. */
  149. function printError()
  150. {
  151. echo "错误信息:".$this->m_error;
  152. echo "<br/>具体返回头:<br/>";
  153. foreach($this->m_httphead as $k=>$v){ echo "$k => $v <br/>\r\n"; }
  154. }
  155. /**
  156. * 判别用Get方法发送的头的应答结果是否正确
  157. *
  158. * @access public
  159. * @return bool
  160. */
  161. function IsGetOK()
  162. {
  163. if( preg_match("/^2/",$this->GetHead("http-state")) )
  164. {
  165. return TRUE;
  166. }
  167. else
  168. {
  169. $this->m_error .= $this->GetHead("http-state")." - ".$this->GetHead("http-describe")."<br/>";
  170. return FALSE;
  171. }
  172. }
  173. /**
  174. * 看看返回的网页是否是text类型
  175. *
  176. * @access public
  177. * @return bool
  178. */
  179. function IsText()
  180. {
  181. if( preg_match("/^2/",$this->GetHead("http-state")) && preg_match("/text|xml/i",$this->GetHead("content-type")) )
  182. {
  183. return TRUE;
  184. }
  185. else
  186. {
  187. $this->m_error .= "内容为非文本类型或网址重定向<br/>";
  188. return FALSE;
  189. }
  190. }
  191. /**
  192. * 判断返回的网页是否是特定的类型
  193. *
  194. * @access public
  195. * @param string $ctype 内容类型
  196. * @return string
  197. */
  198. function IsContentType($ctype)
  199. {
  200. if(preg_match("/^2/",$this->GetHead("http-state"))
  201. && $this->GetHead("content-type")==strtolower($ctype))
  202. { return TRUE; }
  203. else
  204. {
  205. $this->m_error .= "类型不对 ".$this->GetHead("content-type")."<br/>";
  206. return FALSE;
  207. }
  208. }
  209. /**
  210. * 用Http协议下载文件
  211. *
  212. * @access public
  213. * @param string $savefilename 保存文件名称
  214. * @return string
  215. */
  216. function SaveToBin($savefilename)
  217. {
  218. if(!$this->IsGetOK())
  219. {
  220. return FALSE;
  221. }
  222. if (function_exists('curl_init') && function_exists('curl_exec')) {
  223. file_put_contents($savefilename, $this->m_html);
  224. return TRUE;
  225. }
  226. if(@feof($this->m_fp))
  227. {
  228. $this->m_error = "连接已经关闭!"; return FALSE;
  229. }
  230. $fp = fopen($savefilename,"w");
  231. while(!feof($this->m_fp))
  232. {
  233. fwrite($fp, fread($this->m_fp, 1024));
  234. }
  235. fclose($this->m_fp);
  236. fclose($fp);
  237. return TRUE;
  238. }
  239. /**
  240. * 保存网页内容为Text文件
  241. *
  242. * @access public
  243. * @param string $savefilename 保存文件名称
  244. * @return string
  245. */
  246. function SaveToText($savefilename)
  247. {
  248. if($this->IsText())
  249. {
  250. $this->SaveBinFile($savefilename);
  251. }
  252. else
  253. {
  254. return "";
  255. }
  256. }
  257. /**
  258. * 用Http协议获得一个网页的内容
  259. *
  260. * @access public
  261. * @return string
  262. */
  263. function GetHtml()
  264. {
  265. if($this->m_html!='')
  266. {
  267. return $this->m_html;
  268. }
  269. if(!$this->IsText())
  270. {
  271. return '';
  272. }
  273. if(!$this->m_fp||@feof($this->m_fp))
  274. {
  275. return '';
  276. }
  277. while(!feof($this->m_fp))
  278. {
  279. $this->m_html .= fgets($this->m_fp,256);
  280. }
  281. @fclose($this->m_fp);
  282. return $this->m_html;
  283. }
  284. /**
  285. * 开始HTTP会话
  286. *
  287. * @access public
  288. * @param string $requestType 请求类型
  289. * @return string
  290. */
  291. function PrivateStartSession($requestType="GET")
  292. {
  293. if ($this->m_scheme == "https") {
  294. $this->m_port = "443";
  295. }
  296. if (function_exists('curl_init') && function_exists('curl_exec')) {
  297. $this->m_ch = curl_init();
  298. curl_setopt($this->m_ch, CURLOPT_URL, $this->m_scheme.'://'.$this->m_host.':'.$this->m_port.$this->m_path);
  299. curl_setopt($this->m_ch, CURLOPT_RETURNTRANSFER, 1);
  300. curl_setopt($this->m_ch, CURLOPT_FOLLOWLOCATION, 1);
  301. if ($requestType == "POST") {
  302. curl_setopt($this->m_ch, CURLOPT_POST, 1);
  303. // $content = is_array($post) ? http_build_query($post) : $post;
  304. // curl_setopt($this->m_ch, CURLOPT_POSTFIELDS, urldecode($content));
  305. }
  306. if (!empty($this->m_cookies)) {
  307. curl_setopt($this->m_ch, CURLOPT_COOKIE, $this->m_cookies);
  308. }
  309. if ($this->m_scheme == "https") {
  310. curl_setopt($this->m_ch, CURLOPT_SSL_VERIFYPEER, false);
  311. curl_setopt($this->m_ch, CURLOPT_SSL_VERIFYHOST, false);
  312. }
  313. $this->m_puthead = array();
  314. $this->m_puthead["Host"] = $this->m_host;
  315. //发送用户自定义的请求头
  316. if(!isset($this->m_puthead["Accept"]))
  317. {
  318. $this->m_puthead["Accept"] = "*/*";
  319. }
  320. if(!isset($this->m_puthead["User-Agent"]))
  321. {
  322. $this->m_puthead["User-Agent"] = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2)";
  323. }
  324. if(!isset($this->m_puthead["Refer"]))
  325. {
  326. $this->m_puthead["Refer"] = "http://".$this->m_puthead["Host"];
  327. }
  328. $headers = array();
  329. foreach($this->m_puthead as $k=>$v)
  330. {
  331. $k = trim($k);
  332. $v = trim($v);
  333. if($k!=""&&$v!="")
  334. {
  335. $headers[] = "$k: $v";
  336. }
  337. }
  338. if (count($headers) > 0) {
  339. curl_setopt($this->m_ch, CURLOPT_HTTPHEADER, $headers);
  340. }
  341. curl_setopt($this->m_ch, CURLOPT_CONNECTTIMEOUT, 20);
  342. curl_setopt($this->m_ch, CURLOPT_TIMEOUT, 900);
  343. $this->m_html = curl_exec($this->m_ch);
  344. $status = curl_getinfo($this->m_ch);
  345. if (count($status) > 0) {
  346. foreach ($status as $key => $value) {
  347. $key = str_replace("_", "-", $key);
  348. if ($key == "http-code") {
  349. $this->m_httphead["http-state"] = $value;
  350. }
  351. $this->m_httphead[$key] = $value;
  352. }
  353. }
  354. $this->m_error = curl_errno($this->m_ch);
  355. return TRUE;
  356. }
  357. if(!$this->PrivateOpenHost())
  358. {
  359. $this->m_error .= "打开远程主机出错!";
  360. return FALSE;
  361. }
  362. $this->reTry++;
  363. if($this->GetHead("http-edition")=="HTTP/1.1")
  364. {
  365. $httpv = "HTTP/1.1";
  366. }
  367. else
  368. {
  369. $httpv = "HTTP/1.0";
  370. }
  371. $ps = explode('?',$this->m_urlpath);
  372. $headString = '';
  373. //发送固定的起始请求头GET、Host信息
  374. if($requestType=="GET")
  375. {
  376. $headString .= "GET ".$this->m_urlpath." $httpv\r\n";
  377. }
  378. else
  379. {
  380. $headString .= "POST ".$ps[0]." $httpv\r\n";
  381. }
  382. $this->m_puthead["Host"] = $this->m_host;
  383. //发送用户自定义的请求头
  384. if(!isset($this->m_puthead["Accept"]))
  385. {
  386. $this->m_puthead["Accept"] = "*/*";
  387. }
  388. if(!isset($this->m_puthead["User-Agent"]))
  389. {
  390. $this->m_puthead["User-Agent"] = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2)";
  391. }
  392. if(!isset($this->m_puthead["Refer"]))
  393. {
  394. $this->m_puthead["Refer"] = "http://".$this->m_puthead["Host"];
  395. }
  396. foreach($this->m_puthead as $k=>$v)
  397. {
  398. $k = trim($k);
  399. $v = trim($v);
  400. if($k!=""&&$v!="")
  401. {
  402. $headString .= "$k: $v\r\n";
  403. }
  404. }
  405. fputs($this->m_fp, $headString);
  406. if($requestType=="POST")
  407. {
  408. $postdata = "";
  409. if(count($ps)>1)
  410. {
  411. for($i=1;$i<count($ps);$i++)
  412. {
  413. $postdata .= $ps[$i];
  414. }
  415. }
  416. else
  417. {
  418. $postdata = "OK";
  419. }
  420. $plen = strlen($postdata);
  421. fputs($this->m_fp,"Content-Type: application/x-www-form-urlencoded\r\n");
  422. fputs($this->m_fp,"Content-Length: $plen\r\n");
  423. }
  424. //发送固定的结束请求头
  425. //HTTP1.1协议必须指定文档结束后关闭链接,否则读取文档时无法使用feof判断结束
  426. if($httpv=="HTTP/1.1")
  427. {
  428. fputs($this->m_fp,"Connection: Close\r\n\r\n");
  429. }
  430. else
  431. {
  432. fputs($this->m_fp,"\r\n");
  433. }
  434. if($requestType=="POST")
  435. {
  436. fputs($this->m_fp,$postdata);
  437. }
  438. //获取应答头状态信息
  439. $httpstas = explode(" ",fgets($this->m_fp,256));
  440. $this->m_httphead["http-edition"] = trim($httpstas[0]);
  441. $this->m_httphead["http-state"] = trim($httpstas[1]);
  442. $this->m_httphead["http-describe"] = "";
  443. for($i=2;$i<count($httpstas);$i++)
  444. {
  445. $this->m_httphead["http-describe"] .= " ".trim($httpstas[$i]);
  446. }
  447. //获取详细应答头
  448. while(!feof($this->m_fp))
  449. {
  450. $line = trim(fgets($this->m_fp,256));
  451. if($line == "")
  452. {
  453. break;
  454. }
  455. $hkey = "";
  456. $hvalue = "";
  457. $v = 0;
  458. for($i=0;$i<strlen($line);$i++)
  459. {
  460. if($v==1)
  461. {
  462. $hvalue .= $line[$i];
  463. }
  464. if($line[$i]==":")
  465. {
  466. $v = 1;
  467. }
  468. if($v==0)
  469. {
  470. $hkey .= $line[$i];
  471. }
  472. }
  473. $hkey = trim($hkey);
  474. if($hkey!="")
  475. {
  476. $this->m_httphead[strtolower($hkey)] = trim($hvalue);
  477. }
  478. }
  479. //如果连接被不正常关闭,重试
  480. if(feof($this->m_fp))
  481. {
  482. if($this->reTry > 10)
  483. {
  484. return FALSE;
  485. }
  486. $this->PrivateStartSession($requestType);
  487. }
  488. //判断是否是3xx开头的应答
  489. if(preg_match("/^3/",$this->m_httphead["http-state"]))
  490. {
  491. if($this->JumpCount > 3)
  492. {
  493. return;
  494. }
  495. if(isset($this->m_httphead["location"]))
  496. {
  497. $newurl = $this->m_httphead["location"];
  498. if(preg_match("/^http/i",$newurl))
  499. {
  500. $this->JumpOpenUrl($newurl);
  501. }
  502. else
  503. {
  504. $newurl = $this->FillUrl($newurl);
  505. $this->JumpOpenUrl($newurl);
  506. }
  507. }
  508. else
  509. {
  510. $this->m_error = "无法识别的答复!";
  511. }
  512. }
  513. }
  514. /**
  515. * 获得一个Http头的值
  516. *
  517. * @access public
  518. * @param string $headname 头文件名称
  519. * @return string
  520. */
  521. function GetHead($headname)
  522. {
  523. $headname = strtolower($headname);
  524. return isset($this->m_httphead[$headname]) ? $this->m_httphead[$headname] : '';
  525. }
  526. function SetCookie($cookie)
  527. {
  528. $this->m_cookies = $cookie;
  529. }
  530. /**
  531. * 设置Http头的值
  532. *
  533. * @access public
  534. * @param string $skey 键
  535. * @param string $svalue 值
  536. * @return string
  537. */
  538. function SetHead($skey,$svalue)
  539. {
  540. $this->m_puthead[$skey] = $svalue;
  541. }
  542. /**
  543. * 打开连接
  544. *
  545. * @access public
  546. * @return bool
  547. */
  548. function PrivateOpenHost()
  549. {
  550. if($this->m_host=="")
  551. {
  552. return FALSE;
  553. }
  554. $errno = "";
  555. $errstr = "";
  556. $this->m_fp = @fsockopen($this->m_host, $this->m_port, $errno, $errstr,10);
  557. if(!$this->m_fp)
  558. {
  559. $this->m_error = $errstr;
  560. return FALSE;
  561. }
  562. else
  563. {
  564. return TRUE;
  565. }
  566. }
  567. /**
  568. * 关闭连接
  569. *
  570. * @access public
  571. * @return void
  572. */
  573. function Close()
  574. {
  575. if (function_exists('curl_init') && function_exists('curl_exec')) {
  576. curl_close($ch);
  577. }
  578. @fclose($this->m_fp);
  579. }
  580. /**
  581. * 补全相对网址
  582. *
  583. * @access public
  584. * @param string $surl 需要不全的地址
  585. * @return string
  586. */
  587. function FillUrl($surl)
  588. {
  589. $i = 0;
  590. $dstr = "";
  591. $pstr = "";
  592. $okurl = "";
  593. $pathStep = 0;
  594. $surl = trim($surl);
  595. if($surl=="")
  596. {
  597. return "";
  598. }
  599. $pos = strpos($surl,"#");
  600. if($pos>0)
  601. {
  602. $surl = substr($surl,0,$pos);
  603. }
  604. if($surl[0]=="/")
  605. {
  606. $okurl = "http://".$this->HomeUrl.$surl;
  607. }
  608. else if($surl[0]==".")
  609. {
  610. if(strlen($surl)<=1)
  611. {
  612. return "";
  613. }
  614. else if($surl[1]=="/")
  615. {
  616. $okurl = "http://".$this->BaseUrlPath."/".substr($surl,2,strlen($surl)-2);
  617. }
  618. else
  619. {
  620. $urls = explode("/",$surl);
  621. foreach($urls as $u)
  622. {
  623. if($u=="..")
  624. {
  625. $pathStep++;
  626. }
  627. else if($i<count($urls)-1)
  628. {
  629. $dstr .= $urls[$i]."/";
  630. }
  631. else
  632. {
  633. $dstr .= $urls[$i];
  634. }
  635. $i++;
  636. }
  637. $urls = explode("/",$this->BaseUrlPath);
  638. if(count($urls) <= $pathStep)
  639. {
  640. return "";
  641. }
  642. else
  643. {
  644. $pstr = "http://";
  645. for($i=0;$i<count($urls)-$pathStep;$i++)
  646. {
  647. $pstr .= $urls[$i]."/";
  648. }
  649. $okurl = $pstr.$dstr;
  650. }
  651. }
  652. }
  653. else
  654. {
  655. if(strlen($surl)<7)
  656. {
  657. $okurl = "http://".$this->BaseUrlPath."/".$surl;
  658. }
  659. else if(strtolower(substr($surl,0,7))=="http://")
  660. {
  661. $okurl = $surl;
  662. }
  663. else
  664. {
  665. $okurl = "http://".$this->BaseUrlPath."/".$surl;
  666. }
  667. }
  668. $okurl = preg_replace("/^(http:\/\/)/i","",$okurl);
  669. $okurl = preg_replace("/\/{1,}/", "/", $okurl);
  670. return "http://".$okurl;
  671. }
  672. }//End Class