4

I have a plugin Controller that accepts a POSTed form, including an uploaded file. If I make an Assets Source I can successfully save the file into its folder like this:

$file = UploadedFile::getInstanceByName('myFieldName');

$folder = craft()->assets->findFolder(array(
    'sourceId' => 3, // My Asset Source's ID.
));

$response = craft()->assets->insertFileByLocalPath(
    $file->getTempName(), // Local path to file.
    $file->getName(), // Name file should be given when saved.
    $folder->id,
    AssetConflictResolution::KeepBoth
);

if ($response->isSuccess()) {
    ...

However, I want to upload the file to a folder that's not an Asset Source - for security reasons I don't want these particular files to be visible in any way in the CMS. Is there a way to do this, eg, by using a filepath rather than an Asset Source?

(I'm also not sure how to validate the file, in terms of its file extension, size, etc. I can see how to do this in Yii but I'm not sure how to do it having uploaded the file as above.)

1 Answer 1

6

Ahh, a bit of fiddling and poking around later...

$file = UploadedFile::getInstanceByName('myFieldName');
$fileName = AssetsHelper::cleanAssetName($file->getName());

// Make fileName uniqueish by adding a timestamp to it.
$fileParts = explode(".", $fileName);
$extension = array_pop($fileParts);
$fileName = join(".", $fileParts) .'_'. time() .'.'. $extension;

$filePath = '/path/to/my/folder/' . $fileName;

$response = $file->saveAs($filePath);

Seems to work OK!

The unique filename stuff seems not entirely great. Might be better to see if the file exists first, and if so, make a new name.

Just need to work out how to validate my Model now...

UPDATE: Oh, that was quick. So now I do:

$post = craft()->request->getPost();
$myModel = MyForm_FilesModel::populateModel($post);

// All the file-handling stuff as above.

$myModel->myAttribute = $file;

if ($myModel->validate()) {
    ...

Where my model is something like:

<?php
namespace Craft;

class MyForm_FilesModel extends BaseModel
{
    protected function defineAttributes()
    {
        return array(
            'myAttribute' => array(AttributeType::Name),
        );
    }

    public function rules()
    {
        return array(
            array('UploadPassport', 'file',
            'allowEmpty' => false,
            'maxFiles' => 1,
            'maxSize' => 5 * 1000000, // 5MB
            'tooLarge' => 'Sorry, the maximum file size is 5MB',
            'types' => array('jpg', 'png', 'pdf'),
            'wrongType' => 'Files must be one of jpg, png or pdf',
            'message' => 'Please upload a file'),
        );
    }
}

(The defineAttributes() stuff feels very wrong, as this isn't a proper Craft model - I'm not saving any of this as an Entry etc defined in the Craft Admin. But I can't see how else to make this stuff work.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.