HttpRequest.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  1. <?php
  2. namespace loyalsoft\Util;
  3. include_once 'HttpResponse.php';
  4. class HttpRequest
  5. {
  6. /**
  7. * CURL操作对象,`curl_init()`的返回值
  8. * @var resource
  9. */
  10. public $handler;
  11. /**
  12. * 需要请求的Url地址
  13. * @var string
  14. */
  15. public $url;
  16. /**
  17. * 发送内容,可以是字符串、数组、`HttpRequestMultipartBody`
  18. * @var mixed
  19. */
  20. public $content;
  21. /**
  22. * `curl_setopt_array()`所需要的第二个参数
  23. * @var array
  24. */
  25. public $options = array();
  26. /**
  27. * 请求头
  28. * @var array
  29. */
  30. public $headers = array();
  31. /**
  32. * Cookies
  33. * @var array
  34. */
  35. public $cookies = array();
  36. /**
  37. * 保存Cookie文件的文件名,为空不保存
  38. * @var string
  39. */
  40. public $cookieFileName = '';
  41. /**
  42. * 失败重试次数,默认为0
  43. * @var int
  44. */
  45. public $retry = 0;
  46. /**
  47. * 是否使用代理,默认false
  48. * @var bool
  49. */
  50. public $useProxy = false;
  51. /**
  52. * 代理设置
  53. * @var array
  54. */
  55. public $proxy = array();
  56. /**
  57. * 是否验证证书
  58. * @var bool
  59. */
  60. public $isVerifyCA = false;
  61. /**
  62. * CA根证书路径
  63. * @var string
  64. */
  65. public $caCert;
  66. /**
  67. * 连接超时时间,单位:毫秒
  68. * @var int
  69. */
  70. public $connectTimeout = 30000;
  71. /**
  72. * 总超时时间,单位:毫秒
  73. * @var int
  74. */
  75. public $timeout = 0;
  76. /**
  77. * 下载限速,为0则不限制,单位:字节
  78. * @var int
  79. */
  80. public $downloadSpeed;
  81. /**
  82. * 上传限速,为0则不限制,单位:字节
  83. * @var int
  84. */
  85. public $uploadSpeed;
  86. /**
  87. * 用于连接中需要的用户名
  88. * @var string
  89. */
  90. public $username;
  91. /**
  92. * 用于连接中需要的密码
  93. * @var string
  94. */
  95. public $password;
  96. /**
  97. * 请求结果保存至文件的配置
  98. * @var mixed
  99. */
  100. public $saveFileOption = array();
  101. /**
  102. * 根据location自动重定向
  103. * @var bool
  104. */
  105. public $followLocation = true;
  106. /**
  107. * 最大重定向次数
  108. * @var int
  109. */
  110. public $maxRedirects = 10;
  111. /**
  112. * 证书类型
  113. * 支持的格式有"PEM" (默认值), "DER"和"ENG"
  114. * @var string
  115. */
  116. public $certType = 'pem';
  117. /**
  118. * 一个包含 PEM 格式证书的文件名
  119. * @var string
  120. */
  121. public $certPath = '';
  122. /**
  123. * 使用证书需要的密码
  124. * @var string
  125. */
  126. public $certPassword = null;
  127. /**
  128. * certType规定的私钥的加密类型,支持的密钥类型为"PEM"(默认值)、"DER"和"ENG"
  129. * @var string
  130. */
  131. public $keyType = 'pem';
  132. /**
  133. * 包含 SSL 私钥的文件名
  134. * @var string
  135. */
  136. public $keyPath = '';
  137. /**
  138. * SSL私钥的密码
  139. * @var string
  140. */
  141. public $keyPassword = null;
  142. /**
  143. * 使用自定义实现的重定向,性能较差。如果不是环境不支持自动重定向,请勿设为true
  144. * @var bool
  145. */
  146. public static $customLocation = false;
  147. /**
  148. * 临时目录,有些特殊环境(如某国内虚拟主机)需要特别设置一下临时文件目录
  149. * @var string
  150. */
  151. public static $tempDir;
  152. /**
  153. * 代理认证方式
  154. */
  155. public static $proxyAuths = array(
  156. 'basic' => CURLAUTH_BASIC,
  157. 'ntlm' => CURLAUTH_NTLM
  158. );
  159. /**
  160. * 代理类型
  161. */
  162. public static $proxyType = array(
  163. 'http' => CURLPROXY_HTTP,
  164. 'socks4' => CURLPROXY_SOCKS4,
  165. 'socks4a' => 6, // CURLPROXY_SOCKS4A
  166. 'socks5' => CURLPROXY_SOCKS5,
  167. );
  168. /**
  169. * 构造方法
  170. * @return mixed
  171. */
  172. public function __construct()
  173. {
  174. $this->open();
  175. $this->cookieFileName = tempnam(null === self::$tempDir ? sys_get_temp_dir() : self::$tempDir, '');
  176. }
  177. /**
  178. * 析构方法
  179. */
  180. public function __destruct()
  181. {
  182. $this->close();
  183. }
  184. /**
  185. * 打开一个新连接,初始化所有参数。一般不需要手动调用。
  186. * @return void
  187. */
  188. public function open()
  189. {
  190. $this->handler = curl_init();
  191. $this->retry = 0;
  192. $this->headers = $this->options = array();
  193. $this->url = $this->content = '';
  194. $this->useProxy = false;
  195. $this->proxy = array(
  196. 'auth' => 'basic',
  197. 'type' => 'http',
  198. );
  199. $this->isVerifyCA = false;
  200. $this->caCert = null;
  201. $this->connectTimeout = 30000;
  202. $this->timeout = 0;
  203. $this->downloadSpeed = null;
  204. $this->uploadSpeed = null;
  205. $this->username = null;
  206. $this->password = null;
  207. $this->saveFileOption = array();
  208. }
  209. /**
  210. * 关闭连接。一般不需要手动调用。
  211. * @return void
  212. */
  213. public function close()
  214. {
  215. if (null !== $this->handler) {
  216. curl_close($this->handler);
  217. $this->handler = null;
  218. if (is_file($this->cookieFileName)) {
  219. unlink($this->cookieFileName);
  220. }
  221. }
  222. }
  223. /**
  224. * 创建一个新会话,等同于new
  225. * @return HttpRequest
  226. */
  227. public static function newSession()
  228. {
  229. return new static;
  230. }
  231. /**
  232. * 设置请求地址
  233. * @param string $url 请求地址
  234. * @return HttpRequest
  235. */
  236. public function url($url)
  237. {
  238. $this->url = $url;
  239. return $this;
  240. }
  241. /**
  242. * 设置发送内容,requestBody的别名
  243. * @param mixed $content 发送内容,可以是字符串、数组、HttpRequestMultipartBody
  244. * @return HttpRequest
  245. */
  246. public function content($content)
  247. {
  248. return $this->requestBody($content);
  249. }
  250. /**
  251. * 设置参数,requestBody的别名
  252. * @param mixed $params 发送内容,可以是字符串、数组、HttpRequestMultipartBody
  253. * @return HttpRequest
  254. */
  255. public function params($params)
  256. {
  257. return $this->requestBody($params);
  258. }
  259. /**
  260. * 设置请求主体
  261. * @param mixed $requestBody 发送内容,可以是字符串、数组、HttpRequestMultipartBody
  262. * @return HttpRequest
  263. */
  264. public function requestBody($requestBody)
  265. {
  266. $this->content = $requestBody;
  267. return $this;
  268. }
  269. /**
  270. * 批量设置CURL的Option
  271. * @param array $options curl_setopt_array()所需要的第二个参数
  272. * @return HttpRequest
  273. */
  274. public function options($options)
  275. {
  276. foreach ($options as $key => $value) {
  277. $this->options[$key] = $value;
  278. }
  279. return $this;
  280. }
  281. /**
  282. * 设置CURL的Option
  283. * @param int $option 需要设置的CURLOPT_XXX选项
  284. * @param mixed $value 值
  285. * @return HttpRequest
  286. */
  287. public function option($option, $value)
  288. {
  289. $this->options[$option] = $value;
  290. return $this;
  291. }
  292. /**
  293. * 批量设置请求头
  294. * @param array $headers
  295. * @return HttpRequest
  296. */
  297. public function headers($headers)
  298. {
  299. $this->headers = array_merge($this->headers, $headers);
  300. return $this;
  301. }
  302. /**
  303. * 设置请求头
  304. * @param string $header 请求头名称
  305. * @param string $value 值
  306. * @return HttpRequest
  307. */
  308. public function header($header, $value)
  309. {
  310. $this->headers[$header] = $value;
  311. return $this;
  312. }
  313. /**
  314. * 设置Accept
  315. * @param string $accept
  316. * @return HttpRequest
  317. */
  318. public function accept($accept)
  319. {
  320. $this->headers['Accept'] = $accept;
  321. return $this;
  322. }
  323. /**
  324. * 设置Accept-Language
  325. * @param string $acceptLanguage
  326. * @return HttpRequest
  327. */
  328. public function acceptLanguage($acceptLanguage)
  329. {
  330. $this->headers['Accept-Language'] = $acceptLanguage;
  331. return $this;
  332. }
  333. /**
  334. * 设置Accept-Encoding
  335. * @param string $acceptEncoding
  336. * @return HttpRequest
  337. */
  338. public function acceptEncoding($acceptEncoding)
  339. {
  340. $this->headers['Accept-Encoding'] = $acceptEncoding;
  341. return $this;
  342. }
  343. /**
  344. * 设置Accept-Ranges
  345. * @param string $acceptRanges
  346. * @return HttpRequest
  347. */
  348. public function acceptRanges($acceptRanges)
  349. {
  350. $this->headers['Accept-Ranges'] = $acceptRanges;
  351. return $this;
  352. }
  353. /**
  354. * 设置Cache-Control
  355. * @param string $cacheControl
  356. * @return HttpRequest
  357. */
  358. public function cacheControl($cacheControl)
  359. {
  360. $this->headers['Cache-Control'] = $cacheControl;
  361. return $this;
  362. }
  363. /**
  364. * 批量设置Cookies
  365. * @param array $cookies 键值对应数组
  366. * @return HttpRequest
  367. */
  368. public function cookies($cookies)
  369. {
  370. $this->cookies = array_merge($this->cookies, $cookies);
  371. return $this;
  372. }
  373. /**
  374. * 设置Cookie
  375. * @param string $name 名称
  376. * @param string $value 值
  377. * @return HttpRequest
  378. */
  379. public function cookie($name, $value)
  380. {
  381. $this->cookies[$name] = $value;
  382. return $this;
  383. }
  384. /**
  385. * 设置Content-Type
  386. * @param string $contentType
  387. * @return HttpRequest
  388. */
  389. public function contentType($contentType)
  390. {
  391. $this->headers['Content-Type'] = $contentType;
  392. return $this;
  393. }
  394. /**
  395. * 设置Range
  396. * @param string $range
  397. * @return HttpRequest
  398. */
  399. public function range($range)
  400. {
  401. $this->headers['Range'] = $range;
  402. return $this;
  403. }
  404. /**
  405. * 设置Referer
  406. * @param string $referer
  407. * @return HttpRequest
  408. */
  409. public function referer($referer)
  410. {
  411. $this->headers['Referer'] = $referer;
  412. return $this;
  413. }
  414. /**
  415. * 设置User-Agent
  416. * @param string $userAgent
  417. * @return HttpRequest
  418. */
  419. public function userAgent($userAgent)
  420. {
  421. $this->headers['User-Agent'] = $userAgent;
  422. return $this;
  423. }
  424. /**
  425. * 设置User-Agent,userAgent的别名
  426. * @param string $userAgent
  427. * @return HttpRequest
  428. */
  429. public function ua($userAgent)
  430. {
  431. return $this->userAgent($userAgent);
  432. }
  433. /**
  434. * 设置失败重试次数,状态码非200时重试
  435. * @param string $retry
  436. * @return HttpRequest
  437. */
  438. public function retry($retry)
  439. {
  440. $this->retry = $retry < 0 ? 0 : $retry; //至少请求1次,即重试0次
  441. return $this;
  442. }
  443. /**
  444. * 代理
  445. * @param string $server 代理服务器地址
  446. * @param int $port 代理服务器端口
  447. * @param string $type 代理类型,支持:http、socks4、socks4a、socks5
  448. * @param string $auth 代理认证方式,支持:basic、ntlm。一般默认basic
  449. * @return HttpRequest
  450. */
  451. public function proxy($server, $port, $type = 'http', $auth = 'basic')
  452. {
  453. $this->useProxy = true;
  454. $this->proxy = array(
  455. 'server' => $server,
  456. 'port' => $port,
  457. 'type' => $type,
  458. 'auth' => $auth,
  459. );
  460. return $this;
  461. }
  462. /**
  463. * 设置超时时间
  464. * @param int $timeout 总超时时间,单位:毫秒
  465. * @param int $connectTimeout 连接超时时间,单位:毫秒
  466. * @return HttpRequest
  467. */
  468. public function timeout($timeout = null, $connectTimeout = null)
  469. {
  470. if (null !== $timeout) {
  471. $this->timeout = $timeout;
  472. }
  473. if (null !== $connectTimeout) {
  474. $this->connectTimeout = $connectTimeout;
  475. }
  476. return $this;
  477. }
  478. /**
  479. * 限速
  480. * @param int $download 下载速度,为0则不限制,单位:字节
  481. * @param int $upload 上传速度,为0则不限制,单位:字节
  482. * @return HttpRequest
  483. */
  484. public function limitRate($download = 0, $upload = 0)
  485. {
  486. $this->downloadSpeed = $download;
  487. $this->uploadSpeed = $upload;
  488. return $this;
  489. }
  490. /**
  491. * 设置用于连接中需要的用户名和密码
  492. * @param string $username 用户名
  493. * @param string $password 密码
  494. * @return HttpRequest
  495. */
  496. public function userPwd($username, $password)
  497. {
  498. $this->username = $username;
  499. $this->password = $password;
  500. return $this;
  501. }
  502. /**
  503. * 保存至文件的设置
  504. * @param string $filePath 文件路径
  505. * @param string $fileMode 文件打开方式,默认w+
  506. * @return HttpRequest
  507. */
  508. public function saveFile($filePath, $fileMode = 'w+')
  509. {
  510. $this->saveFileOption['filePath'] = $filePath;
  511. $this->saveFileOption['fileMode'] = $fileMode;
  512. return $this;
  513. }
  514. /**
  515. * 获取文件保存路径
  516. * @return string
  517. */
  518. public function getSavePath()
  519. {
  520. return $this->saveFileOption['savePath'];
  521. }
  522. /**
  523. * 设置SSL证书
  524. * @param string $path 一个包含 PEM 格式证书的文件名
  525. * @param string $type 证书类型,支持的格式有”PEM”(默认值),“DER”和”ENG”
  526. * @param string $password 使用证书需要的密码
  527. * @return HttpRequest
  528. */
  529. public function sslCert($path, $type = null, $password = null)
  530. {
  531. $this->certPath = $path;
  532. if (null !== $type) {
  533. $this->certType = $type;
  534. }
  535. if (null !== $password) {
  536. $this->certPassword = $password;
  537. }
  538. return $this;
  539. }
  540. /**
  541. * 设置SSL私钥
  542. * @param string $path 包含 SSL 私钥的文件名
  543. * @param string $type certType规定的私钥的加密类型,支持的密钥类型为”PEM”(默认值)、”DER”和”ENG”
  544. * @param string $password SSL私钥的密码
  545. * @return HttpRequest
  546. */
  547. public function sslKey($path, $type = null, $password = null)
  548. {
  549. $this->keyPath = $path;
  550. if (null !== $type) {
  551. $this->keyType = $type;
  552. }
  553. if (null !== $password) {
  554. $this->keyPassword = $password;
  555. }
  556. return $this;
  557. }
  558. /**
  559. * 发送请求,所有请求的老祖宗
  560. * @param string $url 请求地址,如果为null则取url属性值
  561. * @param array $requestBody 发送内容,可以是字符串、数组、`HttpRequestMultipartBody`,如果为空则取content属性值
  562. * @param array $method 请求方法,GET、POST等
  563. * @return HttpResponse
  564. */
  565. public function send($url = null, $requestBody = array(), $method = 'GET')
  566. {
  567. if (null !== $url) {
  568. $this->url = $url;
  569. }
  570. if (!empty($requestBody)) {
  571. if (is_array($requestBody)) {
  572. $this->content = http_build_query($requestBody, '', '&');
  573. } else if ($requestBody instanceof HttpRequestMultipartBody) {
  574. $this->content = $requestBody->content();
  575. $this->contentType(sprintf('multipart/form-data; boundary=%s', $requestBody->getBoundary()));
  576. } else {
  577. $this->content = $requestBody;
  578. }
  579. }
  580. $options = array(
  581. // 请求方法
  582. CURLOPT_CUSTOMREQUEST => $method,
  583. // 返回内容
  584. CURLOPT_RETURNTRANSFER => true,
  585. // 返回header
  586. CURLOPT_HEADER => true,
  587. // 发送内容
  588. CURLOPT_POSTFIELDS => $this->content,
  589. // 保存cookie
  590. CURLOPT_COOKIEFILE => $this->cookieFileName,
  591. CURLOPT_COOKIEJAR => $this->cookieFileName,
  592. // 自动重定向
  593. CURLOPT_FOLLOWLOCATION => self::$customLocation ? false : $this->followLocation,
  594. // 最大重定向次数
  595. CURLOPT_MAXREDIRS => $this->maxRedirects,
  596. );
  597. // 自动解压缩支持
  598. if (isset($this->headers['Accept-Encoding'])) {
  599. $options[CURLOPT_ENCODING] = $this->headers['Accept-Encoding'];
  600. } else {
  601. $options[CURLOPT_ENCODING] = '';
  602. }
  603. curl_setopt_array($this->handler, $options);
  604. $this->parseSSL();
  605. $this->parseOptions();
  606. $this->parseProxy();
  607. $this->parseHeaders();
  608. $this->parseCookies();
  609. $this->parseNetwork();
  610. $count = 0;
  611. do {
  612. curl_setopt($this->handler, CURLOPT_URL, $url);
  613. for ($i = 0; $i <= $this->retry; ++$i) {
  614. $response = new HttpResponse($this->handler, curl_exec($this->handler));
  615. $httpCode = $response->httpCode();
  616. // 状态码为5XX或者0才需要重试
  617. if (!(0 === $httpCode || (5 === (int) ($httpCode / 100)))) {
  618. break;
  619. }
  620. }
  621. if (self::$customLocation && (301 === $httpCode || 302 === $httpCode) && ++$count <= $this->maxRedirects) {
  622. $url = $response->headers['Location'];
  623. } else {
  624. break;
  625. }
  626. } while (true);
  627. // 关闭保存至文件的句柄
  628. if (isset($this->saveFileOption['fp'])) {
  629. fclose($this->saveFileOption['fp']);
  630. $this->saveFileOption['fp'] = null;
  631. }
  632. return $response;
  633. }
  634. /**
  635. * GET请求
  636. * @param string $url 请求地址,如果为null则取url属性值
  637. * @param array $requestBody 发送内容,可以是字符串、数组、`HttpRequestMultipartBody`,如果为空则取content属性值
  638. * @return HttpResponse
  639. */
  640. public function get($url = null, $requestBody = array())
  641. {
  642. return $this->send($url, $requestBody, 'GET');
  643. }
  644. /**
  645. * POST请求
  646. * @param string $url 请求地址,如果为null则取url属性值
  647. * @param array $requestBody 发送内容,可以是字符串、数组、`HttpRequestMultipartBody`,如果为空则取content属性值
  648. * @return HttpResponse
  649. */
  650. public function post($url = null, $requestBody = array())
  651. {
  652. return $this->send($url, $requestBody, 'POST');
  653. }
  654. /**
  655. * HEAD请求
  656. * @param string $url 请求地址,如果为null则取url属性值
  657. * @param array $requestBody 发送内容,可以是字符串、数组、`HttpRequestMultipartBody`,如果为空则取content属性值
  658. * @return HttpResponse
  659. */
  660. public function head($url = null, $requestBody = array())
  661. {
  662. return $this->send($url, $requestBody, 'HEAD');
  663. }
  664. /**
  665. * PUT请求
  666. * @param string $url 请求地址,如果为null则取url属性值
  667. * @param array $requestBody 发送内容,可以是字符串、数组、`HttpRequestMultipartBody`,如果为空则取content属性值
  668. * @return HttpResponse
  669. */
  670. public function put($url = null, $requestBody = array())
  671. {
  672. return $this->send($url, $requestBody, 'PUT');
  673. }
  674. /**
  675. * PATCH请求
  676. * @param string $url 请求地址,如果为null则取url属性值
  677. * @param array $requestBody 发送内容,可以是字符串、数组、`HttpRequestMultipartBody`,如果为空则取content属性值
  678. * @return HttpResponse
  679. */
  680. public function patch($url = null, $requestBody = array())
  681. {
  682. return $this->send($url, $requestBody, 'PATCH');
  683. }
  684. /**
  685. * DELETE请求
  686. * @param string $url 请求地址,如果为null则取url属性值
  687. * @param array $requestBody 发送内容,可以是字符串、数组、`HttpRequestMultipartBody`,如果为空则取content属性值
  688. * @return HttpResponse
  689. */
  690. public function delete($url = null, $requestBody = array())
  691. {
  692. return $this->send($url, $requestBody, 'DELETE');
  693. }
  694. /**
  695. * 直接下载文件
  696. * @param string $fileName 保存路径
  697. * @param string $url 下载文件地址
  698. * @param array $requestBody 发送内容,可以是字符串、数组、`HttpRequestMultipartBody`,如果为空则取content属性值
  699. * @param string $method 请求方法,GET、POST等,一般用GET
  700. * @return HttpResponse
  701. */
  702. public function download($fileName, $url = null, $requestBody = array(), $method = 'GET')
  703. {
  704. $result = $this->saveFile($fileName)->send($url, $requestBody, $method);
  705. $this->saveFileOption = array();
  706. return $result;
  707. }
  708. /**
  709. * 处理Options
  710. * @return void
  711. */
  712. protected function parseOptions()
  713. {
  714. curl_setopt_array($this->handler, $this->options);
  715. // 请求结果保存为文件
  716. if (isset($this->saveFileOption['filePath']) && null !== $this->saveFileOption['filePath']) {
  717. curl_setopt_array($this->handler, array(
  718. CURLOPT_HEADER => false,
  719. CURLOPT_RETURNTRANSFER => false,
  720. ));
  721. $filePath = $this->saveFileOption['filePath'];
  722. $last = substr($filePath, -1, 1);
  723. if ('/' === $last || '\\' === $last) {
  724. // 自动获取文件名
  725. $filePath .= basename($this->url);
  726. }
  727. $this->saveFileOption['savePath'] = $filePath;
  728. $this->saveFileOption['fp'] = fopen($filePath, isset($this->saveFileOption['fileMode']) ? $this->saveFileOption['fileMode'] : 'w+');
  729. curl_setopt($this->handler, CURLOPT_FILE, $this->saveFileOption['fp']);
  730. }
  731. }
  732. /**
  733. * 处理代理
  734. * @return void
  735. */
  736. protected function parseProxy()
  737. {
  738. if ($this->useProxy) {
  739. curl_setopt_array($this->handler, array(
  740. CURLOPT_PROXYAUTH => self::$proxyAuths[$this->proxy['auth']],
  741. CURLOPT_PROXY => $this->proxy['server'],
  742. CURLOPT_PROXYPORT => $this->proxy['port'],
  743. CURLOPT_PROXYTYPE => 'socks5' === $this->proxy['type'] ? (defined('CURLPROXY_SOCKS5_HOSTNAME') ? CURLPROXY_SOCKS5_HOSTNAME : self::$proxyType[$this->proxy['type']]) : self::$proxyType[$this->proxy['type']],
  744. ));
  745. }
  746. }
  747. /**
  748. * 处理Headers
  749. * @return void
  750. */
  751. protected function parseHeaders()
  752. {
  753. curl_setopt($this->handler, CURLOPT_HTTPHEADER, $this->parseHeadersFormat());
  754. }
  755. /**
  756. * 处理Cookie
  757. * @return void
  758. */
  759. protected function parseCookies()
  760. {
  761. $content = '';
  762. foreach ($this->cookies as $name => $value) {
  763. $content .= "{$name}={$value}; ";
  764. }
  765. curl_setopt($this->handler, CURLOPT_COOKIE, $content);
  766. }
  767. /**
  768. * 处理成CURL可以识别的headers格式
  769. * @return array
  770. */
  771. protected function parseHeadersFormat()
  772. {
  773. $headers = array();
  774. foreach ($this->headers as $name => $value) {
  775. $headers[] = $name . ':' . $value;
  776. }
  777. return $headers;
  778. }
  779. /**
  780. * 处理SSL
  781. * @return void
  782. */
  783. protected function parseSSL()
  784. {
  785. if ($this->isVerifyCA) {
  786. curl_setopt_array($this->handler, array(
  787. CURLOPT_SSL_VERIFYPEER => true,
  788. CURLOPT_CAINFO => $this->caCert,
  789. CURLOPT_SSL_VERIFYHOST => 2,
  790. ));
  791. } else {
  792. curl_setopt_array($this->handler, array(
  793. CURLOPT_SSL_VERIFYPEER => false,
  794. CURLOPT_SSL_VERIFYHOST => 0,
  795. ));
  796. }
  797. if ('' !== $this->certPath) {
  798. curl_setopt_array($this->handler, array(
  799. CURLOPT_SSLCERT => $this->certPath,
  800. CURLOPT_SSLCERTPASSWD => $this->certPassword,
  801. CURLOPT_SSLCERTTYPE => $this->certType,
  802. ));
  803. }
  804. if ('' !== $this->keyPath) {
  805. curl_setopt_array($this->handler, array(
  806. CURLOPT_SSLKEY => $this->keyPath,
  807. CURLOPT_SSLKEYPASSWD => $this->keyPassword,
  808. CURLOPT_SSLKEYTYPE => $this->keyType,
  809. ));
  810. }
  811. }
  812. /**
  813. * 处理网络相关
  814. * @return void
  815. */
  816. protected function parseNetwork()
  817. {
  818. // 用户名密码处理
  819. if ('' != $this->username) {
  820. $userPwd = $this->username . ':' . $this->password;
  821. } else {
  822. $userPwd = '';
  823. }
  824. curl_setopt_array($this->handler, array(
  825. // 连接超时
  826. CURLOPT_CONNECTTIMEOUT_MS => $this->connectTimeout,
  827. // 总超时
  828. CURLOPT_TIMEOUT_MS => $this->timeout,
  829. // 下载限速
  830. CURLOPT_MAX_RECV_SPEED_LARGE => $this->downloadSpeed,
  831. // 上传限速
  832. CURLOPT_MAX_SEND_SPEED_LARGE => $this->uploadSpeed,
  833. // 连接中用到的用户名和密码
  834. CURLOPT_USERPWD => $userPwd,
  835. ));
  836. }
  837. }