PageRenderTime 26ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/filestorage/stored_file.php

https://bitbucket.org/kudutest1/moodlegit
PHP | 959 lines | 453 code | 92 blank | 414 comment | 78 complexity | 9c5418df87f24b5eb54ff8491807eb54 MD5 | raw file
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Definition of a class stored_file.
  18. *
  19. * @package core_files
  20. * @copyright 2008 Petr Skoda {@link http://skodak.org}
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. defined('MOODLE_INTERNAL') || die();
  24. /**
  25. * Class representing local files stored in a sha1 file pool.
  26. *
  27. * Since Moodle 2.0 file contents are stored in sha1 pool and
  28. * all other file information is stored in new "files" database table.
  29. *
  30. * @package core_files
  31. * @category files
  32. * @copyright 2008 Petr Skoda {@link http://skodak.org}
  33. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34. * @since Moodle 2.0
  35. */
  36. class stored_file {
  37. /** @var file_storage file storage pool instance */
  38. private $fs;
  39. /** @var stdClass record from the files table left join files_reference table */
  40. private $file_record;
  41. /** @var string location of content files */
  42. private $filedir;
  43. /** @var repository repository plugin instance */
  44. private $repository;
  45. /**
  46. * Constructor, this constructor should be called ONLY from the file_storage class!
  47. *
  48. * @param file_storage $fs file storage instance
  49. * @param stdClass $file_record description of file
  50. * @param string $filedir location of file directory with sh1 named content files
  51. */
  52. public function __construct(file_storage $fs, stdClass $file_record, $filedir) {
  53. global $DB, $CFG;
  54. $this->fs = $fs;
  55. $this->file_record = clone($file_record); // prevent modifications
  56. $this->filedir = $filedir; // keep secret, do not expose!
  57. if (!empty($file_record->repositoryid)) {
  58. require_once("$CFG->dirroot/repository/lib.php");
  59. $this->repository = repository::get_repository_by_id($file_record->repositoryid, SYSCONTEXTID);
  60. if ($this->repository->supported_returntypes() & FILE_REFERENCE != FILE_REFERENCE) {
  61. // Repository cannot do file reference.
  62. throw new moodle_exception('error');
  63. }
  64. } else {
  65. $this->repository = null;
  66. }
  67. // make sure all reference fields exist in file_record even when it is not a reference
  68. foreach (array('referencelastsync', 'referencelifetime', 'referencefileid', 'reference', 'repositoryid') as $key) {
  69. if (empty($this->file_record->$key)) {
  70. $this->file_record->$key = null;
  71. }
  72. }
  73. }
  74. /**
  75. * Whether or not this is a external resource
  76. *
  77. * @return bool
  78. */
  79. public function is_external_file() {
  80. return !empty($this->repository);
  81. }
  82. /**
  83. * Update some file record fields
  84. * NOTE: Must remain protected
  85. *
  86. * @param stdClass $dataobject
  87. */
  88. protected function update($dataobject) {
  89. global $DB;
  90. $keys = array_keys((array)$this->file_record);
  91. foreach ($dataobject as $field => $value) {
  92. if (in_array($field, $keys)) {
  93. if ($field == 'contextid' and (!is_number($value) or $value < 1)) {
  94. throw new file_exception('storedfileproblem', 'Invalid contextid');
  95. }
  96. if ($field == 'component') {
  97. $value = clean_param($value, PARAM_COMPONENT);
  98. if (empty($value)) {
  99. throw new file_exception('storedfileproblem', 'Invalid component');
  100. }
  101. }
  102. if ($field == 'filearea') {
  103. $value = clean_param($value, PARAM_AREA);
  104. if (empty($value)) {
  105. throw new file_exception('storedfileproblem', 'Invalid filearea');
  106. }
  107. }
  108. if ($field == 'itemid' and (!is_number($value) or $value < 0)) {
  109. throw new file_exception('storedfileproblem', 'Invalid itemid');
  110. }
  111. if ($field == 'filepath') {
  112. $value = clean_param($value, PARAM_PATH);
  113. if (strpos($value, '/') !== 0 or strrpos($value, '/') !== strlen($value)-1) {
  114. // path must start and end with '/'
  115. throw new file_exception('storedfileproblem', 'Invalid file path');
  116. }
  117. }
  118. if ($field == 'filename') {
  119. // folder has filename == '.', so we pass this
  120. if ($value != '.') {
  121. $value = clean_param($value, PARAM_FILE);
  122. }
  123. if ($value === '') {
  124. throw new file_exception('storedfileproblem', 'Invalid file name');
  125. }
  126. }
  127. if ($field === 'timecreated' or $field === 'timemodified') {
  128. if (!is_number($value)) {
  129. throw new file_exception('storedfileproblem', 'Invalid timestamp');
  130. }
  131. if ($value < 0) {
  132. $value = 0;
  133. }
  134. }
  135. if ($field === 'referencefileid') {
  136. if (!is_null($value) and !is_number($value)) {
  137. throw new file_exception('storedfileproblem', 'Invalid reference info');
  138. }
  139. }
  140. if ($field === 'referencelastsync' or $field === 'referencelifetime') {
  141. // do not update those fields
  142. // TODO MDL-33416 [2.4] fields referencelastsync and referencelifetime to be removed from {files} table completely
  143. continue;
  144. }
  145. // adding the field
  146. $this->file_record->$field = $value;
  147. } else {
  148. throw new coding_exception("Invalid field name, $field doesn't exist in file record");
  149. }
  150. }
  151. // Validate mimetype field
  152. // we don't use {@link stored_file::get_content_file_location()} here becaues it will try to update file_record
  153. $pathname = $this->get_pathname_by_contenthash();
  154. // try to recover the content from trash
  155. if (!is_readable($pathname)) {
  156. if (!$this->fs->try_content_recovery($this) or !is_readable($pathname)) {
  157. throw new file_exception('storedfilecannotread', '', $pathname);
  158. }
  159. }
  160. $mimetype = $this->fs->mimetype($pathname, $this->file_record->filename);
  161. $this->file_record->mimetype = $mimetype;
  162. $DB->update_record('files', $this->file_record);
  163. }
  164. /**
  165. * Rename filename
  166. *
  167. * @param string $filepath file path
  168. * @param string $filename file name
  169. */
  170. public function rename($filepath, $filename) {
  171. if ($this->fs->file_exists($this->get_contextid(), $this->get_component(), $this->get_filearea(), $this->get_itemid(), $filepath, $filename)) {
  172. throw new file_exception('storedfilenotcreated', '', 'file exists, cannot rename');
  173. }
  174. $filerecord = new stdClass;
  175. $filerecord->filepath = $filepath;
  176. $filerecord->filename = $filename;
  177. // populate the pathname hash
  178. $filerecord->pathnamehash = $this->fs->get_pathname_hash($this->file_record->contextid, $this->file_record->component, $this->file_record->filearea, $this->file_record->itemid, $filepath, $filename);
  179. $this->update($filerecord);
  180. }
  181. /**
  182. * Replace the content by providing another stored_file instance
  183. *
  184. * @param stored_file $storedfile
  185. */
  186. public function replace_content_with(stored_file $storedfile) {
  187. $contenthash = $storedfile->get_contenthash();
  188. $this->set_contenthash($contenthash);
  189. $this->set_filesize($storedfile->get_filesize());
  190. }
  191. /**
  192. * Unlink the stored file from the referenced file
  193. *
  194. * This methods destroys the link to the record in files_reference table. This effectively
  195. * turns the stored file from being an alias to a plain copy. However, the caller has
  196. * to make sure that the actual file's content has beed synced prior to calling this method.
  197. */
  198. public function delete_reference() {
  199. global $DB;
  200. if (!$this->is_external_file()) {
  201. throw new coding_exception('An attempt to unlink a non-reference file.');
  202. }
  203. $transaction = $DB->start_delegated_transaction();
  204. // Are we the only one referring to the original file? If so, delete the
  205. // referenced file record. Note we do not use file_storage::search_references_count()
  206. // here because we want to count draft files too and we are at a bit lower access level here.
  207. $countlinks = $DB->count_records('files',
  208. array('referencefileid' => $this->file_record->referencefileid));
  209. if ($countlinks == 1) {
  210. $DB->delete_records('files_reference', array('id' => $this->file_record->referencefileid));
  211. }
  212. // Update the underlying record in the database.
  213. $update = new stdClass();
  214. $update->referencefileid = null;
  215. $this->update($update);
  216. $transaction->allow_commit();
  217. // Update our properties and the record in the memory.
  218. $this->repository = null;
  219. $this->file_record->repositoryid = null;
  220. $this->file_record->reference = null;
  221. $this->file_record->referencefileid = null;
  222. $this->file_record->referencelastsync = null;
  223. $this->file_record->referencelifetime = null;
  224. }
  225. /**
  226. * Is this a directory?
  227. *
  228. * Directories are only emulated, internally they are stored as empty
  229. * files with a "." instead of name - this means empty directory contains
  230. * exactly one empty file with name dot.
  231. *
  232. * @return bool true means directory, false means file
  233. */
  234. public function is_directory() {
  235. return ($this->file_record->filename === '.');
  236. }
  237. /**
  238. * Delete file from files table.
  239. *
  240. * The content of files stored in sha1 pool is reclaimed
  241. * later - the occupied disk space is reclaimed much later.
  242. *
  243. * @return bool always true or exception if error occurred
  244. */
  245. public function delete() {
  246. global $DB;
  247. if ($this->is_directory()) {
  248. // Directories can not be referenced, just delete the record.
  249. $DB->delete_records('files', array('id'=>$this->file_record->id));
  250. } else {
  251. $transaction = $DB->start_delegated_transaction();
  252. // If there are other files referring to this file, convert them to copies.
  253. if ($files = $this->fs->get_references_by_storedfile($this)) {
  254. foreach ($files as $file) {
  255. $this->fs->import_external_file($file);
  256. }
  257. }
  258. // If this file is a reference (alias) to another file, unlink it first.
  259. if ($this->is_external_file()) {
  260. $this->delete_reference();
  261. }
  262. // Now delete the file record.
  263. $DB->delete_records('files', array('id'=>$this->file_record->id));
  264. $transaction->allow_commit();
  265. }
  266. // Move pool file to trash if content not needed any more.
  267. $this->fs->deleted_file_cleanup($this->file_record->contenthash);
  268. return true; // BC only
  269. }
  270. /**
  271. * Get file pathname by contenthash
  272. *
  273. * NOTE, this function is not calling sync_external_file, it assume the contenthash is current
  274. * Protected - developers must not gain direct access to this function.
  275. *
  276. * @return string full path to pool file with file content
  277. */
  278. protected function get_pathname_by_contenthash() {
  279. // Detect is local file or not.
  280. $contenthash = $this->file_record->contenthash;
  281. $l1 = $contenthash[0].$contenthash[1];
  282. $l2 = $contenthash[2].$contenthash[3];
  283. return "$this->filedir/$l1/$l2/$contenthash";
  284. }
  285. /**
  286. * Get file pathname by given contenthash, this method will try to sync files
  287. *
  288. * Protected - developers must not gain direct access to this function.
  289. *
  290. * NOTE: do not make this public, we must not modify or delete the pool files directly! ;-)
  291. *
  292. * @return string full path to pool file with file content
  293. **/
  294. protected function get_content_file_location() {
  295. $this->sync_external_file();
  296. return $this->get_pathname_by_contenthash();
  297. }
  298. /**
  299. * adds this file path to a curl request (POST only)
  300. *
  301. * @param curl $curlrequest the curl request object
  302. * @param string $key what key to use in the POST request
  303. * @return void
  304. */
  305. public function add_to_curl_request(&$curlrequest, $key) {
  306. $curlrequest->_tmp_file_post_params[$key] = '@' . $this->get_content_file_location();
  307. }
  308. /**
  309. * Returns file handle - read only mode, no writing allowed into pool files!
  310. *
  311. * When you want to modify a file, create a new file and delete the old one.
  312. *
  313. * @return resource file handle
  314. */
  315. public function get_content_file_handle() {
  316. $path = $this->get_content_file_location();
  317. if (!is_readable($path)) {
  318. if (!$this->fs->try_content_recovery($this) or !is_readable($path)) {
  319. throw new file_exception('storedfilecannotread', '', $path);
  320. }
  321. }
  322. return fopen($path, 'rb'); // Binary reading only!!
  323. }
  324. /**
  325. * Dumps file content to page.
  326. */
  327. public function readfile() {
  328. $path = $this->get_content_file_location();
  329. if (!is_readable($path)) {
  330. if (!$this->fs->try_content_recovery($this) or !is_readable($path)) {
  331. throw new file_exception('storedfilecannotread', '', $path);
  332. }
  333. }
  334. readfile($path);
  335. }
  336. /**
  337. * Returns file content as string.
  338. *
  339. * @return string content
  340. */
  341. public function get_content() {
  342. $path = $this->get_content_file_location();
  343. if (!is_readable($path)) {
  344. if (!$this->fs->try_content_recovery($this) or !is_readable($path)) {
  345. throw new file_exception('storedfilecannotread', '', $path);
  346. }
  347. }
  348. return file_get_contents($this->get_content_file_location());
  349. }
  350. /**
  351. * Copy content of file to given pathname.
  352. *
  353. * @param string $pathname real path to the new file
  354. * @return bool success
  355. */
  356. public function copy_content_to($pathname) {
  357. $path = $this->get_content_file_location();
  358. if (!is_readable($path)) {
  359. if (!$this->fs->try_content_recovery($this) or !is_readable($path)) {
  360. throw new file_exception('storedfilecannotread', '', $path);
  361. }
  362. }
  363. return copy($path, $pathname);
  364. }
  365. /**
  366. * Copy content of file to temporary folder and returns file path
  367. *
  368. * @param string $dir name of the temporary directory
  369. * @param string $fileprefix prefix of temporary file.
  370. * @return string|bool path of temporary file or false.
  371. */
  372. public function copy_content_to_temp($dir = 'files', $fileprefix = 'tempup_') {
  373. $tempfile = false;
  374. if (!$dir = make_temp_directory($dir)) {
  375. return false;
  376. }
  377. if (!$tempfile = tempnam($dir, $fileprefix)) {
  378. return false;
  379. }
  380. if (!$this->copy_content_to($tempfile)) {
  381. // something went wrong
  382. @unlink($tempfile);
  383. return false;
  384. }
  385. return $tempfile;
  386. }
  387. /**
  388. * List contents of archive.
  389. *
  390. * @param file_packer $packer file packer instance
  391. * @return array of file infos
  392. */
  393. public function list_files(file_packer $packer) {
  394. $archivefile = $this->get_content_file_location();
  395. return $packer->list_files($archivefile);
  396. }
  397. /**
  398. * Extract file to given file path (real OS filesystem), existing files are overwritten.
  399. *
  400. * @param file_packer $packer file packer instance
  401. * @param string $pathname target directory
  402. * @return array|bool list of processed files; false if error
  403. */
  404. public function extract_to_pathname(file_packer $packer, $pathname) {
  405. $archivefile = $this->get_content_file_location();
  406. return $packer->extract_to_pathname($archivefile, $pathname);
  407. }
  408. /**
  409. * Extract file to given file path (real OS filesystem), existing files are overwritten.
  410. *
  411. * @param file_packer $packer file packer instance
  412. * @param int $contextid context ID
  413. * @param string $component component
  414. * @param string $filearea file area
  415. * @param int $itemid item ID
  416. * @param string $pathbase path base
  417. * @param int $userid user ID
  418. * @return array|bool list of processed files; false if error
  419. */
  420. public function extract_to_storage(file_packer $packer, $contextid, $component, $filearea, $itemid, $pathbase, $userid = NULL) {
  421. $archivefile = $this->get_content_file_location();
  422. return $packer->extract_to_storage($archivefile, $contextid, $component, $filearea, $itemid, $pathbase);
  423. }
  424. /**
  425. * Add file/directory into archive.
  426. *
  427. * @param file_archive $filearch file archive instance
  428. * @param string $archivepath pathname in archive
  429. * @return bool success
  430. */
  431. public function archive_file(file_archive $filearch, $archivepath) {
  432. if ($this->is_directory()) {
  433. return $filearch->add_directory($archivepath);
  434. } else {
  435. $path = $this->get_content_file_location();
  436. if (!is_readable($path)) {
  437. return false;
  438. }
  439. return $filearch->add_file_from_pathname($archivepath, $path);
  440. }
  441. }
  442. /**
  443. * Returns information about image,
  444. * information is determined from the file content
  445. *
  446. * @return mixed array with width, height and mimetype; false if not an image
  447. */
  448. public function get_imageinfo() {
  449. $path = $this->get_content_file_location();
  450. if (!is_readable($path)) {
  451. if (!$this->fs->try_content_recovery($this) or !is_readable($path)) {
  452. throw new file_exception('storedfilecannotread', '', $path);
  453. }
  454. }
  455. $mimetype = $this->get_mimetype();
  456. if (!preg_match('|^image/|', $mimetype) || !filesize($path) || !($imageinfo = getimagesize($path))) {
  457. return false;
  458. }
  459. $image = array('width'=>$imageinfo[0], 'height'=>$imageinfo[1], 'mimetype'=>image_type_to_mime_type($imageinfo[2]));
  460. if (empty($image['width']) or empty($image['height']) or empty($image['mimetype'])) {
  461. // gd can not parse it, sorry
  462. return false;
  463. }
  464. return $image;
  465. }
  466. /**
  467. * Verifies the file is a valid web image - gif, png and jpeg only.
  468. *
  469. * It should be ok to serve this image from server without any other security workarounds.
  470. *
  471. * @return bool true if file ok
  472. */
  473. public function is_valid_image() {
  474. $mimetype = $this->get_mimetype();
  475. if (!file_mimetype_in_typegroup($mimetype, 'web_image')) {
  476. return false;
  477. }
  478. if (!$info = $this->get_imageinfo()) {
  479. return false;
  480. }
  481. if ($info['mimetype'] !== $mimetype) {
  482. return false;
  483. }
  484. // ok, GD likes this image
  485. return true;
  486. }
  487. /**
  488. * Returns parent directory, creates missing parents if needed.
  489. *
  490. * @return stored_file
  491. */
  492. public function get_parent_directory() {
  493. if ($this->file_record->filepath === '/' and $this->file_record->filename === '.') {
  494. //root dir does not have parent
  495. return null;
  496. }
  497. if ($this->file_record->filename !== '.') {
  498. return $this->fs->create_directory($this->file_record->contextid, $this->file_record->component, $this->file_record->filearea, $this->file_record->itemid, $this->file_record->filepath);
  499. }
  500. $filepath = $this->file_record->filepath;
  501. $filepath = trim($filepath, '/');
  502. $dirs = explode('/', $filepath);
  503. array_pop($dirs);
  504. $filepath = implode('/', $dirs);
  505. $filepath = ($filepath === '') ? '/' : "/$filepath/";
  506. return $this->fs->create_directory($this->file_record->contextid, $this->file_record->component, $this->file_record->filearea, $this->file_record->itemid, $filepath);
  507. }
  508. /**
  509. * Synchronize file if it is a reference and needs synchronizing
  510. *
  511. * Updates contenthash and filesize
  512. */
  513. public function sync_external_file() {
  514. global $CFG;
  515. if (!empty($this->file_record->referencefileid)) {
  516. require_once($CFG->dirroot.'/repository/lib.php');
  517. repository::sync_external_file($this);
  518. }
  519. }
  520. /**
  521. * Returns context id of the file
  522. *
  523. * @return int context id
  524. */
  525. public function get_contextid() {
  526. return $this->file_record->contextid;
  527. }
  528. /**
  529. * Returns component name - this is the owner of the areas,
  530. * nothing else is allowed to read or modify the files directly!!
  531. *
  532. * @return string
  533. */
  534. public function get_component() {
  535. return $this->file_record->component;
  536. }
  537. /**
  538. * Returns file area name, this divides files of one component into groups with different access control.
  539. * All files in one area have the same access control.
  540. *
  541. * @return string
  542. */
  543. public function get_filearea() {
  544. return $this->file_record->filearea;
  545. }
  546. /**
  547. * Returns returns item id of file.
  548. *
  549. * @return int
  550. */
  551. public function get_itemid() {
  552. return $this->file_record->itemid;
  553. }
  554. /**
  555. * Returns file path - starts and ends with /, \ are not allowed.
  556. *
  557. * @return string
  558. */
  559. public function get_filepath() {
  560. return $this->file_record->filepath;
  561. }
  562. /**
  563. * Returns file name or '.' in case of directories.
  564. *
  565. * @return string
  566. */
  567. public function get_filename() {
  568. return $this->file_record->filename;
  569. }
  570. /**
  571. * Returns id of user who created the file.
  572. *
  573. * @return int
  574. */
  575. public function get_userid() {
  576. return $this->file_record->userid;
  577. }
  578. /**
  579. * Returns the size of file in bytes.
  580. *
  581. * @return int bytes
  582. */
  583. public function get_filesize() {
  584. $this->sync_external_file();
  585. return $this->file_record->filesize;
  586. }
  587. /**
  588. * Returns the size of file in bytes.
  589. *
  590. * @param int $filesize bytes
  591. */
  592. public function set_filesize($filesize) {
  593. $filerecord = new stdClass;
  594. $filerecord->filesize = $filesize;
  595. $this->update($filerecord);
  596. }
  597. /**
  598. * Returns mime type of file.
  599. *
  600. * @return string
  601. */
  602. public function get_mimetype() {
  603. return $this->file_record->mimetype;
  604. }
  605. /**
  606. * Returns unix timestamp of file creation date.
  607. *
  608. * @return int
  609. */
  610. public function get_timecreated() {
  611. return $this->file_record->timecreated;
  612. }
  613. /**
  614. * Returns unix timestamp of last file modification.
  615. *
  616. * @return int
  617. */
  618. public function get_timemodified() {
  619. $this->sync_external_file();
  620. return $this->file_record->timemodified;
  621. }
  622. /**
  623. * set timemodified
  624. *
  625. * @param int $timemodified
  626. */
  627. public function set_timemodified($timemodified) {
  628. $filerecord = new stdClass;
  629. $filerecord->timemodified = $timemodified;
  630. $this->update($filerecord);
  631. }
  632. /**
  633. * Returns file status flag.
  634. *
  635. * @return int 0 means file OK, anything else is a problem and file can not be used
  636. */
  637. public function get_status() {
  638. return $this->file_record->status;
  639. }
  640. /**
  641. * Returns file id.
  642. *
  643. * @return int
  644. */
  645. public function get_id() {
  646. return $this->file_record->id;
  647. }
  648. /**
  649. * Returns sha1 hash of file content.
  650. *
  651. * @return string
  652. */
  653. public function get_contenthash() {
  654. $this->sync_external_file();
  655. return $this->file_record->contenthash;
  656. }
  657. /**
  658. * Set contenthash
  659. *
  660. * @param string $contenthash
  661. */
  662. protected function set_contenthash($contenthash) {
  663. // make sure the content exists in moodle file pool
  664. if ($this->fs->content_exists($contenthash)) {
  665. $filerecord = new stdClass;
  666. $filerecord->contenthash = $contenthash;
  667. $this->update($filerecord);
  668. } else {
  669. throw new file_exception('storedfileproblem', 'Invalid contenthash, content must be already in filepool', $contenthash);
  670. }
  671. }
  672. /**
  673. * Returns sha1 hash of all file path components sha1("contextid/component/filearea/itemid/dir/dir/filename.ext").
  674. *
  675. * @return string
  676. */
  677. public function get_pathnamehash() {
  678. return $this->file_record->pathnamehash;
  679. }
  680. /**
  681. * Returns the license type of the file, it is a short name referred from license table.
  682. *
  683. * @return string
  684. */
  685. public function get_license() {
  686. return $this->file_record->license;
  687. }
  688. /**
  689. * Set license
  690. *
  691. * @param string $license license
  692. */
  693. public function set_license($license) {
  694. $filerecord = new stdClass;
  695. $filerecord->license = $license;
  696. $this->update($filerecord);
  697. }
  698. /**
  699. * Returns the author name of the file.
  700. *
  701. * @return string
  702. */
  703. public function get_author() {
  704. return $this->file_record->author;
  705. }
  706. /**
  707. * Set author
  708. *
  709. * @param string $author
  710. */
  711. public function set_author($author) {
  712. $filerecord = new stdClass;
  713. $filerecord->author = $author;
  714. $this->update($filerecord);
  715. }
  716. /**
  717. * Returns the source of the file, usually it is a url.
  718. *
  719. * @return string
  720. */
  721. public function get_source() {
  722. return $this->file_record->source;
  723. }
  724. /**
  725. * Set license
  726. *
  727. * @param string $license license
  728. */
  729. public function set_source($source) {
  730. $filerecord = new stdClass;
  731. $filerecord->source = $source;
  732. $this->update($filerecord);
  733. }
  734. /**
  735. * Returns the sort order of file
  736. *
  737. * @return int
  738. */
  739. public function get_sortorder() {
  740. return $this->file_record->sortorder;
  741. }
  742. /**
  743. * Set file sort order
  744. *
  745. * @param int $sortorder
  746. * @return int
  747. */
  748. public function set_sortorder($sortorder) {
  749. $filerecord = new stdClass;
  750. $filerecord->sortorder = $sortorder;
  751. $this->update($filerecord);
  752. }
  753. /**
  754. * Returns repository id
  755. *
  756. * @return int|null
  757. */
  758. public function get_repository_id() {
  759. if (!empty($this->repository)) {
  760. return $this->repository->id;
  761. } else {
  762. return null;
  763. }
  764. }
  765. /**
  766. * get reference file id
  767. * @return int
  768. */
  769. public function get_referencefileid() {
  770. return $this->file_record->referencefileid;
  771. }
  772. /**
  773. * Get reference last sync time
  774. * @return int
  775. */
  776. public function get_referencelastsync() {
  777. return $this->file_record->referencelastsync;
  778. }
  779. /**
  780. * Get reference last sync time
  781. * @return int
  782. */
  783. public function get_referencelifetime() {
  784. return $this->file_record->referencelifetime;
  785. }
  786. /**
  787. * Returns file reference
  788. *
  789. * @return string
  790. */
  791. public function get_reference() {
  792. return $this->file_record->reference;
  793. }
  794. /**
  795. * Get human readable file reference information
  796. *
  797. * @return string
  798. */
  799. public function get_reference_details() {
  800. return $this->repository->get_reference_details($this->get_reference(), $this->get_status());
  801. }
  802. /**
  803. * Called after reference-file has been synchronized with the repository
  804. *
  805. * We update contenthash, filesize and status in files table if changed
  806. * and we always update lastsync in files_reference table
  807. *
  808. * @param string $contenthash
  809. * @param int $filesize
  810. * @param int $status
  811. * @param int $lifetime the life time of this synchronisation results
  812. */
  813. public function set_synchronized($contenthash, $filesize, $status = 0, $lifetime = null) {
  814. global $DB;
  815. if (!$this->is_external_file()) {
  816. return;
  817. }
  818. $now = time();
  819. if ($contenthash != $this->file_record->contenthash) {
  820. $oldcontenthash = $this->file_record->contenthash;
  821. }
  822. if ($lifetime === null) {
  823. $lifetime = $this->file_record->referencelifetime;
  824. }
  825. // this will update all entries in {files} that have the same filereference id
  826. $this->fs->update_references($this->file_record->referencefileid, $now, $lifetime, $contenthash, $filesize, $status);
  827. // we don't need to call update() for this object, just set the values of changed fields
  828. $this->file_record->contenthash = $contenthash;
  829. $this->file_record->filesize = $filesize;
  830. $this->file_record->status = $status;
  831. $this->file_record->referencelastsync = $now;
  832. $this->file_record->referencelifetime = $lifetime;
  833. if (isset($oldcontenthash)) {
  834. $this->fs->deleted_file_cleanup($oldcontenthash);
  835. }
  836. }
  837. /**
  838. * Sets the error status for a file that could not be synchronised
  839. *
  840. * @param int $lifetime the life time of this synchronisation results
  841. */
  842. public function set_missingsource($lifetime = null) {
  843. $this->set_synchronized($this->get_contenthash(), $this->get_filesize(), 666, $lifetime);
  844. }
  845. /**
  846. * Send file references
  847. *
  848. * @param int $lifetime Number of seconds before the file should expire from caches (default 24 hours)
  849. * @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only
  850. * @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin
  851. * @param array $options additional options affecting the file serving
  852. */
  853. public function send_file($lifetime, $filter, $forcedownload, $options) {
  854. $this->repository->send_file($this, $lifetime, $filter, $forcedownload, $options);
  855. }
  856. /**
  857. * Imports the contents of an external file into moodle filepool.
  858. *
  859. * @throws moodle_exception if file could not be downloaded or is too big
  860. * @param int $maxbytes throw an exception if file size is bigger than $maxbytes (0 means no limit)
  861. */
  862. public function import_external_file_contents($maxbytes = 0) {
  863. if ($this->repository) {
  864. $this->repository->import_external_file_contents($this, $maxbytes);
  865. }
  866. }
  867. }