3 * FusionForge file release system
5 * Copyright 2002, Tim Perdue/GForge, LLC
6 * Copyright 2009, Roland Mas
7 * Copyright 2012-2013, Franck Villaume - TrivialDev
8 * Copyright (C) 2012 Alain Peyrat - Alcatel-Lucent
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/Error.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 WHERE file_id=$1',
43 if (db_numrows($res)<1 ) {
44 $FRSFILE_OBJ['_'.$file_id.'_']=false;
47 $data = db_fetch_array($res);
49 $FRSRelease = frsrelease_get_object($data['release_id']);
50 $FRSFILE_OBJ['_'.$file_id.'_']= new FRSFile($FRSRelease,$data['file_id'],$data);
52 return $FRSFILE_OBJ['_'.$file_id.'_'];
55 class FRSFile extends Error {
58 * Associative array of data from db.
60 * @var array $data_array.
67 * @var object FRSRelease.
74 * @param object $FRSRelease The FRSRelease object to which this file is associated.
75 * @param int|bool $file_id The file_id.
76 * @param array|bool $arr The associative array of data.
79 function __construct(&$FRSRelease, $file_id=false, $arr=false) {
81 if (!$FRSRelease || !is_object($FRSRelease)) {
82 $this->setError(_('Invalid FRS Release Object'));
85 if ($FRSRelease->isError()) {
86 $this->setError('FRSFile: '.$FRSRelease->getErrorMessage());
89 $this->FRSRelease =& $FRSRelease;
92 if (!$arr || !is_array($arr)) {
93 if (!$this->fetchData($file_id)) {
97 $this->data_array =& $arr;
98 if ($this->data_array['release_id'] != $this->FRSRelease->getID()) {
99 $this->setError('FRSRelease_id in db result does not match FRSRelease Object');
100 $this->data_array=null;
108 * create - create a new file in this FRSFileRelease/FRSPackage.
110 * @param string $name The name of this file.
111 * @param string $file_location The location of this file in the local file system.
112 * @param int $type_id The type_id of this file from the frs-file-types table.
113 * @param int $processor_id The processor_id of this file from the frs-processor-types table.
114 * @param int|bool $release_time The release_date of this file in unix time (seconds).
115 * @param string $mime_type The mime type of the file (default: application/octet-stream)
116 * @param bool $is_remote True if file is an URL and not an uploaded file (default: false)
117 * @return bool success.
119 function create($name,$file_location,$type_id,$processor_id,$release_time=false) {
120 if (strlen($name) < 3) {
121 $this->setError(_('Name is too short. It must be at least 3 characters.'));
124 if (!util_is_valid_filename($name)) {
125 $this->setError(_('Filename can only be alphanumeric and “-”, “_”, “+”, “.”, “~” characters.'));
129 // Can't really use is_uploaded_file() or move_uploaded_file()
130 // since we want this to be generalized code
131 // This is potentially exploitable if you do not validate
132 // before calling this function
134 if (!is_file($file_location) || !file_exists($file_location)) {
135 $this->setError(_('FRSFile Appears to be invalid'));
139 if (!forge_check_perm ('frs', $this->FRSRelease->FRSPackage->Group->getID(), 'write')) {
140 $this->setPermissionDeniedError();
145 // Filename must be unique in this release
147 $resfile = db_query_params ('SELECT filename FROM frs_file WHERE filename=$1 AND release_id=$2',
149 $this->FRSRelease->getId())) ;
150 if (!$resfile || db_numrows($resfile) > 0) {
151 $this->setError(_('That filename already exists in this project space').' '.db_error());
155 $path_name = forge_get_config('upload_dir').'/'.$this->FRSRelease->FRSPackage->Group->getUnixName();
156 if (!is_dir($path_name)) {
157 mkdir($path_name, 0755, true);
159 if ( fileperms($path_name) != 0x4755 ) {
160 chmod($path_name, 0755);
163 $path_name = $path_name.'/'.$this->FRSRelease->FRSPackage->getFileName();
164 if (!is_dir($path_name)) {
165 mkdir($path_name, 0755);
167 if ( fileperms($path_name) != 0x4755 ) {
168 chmod($path_name, 0755);
171 $path_name = $path_name.'/'.$this->FRSRelease->getFileName();
172 if (!is_dir($path_name)) {
173 mkdir($path_name, 0755);
175 if ( fileperms($path_name) != 0x4755 ) {
176 chmod($path_name, 0755);
180 $newfilelocation = forge_get_config('upload_dir').'/'.
181 $this->FRSRelease->FRSPackage->Group->getUnixName().'/'.
182 $this->FRSRelease->FRSPackage->getFileName().'/'.
183 $this->FRSRelease->getFileName().'/';
185 $ret = rename($file_location, $newfilelocation.$name);
187 $this->setError(_('File cannot be moved to the permanent location').': '.$newfilelocation.$name);
191 if (!$release_time) {
192 $release_time=time();
194 $file_size=filesize("$newfilelocation$name");
197 $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)',
198 array ($this->FRSRelease->getId(),
206 $this->setError(_('Error Adding Release: ').db_error());
210 $this->file_id=db_insertid($result,'frs_file','file_id');
211 if (!$this->fetchData($this->file_id)) {
216 $this->FRSRelease->FRSPackage->createNewestReleaseFilesAsZip();
222 * fetchData - re-fetch the data for this FRSFile from the database.
224 * @param int $file_id The file_id.
225 * @return boolean success.
227 function fetchData($file_id) {
228 $res = db_query_params ('SELECT * FROM frs_file_vw WHERE file_id=$1 AND release_id=$2',
230 $this->FRSRelease->getID())) ;
231 if (!$res || db_numrows($res) < 1) {
232 $this->setError(_('Invalid file_id'));
235 $this->data_array = db_fetch_array($res);
236 db_free_result($res);
241 * getFRSRelease - get the FRSRelease object this file is associated with.
243 * @return object The FRSRelease object.
245 function &getFRSRelease() {
246 return $this->FRSRelease;
250 * getID - get this file_id.
252 * @return int The id of this file.
255 return $this->data_array['file_id'];
259 * getName - get the name of this file.
261 * @return string The name of this file.
264 return $this->data_array['filename'];
268 * getSize - get the size of this file.
270 * @return int The size.
273 return $this->data_array['file_size'];
277 * getTypeID - the filetype id.
279 * @return int the filetype id.
281 function getTypeID() {
282 return $this->data_array['type_id'];
286 * getTypeName - the filetype name.
288 * @return string The filetype name.
290 // FIXME : Undefined index: filetype in /usr/share/gforge/common/frs/FRSFile.class.php on line 293
291 function getFileType() {
292 return $this->data_array['filetype'];
296 * getProcessorID - the processor id.
298 * @return int the processor id.
300 function getProcessorID() {
301 return $this->data_array['processor_id'];
305 * getProcessor - the processor name.
307 * @return string The processor name.
309 function getProcessor() {
310 return $this->data_array['processor'];
314 * getDownloads - the number of downloads.
316 * @return int The number of downloads.
318 function getDownloads() {
319 return $this->data_array['downloads'];
323 * getReleaseTime - get the releasetime of this file.
325 * @return int The release time in unix time.
327 function getReleaseTime() {
328 return $this->data_array['release_time'];
332 * getPostDate - get the post date of this file.
334 * @return int The post date in unix time.
336 function getPostDate() {
337 return $this->data_array['post_date'];
341 * delete - Delete this file from the database and file system.
343 * @return boolean success.
346 if (!forge_check_perm ('frs', $this->FRSRelease->FRSPackage->Group->getID(), 'write')) {
347 $this->setPermissionDeniedError();
351 $file=forge_get_config('upload_dir').'/'.
352 $this->FRSRelease->FRSPackage->Group->getUnixName() . '/' .
353 $this->FRSRelease->FRSPackage->getFileName().'/'.
354 $this->FRSRelease->getFileName().'/'.
356 if (file_exists($file))
358 $result = db_query_params ('DELETE FROM frs_file WHERE file_id=$1',
359 array ($this->getID())) ;
360 if (!$result || db_affected_rows($result) < 1) {
361 $this->setError("frsDeleteFile()::2 ".db_error());
364 db_query_params ('DELETE FROM frs_dlstats_file WHERE file_id=$1',
365 array ($this->getID())) ;
366 db_query_params ('DELETE FROM frs_dlstats_filetotal_agg WHERE file_id=$1',
367 array ($this->getID())) ;
368 $this->FRSRelease->FRSPackage->createNewestReleaseFilesAsZip();
374 * update - update an existing file in this FRSFileRelease/FRSPackage.
376 * @param int $type_id The type_id of this file from the frs-file-types table.
377 * @param int $processor_id The processor_id of this file from the frs-processor-types table.
378 * @param int $release_time The release_date of this file in unix time (seconds).
379 * @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).
380 * @return boolean success.
382 function update($type_id,$processor_id,$release_time,$release_id=false) {
383 if (!forge_check_perm ('frs', $this->FRSRelease->FRSPackage->Group->getID(), 'write')) {
384 $this->setPermissionDeniedError();
390 // Check that the new FRSRelease id exists
391 if ($FRSRelease=frsrelease_get_object($release_id)) {
392 // Check that the new FRSRelease id belongs to the group of this FRSFile
393 if ($FRSRelease->FRSPackage->Group->getID()!=$this->FRSRelease->FRSPackage->Group->getID()) {
394 $this->setError(_('No Valid Group Object'));
398 $this->setError(_('Invalid FRS Release Object'));
402 // If release_id is not set, defaults to the release id of this file
403 $release_id = $this->FRSRelease->getID();
408 $res = db_query_params ('UPDATE frs_file SET type_id=$1,processor_id=$2,release_time=$3,release_id=$4 WHERE file_id=$5',
415 if (!$res || db_affected_rows($res) < 1) {
416 $this->setError(sprintf(_('Error On Update: %s'), db_error()));
421 // Move physically file if needed
422 if ($release_id != $this->FRSRelease->getID()) {
423 $old_file_location = forge_get_config('upload_dir').'/'.
424 $this->FRSRelease->FRSPackage->Group->getUnixName().'/'.
425 $this->FRSRelease->FRSPackage->getFileName().'/'.
426 $this->FRSRelease->getFileName().'/'.
427 $this->data_array['filename'];
428 $new_file_location = forge_get_config('upload_dir').'/'.
429 $FRSRelease->FRSPackage->Group->getUnixName().'/'.
430 $FRSRelease->FRSPackage->getFileName().'/'.
431 $FRSRelease->getFileName().'/'.
432 $this->data_array['filename'];
433 if (file_exists($new_file_location)) {
434 $this->setError(_('That filename already exists in this project space'));
438 $ret = rename($old_file_location, $new_file_location);
440 $this->setError(_('File cannot be moved to the permanent location').': '.$new_file_location);
446 $this->FRSRelease->FRSPackage->createNewestReleaseFilesAsZip();
453 // c-file-style: "bsd"