Merge branch '3.0'
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / action / ImageProxyAction.class.php
CommitLineData
e934d809
MS
1<?php
2namespace wcf\action;
3use wcf\system\exception\IllegalLinkException;
4use wcf\system\exception\SystemException;
c5b74093 5use wcf\system\WCF;
1861a13b 6use wcf\util\exception\CryptoException;
52621aa3 7use wcf\util\exception\HTTPException;
1861a13b 8use wcf\util\CryptoUtil;
e934d809 9use wcf\util\FileUtil;
c5b74093 10use wcf\util\HeaderUtil;
e934d809
MS
11use wcf\util\HTTPRequest;
12use wcf\util\StringUtil;
13
14/**
15 * Proxies requests for embedded images.
16 *
17 * @author Matthias Schmidt
c839bd49 18 * @copyright 2001-2018 WoltLab GmbH
e934d809 19 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
e71525e4
MW
20 * @package WoltLabSuite\Core\Action
21 * @since 3.0
e934d809
MS
22 */
23class ImageProxyAction extends AbstractAction {
7dc58174
TD
24 /**
25 * @inheritDoc
26 */
27 public $neededModules = ['MODULE_IMAGE_PROXY'];
28
e934d809 29 /**
1861a13b 30 * The image key created by CryptoUtil::createSignedString()
e934d809
MS
31 * @var string
32 */
1861a13b 33 public $key = '';
e934d809
MS
34
35 /**
0fcfe5f6 36 * @inheritDoc
e934d809
MS
37 */
38 public function readParameters() {
39 parent::readParameters();
40
1861a13b 41 if (isset($_REQUEST['key'])) $this->key = StringUtil::trim($_REQUEST['key']);
e934d809
MS
42 }
43
44 /**
0fcfe5f6 45 * @inheritDoc
e934d809
MS
46 */
47 public function execute() {
48 parent::execute();
49
52621aa3
TD
50 if (isset($_SERVER['HTTP_VIA']) && strpos($_SERVER['HTTP_VIA'], 'wsc') !== false) throw new IllegalLinkException();
51
e934d809 52 try {
1861a13b
TD
53 $url = CryptoUtil::getValueFromSignedString($this->key);
54 if ($url === null) throw new IllegalLinkException();
55
56 $fileName = sha1($this->key);
29d0faf2 57 $dir = WCF_DIR.'images/proxy/'.substr($fileName, 0, 2);
1861a13b 58
29d0faf2
TD
59 // ensure that the directory exists
60 if (!file_exists($dir)) {
4879676b 61 FileUtil::makePath($dir);
e934d809 62 }
e934d809 63
29d0faf2 64 // check whether we already downloaded the image
5fe7469d
TD
65 $fileLocation = null;
66 foreach (['png','jpg','gif'] as $extension) {
67 if (is_file($dir.'/'.$fileName.'.'.$extension)) {
68 $fileLocation = $dir.'/'.$fileName.'.'.$extension;
69 break;
70 }
71 }
29d0faf2 72
5fe7469d 73 if ($fileLocation === null) {
0b4b5902 74 try {
1856402e
TD
75 // download image
76 try {
d08d11cd
TD
77 $request = new HTTPRequest($url, [
78 'maxLength' => 10 * (1 << 20) // download at most 10 MiB
79 ]);
52621aa3 80 $request->addHeader('Via', '1.1 wsc');
8c7bfa6d 81 $request->addHeader('Accept', 'image/*');
1856402e
TD
82 $request->execute();
83 }
52621aa3
TD
84 catch (\Exception $e) {
85 $chain = $e;
86 do {
87 if ($chain instanceof HTTPException) {
88 throw new \DomainException();
89 }
c00717d0
TD
90 // TODO: This is the Exception thrown by RemoteFile.
91 // Update if RemoteFile switches to a proper subclass in the future.
92 if (strpos($chain->getMessage(), 'Can not connect to') === 0) {
93 throw new \DomainException();
94 }
52621aa3
TD
95 }
96 while ($chain = $chain->getPrevious());
97
98 throw $e;
1856402e
TD
99 }
100 $image = $request->getReply()['body'];
101
102 // check file type
34e37928 103 $imageData = @getimagesizefromstring($image);
1856402e
TD
104 if (!$imageData) throw new \DomainException();
105
106 switch ($imageData[2]) {
107 case IMAGETYPE_PNG:
108 $extension = 'png';
109 break;
110 case IMAGETYPE_GIF:
111 $extension = 'gif';
112 break;
113 case IMAGETYPE_JPEG:
114 $extension = 'jpg';
115 break;
116 default:
117 throw new \DomainException();
118 }
119 }
120 catch (\DomainException $e) {
121 // save a dummy image in case the server sent us junk, otherwise we might try to download the file over and over and over again.
122 // taken from the public domain gif at https://commons.wikimedia.org/wiki/File%3aBlank.gif
123 $image = "\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\xFF\xFF\xFF\x00\x00\x00\x21\xF9\x04\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3B";
124 $extension = 'gif';
e7566924
TD
125 }
126
29d0faf2
TD
127 $fileLocation = $dir.'/'.$fileName.'.'.$extension;
128
e7566924
TD
129 file_put_contents($fileLocation, $image);
130
131 // update mtime for correct expiration calculation
132 @touch($fileLocation);
133 }
5fe7469d 134
29d0faf2
TD
135 $path = FileUtil::getRelativePath(WCF_DIR, dirname($fileLocation)).basename($fileLocation);
136
e934d809
MS
137 $this->executed();
138
1a01691b 139 HeaderUtil::redirect(WCF::getPath().$path, true, false);
e934d809
MS
140 exit;
141 }
142 catch (SystemException $e) {
0b4b5902 143 \wcf\functions\exception\logThrowable($e);
e934d809
MS
144 throw new IllegalLinkException();
145 }
1861a13b 146 catch (CryptoException $e) {
0b4b5902 147 \wcf\functions\exception\logThrowable($e);
1861a13b
TD
148 throw new IllegalLinkException();
149 }
e934d809
MS
150 }
151}