1<?php
2
3namespace Mpdf;
4
5use Mpdf\Utils\Arrays;
6use Psr\Log\LoggerInterface;
7use Mpdf\Log\Context as LogContext;
8
9class RemoteContentFetcher implements \Psr\Log\LoggerAwareInterface
10{
11
12	/**
13	 * @var \Mpdf\Mpdf
14	 */
15	private $mpdf;
16
17	/**
18	 * @var \Psr\Log\LoggerInterface
19	 */
20	private $logger;
21
22	public function __construct(Mpdf $mpdf, LoggerInterface $logger)
23	{
24		$this->mpdf = $mpdf;
25		$this->logger = $logger;
26	}
27
28	public function getFileContentsByCurl($url)
29	{
30		$this->logger->debug(sprintf('Fetching (cURL) content of remote URL "%s"', $url), ['context' => LogContext::REMOTE_CONTENT]);
31
32		$ch = curl_init($url);
33
34		curl_setopt($ch, CURLOPT_USERAGENT, $this->mpdf->curlUserAgent);
35		curl_setopt($ch, CURLOPT_HEADER, 0);
36		curl_setopt($ch, CURLOPT_NOBODY, 0);
37		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
38		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->mpdf->curlTimeout);
39
40		if ($this->mpdf->curlExecutionTimeout) {
41			curl_setopt($ch, CURLOPT_TIMEOUT, $this->mpdf->curlExecutionTimeout);
42		}
43
44		if ($this->mpdf->curlFollowLocation) {
45			curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
46		}
47
48		if ($this->mpdf->curlAllowUnsafeSslRequests) {
49			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
50			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
51		}
52
53		if ($this->mpdf->curlCaCertificate && is_file($this->mpdf->curlCaCertificate)) {
54			curl_setopt($ch, CURLOPT_CAINFO, $this->mpdf->curlCaCertificate);
55		}
56
57		if ($this->mpdf->curlProxy) {
58			curl_setopt($ch, CURLOPT_PROXY, $this->mpdf->curlProxy);
59			if ($this->mpdf->curlProxyAuth) {
60				curl_setopt($ch, CURLOPT_PROXYUSERPWD, $this->mpdf->curlProxyAuth);
61			}
62		}
63
64		$data = curl_exec($ch);
65
66		if (curl_error($ch)) {
67			$message = sprintf('cURL error: "%s"', curl_error($ch));
68			$this->logger->error($message, ['context' => LogContext::REMOTE_CONTENT]);
69
70			if ($this->mpdf->debug) {
71				throw new \Mpdf\MpdfException($message);
72			}
73		}
74
75		$info = curl_getinfo($ch);
76		if (isset($info['http_code']) && $info['http_code'] !== 200) {
77			$message = sprintf('HTTP error: %d', $info['http_code']);
78			$this->logger->error($message, ['context' => LogContext::REMOTE_CONTENT]);
79
80			if ($this->mpdf->debug) {
81				throw new \Mpdf\MpdfException($message);
82			}
83		}
84
85		curl_close($ch);
86
87		return $data;
88	}
89
90	public function getFileContentsBySocket($url)
91	{
92		$this->logger->debug(sprintf('Fetching (socket) content of remote URL "%s"', $url), ['context' => LogContext::REMOTE_CONTENT]);
93		// mPDF 5.7.3
94
95		$timeout = 1;
96		$p = parse_url($url);
97
98		$file = Arrays::get($p, 'path', '');
99		$scheme = Arrays::get($p, 'scheme', '');
100		$port = Arrays::get($p, 'port', 80);
101		$prefix = '';
102
103		if ($scheme === 'https') {
104			$prefix = 'ssl://';
105			$port = Arrays::get($p, 'port', 443);
106		}
107
108		$query = Arrays::get($p, 'query', null);
109		if ($query) {
110			$file .= '?' . $query;
111		}
112
113		if (!($fh = @fsockopen($prefix . $p['host'], $port, $errno, $errstr, $timeout))) {
114			$this->logger->error(sprintf('Socket error "%s": "%s"', $errno, $errstr), ['context' => LogContext::REMOTE_CONTENT]);
115			return false;
116		}
117
118		$getstring = 'GET ' . $file . " HTTP/1.0 \r\n" .
119			'Host: ' . $p['host'] . " \r\n" .
120			"Connection: close\r\n\r\n";
121
122		fwrite($fh, $getstring);
123
124		// Get rid of HTTP header
125		$s = fgets($fh, 1024);
126		if (!$s) {
127			return false;
128		}
129
130		while (!feof($fh)) {
131			$s = fgets($fh, 1024);
132			if ($s === "\r\n") {
133				break;
134			}
135		}
136
137		$data = '';
138
139		while (!feof($fh)) {
140			$data .= fgets($fh, 1024);
141		}
142
143		fclose($fh);
144
145		return $data;
146	}
147
148	public function setLogger(LoggerInterface $logger)
149	{
150		$this->logger = $logger;
151	}
152}
153