PluginProbe
Contact Forms by Cimatti / 1.9.2
Contact Forms by Cimatti v1.9.2
2.3.6 2.3.5 2.3.0 2.2.32 2.2.4 2.2.0 2.1.2 2.1.1 trunk 1.0 1.1 1.2 1.2.1 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 All 62 releases
← All changes | classes/Element/File.php +38 -147 2.3.61.9.2 View file →
@@ -1,43 +1,24 @@
1 1 <?php
2 2 class AccuaForm_Element_File extends Element_File {
3 3 protected $destPath;
4 4 protected $alreadySubmittedText;
5 - // Modern default extensions: documents, images, archives
6 - protected $validExtensions = array(
7 - // Documents
8 - 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'ods', 'odp', 'txt', 'rtf', 'csv',
9 - // Images
10 - 'jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'heic',
11 - // Archives
12 - 'zip', 'rar', '7z', 'tar', 'gz'
13 - );
14 - protected $maxSize; protected $limitsText;
5 + protected $validExtensions = array('txt','doc','rtf','pdf','jpg','jpeg','png','zip','gz','bz','bz2');
6 + protected $maxSize;
7 + protected $limitsText;
15 8 protected $errorsText;
16 - public function __construct($label, $name, ?array $properties = null) {
17 - $this->alreadySubmittedText = __( "File already submitted.", 'contact-forms' );
18 - // translators: %size% and %extensions% are custom placeholders replaced via str_replace(), not sprintf().
19 - $this->limitsText = __( 'Maximum filesize: %size%. Allowed extensions: %extensions%.', 'contact-forms' ); // phpcs:ignore WordPress.WP.I18n.UnorderedPlaceholdersText -- Custom placeholders used with str_replace(), not sprintf()
9 +
10 + public function __construct($label, $name, array $properties = null) {
11 + $this->alreadySubmittedText = __("File already submitted.", 'contact-forms');
12 + $this->limitsText = __("Maximum filesize: %size%. Allowed extensions: %extensions%.", 'contact-forms');
20 13 $this->errorsText = array(
21 - 'upload' => __( 'Upload failed, please retry. If the problem persists please contact us', 'contact-forms' ),
22 - 'size' => __( 'Uploaded file is too big', 'contact-forms' ),
23 - 'empty' => __( 'Uploaded file is empty', 'contact-forms' ),
24 - 'name' => __( 'File name is not valid. Please rename it avoiding unusual characters', 'contact-forms' ),
25 - // translators: %extensions% is a custom placeholder replaced via str_replace().
26 - 'ext' => __( 'File extension not allowed. Allowed extensions are %extensions%', 'contact-forms' ),
14 + 'upload' => __('Upload failed, please retry. If the problem persists please contact us', 'contact-forms'),
15 + 'size' => __('Uploaded file is too big', 'contact-forms'),
16 + 'empty' => __('Uploaded file is empty', 'contact-forms'),
17 + 'name' => __('File name is not valid. Please rename it avoiding unusual characters', 'contact-forms'),
18 + 'ext' => __('File extension not allowed. Allowed extensions are %extensions%', 'contact-forms'),
27 19 );
28 -
29 - // Use WordPress upload directory function instead of hardcoded path
30 - $wp_upload_dir = wp_upload_dir();
31 - $accua_upload_dir = $wp_upload_dir['basedir'] . '/accua-forms';
32 -
33 - // Create directory if it doesn't exist using WordPress function
34 - if (!file_exists($accua_upload_dir)) {
35 - wp_mkdir_p($accua_upload_dir);
36 - }
37 -
38 - // Use trailingslashit to ensure path ends with a slash
39 - $this->destPath = trailingslashit($accua_upload_dir);
20 + $this->destPath = realpath(ABSPATH . '/wp-content/uploads/accua-forms').'/';
40 21 $this->maxSize = self::file_upload_max_size();
41 22 parent::__construct($label, $name, $properties);
42 23 }
43 24
@@ -46,10 +27,9 @@
46 27 }
47 28
48 29 public function render() {
49 30 if(empty($this->attributes["value"])){
50 - // Build help text for limits
51 - $helpText = '';
31 + parent::render();
52 32 if ($this->limitsText !== ''){
53 33 if ($this->validExtensions) {
54 34 $validExtensions = implode(', ', $this->validExtensions);
55 35 } else {
@@ -55,63 +35,13 @@
55 35 } else {
56 36 $validExtensions = '*';
57 37 }
58 38 $search = array('%size%', '%extensions%');
59 - $replace = array(self::format_size($this->maxSize), $validExtensions);
60 - $helpText = str_replace($search, $replace, $this->limitsText);
39 + $replace = array(self::format_size($this->maxSize),$validExtensions);
40 + echo '<br /><small>', str_replace($search, $replace, $this->limitsText), '</small>';
61 41 }
62 -
63 - // Build accept attribute for file extensions
64 - $acceptAttr = '';
65 - if ($this->validExtensions && is_array($this->validExtensions)) {
66 - $acceptAttr = '.' . implode(',.', $this->validExtensions);
67 - }
68 -
69 - // Generate unique IDs for ARIA associations
70 - $inputId = esc_attr($this->getID() ?: 'accua-file-' . $this->getName());
71 - $helpId = $inputId . '-help';
72 - $announceId = $inputId . '-announce';
73 -
74 - // Open wrapper with data attributes for JS
75 - echo '<div class="accua-file-upload-wrapper" data-max-size="' . esc_attr($this->maxSize) . '" data-accept="' . esc_attr($acceptAttr) . '">';
76 -
77 - // Dropzone container
78 - echo '<div class="accua-file-dropzone" role="button" tabindex="0" ';
79 - echo 'aria-describedby="' . esc_attr($helpId) . '" ';
80 - echo 'aria-dropeffect="none">';
81 -
82 - // Visual content for dropzone
83 - echo '<span class="accua-file-dropzone-text">';
84 - echo '<span class="accua-file-dropzone-icon" aria-hidden="true">📁</span> ';
85 - echo esc_html__('Drag & drop file here or', 'contact-forms') . ' ';
86 - echo '<span class="accua-file-browse-btn">' . esc_html__('browse', 'contact-forms') . '</span>';
87 - echo '</span>';
88 -
89 - // Set accept attribute on native file input for browser file picker filtering
90 - if ($acceptAttr !== '') {
91 - $this->attributes['accept'] = $acceptAttr;
92 - }
93 -
94 - // Hidden native file input (for accessibility and form submission)
95 - parent::render();
96 -
97 - echo '</div>'; // .accua-file-dropzone
98 -
99 - // Help text
100 - if ($helpText !== '') {
101 - echo '<p class="pfbc-help" id="' . esc_attr($helpId) . '">' . esc_html($helpText) . '</p>';
102 - }
103 -
104 - // File list container (populated by JS)
105 - echo '<div class="accua-file-list" hidden aria-live="polite" aria-relevant="additions removals"></div>';
106 -
107 - // Screen reader announcement region
108 - echo '<div class="accua-file-sr-announcement" id="' . esc_attr($announceId) . '" aria-live="polite" aria-atomic="true" class="screen-reader-text"></div>';
109 -
110 - echo '</div>'; // .accua-file-upload-wrapper
111 -
112 42 } else {
113 - echo esc_html($this->alreadySubmittedText);
43 + echo $this->alreadySubmittedText;
114 44 }
115 45 }
116 46
117 47 public function getAlreadySubmittedText() {
@@ -117,16 +47,8 @@
117 47 public function getAlreadySubmittedText() {
118 48 return $this->alreadySubmittedText;
119 49 }
120 50
121 - public function hasHelpText() {
122 - return !empty($this->limitsText);
123 - }
124 -
125 - public function appendToPostHTML($html) {
126 - $this->postHTML = ($this->postHTML ?? '') . $html;
127 - }
128 -
129 51 public static function format_size($size) {
130 52 if ($size >= 1073741824) {
131 53 return round($size/1073741824, 2).' GB';
132 54 } else if ($size >= 1048576) {
@@ -174,34 +96,17 @@
174 96 if(is_array($errors)) {
175 97 $this->errorsText = $errors + $this->errorsText;
176 98 }
177 99 }
178 - public function setDestPath($path) {
179 - // Check if path is absolute BEFORE normalizing (path_is_absolute handles both Unix and Windows)
180 - $is_absolute = path_is_absolute($path);
181 -
182 - // Normalize path separators for consistent handling
183 - $path = wp_normalize_path($path);
184 -
185 - // Handle relative paths by prepending ABSPATH
186 - if (!$is_absolute) {
187 - $path = path_join(ABSPATH, $path);
100 +
101 + public function setDestPath($path) {
102 + if (substr($path,0,1) !== '/') {
103 + $path = ABSPATH . '/' . $path;
188 104 }
189 -
190 - // Create directory with proper WordPress function and secure permissions
191 - if (!file_exists($path)) {
192 - wp_mkdir_p($path);
105 + if (!is_dir($path)){
106 + @ mkdir($path, 0777, true);
193 107 }
194 -
195 - // Verify the directory exists and is writable
196 - if (!is_dir($path) || !wp_is_writable($path)) {
197 - // Fall back to WordPress uploads directory if target path is not writable
198 - $upload_dir = wp_upload_dir();
199 - $path = $upload_dir['basedir'] . '/accua-forms';
200 - wp_mkdir_p($path);
201 - }
202 -
203 - return $this->destPath = trailingslashit($path);
108 + return $this->destPath = realpath($path) . '/';
204 109 }
205 110
206 111 public function handle_upload($filedata){
207 112 $valid = true;
@@ -236,10 +141,9 @@
236 141 $file['errors'][] = $this->errorsText['name'];
237 142 } else if ($this->validExtensions) {
238 143 $ext = strrchr($file['name'], '.');
239 144 $ext = ($ext === false) ? '' : strtolower(ltrim($ext, '.'));
240 - $valid_ext_lower = array_map('strtolower', $this->validExtensions);
241 - if (!in_array($ext, $valid_ext_lower, true)) {
145 + if (!in_array($ext, $this->validExtensions, true)) {
242 146 $valid = false;
243 147 $file['errors'][] = str_replace('%extensions%', implode(', ',$this->validExtensions), $this->errorsText['ext']);
244 148 }
245 149 }
@@ -249,36 +153,23 @@
249 153 $valid = false;
250 154 $file['errors'][] = $this->errorsText['name'];
251 155 }
252 156 }
157 +
158 + if ($valid) {
159 + if (!is_dir($this->destPath)){
160 + @ mkdir($this->destPath, 0777, true);
161 + }
162 +
163 + do {
164 + $tmpname = 'tmp' . mt_rand() . '_' . $file['name'];
165 + } while (is_file($this->destPath.$tmpname));
166 +
167 + @ $valid = move_uploaded_file($filedata['tmp_name'], $this->destPath.$tmpname);
253 168 if ($valid) {
254 - // Additional security check - validate MIME type
255 - $file_info = wp_check_filetype_and_ext($filedata['tmp_name'], $file['name']);
256 - if (empty($file_info['type'])) {
257 - $valid = false;
258 - $file['errors'][] = __('Invalid file type detected', 'contact-forms');
169 + $file['tmp_name'] = $tmpname;
259 170 } else {
260 - // Make sure destination directory exists
261 - if (!is_dir($this->destPath)) {
262 - wp_mkdir_p($this->destPath);
263 - }
264 -
265 - // Generate a unique filename with sanitization
266 - do {
267 - $tmpname = 'tmp' . wp_generate_password(8, false) . '_' . sanitize_file_name($file['name']);
268 - } while (is_file($this->destPath.$tmpname));
269 -
270 - // Move uploaded file
271 - // phpcs:ignore Generic.PHP.ForbiddenFunctions.Found -- move_uploaded_file is required for file uploads, no WP alternative
272 - $valid = move_uploaded_file($filedata['tmp_name'], $this->destPath.$tmpname);
273 - if ($valid) {
274 - $file['tmp_name'] = $tmpname;
275 - // Set proper file permissions
276 - // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod -- Direct chmod needed for upload permissions
277 - chmod($this->destPath.$tmpname, 0644);
278 - } else {
279 - $file['errors'][] = $this->errorsText['upload'];
280 - }
171 + $file['errors'][] = $this->errorsText['upload'];
281 172 }
282 173
283 174 }
284 175