-
Notifications
You must be signed in to change notification settings - Fork 988
/
FileFetcherUploadZip.php
195 lines (171 loc) · 4.88 KB
/
FileFetcherUploadZip.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
<?php
namespace LimeSurvey\ExtensionInstaller;
/**
* Extension file fetcher for upload ZIP file.
* Must work for all extension types: plugins, theme, question theme, etc.
*
* @since 2018-09-25
* @author Olle Haerstedt
*/
class FileFetcherUploadZip extends FileFetcher
{
/**
* Filter to apply to unzipping.
* @var string
*/
protected $filterName;
/**
* @param string $source
* @return void
*/
public function setSource($source)
{
// Not used.
}
/**
* Fetch files, meaning grab uploaded ZIP file and
* unzip it in system tmp folder.
* @return void
*/
public function fetch()
{
$this->checkFileSizeError();
$this->checkZipBom();
$this->extractZipFile($this->getTempdir());
}
/**
* @param string $destdir
*/
public function move($destdir)
{
}
/**
* @return SimpleXMLElement
* @throws Exception
*/
public function getConfig()
{
$tmpdir = $this->getTempdir();
if (empty($tmpdir)) {
throw new \Exception(gT('No destination folder, cannot read configuration file.'));
}
$configFile = $tmpdir . '/config.xml';
if (!file_exists($configFile)) {
throw new \Exception(gT('Configuration file config.xml does not exist.'));
}
$config = \ExtensionConfig::loadConfigFromFile($configFile);
if (empty($config)) {
throw new \Exception(gT('Could not parse config.xml file.'));
}
return $config;
}
/**
* @param string $filterName
* @return void
*/
public function setUnzipFilter($filterName)
{
$this->filterName = $filterName;
}
/**
* Abort unzip, clear files and session.
* @return void
*/
public function abort()
{
// Remove any files.
$tmpdir = $this->getTempdir();
if ($tmpdir) {
rmdirr($tmpdir);
}
// Reset user state.
$this->clearTmpdir();
}
/**
* Get tmp tmpdir for extension to unzip in.
* @return string
*/
protected function getTempdir()
{
// NB: Since the installation procedure can span several page reloads,
// we save the tmpdir in the user session.
$tmpdir = App()->user->getState('filefetcheruploadzip_tmpdir');
if (empty($tmpdir)) {
$tempdir = \Yii::app()->getConfig("tempdir");
$tmpdir = createRandomTempDir($tempdir, 'install_');
App()->user->setState('filefetcheruploadzip_tmpdir', $tmpdir);
}
return $tmpdir;
}
/**
* Set user session tmpdir to null.
* @return void
*/
protected function clearTmpdir()
{
App()->user->setState('filefetcheruploadzip_tmpdir', null);
}
/**
* @todo Duplicate from themes.php.
* @return void
* @throws Exception
*/
protected function checkFileSizeError()
{
if (!isset($_FILES['the_file'])) {
throw new \Exception(gT('Found no file'));
}
if ($_FILES['the_file']['error'] == 1 || $_FILES['the_file']['error'] == 2) {
throw new \Exception(
sprintf(
gT("Sorry, this file is too large. Only files up to %01.2f MB are allowed."),
getMaximumFileUploadSize() / 1024 / 1024
)
);
}
}
/**
* Check if uploaded zip file is a zip bomb.
* @return void
*/
protected function checkZipBom()
{
// Check zip bomb.
\Yii::import('application.helpers.common_helper', true);
if (isZipBomb($_FILES['the_file']['name'])) {
throw new \Exception(gT('Unzipped file is superior to upload_max_filesize or to post_max_size'));
}
}
/**
* @param string $tmpdir
* @return void
*/
protected function extractZipFile($tmpdir)
{
\Yii::import('application.helpers.common_helper', true);
\Yii::app()->loadLibrary('admin.pclzip');
if (!is_file($_FILES['the_file']['tmp_name'])) {
throw new \Exception(
gT("An error occurred uploading your file. This may be caused by incorrect permissions for the application /tmp folder.")
);
}
if (empty($this->filterName)) {
throw new \Exception(gT("No filter name is set, can't unzip."));
}
$zip = new \PclZip($_FILES['the_file']['tmp_name']);
$aExtractResult = $zip->extract(
PCLZIP_OPT_PATH,
$tmpdir,
PCLZIP_CB_PRE_EXTRACT,
$this->filterName
);
if ($aExtractResult === 0) {
throw new \Exception(
gT("This file is not a valid ZIP file archive. Import failed.")
. ' ' . $zip->error_string
);
} else {
// All good?
}
}
}