The "exists file from archive in project" check was flawed because

$name was overwritten. So, this was fixed by adding a special
functionality when archive files are uploaded that replace existing
files with equal names; these are now deleted. This is docuemented
more clearly in the FAQ and it is also documented now that files
in the archive that are not listed in the manifest are not extracted.
This commit is contained in:
Thomas Keller 2011-11-19 01:13:22 +01:00
parent ba365af020
commit ff2b19d587
2 changed files with 48 additions and 28 deletions

View File

@ -58,13 +58,13 @@ class IDF_Form_UploadArchive extends Pluf_Form
$this->archiveHelper->validate(); $this->archiveHelper->validate();
// extension validation // extension validation
$names = $this->archiveHelper->getEntryNames(); $fileNames = $this->archiveHelper->getEntryNames();
foreach ($names as $name) { foreach ($fileNames as $fileName) {
$extra = strtolower(implode('|', explode(' ', Pluf::f('idf_extra_upload_ext')))); $extra = strtolower(implode('|', explode(' ', Pluf::f('idf_extra_upload_ext'))));
if (strlen($extra)) $extra .= '|'; if (strlen($extra)) $extra .= '|';
if (!preg_match('/\.('.$extra.'png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|jar|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|war|wmv|zip)$/i', $name)) { if (!preg_match('/\.('.$extra.'png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|jar|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|war|wmv|zip)$/i', $fileName)) {
@unlink(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['file']); @unlink(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['archive']);
throw new Pluf_Form_Invalid(sprintf(__('For security reasons, you cannot upload a file (%s) with this extension.'), $name)); throw new Pluf_Form_Invalid(sprintf(__('For security reasons, you cannot upload a file (%s) with this extension.'), $fileName));
} }
} }
@ -78,8 +78,8 @@ class IDF_Form_UploadArchive extends Pluf_Form
} }
} }
foreach ($names as $name) { foreach ($fileNames as $fileName) {
$meta = $this->archiveHelper->getMetaData($name); $meta = $this->archiveHelper->getMetaData($fileName);
$count = array(); $count = array();
foreach ($meta['labels'] as $label) { foreach ($meta['labels'] as $label) {
$label = trim($label); $label = trim($label);
@ -100,12 +100,13 @@ class IDF_Form_UploadArchive extends Pluf_Form
} }
} }
$sql = new Pluf_SQL('file=%s AND project=%s', array($name, $this->project->id)); $sql = new Pluf_SQL('file=%s AND project=%s', array($fileName, $this->project->id));
$upload = Pluf::factory('IDF_Upload')->getOne(array('filter' => $sql->gen())); $upload = Pluf::factory('IDF_Upload')->getOne(array('filter' => $sql->gen()));
if ($upload) { $meta = $this->archiveHelper->getMetaData($fileName);
if ($upload != null && $meta['replaces'] !== $fileName) {
throw new Pluf_Form_Invalid( throw new Pluf_Form_Invalid(
sprintf(__('A file with the name "%s" has already been uploaded.'), $name)); sprintf(__('A file with the name "%s" has already been uploaded and is not marked to be replaced.'), $fileName));
} }
} }
@ -158,6 +159,24 @@ class IDF_Form_UploadArchive extends Pluf_Form
} }
} }
// process a possible replacement
if (!empty($meta['replaces'])) {
$sql = new Pluf_SQL('file=%s AND project=%s', array($meta['replaces'], $this->project->id));
$oldUpload = Pluf::factory('IDF_Upload')->getOne(array('filter' => $sql->gen()));
if ($oldUpload) {
if ($meta['replaces'] === $fileName) {
$oldUpload->delete();
} else {
$tags = $this->project->getTagsFromConfig('labels_download_predefined',
IDF_Form_UploadConf::init_predefined);
// the deprecate tag is - by definition - always the last one
$deprecatedTag = array_pop($tags);
$oldUpload->setAssoc($deprecatedTag);
}
}
}
// extract the file // extract the file
$this->archiveHelper->extract($fileName, $uploadDir); $this->archiveHelper->extract($fileName, $uploadDir);
@ -175,19 +194,6 @@ class IDF_Form_UploadArchive extends Pluf_Form
$upload->setAssoc($tag); $upload->setAssoc($tag);
} }
// process a possible replacement
if (!empty($meta['replaces'])) {
$sql = new Pluf_SQL('file=%s AND project=%s', array($meta['replaces'], $this->project->id));
$oldUpload = Pluf::factory('IDF_Upload')->getOne(array('filter' => $sql->gen()));
if ($oldUpload) {
$tags = $this->project->getTagsFromConfig('labels_download_predefined',
IDF_Form_UploadConf::init_predefined);
// the deprecate tag is - by definition - always the last one
$deprecatedTag = array_pop($tags);
$oldUpload->setAssoc($deprecatedTag);
}
}
// send the notification // send the notification
$upload->notify($this->project->getConf()); $upload->notify($this->project->getConf());
/** /**

View File

@ -25,8 +25,9 @@ contain an additional manifest file which describes the files that should be pub
<p> <p>
Once such an archive has been uploaded and validated by InDefero, its files are extracted Once such an archive has been uploaded and validated by InDefero, its files are extracted
and individual downloads are created for each of them. If the archive contains files and individual downloads are created for each of them. If the archive contains files
that should deprecate existing downloads, then InDefero takes care of this as well - that should replace existing downloads, then InDefero takes care of this as well -
automatically. automatically. Files that exist in the archive but are not listed in the manifest are
not extracted.
</p> </p>
<p> <p>
@ -85,9 +86,22 @@ This is the DTD for the format:
<p> <p>
The format is more or less self-explaining, all fields map to properties of a single download. The format is more or less self-explaining, all fields map to properties of a single download.
One special element has been introduced though, <code>replaces</code>. If this optional element One special element has been introduced though, <code>replaces</code>. If this optional element
is given, InDefero looks for a file with that name in the project and deprecates it by attaching is given, InDefero looks for a file with that name in the project and acts in one of the following
the label <code>Other:Deprecated</code> to it. If no such file is found, the element is simply two ways:
ignored. </p>
<ul>
<li>If the new file's name is distinct from the file's name that is given in <code>replaces</code>,
then the replaced file is <strong>marked as deprecated</strong> with the <code>Other:Deprecated</code> label
(or any other label that is configured as the very last label in the download project configuration).</li>
<li>If the new file's name is equal to the file's name that is given in <code>replaces</code>,
then the replaced file <strong>is deleted</strong> before the new file is created. This happens because each file name
has to be unique per project and a deprecated and a new file with the same name cannot coexist in InDefero.
Note that while the filename-based URI of the download keeps intact, the download counter will be reset by
this procedure.</li>
</ul>
If no existing file is found for the <code>replaces</code> tag, then this is completely ignored.
</p> </p>
{/block} {/block}