RepairMimeTypes.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Faruk Uzun <farukuzun@collabora.com>
  6. * @author Joas Schilling <coding@schilljs.com>
  7. * @author Morris Jobke <hey@morrisjobke.de>
  8. * @author Normal Ra <normalraw@gmail.com>
  9. * @author Olivier Paroz <github@oparoz.com>
  10. * @author Roeland Jago Douma <roeland@famdouma.nl>
  11. * @author Thomas Müller <thomas.mueller@tmit.eu>
  12. * @author Victor Dubiniuk <dubiniuk@owncloud.com>
  13. * @author Vincent Petry <pvince81@owncloud.com>
  14. *
  15. * @license AGPL-3.0
  16. *
  17. * This code is free software: you can redistribute it and/or modify
  18. * it under the terms of the GNU Affero General Public License, version 3,
  19. * as published by the Free Software Foundation.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU Affero General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU Affero General Public License, version 3,
  27. * along with this program. If not, see <http://www.gnu.org/licenses/>
  28. *
  29. */
  30. namespace OC\Repair;
  31. use OCP\Migration\IOutput;
  32. use OCP\Migration\IRepairStep;
  33. class RepairMimeTypes implements IRepairStep {
  34. /**
  35. * @var \OCP\IConfig
  36. */
  37. protected $config;
  38. /**
  39. * @var int
  40. */
  41. protected $folderMimeTypeId;
  42. /**
  43. * @param \OCP\IConfig $config
  44. */
  45. public function __construct($config) {
  46. $this->config = $config;
  47. }
  48. public function getName() {
  49. return 'Repair mime types';
  50. }
  51. private static function existsStmt() {
  52. return \OC_DB::prepare('
  53. SELECT count(`mimetype`)
  54. FROM `*PREFIX*mimetypes`
  55. WHERE `mimetype` = ?
  56. ');
  57. }
  58. private static function getIdStmt() {
  59. return \OC_DB::prepare('
  60. SELECT `id`
  61. FROM `*PREFIX*mimetypes`
  62. WHERE `mimetype` = ?
  63. ');
  64. }
  65. private static function insertStmt() {
  66. return \OC_DB::prepare('
  67. INSERT INTO `*PREFIX*mimetypes` ( `mimetype` )
  68. VALUES ( ? )
  69. ');
  70. }
  71. private static function updateWrongStmt() {
  72. return \OC_DB::prepare('
  73. UPDATE `*PREFIX*filecache`
  74. SET `mimetype` = (
  75. SELECT `id`
  76. FROM `*PREFIX*mimetypes`
  77. WHERE `mimetype` = ?
  78. ) WHERE `mimetype` = ?
  79. ');
  80. }
  81. private static function deleteStmt() {
  82. return \OC_DB::prepare('
  83. DELETE FROM `*PREFIX*mimetypes`
  84. WHERE `id` = ?
  85. ');
  86. }
  87. private static function updateByNameStmt() {
  88. return \OC_DB::prepare('
  89. UPDATE `*PREFIX*filecache`
  90. SET `mimetype` = ?
  91. WHERE `mimetype` <> ? AND `mimetype` <> ? AND `name` ILIKE ?
  92. ');
  93. }
  94. private function repairMimetypes($wrongMimetypes) {
  95. foreach ($wrongMimetypes as $wrong => $correct) {
  96. // do we need to remove a wrong mimetype?
  97. $result = \OC_DB::executeAudited(self::getIdStmt(), array($wrong));
  98. $wrongId = $result->fetchOne();
  99. if ($wrongId !== false) {
  100. // do we need to insert the correct mimetype?
  101. $result = \OC_DB::executeAudited(self::existsStmt(), array($correct));
  102. $exists = $result->fetchOne();
  103. if (!is_null($correct)) {
  104. if (!$exists) {
  105. // insert mimetype
  106. \OC_DB::executeAudited(self::insertStmt(), array($correct));
  107. }
  108. // change wrong mimetype to correct mimetype in filecache
  109. \OC_DB::executeAudited(self::updateWrongStmt(), array($correct, $wrongId));
  110. }
  111. // delete wrong mimetype
  112. \OC_DB::executeAudited(self::deleteStmt(), array($wrongId));
  113. }
  114. }
  115. }
  116. private function updateMimetypes($updatedMimetypes) {
  117. if (empty($this->folderMimeTypeId)) {
  118. $result = \OC_DB::executeAudited(self::getIdStmt(), array('httpd/unix-directory'));
  119. $this->folderMimeTypeId = (int)$result->fetchOne();
  120. }
  121. foreach ($updatedMimetypes as $extension => $mimetype) {
  122. $result = \OC_DB::executeAudited(self::existsStmt(), array($mimetype));
  123. $exists = $result->fetchOne();
  124. if (!$exists) {
  125. // insert mimetype
  126. \OC_DB::executeAudited(self::insertStmt(), array($mimetype));
  127. }
  128. // get target mimetype id
  129. $result = \OC_DB::executeAudited(self::getIdStmt(), array($mimetype));
  130. $mimetypeId = $result->fetchOne();
  131. // change mimetype for files with x extension
  132. \OC_DB::executeAudited(self::updateByNameStmt(), array($mimetypeId, $this->folderMimeTypeId, $mimetypeId, '%.' . $extension));
  133. }
  134. }
  135. private function fixOfficeMimeTypes() {
  136. // update wrong mimetypes
  137. $wrongMimetypes = array(
  138. 'application/mspowerpoint' => 'application/vnd.ms-powerpoint',
  139. 'application/msexcel' => 'application/vnd.ms-excel',
  140. );
  141. self::repairMimetypes($wrongMimetypes);
  142. $updatedMimetypes = array(
  143. 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  144. 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  145. 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  146. );
  147. // separate doc from docx etc
  148. self::updateMimetypes($updatedMimetypes);
  149. }
  150. private function fixApkMimeType() {
  151. $updatedMimetypes = array(
  152. 'apk' => 'application/vnd.android.package-archive',
  153. );
  154. self::updateMimetypes($updatedMimetypes);
  155. }
  156. private function fixFontsMimeTypes() {
  157. // update wrong mimetypes
  158. $wrongMimetypes = array(
  159. 'font' => null,
  160. 'font/opentype' => 'application/font-sfnt',
  161. 'application/x-font-ttf' => 'application/font-sfnt',
  162. );
  163. self::repairMimetypes($wrongMimetypes);
  164. $updatedMimetypes = array(
  165. 'ttf' => 'application/font-sfnt',
  166. 'otf' => 'application/font-sfnt',
  167. 'pfb' => 'application/x-font',
  168. );
  169. self::updateMimetypes($updatedMimetypes);
  170. }
  171. private function fixPostscriptMimeType() {
  172. $updatedMimetypes = array(
  173. 'eps' => 'application/postscript',
  174. 'ps' => 'application/postscript',
  175. );
  176. self::updateMimetypes($updatedMimetypes);
  177. }
  178. private function introduceRawMimeType() {
  179. $updatedMimetypes = array(
  180. 'arw' => 'image/x-dcraw',
  181. 'cr2' => 'image/x-dcraw',
  182. 'dcr' => 'image/x-dcraw',
  183. 'dng' => 'image/x-dcraw',
  184. 'erf' => 'image/x-dcraw',
  185. 'iiq' => 'image/x-dcraw',
  186. 'k25' => 'image/x-dcraw',
  187. 'kdc' => 'image/x-dcraw',
  188. 'mef' => 'image/x-dcraw',
  189. 'nef' => 'image/x-dcraw',
  190. 'orf' => 'image/x-dcraw',
  191. 'pef' => 'image/x-dcraw',
  192. 'raf' => 'image/x-dcraw',
  193. 'rw2' => 'image/x-dcraw',
  194. 'srf' => 'image/x-dcraw',
  195. 'sr2' => 'image/x-dcraw',
  196. 'xrf' => 'image/x-dcraw',
  197. );
  198. self::updateMimetypes($updatedMimetypes);
  199. }
  200. private function introduce3dImagesMimeType() {
  201. $updatedMimetypes = array(
  202. 'jps' => 'image/jpeg',
  203. 'mpo' => 'image/jpeg',
  204. );
  205. self::updateMimetypes($updatedMimetypes);
  206. }
  207. private function introduceConfMimeType() {
  208. $updatedMimetypes = array(
  209. 'conf' => 'text/plain',
  210. 'cnf' => 'text/plain',
  211. );
  212. self::updateMimetypes($updatedMimetypes);
  213. }
  214. private function introduceYamlMimeType() {
  215. $updatedMimetypes = array(
  216. 'yaml' => 'application/yaml',
  217. 'yml' => 'application/yaml',
  218. );
  219. self::updateMimetypes($updatedMimetypes);
  220. }
  221. private function introduceJavaMimeType() {
  222. $updatedMimetypes = array(
  223. 'class' => 'application/java',
  224. 'java' => 'text/x-java-source',
  225. );
  226. self::updateMimetypes($updatedMimetypes);
  227. }
  228. private function introduceHppMimeType() {
  229. $updatedMimetypes = array(
  230. 'hpp' => 'text/x-h',
  231. );
  232. self::updateMimetypes($updatedMimetypes);
  233. }
  234. private function introduceRssMimeType() {
  235. $updatedMimetypes = array(
  236. 'rss' => 'application/rss+xml',
  237. );
  238. self::updateMimetypes($updatedMimetypes);
  239. }
  240. private function introduceRtfMimeType() {
  241. $updatedMimetypes = array(
  242. 'rtf' => 'text/rtf',
  243. );
  244. self::updateMimetypes($updatedMimetypes);
  245. }
  246. private function introduceRichDocumentsMimeTypes() {
  247. $updatedMimetypes = array(
  248. 'lwp' => 'application/vnd.lotus-wordpro',
  249. 'one' => 'application/msonenote',
  250. 'vsd' => 'application/vnd.visio',
  251. 'wpd' => 'application/vnd.wordperfect',
  252. );
  253. self::updateMimetypes($updatedMimetypes);
  254. }
  255. /**
  256. * Fix mime types
  257. */
  258. public function run(IOutput $out) {
  259. $ocVersionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
  260. // NOTE TO DEVELOPERS: when adding new mime types, please make sure to
  261. // add a version comparison to avoid doing it every time
  262. // only update mime types if necessary as it can be expensive
  263. if (version_compare($ocVersionFromBeforeUpdate, '8.2.0', '<')) {
  264. if ($this->fixOfficeMimeTypes()) {
  265. $out->info('Fixed office mime types');
  266. }
  267. if ($this->fixApkMimeType()) {
  268. $out->info('Fixed APK mime type');
  269. }
  270. if ($this->fixFontsMimeTypes()) {
  271. $out->info('Fixed fonts mime types');
  272. }
  273. if ($this->fixPostscriptMimeType()) {
  274. $out->info('Fixed Postscript mime types');
  275. }
  276. if ($this->introduceRawMimeType()) {
  277. $out->info('Fixed Raw mime types');
  278. }
  279. if ($this->introduce3dImagesMimeType()) {
  280. $out->info('Fixed 3D images mime types');
  281. }
  282. if ($this->introduceConfMimeType()) {
  283. $out->info('Fixed Conf/cnf mime types');
  284. }
  285. if ($this->introduceYamlMimeType()) {
  286. $out->info('Fixed Yaml/Yml mime types');
  287. }
  288. }
  289. // Mimetype updates from #19272
  290. if (version_compare($ocVersionFromBeforeUpdate, '8.2.0.8', '<')) {
  291. if ($this->introduceJavaMimeType()) {
  292. $out->info('Fixed java/class mime types');
  293. }
  294. if ($this->introduceHppMimeType()) {
  295. $out->info('Fixed hpp mime type');
  296. }
  297. if ($this->introduceRssMimeType()) {
  298. $out->info('Fixed rss mime type');
  299. }
  300. if ($this->introduceRtfMimeType()) {
  301. $out->info('Fixed rtf mime type');
  302. }
  303. }
  304. if (version_compare($ocVersionFromBeforeUpdate, '9.0.0.10', '<')) {
  305. if ($this->introduceRichDocumentsMimeTypes()) {
  306. $out->info('Fixed richdocuments additional office mime types');
  307. }
  308. }
  309. }
  310. }