PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.4
1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk 1.2.0 All 47 releases
fluent-cart / app / Services / FileSystem / Drivers / Local / LocalDriver.php

LocalDriver.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.4, at app/Services/FileSystem/Drivers/Local/LocalDriver.php

266 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Services\FileSystem\Drivers\Local;
4
5 use FluentCart\App\App;
6 use FluentCart\App\Helpers\Helper;
7 use FluentCart\App\Modules\StorageDrivers\BaseStorageDriver;
8 use FluentCart\App\Modules\StorageDrivers\Local\Local as LocalStorageDriver;
9 use FluentCart\App\Services\FileSystem\Drivers\BaseDriver;
10 use FluentCart\App\Services\FileSystem\StoragePath;
11 use FluentCart\Framework\Support\Arr;
12 use FluentCart\Framework\Support\Str;
13
14 class LocalDriver extends BaseDriver
15 {
16 public function getDirName(): string
17 {
18 return $this->dirName;
19 }
20
21
22 public function __construct(?string $dirPath = null, ?string $dirName = null)
23 {
24 parent::__construct($dirPath, $dirName);
25 $this->dirName = $dirName ?? 'fluent-cart';
26 $this->dirPath = $dirPath ?? $this->getDefaultDirPath();
27 $this->storageDriver = new LocalStorageDriver();
28
29 global $wp_filesystem;
30
31 // Initialize the WP_Filesystem API
32 if (empty($wp_filesystem)) {
33 require_once ABSPATH . 'wp-admin/includes/file.php';
34 WP_Filesystem();
35 }
36
37 $this->ensureDirectoryExist();
38
39 }
40
41 protected function getDefaultDirPath(): string
42 {
43 return wp_get_upload_dir()['basedir'] . DIRECTORY_SEPARATOR . $this->getDirName();
44 }
45
46 private function ensureDirectoryExist() {
47
48
49 $uploadDirectory = $this->getDefaultDirPath();
50 global $wp_filesystem;
51 // Check if directory exists
52 if (! $wp_filesystem->is_dir($uploadDirectory)) {
53 $wp_filesystem->mkdir($uploadDirectory, FS_CHMOD_DIR);
54 }
55 }
56
57
58 public function listFiles(array $params = []): array
59 {
60 $filesArray = [];
61 $searchTerm = $params['search'] ?? '';
62
63 $files = scandir($this->getDefaultDirPath());
64
65 $maxFile = App::request()->get('per_page', 10);
66
67 $fileCount = 1;
68
69 foreach ($files as $file) {
70 // Skip hidden files (starting with dot)
71 if (str_starts_with($file, '.')) {
72 continue;
73 }
74
75 if (str_ends_with($file, '.php')) {
76 continue;
77 }
78
79 // Apply search filter if provided
80 if (!empty($searchTerm) && stripos($file, $searchTerm) === false) {
81 continue;
82 }
83
84 $filePath = $this->getDefaultDirPath() . '/' . $file;
85 if (is_file($filePath)) {
86 $filesArray[] = [
87 'name' => $file,
88 'size' => filesize($filePath),
89 'driver' => 'local',
90 'bucket' => ''
91 ];
92 }
93
94 $fileCount++;
95 if($fileCount > $maxFile) {
96 break;
97 }
98 }
99
100 return $filesArray;
101 }
102
103 public function uploadFile($localFilePath, $uploadToFilePath, $file, $params = [])
104 {
105 global $wp_filesystem;
106
107 $uploadToFilePath = sanitize_file_name($uploadToFilePath);
108
109
110 $fileInfo = $file->toArray();
111 $fileSize =Arr::get($fileInfo, 'size_in_bytes', 0);
112
113 $originalName = $file->getClientOriginalName();
114 $sanitizedName = sanitize_file_name($originalName);
115 $checked = wp_check_filetype_and_ext(
116 $localFilePath,
117 $sanitizedName
118 );
119
120
121 if (empty($checked['ext']) || empty($checked['type'])) {
122 return new \WP_Error(
123 'invalid_file_type',
124 __('Invalid or unsupported file type.', 'fluent-cart')
125 );
126 }
127
128 $blockedExts = ['php','phtml','html','htm','svg','exe','sh','bat','cmd','dll'];
129
130 $blockedExts = apply_filters('fluent_cart/local_file_blocked_extensions',$blockedExts,[
131 'localFilePath' => $localFilePath,
132 'uploadToFilePath' => $uploadToFilePath,
133 'fileInfo' => $fileInfo,
134 'fileSize' => $fileSize,
135 'originalName' => $originalName,
136 'file' => $file,
137 'checked_data' => $checked,
138 ]);
139 if (in_array($checked['ext'], $blockedExts, true)) {
140 return new \WP_Error(
141 'forbidden_type',
142 __('This file type is not allowed.', 'fluent-cart')
143 );
144 }
145
146 // Generate unique filename
147 $uploadToFilePath = $uploadToFilePath . '__fluent-cart__.' . time() . '.' . $file->getClientOriginalExtension();
148
149 // Define destination
150 $destination = trailingslashit( $this->getDefaultDirPath() ) . $uploadToFilePath;
151
152 // Read file contents from temp path
153 $contents = @file_get_contents( $localFilePath );
154
155 if ( $contents === false ) {
156 return new \WP_Error( 'failed_to_read', __( 'Failed to read uploaded file', 'fluent-cart' ) );
157 }
158
159 // Write file using WP_Filesystem
160 $isUploaded = $wp_filesystem->put_contents( $destination, $contents, FS_CHMOD_FILE );
161
162 // Optionally delete temp file using WP_Filesystem for compliance
163 if ( $wp_filesystem->exists( $localFilePath ) ) {
164 $wp_filesystem->delete( $localFilePath );
165 }
166
167 if ( ! $isUploaded ) {
168 return new \WP_Error( 'failed_to_upload', __( 'Failed to upload file', 'fluent-cart' ) );
169 }
170
171 return [
172 'message' => __( 'File Uploaded Successfully', 'fluent-cart' ),
173 'path' => $uploadToFilePath,
174 'file' => [
175 'driver' => 'local',
176 'size' => $fileSize,
177 'name' => $uploadToFilePath,
178 'bucket' => '',
179 ],
180 ];
181 }
182
183
184 public function getSignedDownloadUrl(string $filePath, $bucket = null, $productDownload = null): string
185 {
186 return Helper::generateDownloadFileLink($productDownload);
187 }
188
189 public function downloadFile(string $filePath, $fileName = null)
190 {
191 $fileName = sanitize_file_name($fileName);
192
193 $file = $this->getFilePath($filePath);
194 if (ob_get_level()) {
195 ob_end_clean();
196 }
197
198 // A path that escapes the storage directory reports as missing rather
199 // than as rejected, so this never answers whether a file outside the
200 // directory exists.
201 if (!$file || !file_exists($file)) {
202 return new \WP_Error('file_not_found', __('File not found', 'fluent-cart'));
203 }
204 $fileSize = filesize($file);
205 $fileName = $fileName ?? basename($filePath);
206 $fileName = explode('_____fluent-cart_____', $fileName)[0];
207 $fileName = explode('__fluent-cart__', $fileName)[0];
208 $this->setDownloadHeader($fileName ?? basename($filePath), $file, $fileSize);
209 global $wp_filesystem;
210 $content = $wp_filesystem->get_contents( $file );
211 if ( $content !== false ) {
212 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
213 echo $content;
214 }
215 exit;
216 }
217
218 /**
219 * Absolute path for a stored file, or '' when $filePath escapes the
220 * storage directory.
221 *
222 * `..` survives both sanitize_text_field() and wp_normalize_path(), so
223 * composing the path by concatenation alone let a relative path address any
224 * file the web user could reach.
225 */
226 public function getFilePath(string $filePath, $fileName = null): string
227 {
228 return StoragePath::contain($this->dirPath, $filePath);
229 }
230
231 protected function retrieveFileForDownload(string $downloadableFilePath)
232 {
233 // TODO: Implement retrieveFileForDownload() method.
234 }
235
236 public function deleteFile(string $filePath)
237 {
238
239 if ( !current_user_can('manage_options') ) {
240 return new \WP_Error('permission_error', __('You are not allowed to delete file', 'fluent-cart'));
241 }
242
243 $fullPath = $this->getFilePath($filePath);
244
245 // Same as the download path: an escaping path reports as missing so the
246 // response cannot be used to probe for files outside the directory.
247 if (!$fullPath || !file_exists($fullPath)) {
248 return new \WP_Error('file_not_found', __('File not found', 'fluent-cart'));
249 }
250
251 if (!is_file($fullPath)) {
252 return new \WP_Error('not_a_file', __('Path is not a file', 'fluent-cart'));
253 }
254
255 if (wp_delete_file($fullPath)) {
256 return [
257 'message' => __('File Deleted Successfully', 'fluent-cart'),
258 'driver' => 'local',
259 'path' => $filePath
260 ];
261 }
262
263 return new \WP_Error('failed_to_delete', __('Failed to delete file', 'fluent-cart'));
264 }
265 }
266