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

/includes/filerepo/file/OldLocalFile.php

https://gitlab.com/link233/bootmw
PHP | 409 lines | 218 code | 52 blank | 139 comment | 25 complexity | 31e10f15a80d6ebb8ba1faa80c10f516 MD5 | raw file
  1. <?php
  2. /**
  3. * Old file in the oldimage table.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. * http://www.gnu.org/copyleft/gpl.html
  19. *
  20. * @file
  21. * @ingroup FileAbstraction
  22. */
  23. /**
  24. * Class to represent a file in the oldimage table
  25. *
  26. * @ingroup FileAbstraction
  27. */
  28. class OldLocalFile extends LocalFile {
  29. /** @var string Timestamp */
  30. protected $requestedTime;
  31. /** @var string Archive name */
  32. protected $archive_name;
  33. const CACHE_VERSION = 1;
  34. const MAX_CACHE_ROWS = 20;
  35. /**
  36. * @param Title $title
  37. * @param FileRepo $repo
  38. * @param null|int $time Timestamp or null
  39. * @return OldLocalFile
  40. * @throws MWException
  41. */
  42. static function newFromTitle( $title, $repo, $time = null ) {
  43. # The null default value is only here to avoid an E_STRICT
  44. if ( $time === null ) {
  45. throw new MWException( __METHOD__ . ' got null for $time parameter' );
  46. }
  47. return new self( $title, $repo, $time, null );
  48. }
  49. /**
  50. * @param Title $title
  51. * @param FileRepo $repo
  52. * @param string $archiveName
  53. * @return OldLocalFile
  54. */
  55. static function newFromArchiveName( $title, $repo, $archiveName ) {
  56. return new self( $title, $repo, null, $archiveName );
  57. }
  58. /**
  59. * @param stdClass $row
  60. * @param FileRepo $repo
  61. * @return OldLocalFile
  62. */
  63. static function newFromRow( $row, $repo ) {
  64. $title = Title::makeTitle( NS_FILE, $row->oi_name );
  65. $file = new self( $title, $repo, null, $row->oi_archive_name );
  66. $file->loadFromRow( $row, 'oi_' );
  67. return $file;
  68. }
  69. /**
  70. * Create a OldLocalFile from a SHA-1 key
  71. * Do not call this except from inside a repo class.
  72. *
  73. * @param string $sha1 Base-36 SHA-1
  74. * @param LocalRepo $repo
  75. * @param string|bool $timestamp MW_timestamp (optional)
  76. *
  77. * @return bool|OldLocalFile
  78. */
  79. static function newFromKey( $sha1, $repo, $timestamp = false ) {
  80. $dbr = $repo->getSlaveDB();
  81. $conds = [ 'oi_sha1' => $sha1 ];
  82. if ( $timestamp ) {
  83. $conds['oi_timestamp'] = $dbr->timestamp( $timestamp );
  84. }
  85. $row = $dbr->selectRow( 'oldimage', self::selectFields(), $conds, __METHOD__ );
  86. if ( $row ) {
  87. return self::newFromRow( $row, $repo );
  88. } else {
  89. return false;
  90. }
  91. }
  92. /**
  93. * Fields in the oldimage table
  94. * @return array
  95. */
  96. static function selectFields() {
  97. return [
  98. 'oi_name',
  99. 'oi_archive_name',
  100. 'oi_size',
  101. 'oi_width',
  102. 'oi_height',
  103. 'oi_metadata',
  104. 'oi_bits',
  105. 'oi_media_type',
  106. 'oi_major_mime',
  107. 'oi_minor_mime',
  108. 'oi_description',
  109. 'oi_user',
  110. 'oi_user_text',
  111. 'oi_timestamp',
  112. 'oi_deleted',
  113. 'oi_sha1',
  114. ];
  115. }
  116. /**
  117. * @param Title $title
  118. * @param FileRepo $repo
  119. * @param string $time Timestamp or null to load by archive name
  120. * @param string $archiveName Archive name or null to load by timestamp
  121. * @throws MWException
  122. */
  123. function __construct( $title, $repo, $time, $archiveName ) {
  124. parent::__construct( $title, $repo );
  125. $this->requestedTime = $time;
  126. $this->archive_name = $archiveName;
  127. if ( is_null( $time ) && is_null( $archiveName ) ) {
  128. throw new MWException( __METHOD__ . ': must specify at least one of $time or $archiveName' );
  129. }
  130. }
  131. /**
  132. * @return bool
  133. */
  134. function getCacheKey() {
  135. return false;
  136. }
  137. /**
  138. * @return string
  139. */
  140. function getArchiveName() {
  141. if ( !isset( $this->archive_name ) ) {
  142. $this->load();
  143. }
  144. return $this->archive_name;
  145. }
  146. /**
  147. * @return bool
  148. */
  149. function isOld() {
  150. return true;
  151. }
  152. /**
  153. * @return bool
  154. */
  155. function isVisible() {
  156. return $this->exists() && !$this->isDeleted( File::DELETED_FILE );
  157. }
  158. function loadFromDB( $flags = 0 ) {
  159. $this->dataLoaded = true;
  160. $dbr = ( $flags & self::READ_LATEST )
  161. ? $this->repo->getMasterDB()
  162. : $this->repo->getSlaveDB();
  163. $conds = [ 'oi_name' => $this->getName() ];
  164. if ( is_null( $this->requestedTime ) ) {
  165. $conds['oi_archive_name'] = $this->archive_name;
  166. } else {
  167. $conds['oi_timestamp'] = $dbr->timestamp( $this->requestedTime );
  168. }
  169. $row = $dbr->selectRow( 'oldimage', $this->getCacheFields( 'oi_' ),
  170. $conds, __METHOD__, [ 'ORDER BY' => 'oi_timestamp DESC' ] );
  171. if ( $row ) {
  172. $this->loadFromRow( $row, 'oi_' );
  173. } else {
  174. $this->fileExists = false;
  175. }
  176. }
  177. /**
  178. * Load lazy file metadata from the DB
  179. */
  180. protected function loadExtraFromDB() {
  181. $this->extraDataLoaded = true;
  182. $dbr = $this->repo->getSlaveDB();
  183. $conds = [ 'oi_name' => $this->getName() ];
  184. if ( is_null( $this->requestedTime ) ) {
  185. $conds['oi_archive_name'] = $this->archive_name;
  186. } else {
  187. $conds['oi_timestamp'] = $dbr->timestamp( $this->requestedTime );
  188. }
  189. // In theory the file could have just been renamed/deleted...oh well
  190. $row = $dbr->selectRow( 'oldimage', $this->getLazyCacheFields( 'oi_' ),
  191. $conds, __METHOD__, [ 'ORDER BY' => 'oi_timestamp DESC' ] );
  192. if ( !$row ) { // fallback to master
  193. $dbr = $this->repo->getMasterDB();
  194. $row = $dbr->selectRow( 'oldimage', $this->getLazyCacheFields( 'oi_' ),
  195. $conds, __METHOD__, [ 'ORDER BY' => 'oi_timestamp DESC' ] );
  196. }
  197. if ( $row ) {
  198. foreach ( $this->unprefixRow( $row, 'oi_' ) as $name => $value ) {
  199. $this->$name = $value;
  200. }
  201. } else {
  202. throw new MWException( "Could not find data for image '{$this->archive_name}'." );
  203. }
  204. }
  205. /**
  206. * @param string $prefix
  207. * @return array
  208. */
  209. function getCacheFields( $prefix = 'img_' ) {
  210. $fields = parent::getCacheFields( $prefix );
  211. $fields[] = $prefix . 'archive_name';
  212. $fields[] = $prefix . 'deleted';
  213. return $fields;
  214. }
  215. /**
  216. * @return string
  217. */
  218. function getRel() {
  219. return 'archive/' . $this->getHashPath() . $this->getArchiveName();
  220. }
  221. /**
  222. * @return string
  223. */
  224. function getUrlRel() {
  225. return 'archive/' . $this->getHashPath() . rawurlencode( $this->getArchiveName() );
  226. }
  227. function upgradeRow() {
  228. $this->loadFromFile();
  229. # Don't destroy file info of missing files
  230. if ( !$this->fileExists ) {
  231. wfDebug( __METHOD__ . ": file does not exist, aborting\n" );
  232. return;
  233. }
  234. $dbw = $this->repo->getMasterDB();
  235. list( $major, $minor ) = self::splitMime( $this->mime );
  236. wfDebug( __METHOD__ . ': upgrading ' . $this->archive_name . " to the current schema\n" );
  237. $dbw->update( 'oldimage',
  238. [
  239. 'oi_size' => $this->size, // sanity
  240. 'oi_width' => $this->width,
  241. 'oi_height' => $this->height,
  242. 'oi_bits' => $this->bits,
  243. 'oi_media_type' => $this->media_type,
  244. 'oi_major_mime' => $major,
  245. 'oi_minor_mime' => $minor,
  246. 'oi_metadata' => $this->metadata,
  247. 'oi_sha1' => $this->sha1,
  248. ], [
  249. 'oi_name' => $this->getName(),
  250. 'oi_archive_name' => $this->archive_name ],
  251. __METHOD__
  252. );
  253. }
  254. /**
  255. * @param int $field One of DELETED_* bitfield constants for file or
  256. * revision rows
  257. * @return bool
  258. */
  259. function isDeleted( $field ) {
  260. $this->load();
  261. return ( $this->deleted & $field ) == $field;
  262. }
  263. /**
  264. * Returns bitfield value
  265. * @return int
  266. */
  267. function getVisibility() {
  268. $this->load();
  269. return (int)$this->deleted;
  270. }
  271. /**
  272. * Determine if the current user is allowed to view a particular
  273. * field of this image file, if it's marked as deleted.
  274. *
  275. * @param int $field
  276. * @param User|null $user User object to check, or null to use $wgUser
  277. * @return bool
  278. */
  279. function userCan( $field, User $user = null ) {
  280. $this->load();
  281. return Revision::userCanBitfield( $this->deleted, $field, $user );
  282. }
  283. /**
  284. * Upload a file directly into archive. Generally for Special:Import.
  285. *
  286. * @param string $srcPath File system path of the source file
  287. * @param string $archiveName Full archive name of the file, in the form
  288. * $timestamp!$filename, where $filename must match $this->getName()
  289. * @param string $timestamp
  290. * @param string $comment
  291. * @param User $user
  292. * @return FileRepoStatus
  293. */
  294. function uploadOld( $srcPath, $archiveName, $timestamp, $comment, $user ) {
  295. $this->lock();
  296. $dstRel = 'archive/' . $this->getHashPath() . $archiveName;
  297. $status = $this->publishTo( $srcPath, $dstRel );
  298. if ( $status->isGood() ) {
  299. if ( !$this->recordOldUpload( $srcPath, $archiveName, $timestamp, $comment, $user ) ) {
  300. $status->fatal( 'filenotfound', $srcPath );
  301. }
  302. }
  303. $this->unlock();
  304. return $status;
  305. }
  306. /**
  307. * Record a file upload in the oldimage table, without adding log entries.
  308. *
  309. * @param string $srcPath File system path to the source file
  310. * @param string $archiveName The archive name of the file
  311. * @param string $timestamp
  312. * @param string $comment Upload comment
  313. * @param User $user User who did this upload
  314. * @return bool
  315. */
  316. protected function recordOldUpload( $srcPath, $archiveName, $timestamp, $comment, $user ) {
  317. $dbw = $this->repo->getMasterDB();
  318. $dstPath = $this->repo->getZonePath( 'public' ) . '/' . $this->getRel();
  319. $props = $this->repo->getFileProps( $dstPath );
  320. if ( !$props['fileExists'] ) {
  321. return false;
  322. }
  323. $dbw->insert( 'oldimage',
  324. [
  325. 'oi_name' => $this->getName(),
  326. 'oi_archive_name' => $archiveName,
  327. 'oi_size' => $props['size'],
  328. 'oi_width' => intval( $props['width'] ),
  329. 'oi_height' => intval( $props['height'] ),
  330. 'oi_bits' => $props['bits'],
  331. 'oi_timestamp' => $dbw->timestamp( $timestamp ),
  332. 'oi_description' => $comment,
  333. 'oi_user' => $user->getId(),
  334. 'oi_user_text' => $user->getName(),
  335. 'oi_metadata' => $props['metadata'],
  336. 'oi_media_type' => $props['media_type'],
  337. 'oi_major_mime' => $props['major_mime'],
  338. 'oi_minor_mime' => $props['minor_mime'],
  339. 'oi_sha1' => $props['sha1'],
  340. ], __METHOD__
  341. );
  342. return true;
  343. }
  344. /**
  345. * If archive name is an empty string, then file does not "exist"
  346. *
  347. * This is the case for a couple files on Wikimedia servers where
  348. * the old version is "lost".
  349. */
  350. public function exists() {
  351. $archiveName = $this->getArchiveName();
  352. if ( $archiveName === '' || !is_string( $archiveName ) ) {
  353. return false;
  354. }
  355. return parent::exists();
  356. }
  357. }