Hello,
When using Directorist on Windows IIS hosted WordPress, file uploads are broken due to the use of wp_unslash() on lines 577 and 578 of includes/classes/class-add-listing.php. The result is a broken file path to the temp uploaded file. For example, the file C:\Program Files\PHPv8.1\upload\phpAC39.tmp loses all the slashes and ends up being C:Program FilesPHPv8.1uploadphpAC39.tmp. So when the file gets passed over to wp_handle_upload() it fails the validation because the temp_name is not a valid file path.
|
$files = ! empty( $_FILES['listing_img'] ) ? directorist_clean( wp_unslash( $_FILES['listing_img'] ) ) : array(); |
|
$files_meta = ! empty( $_POST['files_meta'] ) ? directorist_clean( wp_unslash( $_POST['files_meta'] ) ) : array(); |
Is it absolutely necessary to unslash the temp_name for the uploaded files? If you're really concerned about validating the values in the $file array ('name', 'tmp_name', 'type', etc.) I suggest writing validation that is specific for the array and then validate the value for each key instead of the brute-force approach of running the whole set of data through wp_unslash().
You can set up a simple validation using array_filter() to remove invalid files. In the example below, isFileUploadValid() is run for every uploaded file. If it returns true, the file is added to the resulting array, otherwise it is not, essentially cleaning out the invalid uploads.
/**
* Filter callback for use with array_filter(). Receives a file array. Ensures it has all the required keys and
* that all the values pass the required validations. Any arrays that fail, will be removed, thus that file will
* not be uploaded
*/
function isFileUploadValid(array $file): bool
{
// An array of keys that MUST be in the $file array
$validKeys = ['name', 'type', 'tmp_name', 'error', 'size',];
// Configure the validations you want to run on each key in $file. The keys in this array
// match the names of the keys in $file, the values are the names of callbacks you can
// set up to validate the key's value. They return true if the value passes, false otherwise
$validations = [
'name' => 'fileNameIsValid',
'type' => 'fileTypeIsValid',
'tmp_name' => 'fileTmpNameIsValid',
'error' => 'fileErrorIsValid',
'size' => 'fileSizeIsValid',
];
// Loop through the keys and make sure the $file array has all the ones we want
foreach ($validKeys as $key) {
if (!array_key_exists($key, $file)) {
return false;
}
}
// unset $key to avoid any cross-contamination from the previous foreach
unset($key);
// Loop through the validations and apply them to each value in $file
foreach($validations as $key => $callback) {
if (call_user_func($callback, $file[$key]) === false) {
return false;
}
}
// do any other validation you deem necessary
// return true if you get this far
return true;
}
/*
* Normalizes the $_FILES array. Necessary when multiple files are uploaded under the same input name, i.e.
* name="my_input[]". The result is a 2D array where the values for each key are arrays too.
* [
* 'my_input' => [
* 'name' => [
* 'somefile.jpg',
* 'somefile2.jpg',
* ],
* 'type' => [
* 'image/jpg',
* 'image/jpg',
* ],
* // etc.
* ]
* ]
* This function returns a 2D array that looks like this:
* [
* 'my_input_0' => [
* 'name' => 'somefile.jpg',
* 'type' => 'image/jpg',
* // etc.
* ],
* 'my_input_1' => [
* 'name' => 'somefile2.jpg',
* 'type' => 'image/jpg',
* // etc.
* ],
* ]
*/
function normalizeFiles(array $files): array
{
$returnArray = [];
foreach ($files as $file => $fileData) {
foreach ($fileData as $fileKey => $fileKeyValues) {
if (is_array($fileKeyValues)) {
foreach ($fileKeyValues as $index => $value) {
$fileName = "{$file}_$index";
if (!array_key_exists($fileName, $returnArray)) {
$returnArray[$fileName] = [];
}
$returnArray[$fileName][$fileKey] = $value;
}
} elseif (is_scalar($fileKeyValues)) {
if (!array_key_exists($file, $returnArray)) {
$returnArray[$file] = [];
}
$returnArray[$file][$fileKey] = $fileKeyValues;
}
}
}
return $returnArray;
}
// In the event that you have multiple files uploaded, you'll need to normalize the $_FILES array
$filesToValidate = normalizeFiles($_FILES);
$validUploads = array_filter($filesToValidate, isFileUploadValid);
// continue uploading the file to the DB
Hello,
When using Directorist on Windows IIS hosted WordPress, file uploads are broken due to the use of
wp_unslash()on lines 577 and 578 of includes/classes/class-add-listing.php. The result is a broken file path to the temp uploaded file. For example, the fileC:\Program Files\PHPv8.1\upload\phpAC39.tmploses all the slashes and ends up beingC:Program FilesPHPv8.1uploadphpAC39.tmp. So when the file gets passed over towp_handle_upload()it fails the validation because the temp_name is not a valid file path.directorist/includes/classes/class-add-listing.php
Line 577 in 362c2fa
directorist/includes/classes/class-add-listing.php
Line 578 in 362c2fa
Is it absolutely necessary to unslash the temp_name for the uploaded files? If you're really concerned about validating the values in the
$filearray ('name', 'tmp_name', 'type', etc.) I suggest writing validation that is specific for the array and then validate the value for each key instead of the brute-force approach of running the whole set of data throughwp_unslash().You can set up a simple validation using
array_filter()to remove invalid files. In the example below,isFileUploadValid()is run for every uploaded file. If it returns true, the file is added to the resulting array, otherwise it is not, essentially cleaning out the invalid uploads.