PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/web/concrete/core/models/file_version.php

https://github.com/glockops/concrete5
PHP | 599 lines | 458 code | 83 blank | 58 comment | 63 complexity | 1108e7bd19e2b54e6d12f9fa9906b772 MD5 | raw file
Possible License(s): MIT, LGPL-2.1, BSD-3-Clause
  1. <?
  2. class Concrete5_Model_FileVersion extends Object {
  3. protected $numThumbnailLevels = 3;
  4. protected $attributes = array();
  5. // Update type constants
  6. const UT_REPLACE_FILE = 1;
  7. const UT_TITLE = 2;
  8. const UT_DESCRIPTION = 3;
  9. const UT_TAGS = 4;
  10. const UT_EXTENDED_ATTRIBUTE = 5;
  11. public function getFileID() {return $this->fID;}
  12. public function getFileVersionID() {return $this->fvID;}
  13. public function getPrefix() {return $this->fvPrefix;}
  14. public function getFileName() {return $this->fvFilename;}
  15. public function getTitle() {return $this->fvTitle;}
  16. public function getTags() {return $this->fvTags;}
  17. public function getDescription() {return $this->fvDescription;}
  18. public function isApproved() {return $this->fvIsApproved;}
  19. public function getGenericTypeText() {
  20. $to = $this->getTypeObject();
  21. return $to->getGenericTypeText( $to->getGenericType() );
  22. }
  23. /**
  24. * returns the File object associated with this FileVersion object
  25. * @return File
  26. */
  27. public function getFile() {
  28. $fo = File::getByID($this->fID);
  29. return $fo;
  30. }
  31. //returns an array of tags, instead of a string
  32. public function getTagsList(){
  33. $tags=explode("\n",str_replace("\r","\n",trim($this->getTags())));
  34. $clean_tags=array();
  35. foreach($tags as $tag){
  36. if( strlen(trim($tag)) )
  37. $clean_tags[]=trim($tag);
  38. }
  39. return $clean_tags;
  40. }
  41. /**
  42. * Gets an associative array of all attributes for a file version
  43. */
  44. public function getAttributeList() {
  45. $db = Loader::db();
  46. $v = array($this->fID, $this->fvID);
  47. Loader::model('attribute/categories/file');
  48. $attributes = FileAttributeKey::getAttributes($this->fID, $this->fvID);
  49. return $attributes;
  50. }
  51. /**
  52. * Gets an attribute for the file. If "nice mode" is set, we display it nicely
  53. * for use in the file attributes table
  54. */
  55. public function getAttribute($ak, $mode = false) {
  56. if (is_object($ak)) {
  57. $akHandle = $ak->getAttributeKeyHandle();
  58. } else {
  59. $akHandle = $ak;
  60. }
  61. if (!isset($this->attributes[$akHandle . $mode])) {
  62. $this->attributes[$akHandle . $mode] = false;
  63. $ak = FileAttributeKey::getByHandle($akHandle);
  64. if (is_object($ak)) {
  65. $av = $this->getAttributeValueObject($ak);
  66. if (is_object($av)) {
  67. $this->attributes[$akHandle . $mode] = $av->getValue($mode);
  68. }
  69. }
  70. }
  71. return $this->attributes[$akHandle . $mode];
  72. }
  73. public function getMimeType() {
  74. $h = Loader::helper('mime');
  75. $fh = Loader::helper('file');
  76. $ext = $fh->getExtension($this->fvFilename);
  77. return $h->mimeFromExtension($ext);
  78. }
  79. public function getSize() {
  80. return Loader::helper('number')->formatSize($this->fvSize, 'KB');
  81. }
  82. public function getFullSize() {
  83. return $this->fvSize;
  84. }
  85. public function getAuthorName() {
  86. return $this->fvAuthorName;
  87. }
  88. public function getAuthorUserID() {
  89. return $this->fvAuthorUID;
  90. }
  91. /**
  92. * Gets the date a file version was added
  93. * if user is specified, returns in the current user's timezone
  94. * @param string $type (system || user)
  95. * @return string date formated like: 2009-01-01 00:00:00
  96. */
  97. function getDateAdded($type = 'system') {
  98. if(ENABLE_USER_TIMEZONES && $type == 'user') {
  99. $dh = Loader::helper('date');
  100. return $dh->getLocalDateTime($this->fvDateAdded);
  101. } else {
  102. return $this->fvDateAdded;
  103. }
  104. }
  105. public function getExtension() {
  106. return $this->fvExtension;
  107. }
  108. public function logVersionUpdate($updateTypeID, $updateTypeAttributeID = 0) {
  109. $db = Loader::db();
  110. $db->Execute('insert into FileVersionLog (fID, fvID, fvUpdateTypeID, fvUpdateTypeAttributeID) values (?, ?, ?, ?)', array(
  111. $this->getFileID(),
  112. $this->getFileVersionID(),
  113. $updateTypeID,
  114. $updateTypeAttributeID
  115. ));
  116. }
  117. /**
  118. * Takes the current value of the file version and makes a new one with the same values
  119. */
  120. public function duplicate() {
  121. $f = File::getByID($this->fID);
  122. $dh = Loader::helper('date');
  123. $date = $dh->getSystemDateTime();
  124. $db = Loader::db();
  125. $fvID = $db->GetOne("select max(fvID) from FileVersions where fID = ?", array($this->fID));
  126. if ($fvID > 0) {
  127. $fvID++;
  128. }
  129. $data = $db->GetRow("select * from FileVersions where fID = ? and fvID = ?", array($this->fID, $this->fvID));
  130. $data['fvID'] = $fvID;
  131. $data['fvDateAdded'] = $date;
  132. $u = new User();
  133. if ($u->isRegistered()) {
  134. $data['fvAuthorUID'] = $u->getUserID();
  135. } else {
  136. $data['fvAuthorUID'] = 0;
  137. }
  138. // If This version is the approved version, we approve the new one.
  139. if ($this->isApproved()) {
  140. $data['fvIsApproved'] = 1;
  141. } else {
  142. $data['fvIsApproved'] = 0;
  143. }
  144. // build the field insert query
  145. $fields = '';
  146. $i = 0;
  147. $data2 = array();
  148. foreach($data as $key => $value) {
  149. if (!is_integer($key)) {
  150. $data2[$key] = $value;
  151. }
  152. }
  153. foreach($data2 as $key => $value) {
  154. $fields .= $key;
  155. $questions .= '?';
  156. if (($i + 1) < count($data2)) {
  157. $fields .= ',';
  158. $questions .= ',';
  159. }
  160. $i++;
  161. }
  162. $db->Execute("insert into FileVersions (" . $fields . ") values (" . $questions . ")", $data2);
  163. $this->deny();
  164. $r = $db->Execute('select fvID, akID, avID from FileAttributeValues where fID = ? and fvID = ?', array($this->getFileID(), $this->fvID));
  165. while ($row = $r->fetchRow()) {
  166. $db->Execute("insert into FileAttributeValues (fID, fvID, akID, avID) values (?, ?, ?, ?)", array(
  167. $this->fID,
  168. $fvID,
  169. $row['akID'],
  170. $row['avID']
  171. ));
  172. }
  173. $fv2 = $f->getVersion($fvID);
  174. Events::fire('on_file_version_duplicate', $fv2);
  175. return $fv2;
  176. }
  177. public function getType() {
  178. $ftl = $this->getTypeObject();
  179. if (is_object($ftl)) {
  180. return $ftl->getName();
  181. }
  182. }
  183. public function getTypeObject() {
  184. $fh = Loader::helper('file');
  185. $ext = $fh->getExtension($this->fvFilename);
  186. $ftl = FileTypeList::getType($ext);
  187. return $ftl;
  188. }
  189. /**
  190. * Returns an array containing human-readable descriptions of everything that happened in this version
  191. */
  192. public function getVersionLogComments() {
  193. $updates = array();
  194. $db = Loader::db();
  195. $ga = $db->GetAll('select fvUpdateTypeID, fvUpdateTypeAttributeID from FileVersionLog where fID = ? and fvID = ? order by fvlID asc', array($this->getFileID(), $this->getFileVersionID()));
  196. foreach($ga as $a) {
  197. switch($a['fvUpdateTypeID']) {
  198. case FileVersion::UT_REPLACE_FILE:
  199. $updates[] = t('File');
  200. break;
  201. case FileVersion::UT_TITLE:
  202. $updates[] = t('Title');
  203. break;
  204. case FileVersion::UT_DESCRIPTION:
  205. $updates[] = t('Description');
  206. break;
  207. case FileVersion::UT_TAGS:
  208. $updates[] = t('Tags');
  209. break;
  210. case FileVersion::UT_EXTENDED_ATTRIBUTE:
  211. $val = $db->GetOne("select akName from AttributeKeys where akID = ?", array($a['fvUpdateTypeAttributeID']));
  212. if ($val != '') {
  213. $updates[] = $val;
  214. }
  215. break;
  216. }
  217. }
  218. $updates = array_unique($updates);
  219. $updates1 = array();
  220. foreach($updates as $val) {
  221. // normalize the keys
  222. $updates1[] = $val;
  223. }
  224. return $updates1;
  225. }
  226. public function updateTitle($title) {
  227. $db = Loader::db();
  228. $db->Execute("update FileVersions set fvTitle = ? where fID = ? and fvID = ?", array($title, $this->getFileID(), $this->getFileVersionID()));
  229. $this->logVersionUpdate(FileVersion::UT_TITLE);
  230. $this->fvTitle = $title;
  231. Events::fire('on_file_version_update_title', $this, $title);
  232. $fo = $this->getFile();
  233. $fo->refreshCache();
  234. }
  235. public function updateTags($tags) {
  236. $db = Loader::db();
  237. $tags = FileVersion::cleanTags($tags);
  238. $db->Execute("update FileVersions set fvTags = ? where fID = ? and fvID = ?", array($tags, $this->getFileID(), $this->getFileVersionID()));
  239. $this->logVersionUpdate(FileVersion::UT_TAGS);
  240. $this->fvTags = $tags;
  241. Events::fire('on_file_version_update_tags', $this, $tags);
  242. $fo = $this->getFile();
  243. $fo->refreshCache();
  244. }
  245. public function updateDescription($descr) {
  246. $db = Loader::db();
  247. $db->Execute("update FileVersions set fvDescription = ? where fID = ? and fvID = ?", array($descr, $this->getFileID(), $this->getFileVersionID()));
  248. $this->logVersionUpdate(FileVersion::UT_DESCRIPTION);
  249. $this->fvDescription = $descr;
  250. Events::fire('on_file_version_update_description', $this, $descr);
  251. $fo = $this->getFile();
  252. $fo->refreshCache();
  253. }
  254. public function updateFile($filename, $prefix) {
  255. $db = Loader::db();
  256. $db->Execute("update FileVersions set fvFilename = ?, fvPrefix = ? where fID = ? and fvID = ?", array($filename, $prefix, $this->getFileID(), $this->getFileVersionID()));
  257. $this->logVersionUpdate(FileVersion::UT_REPLACE_FILE);
  258. $this->fvFilename = $filename;
  259. $this->fvPrefix = $prefix;
  260. $fo = $this->getFile();
  261. $fo->refreshCache();
  262. }
  263. public function approve() {
  264. $db = Loader::db();
  265. $db->Execute("update FileVersions set fvIsApproved = 0 where fID = ?", array($this->getFileID()));
  266. $db->Execute("update FileVersions set fvIsApproved = 1 where fID = ? and fvID = ?", array($this->getFileID(), $this->getFileVersionID()));
  267. Events::fire('on_file_version_approve', $this);
  268. $fo = $this->getFile();
  269. $fo->reindex();
  270. $fo->refreshCache();
  271. }
  272. public function deny() {
  273. $db = Loader::db();
  274. $db->Execute("update FileVersions set fvIsApproved = 0 where fID = ? and fvID = ?", array($this->getFileID(), $this->getFileVersionID()));
  275. Events::fire('on_file_version_deny', $this);
  276. $fo = $this->getFile();
  277. $fo->refreshCache();
  278. }
  279. public function setAttribute($ak, $value) {
  280. if (!is_object($ak)) {
  281. $ak = FileAttributeKey::getByHandle($ak);
  282. }
  283. $ak->setAttribute($this, $value);
  284. $fo = $this->getFile();
  285. $fo->refreshCache();
  286. $fo->reindex();
  287. unset($ak);
  288. }
  289. /**
  290. * Removes a version of a file. Note, does NOT remove the file because we don't know where the file might elsewhere be used/referenced.
  291. */
  292. public function delete() {
  293. if ($this->fvIsApproved == 1) {
  294. return false; // can only delete non-live files
  295. }
  296. $db = Loader::db();
  297. // now from the DB
  298. $db->Execute("delete from FileVersions where fID = ? and fvID = ?", array($this->fID, $this->fvID));
  299. $db->Execute("delete from FileAttributeValues where fID = ? and fvID = ?", array($this->fID, $this->fvID));
  300. $db->Execute("delete from FileVersionLog where fID = ? and fvID = ?", array($this->fID, $this->fvID));
  301. }
  302. /**
  303. * Returns a full filesystem path to the file on disk.
  304. */
  305. public function getPath() {
  306. $f = Loader::helper('concrete/file');
  307. if ($this->fslID > 0) {
  308. Loader::model('file_storage_location');
  309. $fsl = FileStorageLocation::getByID($this->fslID);
  310. $path = $f->mapSystemPath($this->fvPrefix, $this->fvFilename, false, $fsl->getDirectory());
  311. } else {
  312. $path = $f->getSystemPath($this->fvPrefix, $this->fvFilename);
  313. }
  314. return $path;
  315. }
  316. /**
  317. * Returns a full URL to the file on disk
  318. */
  319. public function getURL() {
  320. return BASE_URL . $this->getRelativePath();
  321. }
  322. /**
  323. * Returns a URL that can be used to download the file. This passes through the download_file single page.
  324. */
  325. public function getDownloadURL() {
  326. $c = Page::getCurrentPage();
  327. if($c instanceof Page) {
  328. $cID = $c->getCollectionID();
  329. } else {
  330. $cID = 0;
  331. }
  332. return BASE_URL . View::url('/download_file',$this->getFileID(),$cID);
  333. }
  334. /**
  335. * Returns a url that can be used to download a file, will force the download of all file types, even if your browser can display them.
  336. */
  337. public function getForceDownloadURL() {
  338. $c = Page::getCurrentPage();
  339. if($c instanceof Page) {
  340. $cID = $c->getCollectionID();
  341. } else {
  342. $cID = 0;
  343. }
  344. return BASE_URL . View::url('/download_file','force', $this->getFileID(),$cID);
  345. }
  346. public function getRelativePath($fullurl = false) {
  347. $f = Loader::helper('concrete/file');
  348. if ($this->fslID > 0) {
  349. $c = Page::getCurrentPage();
  350. if($c instanceof Page) {
  351. $cID = $c->getCollectionID();
  352. } else {
  353. $cID = 0;
  354. }
  355. $path = BASE_URL . View::url('/download_file', 'view_inline', $this->getFileID(),$cID);
  356. } else {
  357. if ($fullurl) {
  358. $path = BASE_URL . $f->getFileRelativePath($this->fvPrefix, $this->fvFilename );
  359. } else {
  360. $path = $f->getFileRelativePath($this->fvPrefix, $this->fvFilename );
  361. }
  362. }
  363. return $path;
  364. }
  365. public function getThumbnailPath($level) {
  366. $f = Loader::helper('concrete/file');
  367. $path = $f->getThumbnailSystemPath($this->fvPrefix, $this->fvFilename, $level);
  368. return $path;
  369. }
  370. public function getThumbnailSRC($level) {
  371. if ($this->{"fvHasThumbnail{$level}"}) {
  372. $f = Loader::helper('concrete/file');
  373. $path = $f->getThumbnailRelativePath($this->fvPrefix, $this->fvFilename, $level);
  374. return $path;
  375. }
  376. }
  377. public function hasThumbnail($level) {
  378. return $this->{"fvHasThumbnail{$level}"};
  379. }
  380. public function getThumbnail($level, $fullImageTag = true) {
  381. $html = Loader::helper('html');
  382. if ($this->{"fvHasThumbnail{$level}"}) {
  383. if ($fullImageTag) {
  384. return $html->image($this->getThumbnailSRC($level));
  385. } else {
  386. return $this->getThumbnailSRC($level);
  387. }
  388. } else {
  389. $ft = FileTypeList::getType($this->fvFilename);
  390. return $ft->getThumbnail($level, $fullImageTag);
  391. }
  392. }
  393. //
  394. public function refreshThumbnails($refreshCache = true) {
  395. $db = Loader::db();
  396. $f = Loader::helper('concrete/file');
  397. for ($i = 1; $i <= $this->numThumbnailLevels; $i++) {
  398. $path = $f->getThumbnailSystemPath($this->fvPrefix, $this->fvFilename, $i);
  399. $hasThumbnail = 0;
  400. if (file_exists($path)) {
  401. $hasThumbnail = 1;
  402. }
  403. $db->Execute("update FileVersions set fvHasThumbnail" . $i . "= ? where fID = ? and fvID = ?", array($hasThumbnail, $this->fID, $this->fvID));
  404. }
  405. if ($refreshCache) {
  406. $fo = $this->getFile();
  407. $fo->refreshCache();
  408. }
  409. }
  410. // update types
  411. const UT_NEW = 0;
  412. /**
  413. * Responsible for taking a particular version of a file and rescanning all its attributes
  414. * This will run any type-based import routines, and store those attributes, generate thumbnails,
  415. * etc...
  416. */
  417. public function refreshAttributes($firstRun = false) {
  418. $fh = Loader::helper('file');
  419. $ext = $fh->getExtension($this->fvFilename);
  420. $ftl = FileTypeList::getType($ext);
  421. $db = Loader::db();
  422. if (!file_exists($this->getPath())) {
  423. return File::F_ERROR_FILE_NOT_FOUND;
  424. }
  425. $size = filesize($this->getPath());
  426. $title = ($firstRun) ? $this->getFilename() : $this->getTitle();
  427. $db->Execute('update FileVersions set fvExtension = ?, fvType = ?, fvTitle = ?, fvSize = ? where fID = ? and fvID = ?',
  428. array($ext, $ftl->getGenericType(), $title, $size, $this->getFileID(), $this->getFileVersionID())
  429. );
  430. if (is_object($ftl)) {
  431. if ($ftl->getCustomImporter() != false) {
  432. Loader::library('file/inspector');
  433. $db->Execute('update FileVersions set fvGenericType = ? where fID = ? and fvID = ?',
  434. array($ftl->getGenericType(), $this->getFileID(), $this->getFileVersionID())
  435. );
  436. // we have a custom library script that handles this stuff
  437. $cl = $ftl->getCustomInspector();
  438. $cl->inspect($this);
  439. }
  440. }
  441. $this->refreshThumbnails(false);
  442. $f = $this->getFile();
  443. $f->refreshCache();
  444. $f->reindex();
  445. }
  446. public function createThumbnailDirectories(){
  447. $f = Loader::helper('concrete/file');
  448. for ($i = 1; $i <= $this->numThumbnailLevels; $i++) {
  449. $path = $f->getThumbnailSystemPath($this->fvPrefix, $this->fvFilename, $i, true);
  450. }
  451. }
  452. /**
  453. * Checks current viewers for this type and returns true if there is a viewer for this type, false if not
  454. */
  455. public function canView() {
  456. $to = $this->getTypeObject();
  457. if (is_object($to) && $to->getView() != '') {
  458. return true;
  459. }
  460. return false;
  461. }
  462. public function canEdit() {
  463. $to = $this->getTypeObject();
  464. if (is_object($to) && $to->getEditor() != '') {
  465. return true;
  466. }
  467. return false;
  468. }
  469. public function clearAttribute($ak) {
  470. $db = Loader::db();
  471. $cav = $this->getAttributeValueObject($ak);
  472. if (is_object($cav)) {
  473. $cav->delete();
  474. }
  475. $fo = $this->getFile();
  476. $fo->refreshCache();
  477. $fo->reindex();
  478. }
  479. public function getAttributeValueObject($ak, $createIfNotFound = false) {
  480. $db = Loader::db();
  481. $av = false;
  482. $v = array($this->getFileID(), $this->getFileVersionID(), $ak->getAttributeKeyID());
  483. $avID = $db->GetOne("select avID from FileAttributeValues where fID = ? and fvID = ? and akID = ?", $v);
  484. if ($avID > 0) {
  485. $av = FileAttributeValue::getByID($avID);
  486. if (is_object($av)) {
  487. $av->setFile($this->getFile());
  488. $av->setAttributeKey($ak);
  489. }
  490. }
  491. if ($createIfNotFound) {
  492. $cnt = 0;
  493. // Is this avID in use ?
  494. if (is_object($av)) {
  495. $cnt = $db->GetOne("select count(avID) from FileAttributeValues where avID = ?", $av->getAttributeValueID());
  496. }
  497. if ((!is_object($av)) || ($cnt > 1)) {
  498. $newAV = $ak->addAttributeValue();
  499. $av = FileAttributeValue::getByID($newAV->getAttributeValueID());
  500. $av->setFile($this->getFile());
  501. }
  502. }
  503. return $av;
  504. }
  505. //takes a string of comma or new line delimited tags, and puts them in the appropriate format
  506. public static function cleanTags($tagsStr){
  507. $tagsArray=explode("\n",str_replace(array("\r",","),"\n",$tagsStr));
  508. $cleanTags=array();
  509. foreach($tagsArray as $tag){
  510. if( !strlen(trim($tag)) ) continue;
  511. $cleanTags[]=trim($tag);
  512. }
  513. //the leading and trailing line break char is for searching: fvTag like %\ntag\n%
  514. return "\n".join("\n",$cleanTags)."\n";
  515. }
  516. }