[0] | 1 | <?php |
---|
[3731] | 2 | /** |
---|
| 3 | * @brief importExport, a plugin for Dotclear 2 |
---|
| 4 | * |
---|
| 5 | * @package Dotclear |
---|
| 6 | * @subpackage Plugins |
---|
| 7 | * |
---|
| 8 | * @copyright Olivier Meunier & Association Dotclear |
---|
| 9 | * @copyright GPL-2.0-only |
---|
| 10 | */ |
---|
| 11 | |
---|
[3699] | 12 | if (!defined('DC_RC_PATH')) {return;} |
---|
[0] | 13 | |
---|
| 14 | class dcImportFlat extends dcIeModule |
---|
| 15 | { |
---|
[3699] | 16 | protected $status = false; |
---|
[2485] | 17 | |
---|
[3699] | 18 | public function setInfo() |
---|
| 19 | { |
---|
| 20 | $this->type = 'import'; |
---|
| 21 | $this->name = __('Flat file import'); |
---|
| 22 | $this->description = __('Imports a blog or a full Dotclear installation from flat file.'); |
---|
| 23 | } |
---|
[2485] | 24 | |
---|
[3699] | 25 | public function process($do) |
---|
| 26 | { |
---|
| 27 | if ($do == 'single' || $do == 'full') { |
---|
| 28 | $this->status = $do; |
---|
| 29 | return; |
---|
| 30 | } |
---|
[2485] | 31 | |
---|
[3699] | 32 | $to_unlink = false; |
---|
[2485] | 33 | |
---|
[3699] | 34 | # Single blog import |
---|
| 35 | $files = $this->getPublicFiles(); |
---|
| 36 | $single_upl = null; |
---|
| 37 | if (!empty($_POST['public_single_file']) && in_array($_POST['public_single_file'], $files)) { |
---|
| 38 | $single_upl = false; |
---|
| 39 | } elseif (!empty($_FILES['up_single_file'])) { |
---|
| 40 | $single_upl = true; |
---|
| 41 | } |
---|
[2485] | 42 | |
---|
[3699] | 43 | if ($single_upl !== null) { |
---|
| 44 | if ($single_upl) { |
---|
| 45 | files::uploadStatus($_FILES['up_single_file']); |
---|
| 46 | $file = DC_TPL_CACHE . '/' . md5(uniqid()); |
---|
| 47 | if (!move_uploaded_file($_FILES['up_single_file']['tmp_name'], $file)) { |
---|
| 48 | throw new Exception(__('Unable to move uploaded file.')); |
---|
| 49 | } |
---|
| 50 | $to_unlink = true; |
---|
| 51 | } else { |
---|
| 52 | $file = $_POST['public_single_file']; |
---|
| 53 | } |
---|
[2485] | 54 | |
---|
[3699] | 55 | try { |
---|
| 56 | # Try to unzip file |
---|
| 57 | $unzip_file = $this->unzip($file); |
---|
| 58 | if (false !== $unzip_file) { |
---|
| 59 | $bk = new flatImport($this->core, $unzip_file); |
---|
| 60 | } |
---|
| 61 | # Else this is a normal file |
---|
| 62 | else { |
---|
| 63 | $bk = new flatImport($this->core, $file); |
---|
| 64 | } |
---|
[2485] | 65 | |
---|
[3699] | 66 | $bk->importSingle(); |
---|
| 67 | } catch (Exception $e) { |
---|
| 68 | @unlink($unzip_file); |
---|
| 69 | if ($to_unlink) { |
---|
| 70 | @unlink($file); |
---|
| 71 | } |
---|
| 72 | throw $e; |
---|
| 73 | } |
---|
| 74 | @unlink($unzip_file); |
---|
| 75 | if ($to_unlink) { |
---|
| 76 | @unlink($file); |
---|
| 77 | } |
---|
| 78 | http::redirect($this->getURL() . '&do=single'); |
---|
| 79 | } |
---|
[2485] | 80 | |
---|
[3699] | 81 | # Full import |
---|
| 82 | $full_upl = null; |
---|
| 83 | if (!empty($_POST['public_full_file']) && in_array($_POST['public_full_file'], $files)) { |
---|
| 84 | $full_upl = false; |
---|
| 85 | } elseif (!empty($_FILES['up_full_file'])) { |
---|
| 86 | $full_upl = true; |
---|
| 87 | } |
---|
[2485] | 88 | |
---|
[3699] | 89 | if ($full_upl !== null && $this->core->auth->isSuperAdmin()) { |
---|
| 90 | if (empty($_POST['your_pwd']) || !$this->core->auth->checkPassword($_POST['your_pwd'])) { |
---|
| 91 | throw new Exception(__('Password verification failed')); |
---|
| 92 | } |
---|
[2485] | 93 | |
---|
[3699] | 94 | if ($full_upl) { |
---|
| 95 | files::uploadStatus($_FILES['up_full_file']); |
---|
| 96 | $file = DC_TPL_CACHE . '/' . md5(uniqid()); |
---|
| 97 | if (!move_uploaded_file($_FILES['up_full_file']['tmp_name'], $file)) { |
---|
| 98 | throw new Exception(__('Unable to move uploaded file.')); |
---|
| 99 | } |
---|
| 100 | $to_unlink = true; |
---|
| 101 | } else { |
---|
| 102 | $file = $_POST['public_full_file']; |
---|
| 103 | } |
---|
[2485] | 104 | |
---|
[3699] | 105 | try { |
---|
| 106 | # Try to unzip file |
---|
| 107 | $unzip_file = $this->unzip($file); |
---|
| 108 | if (false !== $unzip_file) { |
---|
| 109 | $bk = new flatImport($this->core, $unzip_file); |
---|
| 110 | } |
---|
| 111 | # Else this is a normal file |
---|
| 112 | else { |
---|
| 113 | $bk = new flatImport($this->core, $file); |
---|
| 114 | } |
---|
[2485] | 115 | |
---|
[3699] | 116 | $bk->importFull(); |
---|
| 117 | } catch (Exception $e) { |
---|
| 118 | @unlink($unzip_file); |
---|
| 119 | if ($to_unlink) { |
---|
| 120 | @unlink($file); |
---|
| 121 | } |
---|
| 122 | throw $e; |
---|
| 123 | } |
---|
| 124 | @unlink($unzip_file); |
---|
| 125 | if ($to_unlink) { |
---|
| 126 | @unlink($file); |
---|
| 127 | } |
---|
| 128 | http::redirect($this->getURL() . '&do=full'); |
---|
| 129 | } |
---|
[2485] | 130 | |
---|
[3699] | 131 | header('content-type:text/plain'); |
---|
| 132 | var_dump($_POST); |
---|
| 133 | exit; |
---|
[2485] | 134 | |
---|
[3699] | 135 | $this->status = true; |
---|
| 136 | } |
---|
[2485] | 137 | |
---|
[3699] | 138 | public function gui() |
---|
| 139 | { |
---|
| 140 | if ($this->status == 'single') { |
---|
| 141 | dcPage::success(__('Single blog successfully imported.')); |
---|
| 142 | return; |
---|
| 143 | } |
---|
| 144 | if ($this->status == 'full') { |
---|
| 145 | dcPage::success(__('Content successfully imported.')); |
---|
| 146 | return; |
---|
| 147 | } |
---|
[2485] | 148 | |
---|
[3874] | 149 | $public_files = array_merge(['-' => ''], $this->getPublicFiles()); |
---|
[3699] | 150 | $has_files = (boolean) (count($public_files) - 1); |
---|
[2485] | 151 | |
---|
[3699] | 152 | echo |
---|
[3993] | 153 | dcPage::jsJson('ie_import_flat_msg', |
---|
| 154 | ['confirm_full_import' => __('Are you sure you want to import a full backup file?')]) . |
---|
| 155 | dcPage::jsLoad(dcPage::getPF('importExport/js/import_flat.js')); |
---|
[3699] | 156 | echo |
---|
| 157 | '<form action="' . $this->getURL(true) . '" method="post" enctype="multipart/form-data" class="fieldset">' . |
---|
| 158 | '<h3>' . __('Single blog') . '</h3>' . |
---|
| 159 | '<p>' . sprintf(__('This will import a single blog backup as new content in the current blog: <strong>%s</strong>.'), html::escapeHTML($this->core->blog->name)) . '</p>' . |
---|
[2485] | 160 | |
---|
[3699] | 161 | '<p><label for="up_single_file">' . __('Upload a backup file') . |
---|
| 162 | ' (' . sprintf(__('maximum size %s'), files::size(DC_MAX_UPLOAD_SIZE)) . ')' . ' </label>' . |
---|
| 163 | ' <input type="file" id="up_single_file" name="up_single_file" size="20" />' . |
---|
| 164 | '</p>'; |
---|
[2485] | 165 | |
---|
[3699] | 166 | if ($has_files) { |
---|
| 167 | echo |
---|
| 168 | '<p><label for="public_single_file" class="">' . __('or pick up a local file in your public directory') . ' </label> ' . |
---|
| 169 | form::combo('public_single_file', $public_files) . |
---|
| 170 | '</p>'; |
---|
| 171 | } |
---|
[2485] | 172 | |
---|
[3699] | 173 | echo |
---|
| 174 | '<p>' . |
---|
| 175 | $this->core->formNonce() . |
---|
[3874] | 176 | form::hidden(['do'], 1) . |
---|
| 177 | form::hidden(['MAX_FILE_SIZE'], DC_MAX_UPLOAD_SIZE) . |
---|
[3699] | 178 | '<input type="submit" value="' . __('Import') . '" /></p>' . |
---|
[2485] | 179 | |
---|
[3699] | 180 | '</form>'; |
---|
[2485] | 181 | |
---|
[3699] | 182 | if ($this->core->auth->isSuperAdmin()) { |
---|
| 183 | echo |
---|
| 184 | '<form action="' . $this->getURL(true) . '" method="post" enctype="multipart/form-data" id="formfull" class="fieldset">' . |
---|
| 185 | '<h3>' . __('Multiple blogs') . '</h3>' . |
---|
| 186 | '<p class="warning">' . __('This will reset all the content of your database, except users.') . '</p>' . |
---|
[2485] | 187 | |
---|
[3699] | 188 | '<p><label for="up_full_file">' . __('Upload a backup file') . ' ' . |
---|
| 189 | ' (' . sprintf(__('maximum size %s'), files::size(DC_MAX_UPLOAD_SIZE)) . ')' . ' </label>' . |
---|
| 190 | '<input type="file" id="up_full_file" name="up_full_file" size="20" />' . |
---|
| 191 | '</p>'; |
---|
[2485] | 192 | |
---|
[3699] | 193 | if ($has_files) { |
---|
| 194 | echo |
---|
| 195 | '<p><label for="public_full_file">' . __('or pick up a local file in your public directory') . ' </label>' . |
---|
| 196 | form::combo('public_full_file', $public_files) . |
---|
| 197 | '</p>'; |
---|
| 198 | } |
---|
[2485] | 199 | |
---|
[3699] | 200 | echo |
---|
| 201 | '<p><label for="your_pwd" class="required"><abbr title="' . __('Required field') . '">*</abbr> ' . __('Your password:') . '</label>' . |
---|
| 202 | form::password('your_pwd', 20, 255, |
---|
[3874] | 203 | [ |
---|
[3699] | 204 | 'extra_html' => 'required placeholder="' . __('Password') . '"', |
---|
| 205 | 'autocomplete' => 'current-password' |
---|
[3874] | 206 | ] |
---|
[3699] | 207 | ) . '</p>' . |
---|
[2485] | 208 | |
---|
[3699] | 209 | '<p>' . |
---|
| 210 | $this->core->formNonce() . |
---|
[3874] | 211 | form::hidden(['do'], 1) . |
---|
| 212 | form::hidden(['MAX_FILE_SIZE'], DC_MAX_UPLOAD_SIZE) . |
---|
[3699] | 213 | '<input type="submit" value="' . __('Import') . '" /></p>' . |
---|
[2485] | 214 | |
---|
[3699] | 215 | '</form>'; |
---|
| 216 | } |
---|
| 217 | } |
---|
[2485] | 218 | |
---|
[3699] | 219 | protected function getPublicFiles() |
---|
| 220 | { |
---|
[3874] | 221 | $public_files = []; |
---|
[3699] | 222 | $dir = @dir($this->core->blog->public_path); |
---|
| 223 | if ($dir) { |
---|
| 224 | while (($entry = $dir->read()) !== false) { |
---|
| 225 | $entry_path = $dir->path . '/' . $entry; |
---|
[2485] | 226 | |
---|
[3699] | 227 | if (is_file($entry_path) && is_readable($entry_path)) { |
---|
| 228 | # Do not test each zip file content here, its too long |
---|
| 229 | if (substr($entry_path, -4) == '.zip') { |
---|
| 230 | $public_files[$entry] = $entry_path; |
---|
| 231 | } elseif (self::checkFileContent($entry_path)) { |
---|
| 232 | $public_files[$entry] = $entry_path; |
---|
| 233 | } |
---|
| 234 | } |
---|
| 235 | } |
---|
| 236 | } |
---|
| 237 | return $public_files; |
---|
| 238 | } |
---|
[2485] | 239 | |
---|
[3699] | 240 | protected static function checkFileContent($entry_path) |
---|
| 241 | { |
---|
| 242 | $ret = false; |
---|
[2485] | 243 | |
---|
[3699] | 244 | $fp = fopen($entry_path, 'rb'); |
---|
| 245 | $ret = strpos(fgets($fp), '///DOTCLEAR|') === 0; |
---|
| 246 | fclose($fp); |
---|
[2485] | 247 | |
---|
[3699] | 248 | return $ret; |
---|
| 249 | } |
---|
[2485] | 250 | |
---|
[3699] | 251 | private function unzip($file) |
---|
| 252 | { |
---|
| 253 | $zip = new fileUnzip($file); |
---|
[2485] | 254 | |
---|
[3699] | 255 | if ($zip->isEmpty()) { |
---|
| 256 | $zip->close(); |
---|
| 257 | return false; //throw new Exception(__('File is empty or not a compressed file.')); |
---|
| 258 | } |
---|
[2485] | 259 | |
---|
[3699] | 260 | foreach ($zip->getFilesList() as $zip_file) { |
---|
| 261 | # Check zipped file name |
---|
| 262 | if (substr($zip_file, -4) != '.txt') { |
---|
| 263 | continue; |
---|
| 264 | } |
---|
[2485] | 265 | |
---|
[3699] | 266 | # Check zipped file contents |
---|
| 267 | $content = $zip->unzip($zip_file); |
---|
| 268 | if (strpos($content, '///DOTCLEAR|') !== 0) { |
---|
| 269 | unset($content); |
---|
| 270 | continue; |
---|
| 271 | } |
---|
[2485] | 272 | |
---|
[3699] | 273 | $target = path::fullFromRoot($zip_file, dirname($file)); |
---|
[2485] | 274 | |
---|
[3699] | 275 | # Check existing files with same name |
---|
| 276 | if (file_exists($target)) { |
---|
| 277 | $zip->close(); |
---|
| 278 | unset($content); |
---|
| 279 | throw new Exception(__('Another file with same name exists.')); |
---|
| 280 | } |
---|
[2485] | 281 | |
---|
[3699] | 282 | # Extract backup content |
---|
| 283 | if (file_put_contents($target, $content) === false) { |
---|
| 284 | $zip->close(); |
---|
| 285 | unset($content); |
---|
| 286 | throw new Exception(__('Failed to extract backup file.')); |
---|
| 287 | } |
---|
[2485] | 288 | |
---|
[3699] | 289 | $zip->close(); |
---|
| 290 | unset($content); |
---|
[2485] | 291 | |
---|
[3699] | 292 | # Return extracted file name |
---|
| 293 | return $target; |
---|
| 294 | } |
---|
[2485] | 295 | |
---|
[3699] | 296 | $zip->close(); |
---|
| 297 | throw new Exception(__('No backup in compressed file.')); |
---|
| 298 | } |
---|
[0] | 299 | } |
---|