PageRenderTime 50ms CodeModel.GetById 18ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/web/concrete/core/models/file_list.php

https://github.com/glockops/concrete5
PHP | 448 lines | 341 code | 50 blank | 57 comment | 61 complexity | 3d932c84da566ee3351f437d91357efa MD5 | raw file
  1<?php defined('C5_EXECUTE') or die("Access Denied.");
  2/**
  3*
  4* An object that allows a filtered list of files to be returned.
  5* @package Files
  6*
  7*/
  8class Concrete5_Model_FileList extends DatabaseItemList { 
  9
 10	protected $attributeFilters = array();
 11	protected $autoSortColumns = array('fvFilename', 'fvAuthorName','fvTitle', 'fDateAdded', 'fvDateAdded', 'fvSize');
 12	protected $itemsPerPage = 10;
 13	protected $attributeClass = 'FileAttributeKey';
 14	protected $permissionLevel = 'search_file_set';
 15	protected $filteredFileSetIDs = array();
 16	
 17	/* magic method for filtering by attributes. */
 18	public function __call($nm, $a) {
 19		if (substr($nm, 0, 8) == 'filterBy') {
 20			$txt = Loader::helper('text');
 21			$attrib = $txt->uncamelcase(substr($nm, 8));
 22			if (count($a) == 2) {
 23				$this->filterByAttribute($attrib, $a[0], $a[1]);
 24			} else {
 25				$this->filterByAttribute($attrib, $a[0]);
 26			}
 27		}			
 28	}
 29
 30	/** 
 31	 * Filters by file extension
 32	 * @param mixed $extension
 33	 */
 34	public function filterByExtension($ext) {
 35		$this->filter('fv.fvExtension', $ext, '=');
 36	}
 37
 38	/** 
 39	 * Filters by type of file
 40	 * @param mixed $type
 41	 */
 42	public function filterByType($type) {
 43		$this->filter('fv.fvType', $type, '=');
 44	}
 45	
 46	/** 
 47	 * Filters by "keywords" (which searches everything including filenames, title, tags, users who uploaded the file, tags)
 48	 */
 49	public function filterByKeywords($keywords) {
 50		$db = Loader::db();
 51		$keywordsExact = $db->quote($keywords);
 52		$qkeywords = $db->quote('%' . $keywords . '%');
 53		$keys = FileAttributeKey::getSearchableIndexedList();
 54		$attribsStr = '';
 55		foreach ($keys as $ak) {
 56			$cnt = $ak->getController();			
 57			$attribsStr.=' OR ' . $cnt->searchKeywords($keywords);
 58		}
 59		$this->filter(false, '(fvFilename like ' . $qkeywords . ' or fvDescription like ' . $qkeywords . ' or fvTitle like ' . $qkeywords . ' or fvTags like ' . $qkeywords . ' or u.uName = ' . $keywordsExact . $attribsStr . ')');
 60	}
 61	
 62
 63	public function filterBySet($fs) {
 64		if ($fs != false) {
 65			$this->filteredFileSetIDs[] = intval($fs->getFileSetID());
 66		} else {
 67			// this is what we do when we are filtering by files in NO sets.
 68			$s1 = FileSet::getMySets();
 69			$sets = array();
 70			foreach($s1 as $fs) {
 71				$sets[] = $fs->getFileSetID();
 72			}
 73			if (count($sets) == 0) {
 74				return false;
 75			}
 76			$db = Loader::db();
 77			$setStr = implode(',', $sets);
 78			$this->addToQuery("left join FileSetFiles fsfex on fsfex.fID = f.fID");
 79			$this->filter(false, '(fsfex.fID is null or (select count(fID) from FileSetFiles where fID = fsfex.fID and fsID in (' . $setStr . ')) = 0)');
 80		}
 81	}
 82
 83	public static function export($xml) {
 84		$fl = new FileList();
 85		$files = $fl->get();
 86		if (count($files) > 0) {
 87			$pkgs = $xml->addChild("files");
 88			foreach($files as $f) {
 89				$node = $pkgs->addChild('file');
 90				$node->addAttribute('filename', $f->getFileName());
 91			}
 92		}
 93	}
 94
 95	public static function exportArchive($archive) {
 96		$fl = new FileList();
 97		$files = $fl->get();
 98		$filestring = '';
 99		$fh = Loader::helper('file');
100		$filenames = array();
101		$filename = $fh->getTemporaryDirectory() . '/' . $archive . '.zip';
102		if (count($files) > 0) {
103			try {
104				if (class_exists('ZipArchive', false)) {
105					$zip = new ZipArchive;
106					$res = $zip->open($filename, ZipArchive::CREATE);
107					if ($res === TRUE) {
108						foreach($files as $f) {
109							$file = $f->getPath();
110							if (!in_array(basename($file), $filenames)) {
111								$filenames[] = basename($file);
112								$zip->addFile(addslashes($file), basename($file));
113							}
114						}
115						$zip->close();
116					} else {
117						throw new Exception(t('Could not open with ZipArchive::CREATE'));
118					}
119				} else {
120					$filestring = "'" . addslashes($filename) . "' ";
121					foreach($files as $f) {
122						$file = $f->getPath();
123						if (!in_array(basename($file), $filenames)) {
124							$filenames[] = basename($file);
125							$filestring .= "'" . addslashes($file) . "' ";
126						}
127					}
128					exec(DIR_FILES_BIN_ZIP . ' -j ' . $filestring);
129				}
130			} catch(Exception $e) {
131				throw new Exception(t('Failed to create zip file as "%s": %s', $filename, $e->getMessage()));
132			}
133		}
134	}
135	
136	protected function setupFileSetFilters() {	
137		$fsIDs = array_unique($this->filteredFileSetIDs);
138		$fsIDs = array_filter($fsIDs,'is_numeric');
139		
140		$db = Loader::db();
141		$i = 0;
142		$_fsIDs = array();
143		if(is_array($fsIDs) && count($fsIDs)) {
144			foreach($fsIDs as $fsID) {
145				if($fsID > 0) {
146					$_fsIDs[] = $fsID;
147				}
148			}
149		}
150		
151		if (count($_fsIDs) > 1) {
152			foreach($_fsIDs as $fsID) {
153				if($fsID > 0) {
154					if ($i == 0) {
155						$this->addToQuery("left join FileSetFiles fsfl on fsfl.fID = f.fID");
156					}
157					$this->filter(false,'f.fID IN (SELECT DISTINCT fID FROM FileSetFiles WHERE fsID = '.$db->quote($fsID).')');
158					$i++;
159				}
160			}
161		} else if (count($_fsIDs) > 0) {
162			$this->addToQuery("inner join FileSetFiles fsfl on fsfl.fID = f.fID");
163			$this->filter('fsfl.fsID', $fsID);
164			$i++;
165		}
166		
167		// add FileSetFiles if we had a file set filter but
168		// couldn't add it because it has been removed
169		if ($i == 0 && count($this->filteredFileSetIDs)>0) {
170			$this->addToQuery("inner join FileSetFiles fsfl on 1=2");
171		}		
172	}
173	
174	
175	/** 
176	 * Filters the file list by file size (in kilobytes)
177	 */
178	public function filterBySize($from, $to) {
179		$this->filter('fv.fvSize', $from * 1024, '>=');
180		$this->filter('fv.fvSize', $to * 1024, '<=');
181	}
182	
183	/** 
184	 * Filters by public date
185	 * @param string $date
186	 */
187	public function filterByDateAdded($date, $comparison = '=') {
188		$this->filter('f.fDateAdded', $date, $comparison);
189	}
190	
191	public function filterByOriginalPageID($ocID) {
192		$this->filter('f.ocID', $ocID);
193	}
194	
195	/**
196	 * filters a FileList by the uID of the approving User
197	 * @param int $uID
198	 * @return void
199	 * @since 5.4.1.1+
200	 */
201	public function filterByApproverUID($uID) {
202		$this->filter('fv.fvApproverUID', $uID);	
203	}
204	
205	/**
206	 * filters a FileList by the uID of the owning User
207	 * @param int $uID
208	 * @return void
209	 * @since 5.4.1.1+
210	*/
211	public function filterByAuthorUID($uID) {
212		$this->filter('fv.fvAuthorUID', $uID);	
213	}
214	
215	public function setPermissionLevel($plevel) {
216		$this->permissionLevel = $plevel;
217	}
218	
219	/** 
220	 * Filters by tag
221	 * @param string $tag
222	 */
223	public function filterByTag($tag='') { 
224		$db=Loader::db();  
225		$this->filter(false, "( fv.fvTags like ".$db->qstr("%\n".$tag."\n%")."  )");
226	}	
227	
228	protected function setBaseQuery() {
229		$this->setQuery('SELECT DISTINCT f.fID, u.uName as fvAuthorName
230		FROM Files f INNER JOIN FileVersions fv ON f.fID = fv.fID 
231		LEFT JOIN Users u on u.uID = fv.fvAuthorUID
232		');
233	}
234
235	protected function setupFilePermissions() {
236		$u = new User();
237		if ($this->permissionLevel == false || $u->isSuperUser()) {
238			return false;
239		}
240
241		$accessEntities = $u->getUserAccessEntityObjects();
242		foreach($accessEntities as $pae) {
243			$peIDs[] = $pae->getAccessEntityID();
244		}
245		$db = Loader::db();
246		// figure out which sets can read files in, not read files in, and read only my files in.
247		$fsIDs = $db->GetCol('select fsID from FileSets where fsOverrideGlobalPermissions = 1');
248		$viewableSets = array(-1);
249		$nonviewableSets = array(-1);
250		$myviewableSets = array(-1);
251
252		$owpae = FileUploaderPermissionAccessEntity::getOrCreate();
253		
254		if (count($fsIDs) > 0) { 
255			$pk = PermissionKey::getByHandle($this->permissionLevel);
256			foreach($fsIDs as $fsID) {
257				$fs = FileSet::getByID($fsID);
258				$pk->setPermissionObject($fs);
259				$list = $pk->getAccessListItems(PermissionKey::ACCESS_TYPE_ALL, $accessEntities);
260				$list = PermissionDuration::filterByActive($list);
261				if (count($list) > 0) { 
262					foreach($list as $l) {
263						$pae = $l->getAccessEntityObject();
264						if ($pae->getAccessEntityID() == $owpae->getAccessEntityID()) {
265							$myviewableSets[] = $fs->getFileSetID();
266						} else {
267							if ($l->getAccessType() == PermissionKey::ACCESS_TYPE_INCLUDE) {
268								$viewableSets[] = $fs->getFileSetID();
269							}
270							if ($l->getAccessType() == PermissionKey::ACCESS_TYPE_EXCLUDE) {
271								$nonviewableSets[] = $fs->getFileSetID();
272							}
273						}
274					}
275				} else {
276					$nonviewableSets[] = $fs->getFileSetID();
277				}
278			}
279		}
280
281		$fs = FileSet::getGlobal();
282		$fk = PermissionKey::getByHandle('search_file_set');
283		$fk->setPermissionObject($fs);
284		$accessEntities[] = $owpae;
285		$list = $fk->getAccessListItems(PermissionKey::ACCESS_TYPE_ALL, $accessEntities);
286		$list = PermissionDuration::filterByActive($list);
287		foreach($list as $l) {
288			$pae = $l->getAccessEntityObject();
289			if ($pae->getAccessEntityID() == $owpae->getAccessEntityID()) {
290				$valid = 'mine';
291			} else {
292				if ($l->getAccessType() == PermissionKey::ACCESS_TYPE_INCLUDE) {
293					$valid = PermissionKey::ACCESS_TYPE_INCLUDE;
294				}
295				if ($l->getAccessType() == PermissionKey::ACCESS_TYPE_EXCLUDE) {
296					$valid = PermissionKey::ACCESS_TYPE_EXCLUDE;
297				}
298			}
299		}
300		
301		$uID = ($u->isRegistered()) ? $u->getUserID() : 0;
302		// This excludes all files found in sets where I may only read mine, and I did not upload the file
303		$this->filter(false, '(f.uID = ' . $uID . ' or (select count(fID) from FileSetFiles where FileSetFiles.fID = f.fID and fsID in (' . implode(',',$myviewableSets) . ')) = 0)');		
304		
305		if ($valid == 'mine') {
306			// this means that we're only allowed to read files we've uploaded (unless, of course, those files are in previously covered sets)
307			$this->filter(false, '(f.uID = ' . $uID . ' or (select count(fID) from FileSetFiles where FileSetFiles.fID = f.fID and fsID in (' . implode(',',$viewableSets) . ')) > 0)');		
308		}
309		
310		// this excludes all file that are found in sets that I can't find
311		$this->filter(false, '((select count(fID) from FileSetFiles where FileSetFiles.fID = f.fID and fsID in (' . implode(',', $nonviewableSets) . ')) = 0)');		
312		
313		$uID = ($u->isRegistered()) ? $u->getUserID() : 0;
314		// This excludes all files found in sets where I may only read mine, and I did not upload the file
315		$this->filter(false, '(f.uID = ' . $uID . ' or (select count(fID) from FileSetFiles where FileSetFiles.fID = f.fID and fsID in (' . implode(',',$myviewableSets) . ')) = 0)');		
316
317		$db = Loader::db();
318		$vpvPKID = $db->GetOne('select pkID from PermissionKeys where pkHandle = \'view_file\'');
319		if ($this->permissionLevel == 'search_file_set') { 
320			$vpPKID = $db->GetOne('select pkID from PermissionKeys where pkHandle = \'view_file_in_file_manager\'');
321		} else {
322			$vpPKID = $vpvPKID;
323		}
324		$pdIDs = $db->GetCol("select distinct pdID from FilePermissionAssignments fpa inner join PermissionAccessList pal on fpa.paID = pal.paID where pkID in (?, ?) and pdID > 0", array($vpPKID, $vpvPKID));
325		$activePDIDs = array();
326		if (count($pdIDs) > 0) {
327			// then we iterate through all of them and find any that are active RIGHT NOW
328			foreach($pdIDs as $pdID) {
329				$pd = PermissionDuration::getByID($pdID);
330				if ($pd->isActive()) {
331					$activePDIDs[] = $pd->getPermissionDurationID();	
332				}
333			}
334		}
335		$activePDIDs[] = 0;
336		
337		// exclude files where its overridden but I don't have the ability to read		
338		$this->filter(false, "(f.fOverrideSetPermissions = 0 or (select count(fID) from FilePermissionAssignments fpa inner join PermissionAccessList fpal on fpa.paID = fpal.paID where fpa.fID = f.fID and fpal.accessType = " . PermissionKey::ACCESS_TYPE_INCLUDE . " and fpal.pdID in (" . implode(',', $activePDIDs) . ") and fpal.peID in (" . implode(',', $peIDs) . ") and (if(fpal.peID = " . $owpae->getAccessEntityID() . " and f.uID <> " . $uID . ", false, true)) and (fpa.pkID = " . $vpPKID . ")) > 0)");
339
340		
341		// exclude detail files where read is excluded
342		$this->filter(false, "f.fID not in (select ff.fID from Files ff inner join FilePermissionAssignments fpaExclude on ff.fID = fpaExclude.fID inner join PermissionAccessList palExclude on fpaExclude.paID = palExclude.paID where fOverrideSetPermissions = 1 and palExclude.accessType = " . PermissionKey::ACCESS_TYPE_EXCLUDE . " and palExclude.pdID in (" . implode(',', $activePDIDs) . ")
343			and palExclude.peID in (" . implode(',', $peIDs) . ") and fpaExclude.pkID in (" . $vpPKID . "," . $vpvPKID . "))");		
344	}
345	
346	
347	/** 
348	 * Returns an array of file objects based on current settings
349	 */
350	public function get($itemsToGet = 0, $offset = 0) {
351		$files = array();
352		Loader::model('file');
353		$this->createQuery();
354		$r = parent::get($itemsToGet, $offset);
355		foreach($r as $row) {
356			$f = File::getByID($row['fID']);			
357			$files[] = $f;
358		}
359		return $files;
360	}
361	
362	public function getTotal(){
363		$files = array();
364		Loader::model('file');
365		$this->createQuery();
366		return parent::getTotal();
367	}
368	
369	//this was added because calling both getTotal() and get() was duplicating some of the query components
370	protected function createQuery(){
371		if(!$this->queryCreated){
372			$this->setBaseQuery();
373			$this->filter('fvIsApproved', 1);
374			$this->setupAttributeFilters("left join FileSearchIndexAttributes on (fv.fID = FileSearchIndexAttributes.fID)");
375			$this->setupFilePermissions();
376			$this->setupFileSetFilters();
377			$this->queryCreated=1;
378		}
379	}
380	
381	//$key can be handle or fak id
382	public function sortByAttributeKey($key,$order='asc') {
383		$this->sortBy($key, $order); // this is handled natively now
384	}
385	
386	public function sortByFileSetDisplayOrder() {
387		$this->sortByMultiple('fsDisplayOrder asc', 'fID asc');
388	}
389	
390	public static function getExtensionList() {
391		$db = Loader::db();
392		$col = $db->GetCol('select distinct(trim(fvExtension)) as extension from FileVersions where fvIsApproved = 1 and fvExtension <> ""');
393		return $col;
394	}
395
396	public static function getTypeList() {
397		$db = Loader::db();
398		$col = $db->GetCol('select distinct(trim(fvType)) as type from FileVersions where fvIsApproved = 1 and fvType <> 0');
399		return $col;
400	}
401
402}
403
404class Concrete5_Model_FileManagerDefaultColumnSet extends DatabaseItemListColumnSet {
405	protected $attributeClass = 'FileAttributeKey';	
406	
407	public static function getFileDateAdded($f) {
408		return date(DATE_APP_DASHBOARD_SEARCH_RESULTS_FILES, strtotime($f->getDateAdded()));
409	}
410
411	public static function getFileDateActivated($f) {
412		$fv = $f->getVersion();
413		return date(DATE_APP_DASHBOARD_SEARCH_RESULTS_FILES, strtotime($fv->getDateAdded()));
414	}
415	
416	public function __construct() {
417		$this->addColumn(new DatabaseItemListColumn('fvType', t('Type'), 'getType', false));
418		$this->addColumn(new DatabaseItemListColumn('fvTitle', t('Title'), 'getTitle'));
419		$this->addColumn(new DatabaseItemListColumn('fDateAdded', t('Added'), array('FileManagerDefaultColumnSet', 'getFileDateAdded')));
420		$this->addColumn(new DatabaseItemListColumn('fvDateAdded', t('Active'), array('FileManagerDefaultColumnSet', 'getFileDateActivated')));
421		$this->addColumn(new DatabaseItemListColumn('fvSize', t('Size'), 'getSize'));
422		$title = $this->getColumnByKey('fDateAdded');
423		$this->setDefaultSortColumn($title, 'desc');
424	}
425}
426
427class Concrete5_Model_FileManagerAvailableColumnSet extends Concrete5_Model_FileManagerDefaultColumnSet {
428	protected $attributeClass = 'FileAttributeKey';
429	public function __construct() {
430		parent::__construct();
431		$this->addColumn(new DatabaseItemListColumn('fvAuthorName', t('Author'), 'getAuthorName'));
432	}
433}
434
435class Concrete5_Model_FileManagerColumnSet extends DatabaseItemListColumnSet {
436	protected $attributeClass = 'FileAttributeKey';
437	public function getCurrent() {
438		$u = new User();
439		$fldc = $u->config('FILE_LIST_DEFAULT_COLUMNS');
440		if ($fldc != '') {
441			$fldc = @unserialize($fldc);
442		}
443		if (!($fldc instanceof DatabaseItemListColumnSet)) {
444			$fldc = new FileManagerDefaultColumnSet();
445		}
446		return $fldc;
447	}
448}