3 * FusionForge file release system
5 * Copyright 2002, Tim Perdue/GForge, LLC
6 * Copyright 2009, Roland Mas
7 * Copyright (C) 2012 Alain Peyrat - Alcatel-Lucent
8 * Copyright 2012-2014, Franck Villaume - TrivialDev
10 * This file is part of FusionForge. FusionForge is free software;
11 * you can redistribute it and/or modify it under the terms of the
12 * GNU General Public License as published by the Free Software
13 * Foundation; either version 2 of the Licence, or (at your option)
16 * FusionForge is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 require_once $gfcommon.'include/FFError.class.php';
29 * Factory method which creates a FRSFile from an file id
31 * @param int $file_id The file id
32 * @param array|bool $data The result array, if it's passed in
33 * @return object FRSFile object
35 function &frsfile_get_object($file_id, $data=false) {
37 if (!isset($FRSFILE_OBJ['_'.$file_id.'_'])) {
39 //the db result handle was passed in
41 $res = db_query_params('SELECT * FROM frs_file_vw WHERE file_id=$1', array($file_id));
42 if (db_numrows($res) < 1) {
43 $FRSFILE_OBJ['_'.$file_id.'_']=false;
46 $data = db_fetch_array($res);
48 $FRSRelease = frsrelease_get_object($data['release_id']);
49 $FRSFILE_OBJ['_'.$file_id.'_']= new FRSFile($FRSRelease,$data['file_id'], $data);
51 return $FRSFILE_OBJ['_'.$file_id.'_'];
54 class FRSFile extends FFError {
57 * Associative array of data from db.
59 * @var array $data_array.
66 * @var object FRSRelease.
71 * @param object $FRSRelease The FRSRelease object to which this file is associated.
72 * @param int|bool $file_id The file_id.
73 * @param array|bool $arr The associative array of data.
75 function __construct(&$FRSRelease, $file_id=false, $arr=false) {
76 parent::__construct();
77 if (!$FRSRelease || !is_object($FRSRelease)) {
78 $this->setError(_('Invalid FRS Release Object'));
81 if ($FRSRelease->isError()) {
82 $this->setError('FRSFile: '.$FRSRelease->getErrorMessage());
85 $this->FRSRelease =& $FRSRelease;
88 if (!$arr || !is_array($arr)) {
89 if (!$this->fetchData($file_id)) {
93 $this->data_array =& $arr;
94 if ($this->data_array['release_id'] != $this->FRSRelease->getID()) {
95 $this->setError('FRSRelease_id in db result does not match FRSRelease Object');
96 $this->data_array=null;
104 * create - create a new file in this FRSFileRelease/FRSPackage.
106 * @param string $name The name of this file.
107 * @param string $file_location The location of this file in the local file system.
108 * @param int $type_id The type_id of this file from the frs-file-types table.
109 * @param int $processor_id The processor_id of this file from the frs-processor-types table.
110 * @param int|bool $release_time The release_date of this file in unix time (seconds).
111 * @return bool success.
113 function create($name,$file_location,$type_id,$processor_id,$release_time=false) {
114 if (strlen($name) < 3) {
115 $this->setError(_('Name is too short. It must be at least 3 characters.'));
118 if (!util_is_valid_filename($name)) {
119 $this->setError(_('Filename can only be alphanumeric and “-”, “_”, “+”, “.”, “~” characters.'));
123 // Can't really use is_uploaded_file() or move_uploaded_file()
124 // since we want this to be generalized code
125 // This is potentially exploitable if you do not validate
126 // before calling this function
128 if (!is_file($file_location) || !file_exists($file_location)) {
129 $this->setError(_('FRSFile appears to be invalid.'));
133 if (!forge_check_perm('frs', $this->FRSRelease->FRSPackage->getID(), 'file')) {
134 $this->setPermissionDeniedError();
139 // Filename must be unique in this release
141 $resfile = db_query_params('SELECT filename FROM frs_file WHERE filename=$1 AND release_id=$2',
143 $this->FRSRelease->getID()));
144 if (!$resfile || db_numrows($resfile) > 0) {
145 $this->setError(_('That filename already exists in this release').' '.db_error());
149 $path_name = forge_get_config('upload_dir').'/'.$this->FRSRelease->FRSPackage->Group->getUnixName();
150 if (!is_dir($path_name)) {
151 mkdir($path_name, 0755, true);
153 if (fileperms($path_name) != 0x4755) {
154 chmod($path_name, 0755);
157 $path_name = $path_name.'/'.$this->FRSRelease->FRSPackage->getFileName();
158 if (!is_dir($path_name)) {
159 mkdir($path_name, 0755);
161 if (fileperms($path_name) != 0x4755) {
162 chmod($path_name, 0755);
165 $path_name = $path_name.'/'.$this->FRSRelease->getFileName();
166 if (!is_dir($path_name)) {
167 mkdir($path_name, 0755);
169 if (fileperms($path_name) != 0x4755) {
170 chmod($path_name, 0755);
174 $newfilelocation = forge_get_config('upload_dir').'/'.
175 $this->FRSRelease->FRSPackage->Group->getUnixName().'/'.
176 $this->FRSRelease->FRSPackage->getFileName().'/'.
177 $this->FRSRelease->getFileName().'/';
179 $ret = rename($file_location, $newfilelocation.$name);
181 $this->setError(_('File cannot be moved to the permanent location')._(': ').$newfilelocation.$name);
185 if (!$release_time) {
186 $release_time = time();
188 $file_size = filesize($newfilelocation.$name);
191 $result = db_query_params('INSERT INTO frs_file(release_id,filename,release_time,type_id,processor_id,file_size,post_date) VALUES ($1,$2,$3,$4,$5,$6,$7)',
192 array ($this->FRSRelease->getID(),
200 $this->setError(_('Error Adding File')._(': ').db_error());
204 $this->file_id = db_insertid($result, 'frs_file', 'file_id');
205 if (!$this->fetchData($this->file_id)) {
209 if ($this->FRSRelease->FRSPackage->createReleaseFilesAsZip($this->FRSRelease->getID())) {
213 $this->setError($this->FRSRelease->FRSPackage->getErrorMessage());
219 * fetchData - re-fetch the data for this FRSFile from the database.
221 * @param int $file_id The file_id.
222 * @return bool success.
224 function fetchData($file_id) {
225 $res = db_query_params ('SELECT * FROM frs_file_vw WHERE file_id=$1 AND release_id=$2',
227 $this->FRSRelease->getID())) ;
228 if (!$res || db_numrows($res) < 1) {
229 $this->setError(_('Invalid file_id'));
232 $this->data_array = db_fetch_array($res);
233 db_free_result($res);
238 * getFRSRelease - get the FRSRelease object this file is associated with.
240 * @return object The FRSRelease object.
242 function &getFRSRelease() {
243 return $this->FRSRelease;
247 * getID - get this file_id.
249 * @return int The id of this file.
252 return $this->data_array['file_id'];
256 * getName - get the name of this file.
258 * @return string The name of this file.
261 return $this->data_array['filename'];
265 * getSize - get the size of this file.
267 * @return int The size.
270 return $this->data_array['file_size'];
274 * getTypeID - the filetype id.
276 * @return int the filetype id.
278 function getTypeID() {
279 return $this->data_array['type_id'];
283 * getTypeName - the filetype name.
285 * @return string The filetype name.
287 // FIXME : Undefined index: filetype in .../common/frs/FRSFile.class.php on line 293
288 function getFileType() {
289 return $this->data_array['filetype'];
293 * getProcessorID - the processor id.
295 * @return int the processor id.
297 function getProcessorID() {
298 return $this->data_array['processor_id'];
302 * getProcessor - the processor name.
304 * @return string The processor name.
306 function getProcessor() {
307 return $this->data_array['processor'];
311 * getDownloads - the number of downloads.
313 * @return int The number of downloads.
315 function getDownloads() {
316 return $this->data_array['downloads'];
320 * getReleaseTime - get the releasetime of this file.
322 * @return int The release time in unix time.
324 function getReleaseTime() {
325 return $this->data_array['release_time'];
329 * getPostDate - get the post date of this file.
331 * @return int The post date in unix time.
333 function getPostDate() {
334 return $this->data_array['post_date'];
338 * delete - Delete this file from the database and file system.
340 * @return bool success.
343 if (!forge_check_perm('frs', $this->FRSRelease->FRSPackage->getID(), 'file')) {
344 $this->setPermissionDeniedError();
348 $file = forge_get_config('upload_dir').'/'.
349 $this->FRSRelease->FRSPackage->Group->getUnixName().'/'.
350 $this->FRSRelease->FRSPackage->getFileName().'/'.
351 $this->FRSRelease->getFileName().'/'.
354 if (file_exists($file))
357 if (isset($this->FRSRelease->release_files[$this->getID()])) {
358 unset($this->FRSRelease->release_files[$this->getID()]);
360 $result = db_query_params('DELETE FROM frs_file WHERE file_id=$1', array($this->getID()));
361 if (!$result || db_affected_rows($result) < 1) {
362 $this->setError("frsDeleteFile()::2 ".db_error());
365 db_query_params('DELETE FROM frs_dlstats_file WHERE file_id=$1', array($this->getID()));
366 db_query_params('DELETE FROM frs_dlstats_filetotal_agg WHERE file_id=$1', array($this->getID()));
367 if ($this->FRSRelease->hasFiles()) {
368 $this->FRSRelease->FRSPackage->createReleaseFilesAsZip($this->FRSRelease->getID());
370 $this->FRSRelease->FRSPackage->deleteReleaseFilesAsZip($this->FRSRelease->getID());
377 * update - update an existing file in this FRSFileRelease/FRSPackage.
379 * @param int $type_id The type_id of this file from the frs-file-types table.
380 * @param int $processor_id The processor_id of this file from the frs-processor-types table.
381 * @param int $release_time The release_date of this file in unix time (seconds).
382 * @param int|bool $release_id The release_id of the release this file belongs to (if not set, defaults to the release id of this file).
383 * @return bool success.
385 function update($type_id, $processor_id, $release_time, $release_id = false) {
386 if (!forge_check_perm('frs', $this->FRSRelease->FRSPackage->getID(), 'file')) {
387 $this->setPermissionDeniedError();
393 // Check that the new FRSRelease id exists
394 if ($FRSRelease = frsrelease_get_object($release_id)) {
395 // Check that the new FRSRelease id belongs to the group of this FRSFile
396 if ($FRSRelease->FRSPackage->Group->getID() != $this->FRSRelease->FRSPackage->Group->getID()) {
397 $this->setError(_('Invalid Project'));
401 $this->setError(_('Invalid FRS Release Object'));
405 // If release_id is not set, defaults to the release id of this file
406 $release_id = $this->FRSRelease->getID();
411 $res = db_query_params('UPDATE frs_file SET type_id=$1,processor_id=$2,release_time=$3,release_id=$4 WHERE file_id=$5',
418 if (!$res || db_affected_rows($res) < 1) {
419 $this->setError(_('Error On Update')._(': ').db_error());
424 // Move physically file if needed
425 if ($release_id != $this->FRSRelease->getID()) {
426 $old_file_location = forge_get_config('upload_dir').'/'.
427 $this->FRSRelease->FRSPackage->Group->getUnixName().'/'.
428 $this->FRSRelease->FRSPackage->getFileName().'/'.
429 $this->FRSRelease->getFileName().'/'.
430 $this->data_array['filename'];
431 $new_file_location = forge_get_config('upload_dir').'/'.
432 $FRSRelease->FRSPackage->Group->getUnixName().'/'.
433 $FRSRelease->FRSPackage->getFileName().'/'.
434 $FRSRelease->getFileName().'/'.
435 $this->data_array['filename'];
436 if (file_exists($new_file_location)) {
437 $this->setError(_('That filename already exists in this project space'));
441 $ret = rename($old_file_location, $new_file_location);
443 $this->setError(_('File cannot be moved to the permanent location')._(': ').$new_file_location);
447 if (isset($this->FRSRelease->release_files[$this->getID()])) {
448 unset($this->FRSRelease->release_files[$this->getID()]);
452 if (!$FRSRelease->FRSPackage->createReleaseFilesAsZip($FRSRelease->getID())) {
453 $this->setError($FRSRelease->FRSPackage->getErrorMessage());
458 if ($this->FRSRelease->FRSPackage->createReleaseFilesAsZip($this->FRSRelease->getID())) {
462 $this->setError($this->FRSRelease->FRSPackage->getErrorMessage());
470 // c-file-style: "bsd"