Я создаю веб-приложение, которое включает обычную загрузку и извлечение файлов (PDF-файлы, документы Word и т. Д.).
Вот требования:
- необходимо иметь возможность ссылаться на них в моем скрипте вида, чтобы пользователь мог загружать файлы.
- не должны быть доступны пользователям, не вошедшим в систему.
Вопрос № 1: Где мне хранить эти файлы?
В файловой системе?
- Означает ли это каталог
uploads
в моем каталоге public
?
- Я также хочу, чтобы мне было легко развернуть новую версию моего приложения после внесения изменений в код. В настоящее время у меня есть процесс, когда я загружаю свое приложение в каталог с текущей датой (т.е.
2009-12-01
) и создаю ссылку на него с названием current
. Это будет означать, что каталог uploads
должен находиться за пределами этого каталога, чтобы его можно было использовать для всех различных версий приложения, независимо от того, какая из них используется в данный момент.
В базе данных?
- Я мог бы хранить содержимое файла в базе данных и подавать его, когда пользователь запрашивает их загрузку. Это защитит файлы в моем приложении от неавторизованных пользователей, но я смогу достичь того же результата, когда создам контроллер для этой работы.
- Это решит проблему с символьной ссылкой.
- Однако это может быть плохой практикой (хранение содержимого файла в базе данных в дополнение к информации).
Как вы думаете, что я должен делать?
Решение:
Вот что я в итоге сделал:
Я развертываю новую версию своего приложения и создаю символическую ссылку на версию, которую я хотел бы использовать:
/server/myapp/releases/2009-12-15
/server/myapp/current -> /server/myapp/releases/2009-12-15
Я создал каталог над каталогом своего приложения и в нем указала символическая ссылка на этот каталог:
/server/uploads
/server/myapp/current/application/data/uploads -> /server/uploads
Я определил переменную APPLICATION_UPLOADS_DIR
в своем файле /public/index.php
:
// Define path to uploads directory
defined('APPLICATION_UPLOADS_DIR')
|| define('APPLICATION_UPLOADS_DIR', realpath(dirname(__FILE__) . '/../data/uploads'));
И использовал эту переменную в моей форме загрузки, чтобы установить каталог для загрузки:
<?php
class Default_Form_UploadFile extends Zend_Form
{
public function init()
{
//excerpt
$file = new Zend_Form_Element_File('file');
$file->setLabel('File to upload:')
->setRequired(true)
->setDestination(APPLICATION_UPLOADS_DIR);
}
}
В моем контроллере я переименовываю файл во что-то уникальное, чтобы он не мог быть перезаписан файлом с тем же именем. Я сохраняю уникальное имя файла, исходное имя файла и mime-тип в базе данных, чтобы использовать его позже:
public function uploadAction()
{
//...excerpt...form has already been validated
$originalFilename = pathinfo($form->file->getFileName());
$newFilename = 'file-' . uniqid() . '.' . $originalFilename['extension'];
$form->file->addFilter('Rename', $newFilename);
try {
$form->file->receive();
//upload complete!
$file = new Default_Model_File();
$file->setDisplayFilename($originalFilename['basename'])
->setActualFilename($newFilename)
->setMimeType($form->file->getMimeType())
->setDescription($form->description->getValue());
$file->save();
return $this->_helper->FlashMessenger(array('success'=>'The file has been uploaded.'));
} catch (Exception $exception) {
//error
}
}
Для загрузки файлов я создал действие загрузки, которое извлекает файл и отправляет его пользователю с помощью Помощника действий SendFile от Noginn .
public function downloadAction()
{
//user already has permission to download the file
$this->_helper->layout()->disableLayout(); //won't work if you don't do this
$file = $this->_getFileFromRequest();
$location = APPLICATION_UPLOADS_DIR . '/' . $file->getActualFilename();
$mimeType = $file->getMimeType();
$filename = $file->getDisplayFilename();
$this->_helper->sendFile($location, $mimeType, array(
'disposition' => 'attachment',
'filename' => $filename
));
}
Чтобы предложить ссылку для скачивания в скрипте вида, я указываю на действие загрузки с параметром id файла:
<a href="<?php echo $this->url(array(
'controller'=>'files',
'action'=>'download',
'file'=>$file->id)); ?>"><?php echo $file->displayFilename; ?></a>
Вот и все! Если у вас есть другие советы или критические замечания по поводу этого метода, пожалуйста, оставьте свои ответы / комментарии.