PluginProbe
Depicter — Popup & Slider Builder / trunk
Depicter — Popup & Slider Builder vtrunk
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / app / src / Services / ImportService.php

ImportService.php in Depicter — Popup & Slider Builder trunk, at app/src/Services/ImportService.php

236 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Depicter\Services;
3
4 use Averta\WordPress\Utility\JSON;
5 use Averta\WordPress\Utility\Sanitize;
6 use GuzzleHttp\Psr7\UploadedFile;
7
8 class ImportService
9 {
10
11 protected $importFolderName = 'import';
12
13 protected $assetsFolderName = 'assets';
14
15 /**
16 * Extract uploaded zip file and import slider
17 * @param $file
18 *
19 * @return bool
20 */
21 public function unpack( $file ) {
22
23 $wp_upload_dir = \Depicter::storage()->uploads();
24 $fileSystem = \Depicter::storage()->filesystem();
25
26 // Generate a randomized and unpredictable folder name for temporary extraction
27 $randomFolder = 'temp_import_' . wp_generate_password( 16, false, false );
28 $depicterUploadPath = \Depicter::storage()->getPluginUploadsDirectory() . '/';
29 $extractPath = $depicterUploadPath . $randomFolder . '/';
30
31 try {
32
33 if ( $file instanceof UploadedFile ) {
34 // Assign a random filename to the uploaded zip file instead of client filename
35 $randomZipName = 'import_' . wp_generate_password( 12, false, false ) . '.zip';
36 $uploadedZipFilePath = $depicterUploadPath . $randomZipName;
37
38 if ( !is_dir( $depicterUploadPath ) ) {
39 $fileSystem->mkdir( $depicterUploadPath );
40 }
41
42 // Move uploaded zip file to destination directory
43 $file->moveTo( $uploadedZipFilePath );
44
45 } else {
46 $uploadedZipFilePath = $file;
47 if ( ! $fileSystem->isFile( $file ) ) {
48 return false;
49 }
50 }
51
52 if ( !is_dir( $extractPath ) ) {
53 $fileSystem->mkdir( $extractPath );
54 }
55
56 $zipFile = new \ZipArchive();
57 if ( $zipFile->open( $uploadedZipFilePath ) === true ) {
58
59 // Secure extraction: prevents zip slip attacks and blocks dangerous file extensions
60 for ( $i = 0; $i < $zipFile->numFiles; $i++ ) {
61 $filename = $zipFile->getNameIndex( $i );
62 $ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
63
64 // Ignore executable or dangerous files
65 if ( in_array( $ext, [ 'php', 'php3', 'php4', 'php5', 'phtml', 'htaccess', 'phar' ], true ) ) {
66 continue;
67 }
68
69 // Prevent Zip Slip / Path Traversal vulnerability
70 if ( strstr( $filename, '../' ) !== false || strstr( $filename, '..\\' ) !== false ) {
71 continue;
72 }
73
74 $zipFile->extractTo( $extractPath, array( $filename ) );
75 }
76
77 $zipFile->close();
78 } else {
79 throw new \Exception('Failed to open zip archive.');
80 }
81
82 $importedAssetIDs = $this->importAssets( $fileSystem, $wp_upload_dir, $extractPath );
83 $sliderID = $this->importSlider( $importedAssetIDs, $extractPath );
84
85 // Cleanup temporary zip file and extract directory
86 if ( $file instanceof UploadedFile && file_exists( $uploadedZipFilePath ) ) {
87 wp_delete_file( $uploadedZipFilePath );
88 }
89 $fileSystem->rmdir( $extractPath, true );
90
91 if ( \Depicter::options()->get('use_google_fonts', 'on') === 'save_locally' ) {
92 $documentModel = \Depicter::document()->getModel( $sliderID )->prepare();
93 \Depicter::googleFontsService()->download( $documentModel->getFontsLink() );
94 }
95
96 return $sliderID;
97
98 } catch( \Exception $e ) {
99 // Ensure cleanup occurs even if an exception is thrown
100 if ( isset( $uploadedZipFilePath ) && $file instanceof UploadedFile && file_exists( $uploadedZipFilePath ) ) {
101 wp_delete_file( $uploadedZipFilePath );
102 }
103 if ( isset( $extractPath ) && is_dir( $extractPath ) ) {
104 $fileSystem->rmdir( $extractPath, true );
105 }
106 return false;
107 }
108 }
109
110 /**
111 * Import available assets inside assets directory
112 * @param $fileSystem
113 * @param $uploadDirectory
114 * @param string $extractPath
115 *
116 * @return array $importedIDs
117 */
118 protected function importAssets( $fileSystem, $uploadDirectory, $extractPath = '' ) {
119 $allowedMimeTypes = array_values( get_allowed_mime_types() );
120 $importedIDs = [];
121
122 $assetsDir = $extractPath . $this->assetsFolderName;
123
124 // Scan assets directory to import assets
125 $assets = $fileSystem->scan( $assetsDir );
126 if ( $assets ) {
127 foreach( $assets as $asset ) {
128 $assetMimeType = wp_check_filetype( $asset['name'] )['type'];
129 if ( !in_array( $assetMimeType, $allowedMimeTypes, true ) ) {
130 continue;
131 }
132 $sanitizedFileName = Sanitize::fileName( $asset['name'] );
133
134 $fileSystem->move( $assetsDir . '/' . $asset['name'], $uploadDirectory->getPath() . "/" . $sanitizedFileName );
135 $attachmentTitle = preg_replace( '/\.[^.]+$/', '', $sanitizedFileName );
136 $attachment = array(
137 'guid' => $uploadDirectory->getUrl() . '/' . $sanitizedFileName,
138 'post_mime_type' => $assetMimeType,
139 'post_title' => $attachmentTitle,
140 'post_content' => '',
141 'post_status' => 'inherit'
142 );
143
144 $attachID = wp_insert_attachment( $attachment, $uploadDirectory->getPath() . "/" . $sanitizedFileName );
145 if ( !is_wp_error( $attachID ) ) {
146 // Generate meta data for the inserted attachment
147 $attachment_metadata = wp_generate_attachment_metadata( $attachID, $uploadDirectory->getPath() . "/" . $sanitizedFileName );
148 wp_update_attachment_metadata( $attachID, $attachment_metadata );
149 update_attached_file( $attachID, $uploadDirectory->getPath() . "/" . $sanitizedFileName );
150
151 $attachmentTitleParts = explode( '-', $attachmentTitle );
152 $oldID = end( $attachmentTitleParts );
153 $importedIDs[ $oldID ] = $attachID;
154 }
155 }
156 }
157
158 return $importedIDs;
159 }
160
161 /**
162 * Import Slider
163 *
164 * @param $importedIDs
165 * @param string $extractPath
166 *
167 * @return mixed|null
168 * @throws \Exception
169 */
170 protected function importSlider( $importedIDs, $extractPath = '' ) {
171 $dataPath = $extractPath . 'data.json';
172
173 if ( !\Depicter::storage()->filesystem()->exists( $dataPath ) ) {
174 throw new \Exception('data.json not found in zip package.');
175 }
176
177 $data = \Depicter::storage()->filesystem()->read( $dataPath );
178 $dataArray = JSON::decode( $data, true );
179 $oldUploadURL = '';
180 $jsonAssets = "";
181
182 if ( ! isset( $dataArray['lastId'] ) ) {
183 $content = $dataArray['content'];
184 $type = $dataArray['type'] ?? 'custom';
185 $oldUploadURL = $dataArray['uploadURL'];
186 $jsonAssets = $dataArray['jsonAssets'];
187
188 } else {
189 $content = $data;
190 $type = 'custom';
191 }
192
193 $content = preg_replace( '/"activeBreakpoint":".+?"/', '"activeBreakpoint":"default"', $content );
194 preg_match_all( '/\"(source|src)\":\"(\d+)\"/', $content, $assets, PREG_SET_ORDER );
195 if ( !empty( $assets ) ) {
196 foreach( $assets as $asset ) {
197 if ( !empty( $asset[2] ) && !empty( $importedIDs[ $asset[2] ] ) ) {
198 $content = str_replace( $asset[0], '"' . $asset[1] . '":"'. $importedIDs[ $asset[2] ] .'"', $content );
199 }
200 }
201 }
202
203 preg_match_all( '/"src":\{[^\}]+\}/', $content, $backgroundImages, PREG_SET_ORDER );
204 if ( ! empty( $backgroundImages ) ) {
205 foreach( $backgroundImages as $backgroundImage ) {
206 if ( ! empty( $backgroundImage[0] ) ) {
207 $newBackgroundImage = $backgroundImage[0];
208 $patterns = [ '"default":"(\d+)"','"tablet":"(\d+)"','"mobile":"(\d+)"'];
209 foreach( $patterns as $pattern ) {
210 if ( preg_match( '/' . $pattern . '/', $backgroundImage[0], $asset ) ) {
211 $convertMedia = str_replace( $asset[1], $importedIDs[ $asset[1] ], $asset[0] );
212 $newBackgroundImage = str_replace( $asset[0], $convertMedia, $newBackgroundImage);
213 }
214 }
215 $content = str_replace( $backgroundImage[0], $newBackgroundImage, $content );
216 }
217 }
218 }
219
220 if ( !empty( $oldUploadURL ) && ! empty( $jsonAssets ) ) {
221 $oldUploadURL = str_replace( "/", "\\\\\\/", $oldUploadURL );
222 $pattern = "/$oldUploadURL\\\\\\/\\d+\\\\\\/\\d+\d+/";
223 $newUploadURL = str_replace( "/", "\\\\\\/", \Depicter::storage()->uploads()->getUrl() );
224 $content = preg_replace( $pattern, $newUploadURL, $content );
225 }
226
227 $document = \Depicter::documentRepository()->create();
228 $document->update([
229 'content' => $content,
230 'status' => 'publish',
231 'type' => $type
232 ]);
233
234 return $document->id;
235 }
236 }