Loader.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Joas Schilling <coding@schilljs.com>
  6. * @author Rello <Rello@users.noreply.github.com>
  7. * @author Robin Appelman <robin@icewind.nl>
  8. * @author Robin McCorkell <robin@mccorkell.me.uk>
  9. *
  10. * @license AGPL-3.0
  11. *
  12. * This code is free software: you can redistribute it and/or modify
  13. * it under the terms of the GNU Affero General Public License, version 3,
  14. * as published by the Free Software Foundation.
  15. *
  16. * This program 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 Affero General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Affero General Public License, version 3,
  22. * along with this program. If not, see <http://www.gnu.org/licenses/>
  23. *
  24. */
  25. namespace OC\Files\Type;
  26. use OC\DB\Exceptions\DbalException;
  27. use OCP\AppFramework\Db\TTransactional;
  28. use OCP\DB\Exception as DBException;
  29. use OCP\Files\IMimeTypeLoader;
  30. use OCP\IDBConnection;
  31. /**
  32. * Mimetype database loader
  33. *
  34. * @package OC\Files\Type
  35. */
  36. class Loader implements IMimeTypeLoader {
  37. use TTransactional;
  38. /** @var IDBConnection */
  39. private $dbConnection;
  40. /** @var array [id => mimetype] */
  41. protected $mimetypes;
  42. /** @var array [mimetype => id] */
  43. protected $mimetypeIds;
  44. /**
  45. * @param IDBConnection $dbConnection
  46. */
  47. public function __construct(IDBConnection $dbConnection) {
  48. $this->dbConnection = $dbConnection;
  49. $this->mimetypes = [];
  50. $this->mimetypeIds = [];
  51. }
  52. /**
  53. * Get a mimetype from its ID
  54. *
  55. * @param int $id
  56. * @return string|null
  57. */
  58. public function getMimetypeById($id) {
  59. if (!$this->mimetypes) {
  60. $this->loadMimetypes();
  61. }
  62. if (isset($this->mimetypes[$id])) {
  63. return $this->mimetypes[$id];
  64. }
  65. return null;
  66. }
  67. /**
  68. * Get a mimetype ID, adding the mimetype to the DB if it does not exist
  69. *
  70. * @param string $mimetype
  71. * @return int
  72. */
  73. public function getId($mimetype) {
  74. if (!$this->mimetypeIds) {
  75. $this->loadMimetypes();
  76. }
  77. if (isset($this->mimetypeIds[$mimetype])) {
  78. return $this->mimetypeIds[$mimetype];
  79. }
  80. return $this->store($mimetype);
  81. }
  82. /**
  83. * Test if a mimetype exists in the database
  84. *
  85. * @param string $mimetype
  86. * @return bool
  87. */
  88. public function exists($mimetype) {
  89. if (!$this->mimetypeIds) {
  90. $this->loadMimetypes();
  91. }
  92. return isset($this->mimetypeIds[$mimetype]);
  93. }
  94. /**
  95. * Clear all loaded mimetypes, allow for re-loading
  96. */
  97. public function reset() {
  98. $this->mimetypes = [];
  99. $this->mimetypeIds = [];
  100. }
  101. /**
  102. * Store a mimetype in the DB
  103. *
  104. * @param string $mimetype
  105. * @return int inserted ID
  106. */
  107. protected function store($mimetype) {
  108. $mimetypeId = $this->atomic(function () use ($mimetype) {
  109. try {
  110. $insert = $this->dbConnection->getQueryBuilder();
  111. $insert->insert('mimetypes')
  112. ->values([
  113. 'mimetype' => $insert->createNamedParameter($mimetype)
  114. ])
  115. ->executeStatement();
  116. return $insert->getLastInsertId();
  117. } catch (DbalException $e) {
  118. if ($e->getReason() !== DBException::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
  119. throw $e;
  120. }
  121. $qb = $this->dbConnection->getQueryBuilder();
  122. $qb->select('id')
  123. ->from('mimetypes')
  124. ->where($qb->expr()->eq('mimetype', $qb->createNamedParameter($mimetype)));
  125. $result = $qb->executeQuery();
  126. $id = $result->fetchOne();
  127. $result->closeCursor();
  128. if ($id !== false) {
  129. return (int) $id;
  130. }
  131. throw new \Exception("Database threw an unique constraint on inserting a new mimetype, but couldn't return the ID for this very mimetype");
  132. }
  133. }, $this->dbConnection);
  134. if (!$mimetypeId) {
  135. throw new \Exception("Failed to get mimetype id for $mimetype after trying to store it");
  136. }
  137. $this->mimetypes[$mimetypeId] = $mimetype;
  138. $this->mimetypeIds[$mimetype] = $mimetypeId;
  139. return $mimetypeId;
  140. }
  141. /**
  142. * Load all mimetypes from DB
  143. */
  144. private function loadMimetypes() {
  145. $qb = $this->dbConnection->getQueryBuilder();
  146. $qb->select('id', 'mimetype')
  147. ->from('mimetypes');
  148. $result = $qb->execute();
  149. $results = $result->fetchAll();
  150. $result->closeCursor();
  151. foreach ($results as $row) {
  152. $this->mimetypes[$row['id']] = $row['mimetype'];
  153. $this->mimetypeIds[$row['mimetype']] = $row['id'];
  154. }
  155. }
  156. /**
  157. * Update filecache mimetype based on file extension
  158. *
  159. * @param string $ext file extension
  160. * @param int $mimeTypeId
  161. * @return int number of changed rows
  162. */
  163. public function updateFilecache($ext, $mimeTypeId) {
  164. $folderMimeTypeId = $this->getId('httpd/unix-directory');
  165. $update = $this->dbConnection->getQueryBuilder();
  166. $update->update('filecache')
  167. ->set('mimetype', $update->createNamedParameter($mimeTypeId))
  168. ->where($update->expr()->neq(
  169. 'mimetype', $update->createNamedParameter($mimeTypeId)
  170. ))
  171. ->andWhere($update->expr()->neq(
  172. 'mimetype', $update->createNamedParameter($folderMimeTypeId)
  173. ))
  174. ->andWhere($update->expr()->like(
  175. $update->func()->lower('name'),
  176. $update->createNamedParameter('%' . $this->dbConnection->escapeLikeParameter('.' . $ext))
  177. ));
  178. return $update->execute();
  179. }
  180. }