Creating dynamic Upload Folder

I created a dynamic upload folder script. When I added a sql query to obtain a value from a parent table the script failed. Any suggestions:

// Row Inserting event
function Row_Inserting($rsold, &$rsnew)
{

    // Ensure DrawingSetID exists in the new row data (rsnew) and is not null
    $DrawingSetID = $rsnew['DrawingSetID'] ?? null;

    if (!is_null($DrawingSetID)) {
        // Query to get the ProjectID from tblProject_DrawingSet
        $row = ExecuteRow("SELECT ProjectID FROM tblProject_DrawingSet WHERE DrawingSetID = ?");

        if ($row && isset($row['ProjectID'])) {
            $ProjectID = $row['ProjectID'];

            // Customize the upload folder path dynamically using ProjectID
            $uploadFolderPath = UploadPath(true) . "projects/projectid_" . $ProjectID . "/cad_drawings/drawingsetid_" . $DrawingSetID . "/";

            // Set the file upload path for the "File" field
            $this->File->UploadPath = "projects/projectid_" . $ProjectID . "/cad_drawings/drawingsetid_" . $DrawingSetID . "/";

            // Check if the folder exists, if not create it
            if (!is_dir($uploadFolderPath)) {
                try {
                    if (!mkdir($uploadFolderPath, 0777, true)) {
                        throw new Exception("Failed to create directory: " . $uploadFolderPath);
                    }
                } catch (Exception $e) {
                    // Log the error (or handle it as required)
                    error_log($e->getMessage());
                    return false; // Cancel the row inserting if folder creation fails
                }
            }
        } else {
            // Log an error or handle the case where ProjectID is not found
            error_log("ProjectID not found for DrawingSetID: " . $DrawingSetID);
            return false; // Cancel the row inserting if ProjectID is not found
        }
    }

    // Return true to continue inserting the row, return false to cancel
    return true;
}

What I found is that the binding of the string to prevent sql injection is not working. When I switched to direct interpolation instead of a prepared statement the query functions and I was able to achieve the result I was looking for. Below is the final working code:

// Row Inserting event
function Row_Inserting($rsold, &$rsnew)
{
    // Ensure DrawingSetID exists in the new row data (rsnew) and is not null
    $DrawingSetID = $rsnew['DrawingSetID'] ?? null;

    if (!is_null($DrawingSetID)) {
        // Query to get the ProID from tblProject_DrawingSet
        $row = ExecuteRow("SELECT ProID FROM tblProject_DrawingSet WHERE DrawingSetID = $DrawingSetID");

        if ($row && isset($row['ProID'])) {
            $ProID = $row['ProID'];

            // Customize the upload folder path dynamically using ProID
            $uploadFolderPath = UploadPath(true) . "_amsuploads/projects/projectid_" . $ProID . "/cad_drawings/drawingsetid_" . $DrawingSetID . "/";

            // Set the file upload path for the "File" field
            $this->File->UploadPath = "_amsuploads/projects/projectid_" . $ProID . "/cad_drawings/drawingsetid_" . $DrawingSetID . "/";

            // Check if the folder exists, if not, create it
            if (!is_dir($uploadFolderPath)) {
                try {
                    if (!mkdir($uploadFolderPath, 0777, true) && !is_dir($uploadFolderPath)) {
                        throw new Exception("Failed to create directory: " . $uploadFolderPath);
                    }
                } catch (Exception $e) {
                    // Log the error (or handle it as required)
                    error_log($e->getMessage());
                    $this->setFailureMessage("Directory creation failed: " . $e->getMessage());
                    return false; // Cancel the row inserting if folder creation fails
                }
            }
        } else {
            // Log an error or handle the case where ProID is not found
            error_log("Project ID not found for DrawingSetID: " . $DrawingSetID);
            $this->setFailureMessage("Project ID not found for DrawingSetID: " . $DrawingSetID);
            return false; // Cancel the row inserting if ProID is not found
            }
    } else {
        $this->setFailureMessage("DrawingSetID is required.");
        return false; // Cancel the row inserting if DrawingSetID is not provided
    }

    // Return true to continue inserting the row, return false to cancel
    return true;
}

i don’t see where you bound the parameter ?

My apologies, I pasted the wrong version of the earlier code. The code was bound in the following manner:

$row = ExecuteRow("SELECT ProjectID FROM tblProject_DrawingSet WHERE DrawingSetID = ?", [$DrawingSetID]);

When I generated the site it wouldn’t work. Once I removed the binding and replaced it with the variable it worked properly. In this case, there isn’t an opportunity for the used to inject any data.

you’re not binding correctly

// $conn instanceof Doctrine\DBAL\Connection
$sql = "SELECT * FROM articles WHERE id = ? AND status = ?";
$stmt = $conn->prepare($sql);
$stmt->bindValue(1, $id);
$stmt->bindValue(2, $status);
$resultSet = $stmt->executeQuery();

take a look at:

I need to upload and retieve files to dynamic folders.
Could you please provide some help how to achieve this.

Path to the folder is like this "path/".date("Y")."/".date("F")."/";
Eg. year/month: 2025/January

I created in database a field to store the path to the folder:
eg. “folder_path”
and also another field for file name
eg. “file_name”

Should I use code events to achieve this or is possible using “Fields” from PHPMAKER?

I tried the followings:

In the “Edit tag” → “Upload folder” I set the path:“path/”.date(“Y”).“/”.date(“F”).“/”
files are saved properly in database and I can NOT see them next month due to the fact that
date(“F”) display current month.

There is any way to save “Upload folder” in the code event?
How to have in the URL link correct path saved in database at “folder_path”

I tried also with
$uploadFolderPath = "path/".date("Y")."/".date("F")."/";
in

function Row_Inserting($rsold, &$rsnew) {
	// Enter your code here
	// To cancel, set return value to FALSE
$uploadFolderPath = path/".date("Y")."/".date("F")."/";
	return TRUE;
}

But files are not saved in this path: path/".date("Y")."/".date("F")."/";
but are saved in in the upload folder mentioned in the tab PHP-> General options

  1. You should not use ";" when you set the upload paths in the UI.
  2. You should not use date("Y") and date("F") as part of the upload path because the values (years and months) are different when you save the file and when you retrieve the file later.
  3. If you must use years and months as upload paths, you need to prepend the path to the file name. (v2025 only)

So there is a way to save file in dynamic folders with date in path and retrieve them correctly? Is this possbile in version V2023 or V2024?

Do you have an example or documentation of what you mean with prepend the path to the file name? (v2025 only)

I have issue in retrieving the file. Saving it is clear and easy.

For Retrieving Files I need to the stored dynamic path from database to generate the URL. Where this URL can be changed, generated. I assume somewhere in Code Snippet (Server Events…

You may read Error for Upload files - Path traversal detected - #11 by Webmaster.

I didnt see a way to retrieve correct dynamic path just to upload files to dymanic folder. Can the path be modified somewhere in code Code Snippet (Server Events?
Thank you!

I’m using v2024. I decided to deviate from the above code and used the following structure in the “Upload folder” of the the “Edit Tag”

"/_amsuploads/assets/assetID_" . $this->AssetID->CurrentValue . "/files/"

This makes it work in all views as long as you use the absolute path.

1 Like