Exemplo n.º 1
0
 /**
  * Update the images's fa_deleted field
  * @param ArchivedFile $file
  * @param int $bitfield new rev_deleted bitfield value
  */
 function updateArchFiles($file, $bitfield)
 {
     $this->dbw->update('filearchive', array('fa_deleted' => $bitfield), array('fa_id' => $file->getId()), __METHOD__);
 }
Exemplo n.º 2
0
 /**
  * Run the transaction, except the cleanup batch.
  * The cleanup batch should be run in a separate transaction, because it locks different
  * rows and there's no need to keep the image row locked while it's acquiring those locks
  * The caller may have its own transaction open.
  * So we save the batch and let the caller call cleanup()
  * @return FileRepoStatus
  */
 function execute()
 {
     global $wgLang;
     if (!$this->all && !$this->ids) {
         // Do nothing
         return $this->file->repo->newGood();
     }
     $exists = $this->file->lock();
     $dbw = $this->file->repo->getMasterDB();
     $status = $this->file->repo->newGood();
     // Fetch all or selected archived revisions for the file,
     // sorted from the most recent to the oldest.
     $conditions = array('fa_name' => $this->file->getName());
     if (!$this->all) {
         $conditions['fa_id'] = $this->ids;
     }
     $result = $dbw->select('filearchive', ArchivedFile::selectFields(), $conditions, __METHOD__, array('ORDER BY' => 'fa_timestamp DESC'));
     $idsPresent = array();
     $storeBatch = array();
     $insertBatch = array();
     $insertCurrent = false;
     $deleteIds = array();
     $first = true;
     $archiveNames = array();
     foreach ($result as $row) {
         $idsPresent[] = $row->fa_id;
         if ($row->fa_name != $this->file->getName()) {
             $status->error('undelete-filename-mismatch', $wgLang->timeanddate($row->fa_timestamp));
             $status->failCount++;
             continue;
         }
         if ($row->fa_storage_key == '') {
             // Revision was missing pre-deletion
             $status->error('undelete-bad-store-key', $wgLang->timeanddate($row->fa_timestamp));
             $status->failCount++;
             continue;
         }
         $deletedRel = $this->file->repo->getDeletedHashPath($row->fa_storage_key) . $row->fa_storage_key;
         $deletedUrl = $this->file->repo->getVirtualUrl() . '/deleted/' . $deletedRel;
         if (isset($row->fa_sha1)) {
             $sha1 = $row->fa_sha1;
         } else {
             // old row, populate from key
             $sha1 = LocalRepo::getHashFromKey($row->fa_storage_key);
         }
         # Fix leading zero
         if (strlen($sha1) == 32 && $sha1[0] == '0') {
             $sha1 = substr($sha1, 1);
         }
         if (is_null($row->fa_major_mime) || $row->fa_major_mime == 'unknown' || is_null($row->fa_minor_mime) || $row->fa_minor_mime == 'unknown' || is_null($row->fa_media_type) || $row->fa_media_type == 'UNKNOWN' || is_null($row->fa_metadata)) {
             // Refresh our metadata
             // Required for a new current revision; nice for older ones too. :)
             $props = RepoGroup::singleton()->getFileProps($deletedUrl);
         } else {
             $props = array('minor_mime' => $row->fa_minor_mime, 'major_mime' => $row->fa_major_mime, 'media_type' => $row->fa_media_type, 'metadata' => $row->fa_metadata);
         }
         if ($first && !$exists) {
             // This revision will be published as the new current version
             $destRel = $this->file->getRel();
             $insertCurrent = array('img_name' => $row->fa_name, 'img_size' => $row->fa_size, 'img_width' => $row->fa_width, 'img_height' => $row->fa_height, 'img_metadata' => $props['metadata'], 'img_bits' => $row->fa_bits, 'img_media_type' => $props['media_type'], 'img_major_mime' => $props['major_mime'], 'img_minor_mime' => $props['minor_mime'], 'img_description' => $row->fa_description, 'img_user' => $row->fa_user, 'img_user_text' => $row->fa_user_text, 'img_timestamp' => $row->fa_timestamp, 'img_sha1' => $sha1);
             // The live (current) version cannot be hidden!
             if (!$this->unsuppress && $row->fa_deleted) {
                 $status->fatal('undeleterevdel');
                 $this->file->unlock();
                 return $status;
             }
         } else {
             $archiveName = $row->fa_archive_name;
             if ($archiveName == '') {
                 // This was originally a current version; we
                 // have to devise a new archive name for it.
                 // Format is <timestamp of archiving>!<name>
                 $timestamp = wfTimestamp(TS_UNIX, $row->fa_deleted_timestamp);
                 do {
                     $archiveName = wfTimestamp(TS_MW, $timestamp) . '!' . $row->fa_name;
                     $timestamp++;
                 } while (isset($archiveNames[$archiveName]));
             }
             $archiveNames[$archiveName] = true;
             $destRel = $this->file->getArchiveRel($archiveName);
             $insertBatch[] = array('oi_name' => $row->fa_name, 'oi_archive_name' => $archiveName, 'oi_size' => $row->fa_size, 'oi_width' => $row->fa_width, 'oi_height' => $row->fa_height, 'oi_bits' => $row->fa_bits, 'oi_description' => $row->fa_description, 'oi_user' => $row->fa_user, 'oi_user_text' => $row->fa_user_text, 'oi_timestamp' => $row->fa_timestamp, 'oi_metadata' => $props['metadata'], 'oi_media_type' => $props['media_type'], 'oi_major_mime' => $props['major_mime'], 'oi_minor_mime' => $props['minor_mime'], 'oi_deleted' => $this->unsuppress ? 0 : $row->fa_deleted, 'oi_sha1' => $sha1);
         }
         $deleteIds[] = $row->fa_id;
         if (!$this->unsuppress && $row->fa_deleted & File::DELETED_FILE) {
             // private files can stay where they are
             $status->successCount++;
         } else {
             $storeBatch[] = array($deletedUrl, 'public', $destRel);
             $this->cleanupBatch[] = $row->fa_storage_key;
         }
         $first = false;
     }
     unset($result);
     // Add a warning to the status object for missing IDs
     $missingIds = array_diff($this->ids, $idsPresent);
     foreach ($missingIds as $id) {
         $status->error('undelete-missing-filearchive', $id);
     }
     // Remove missing files from batch, so we don't get errors when undeleting them
     $storeBatch = $this->removeNonexistentFiles($storeBatch);
     // Run the store batch
     // Use the OVERWRITE_SAME flag to smooth over a common error
     $storeStatus = $this->file->repo->storeBatch($storeBatch, FileRepo::OVERWRITE_SAME);
     $status->merge($storeStatus);
     if (!$status->isGood()) {
         // Even if some files could be copied, fail entirely as that is the
         // easiest thing to do without data loss
         $this->cleanupFailedBatch($storeStatus, $storeBatch);
         $status->ok = false;
         $this->file->unlock();
         return $status;
     }
     // Run the DB updates
     // Because we have locked the image row, key conflicts should be rare.
     // If they do occur, we can roll back the transaction at this time with
     // no data loss, but leaving unregistered files scattered throughout the
     // public zone.
     // This is not ideal, which is why it's important to lock the image row.
     if ($insertCurrent) {
         $dbw->insert('image', $insertCurrent, __METHOD__);
     }
     if ($insertBatch) {
         $dbw->insert('oldimage', $insertBatch, __METHOD__);
     }
     if ($deleteIds) {
         $dbw->delete('filearchive', array('fa_id' => $deleteIds), __METHOD__);
     }
     // If store batch is empty (all files are missing), deletion is to be considered successful
     if ($status->successCount > 0 || !$storeBatch) {
         if (!$exists) {
             wfDebug(__METHOD__ . " restored {$status->successCount} items, creating a new current\n");
             DeferredUpdates::addUpdate(SiteStatsUpdate::factory(array('images' => 1)));
             $this->file->purgeEverything();
         } else {
             wfDebug(__METHOD__ . " restored {$status->successCount} as archived versions\n");
             $this->file->purgeDescription();
             $this->file->purgeHistory();
         }
     }
     $this->file->unlock();
     return $status;
 }
 /**
  * @param IDatabase $db
  * @return mixed
  */
 public function doQuery($db)
 {
     $ids = array_map('intval', $this->ids);
     return $db->select('filearchive', ArchivedFile::selectFields(), array('fa_name' => $this->title->getDBkey(), 'fa_id' => $ids), __METHOD__, array('ORDER BY' => 'fa_id DESC'));
 }
Exemplo n.º 4
0
 /**
  * Check for non fatal problems with the file.
  *
  * This should not assume that mTempPath is set.
  *
  * @return Array of warnings
  */
 public function checkWarnings()
 {
     global $wgLang;
     wfProfileIn(__METHOD__);
     $warnings = array();
     $localFile = $this->getLocalFile();
     $filename = $localFile->getName();
     /**
      * Check whether the resulting filename is different from the desired one,
      * but ignore things like ucfirst() and spaces/underscore things
      */
     $comparableName = str_replace(' ', '_', $this->mDesiredDestName);
     $comparableName = Title::capitalize($comparableName, NS_FILE);
     if ($this->mDesiredDestName != $filename && $comparableName != $filename) {
         $warnings['badfilename'] = $filename;
         // Debugging for bug 62241
         wfDebugLog('upload', "Filename: '{$filename}', mDesiredDestName: '{$this->mDesiredDestName}', comparableName: '{$comparableName}'");
     }
     // Check whether the file extension is on the unwanted list
     global $wgCheckFileExtensions, $wgFileExtensions;
     if ($wgCheckFileExtensions) {
         $extensions = array_unique($wgFileExtensions);
         if (!$this->checkFileExtension($this->mFinalExtension, $extensions)) {
             $warnings['filetype-unwanted-type'] = array($this->mFinalExtension, $wgLang->commaList($extensions), count($extensions));
         }
     }
     global $wgUploadSizeWarning;
     if ($wgUploadSizeWarning && $this->mFileSize > $wgUploadSizeWarning) {
         $warnings['large-file'] = array($wgUploadSizeWarning, $this->mFileSize);
     }
     if ($this->mFileSize == 0) {
         $warnings['emptyfile'] = true;
     }
     $exists = self::getExistsWarning($localFile);
     if ($exists !== false) {
         $warnings['exists'] = $exists;
     }
     // Check dupes against existing files
     $hash = $this->getTempFileSha1Base36();
     $dupes = RepoGroup::singleton()->findBySha1($hash);
     $title = $this->getTitle();
     // Remove all matches against self
     foreach ($dupes as $key => $dupe) {
         if ($title->equals($dupe->getTitle())) {
             unset($dupes[$key]);
         }
     }
     if ($dupes) {
         $warnings['duplicate'] = $dupes;
     }
     // Check dupes against archives
     $archivedImage = new ArchivedFile(null, 0, "{$hash}.{$this->mFinalExtension}");
     if ($archivedImage->getID() > 0) {
         if ($archivedImage->userCan(File::DELETED_FILE)) {
             $warnings['duplicate-archive'] = $archivedImage->getName();
         } else {
             $warnings['duplicate-archive'] = '';
         }
     }
     wfProfileOut(__METHOD__);
     return $warnings;
 }
Exemplo n.º 5
0
 private function formatFileRow($row, $sk)
 {
     global $wgUser, $wgLang;
     $file = ArchivedFile::newFromRow($row);
     $ts = wfTimestamp(TS_MW, $row->fa_timestamp);
     if ($this->mAllowed && $row->fa_storage_key) {
         $checkBox = Xml::check("fileid" . $row->fa_id);
         $key = urlencode($row->fa_storage_key);
         $target = urlencode($this->mTarget);
         $titleObj = SpecialPage::getTitleFor("Undelete");
         $pageLink = $this->getFileLink($file, $titleObj, $ts, $key, $sk);
     } else {
         $checkBox = '';
         $pageLink = $wgLang->timeanddate($ts, true);
     }
     $userLink = $this->getFileUser($file, $sk);
     $data = wfMsg('widthheight', $wgLang->formatNum($row->fa_width), $wgLang->formatNum($row->fa_height)) . ' (' . wfMsg('nbytes', $wgLang->formatNum($row->fa_size)) . ')';
     $data = htmlspecialchars($data);
     $comment = $this->getFileComment($file, $sk);
     $revdlink = '';
     if ($wgUser->isAllowed('deleterevision')) {
         $revdel = SpecialPage::getTitleFor('Revisiondelete');
         if (!$file->userCan(File::DELETED_RESTRICTED)) {
             // If revision was hidden from sysops
             $del = wfMsgHtml('rev-delundel');
         } else {
             $del = $sk->makeKnownLinkObj($revdel, wfMsgHtml('rev-delundel'), 'target=' . $this->mTargetObj->getPrefixedUrl() . '&fileid=' . $row->fa_id);
             // Bolden oversighted content
             if ($file->isDeleted(File::DELETED_RESTRICTED)) {
                 $del = "<strong>{$del}</strong>";
             }
         }
         $revdlink = "<tt>(<small>{$del}</small>)</tt>";
     }
     return "<li>{$checkBox} {$revdlink} {$pageLink} . . {$userLink} {$data} {$comment}</li>\n";
 }
Exemplo n.º 6
0
 /**
  * Loads a file object from the filearchive table
  *
  * @param stdClass $row
  * @return ArchivedFile
  */
 public static function newFromRow($row)
 {
     $file = new ArchivedFile(Title::makeTitle(NS_FILE, $row->fa_name));
     $file->loadFromRow($row);
     return $file;
 }
Exemplo n.º 7
0
 /**
  * Check for non fatal problems with the file.
  *
  * This should not assume that mTempPath is set.
  *
  * @return array Array of warnings
  */
 public function checkWarnings()
 {
     global $wgLang;
     $warnings = [];
     $localFile = $this->getLocalFile();
     $localFile->load(File::READ_LATEST);
     $filename = $localFile->getName();
     /**
      * Check whether the resulting filename is different from the desired one,
      * but ignore things like ucfirst() and spaces/underscore things
      */
     $comparableName = str_replace(' ', '_', $this->mDesiredDestName);
     $comparableName = Title::capitalize($comparableName, NS_FILE);
     if ($this->mDesiredDestName != $filename && $comparableName != $filename) {
         $warnings['badfilename'] = $filename;
     }
     // Check whether the file extension is on the unwanted list
     global $wgCheckFileExtensions, $wgFileExtensions;
     if ($wgCheckFileExtensions) {
         $extensions = array_unique($wgFileExtensions);
         if (!$this->checkFileExtension($this->mFinalExtension, $extensions)) {
             $warnings['filetype-unwanted-type'] = [$this->mFinalExtension, $wgLang->commaList($extensions), count($extensions)];
         }
     }
     global $wgUploadSizeWarning;
     if ($wgUploadSizeWarning && $this->mFileSize > $wgUploadSizeWarning) {
         $warnings['large-file'] = [$wgUploadSizeWarning, $this->mFileSize];
     }
     if ($this->mFileSize == 0) {
         $warnings['empty-file'] = true;
     }
     $hash = $this->getTempFileSha1Base36();
     $exists = self::getExistsWarning($localFile);
     if ($exists !== false) {
         $warnings['exists'] = $exists;
         // check if file is an exact duplicate of current file version
         if ($hash === $localFile->getSha1()) {
             $warnings['no-change'] = $localFile;
         }
         // check if file is an exact duplicate of older versions of this file
         $history = $localFile->getHistory();
         foreach ($history as $oldFile) {
             if ($hash === $oldFile->getSha1()) {
                 $warnings['duplicate-version'][] = $oldFile;
             }
         }
     }
     if ($localFile->wasDeleted() && !$localFile->exists()) {
         $warnings['was-deleted'] = $filename;
     }
     // Check dupes against existing files
     $dupes = RepoGroup::singleton()->findBySha1($hash);
     $title = $this->getTitle();
     // Remove all matches against self
     foreach ($dupes as $key => $dupe) {
         if ($title->equals($dupe->getTitle())) {
             unset($dupes[$key]);
         }
     }
     if ($dupes) {
         $warnings['duplicate'] = $dupes;
     }
     // Check dupes against archives
     $archivedFile = new ArchivedFile(null, 0, '', $hash);
     if ($archivedFile->getID() > 0) {
         if ($archivedFile->userCan(File::DELETED_FILE)) {
             $warnings['duplicate-archive'] = $archivedFile->getName();
         } else {
             $warnings['duplicate-archive'] = '';
         }
     }
     return $warnings;
 }
Exemplo n.º 8
0
 public function execute()
 {
     $user = $this->getUser();
     // Before doing anything at all, let's check permissions
     if (!$user->isAllowed('deletedhistory')) {
         $this->dieUsage('You don\'t have permission to view deleted file information', 'permissiondenied');
     }
     $db = $this->getDB();
     $params = $this->extractRequestParams();
     $prop = array_flip($params['prop']);
     $fld_sha1 = isset($prop['sha1']);
     $fld_timestamp = isset($prop['timestamp']);
     $fld_user = isset($prop['user']);
     $fld_size = isset($prop['size']);
     $fld_dimensions = isset($prop['dimensions']);
     $fld_description = isset($prop['description']) || isset($prop['parseddescription']);
     $fld_mime = isset($prop['mime']);
     $fld_mediatype = isset($prop['mediatype']);
     $fld_metadata = isset($prop['metadata']);
     $fld_bitdepth = isset($prop['bitdepth']);
     $fld_archivename = isset($prop['archivename']);
     $this->addTables('filearchive');
     $this->addFields(ArchivedFile::selectFields());
     $this->addFields(array('fa_id', 'fa_name', 'fa_timestamp', 'fa_deleted'));
     $this->addFieldsIf('fa_sha1', $fld_sha1);
     $this->addFieldsIf(array('fa_user', 'fa_user_text'), $fld_user);
     $this->addFieldsIf(array('fa_height', 'fa_width', 'fa_size'), $fld_dimensions || $fld_size);
     $this->addFieldsIf('fa_description', $fld_description);
     $this->addFieldsIf(array('fa_major_mime', 'fa_minor_mime'), $fld_mime);
     $this->addFieldsIf('fa_media_type', $fld_mediatype);
     $this->addFieldsIf('fa_metadata', $fld_metadata);
     $this->addFieldsIf('fa_bits', $fld_bitdepth);
     $this->addFieldsIf('fa_archive_name', $fld_archivename);
     if (!is_null($params['continue'])) {
         $cont = explode('|', $params['continue']);
         $this->dieContinueUsageIf(count($cont) != 3);
         $op = $params['dir'] == 'descending' ? '<' : '>';
         $cont_from = $db->addQuotes($cont[0]);
         $cont_timestamp = $db->addQuotes($db->timestamp($cont[1]));
         $cont_id = (int) $cont[2];
         $this->dieContinueUsageIf($cont[2] !== (string) $cont_id);
         $this->addWhere("fa_name {$op} {$cont_from} OR " . "(fa_name = {$cont_from} AND " . "(fa_timestamp {$op} {$cont_timestamp} OR " . "(fa_timestamp = {$cont_timestamp} AND " . "fa_id {$op}= {$cont_id} )))");
     }
     // Image filters
     $dir = $params['dir'] == 'descending' ? 'older' : 'newer';
     $from = $params['from'] === null ? null : $this->titlePartToKey($params['from'], NS_FILE);
     $to = $params['to'] === null ? null : $this->titlePartToKey($params['to'], NS_FILE);
     $this->addWhereRange('fa_name', $dir, $from, $to);
     if (isset($params['prefix'])) {
         $this->addWhere('fa_name' . $db->buildLike($this->titlePartToKey($params['prefix'], NS_FILE), $db->anyString()));
     }
     $sha1Set = isset($params['sha1']);
     $sha1base36Set = isset($params['sha1base36']);
     if ($sha1Set || $sha1base36Set) {
         $sha1 = false;
         if ($sha1Set) {
             $sha1 = strtolower($params['sha1']);
             if (!$this->validateSha1Hash($sha1)) {
                 $this->dieUsage('The SHA1 hash provided is not valid', 'invalidsha1hash');
             }
             $sha1 = wfBaseConvert($sha1, 16, 36, 31);
         } elseif ($sha1base36Set) {
             $sha1 = strtolower($params['sha1base36']);
             if (!$this->validateSha1Base36Hash($sha1)) {
                 $this->dieUsage('The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash');
             }
         }
         if ($sha1) {
             $this->addWhereFld('fa_sha1', $sha1);
         }
     }
     // Exclude files this user can't view.
     if (!$user->isAllowed('deletedtext')) {
         $bitmask = File::DELETED_FILE;
     } elseif (!$user->isAllowedAny('suppressrevision', 'viewsuppressed')) {
         $bitmask = File::DELETED_FILE | File::DELETED_RESTRICTED;
     } else {
         $bitmask = 0;
     }
     if ($bitmask) {
         $this->addWhere($this->getDB()->bitAnd('fa_deleted', $bitmask) . " != {$bitmask}");
     }
     $limit = $params['limit'];
     $this->addOption('LIMIT', $limit + 1);
     $sort = $params['dir'] == 'descending' ? ' DESC' : '';
     $this->addOption('ORDER BY', array('fa_name' . $sort, 'fa_timestamp' . $sort, 'fa_id' . $sort));
     $res = $this->select(__METHOD__);
     $count = 0;
     $result = $this->getResult();
     foreach ($res as $row) {
         if (++$count > $limit) {
             // We've reached the one extra which shows that there are
             // additional pages to be had. Stop here...
             $this->setContinueEnumParameter('continue', "{$row->fa_name}|{$row->fa_timestamp}|{$row->fa_id}");
             break;
         }
         $file = array();
         $file['id'] = (int) $row->fa_id;
         $file['name'] = $row->fa_name;
         $title = Title::makeTitle(NS_FILE, $row->fa_name);
         self::addTitleInfo($file, $title);
         if ($fld_description && Revision::userCanBitfield($row->fa_deleted, File::DELETED_COMMENT, $user)) {
             $file['description'] = $row->fa_description;
             if (isset($prop['parseddescription'])) {
                 $file['parseddescription'] = Linker::formatComment($row->fa_description, $title);
             }
         }
         if ($fld_user && Revision::userCanBitfield($row->fa_deleted, File::DELETED_USER, $user)) {
             $file['userid'] = (int) $row->fa_user;
             $file['user'] = $row->fa_user_text;
         }
         if ($fld_sha1) {
             $file['sha1'] = wfBaseConvert($row->fa_sha1, 36, 16, 40);
         }
         if ($fld_timestamp) {
             $file['timestamp'] = wfTimestamp(TS_ISO_8601, $row->fa_timestamp);
         }
         if ($fld_size || $fld_dimensions) {
             $file['size'] = $row->fa_size;
             $pageCount = ArchivedFile::newFromRow($row)->pageCount();
             if ($pageCount !== false) {
                 $file['pagecount'] = $pageCount;
             }
             $file['height'] = $row->fa_height;
             $file['width'] = $row->fa_width;
         }
         if ($fld_mediatype) {
             $file['mediatype'] = $row->fa_media_type;
         }
         if ($fld_metadata) {
             $file['metadata'] = $row->fa_metadata ? ApiQueryImageInfo::processMetaData(unserialize($row->fa_metadata), $result) : null;
         }
         if ($fld_bitdepth) {
             $file['bitdepth'] = $row->fa_bits;
         }
         if ($fld_mime) {
             $file['mime'] = "{$row->fa_major_mime}/{$row->fa_minor_mime}";
         }
         if ($fld_archivename && !is_null($row->fa_archive_name)) {
             $file['archivename'] = $row->fa_archive_name;
         }
         if ($row->fa_deleted & File::DELETED_FILE) {
             $file['filehidden'] = true;
         }
         if ($row->fa_deleted & File::DELETED_COMMENT) {
             $file['commenthidden'] = true;
         }
         if ($row->fa_deleted & File::DELETED_USER) {
             $file['userhidden'] = true;
         }
         if ($row->fa_deleted & File::DELETED_RESTRICTED) {
             // This file is deleted for normal admins
             $file['suppressed'] = true;
         }
         $fit = $result->addValue(array('query', $this->getModuleName()), null, $file);
         if (!$fit) {
             $this->setContinueEnumParameter('continue', "{$row->fa_name}|{$row->fa_timestamp}|{$row->fa_id}");
             break;
         }
     }
     $result->addIndexedTagName(array('query', $this->getModuleName()), 'fa');
 }
Exemplo n.º 9
0
 protected function scrubVersion(ArchivedFile $archivedFile)
 {
     $key = $archivedFile->getStorageKey();
     $name = $archivedFile->getName();
     $ts = $archivedFile->getTimestamp();
     $repo = RepoGroup::singleton()->getLocalRepo();
     $path = $repo->getZonePath('deleted') . '/' . $repo->getDeletedHashPath($key) . $key;
     if ($this->hasOption('delete')) {
         $status = $repo->getBackend()->delete(['src' => $path]);
         if ($status->isOK()) {
             $this->output("Deleted version '{$key}' ({$ts}) of file '{$name}'\n");
         } else {
             $this->output("Failed to delete version '{$key}' ({$ts}) of file '{$name}'\n");
             $this->output(print_r($status->getErrorsArray(), true));
         }
     } else {
         $this->output("Would delete version '{$key}' ({$ts}) of file '{$name}'\n");
     }
 }
Exemplo n.º 10
0
 function purgeArchivedFilesSQL($whereSQL)
 {
     # Purge files of archived images
     # lance.gatlin@gmail.com: TESTME
     $archivedImages_rows = $this->dbw->select('filearchive', array('*'), array($whereSQL));
     if ($archivedImages_rows->numRows() == 0) {
         return;
     }
     foreach ($archivedImages_rows as $row) {
         # Images that have been deleted use ArchivedFile path => $IP/images/deleted
         $archivedFile = ArchivedFile::newFromRow($row);
         // No path helper in ArchivedFile class
         // Path code taken from DeleteArchiveFiles maintenance class
         $key = $archivedFile->getKey();
         $path = $this->repo->getZonePath('deleted') . '/' . $this->repo->getDeletedHashPath($key) . $key;
         if ($path !== false && file_exists($path)) {
             unlink($path);
         }
     }
     # Purge the archived images from database
     # lance.gatlin@gmail.com: TESTME
     $this->dbw->delete('filearchive', array($whereSQL));
 }
Exemplo n.º 11
0
 public function __construct($list, $row)
 {
     RevDelItem::__construct($list, $row);
     $this->file = ArchivedFile::newFromRow($row);
     $this->lockFile = RepoGroup::singleton()->getLocalRepo()->newFile($row->fa_name);
 }
Exemplo n.º 12
0
 private function formatFileRow($row, $sk)
 {
     global $wgUser, $wgLang;
     $file = ArchivedFile::newFromRow($row);
     $ts = wfTimestamp(TS_MW, $row->fa_timestamp);
     if ($this->mAllowed && $row->fa_storage_key) {
         $checkBox = Xml::check("fileid" . $row->fa_id);
         $key = urlencode($row->fa_storage_key);
         $target = urlencode($this->mTarget);
         $titleObj = SpecialPage::getTitleFor("Undelete");
         $pageLink = $this->getFileLink($file, $titleObj, $ts, $key, $sk);
     } else {
         $checkBox = '';
         $pageLink = $wgLang->timeanddate($ts, true);
     }
     $userLink = $this->getFileUser($file, $sk);
     $data = wfMsg('widthheight', $wgLang->formatNum($row->fa_width), $wgLang->formatNum($row->fa_height)) . ' (' . wfMsg('nbytes', $wgLang->formatNum($row->fa_size)) . ')';
     $data = htmlspecialchars($data);
     $comment = $this->getFileComment($file, $sk);
     // Add show/hide deletion links if available
     $canHide = $wgUser->isAllowed('deleterevision');
     if ($canHide || $file->getVisibility() && $wgUser->isAllowed('deletedhistory')) {
         if (!$file->userCan(File::DELETED_RESTRICTED)) {
             $revdlink = $sk->revDeleteLinkDisabled($canHide);
             // revision was hidden from sysops
         } else {
             $query = array('type' => 'filearchive', 'target' => $this->mTargetObj->getPrefixedDBkey(), 'ids' => $row->fa_id);
             $revdlink = $sk->revDeleteLink($query, $file->isDeleted(File::DELETED_RESTRICTED), $canHide);
         }
     } else {
         $revdlink = '';
     }
     return "<li>{$checkBox} {$revdlink} {$pageLink} . . {$userLink} {$data} {$comment}</li>\n";
 }
Exemplo n.º 13
0
 /**
  * Check for duplicate files and throw up a warning before the upload
  * completes.
  */
 function getDupeWarning($tempfile, $extension, $destinationTitle)
 {
     $hash = File::sha1Base36($tempfile);
     $dupes = RepoGroup::singleton()->findBySha1($hash);
     $archivedImage = new ArchivedFile(null, 0, $hash . ".{$extension}");
     if ($dupes) {
         global $wgOut;
         $msg = "<gallery>";
         foreach ($dupes as $file) {
             $title = $file->getTitle();
             # Don't throw the warning when the titles are the same, it's a reupload
             # and highly redundant.
             if (!$title->equals($destinationTitle) || !$this->mForReUpload) {
                 $msg .= $title->getPrefixedText() . "|" . $title->getText() . "\n";
             }
         }
         $msg .= "</gallery>";
         return "<li>" . wfMsgExt("file-exists-duplicate", array("parse"), count($dupes)) . $wgOut->parse($msg) . "</li>\n";
     } elseif ($archivedImage->getID() > 0) {
         global $wgOut;
         $name = Title::makeTitle(NS_FILE, $archivedImage->getName())->getPrefixedText();
         return Xml::tags('li', null, wfMsgExt('file-deleted-duplicate', array('parseinline'), array($name)));
     } else {
         return '';
     }
 }
Exemplo n.º 14
0
 public function execute()
 {
     $user = $this->getUser();
     // Before doing anything at all, let's check permissions
     if (!$user->isAllowed('deletedhistory')) {
         $this->dieUsage('You don\'t have permission to view deleted file information', 'permissiondenied');
     }
     $db = $this->getDB();
     $params = $this->extractRequestParams();
     $prop = array_flip($params['prop']);
     $fld_sha1 = isset($prop['sha1']);
     $fld_timestamp = isset($prop['timestamp']);
     $fld_user = isset($prop['user']);
     $fld_size = isset($prop['size']);
     $fld_dimensions = isset($prop['dimensions']);
     $fld_description = isset($prop['description']) || isset($prop['parseddescription']);
     $fld_mime = isset($prop['mime']);
     $fld_mediatype = isset($prop['mediatype']);
     $fld_metadata = isset($prop['metadata']);
     $fld_bitdepth = isset($prop['bitdepth']);
     $fld_archivename = isset($prop['archivename']);
     $this->addTables('filearchive');
     $this->addFields(array('fa_name', 'fa_deleted'));
     $this->addFieldsIf('fa_storage_key', $fld_sha1);
     $this->addFieldsIf('fa_timestamp', $fld_timestamp);
     $this->addFieldsIf(array('fa_user', 'fa_user_text'), $fld_user);
     $this->addFieldsIf(array('fa_height', 'fa_width', 'fa_size'), $fld_dimensions || $fld_size);
     $this->addFieldsIf('fa_description', $fld_description);
     $this->addFieldsIf(array('fa_major_mime', 'fa_minor_mime'), $fld_mime);
     $this->addFieldsIf('fa_media_type', $fld_mediatype);
     $this->addFieldsIf('fa_metadata', $fld_metadata);
     $this->addFieldsIf('fa_bits', $fld_bitdepth);
     $this->addFieldsIf('fa_archive_name', $fld_archivename);
     if (!is_null($params['continue'])) {
         $cont = explode('|', $params['continue']);
         if (count($cont) != 1) {
             $this->dieUsage("Invalid continue param. You should pass the " . "original value returned by the previous query", "_badcontinue");
         }
         $op = $params['dir'] == 'descending' ? '<' : '>';
         $cont_from = $db->addQuotes($cont[0]);
         $this->addWhere("fa_name {$op}= {$cont_from}");
     }
     // Image filters
     $dir = $params['dir'] == 'descending' ? 'older' : 'newer';
     $from = is_null($params['from']) ? null : $this->titlePartToKey($params['from']);
     if (!is_null($params['continue'])) {
         $from = $params['continue'];
     }
     $to = is_null($params['to']) ? null : $this->titlePartToKey($params['to']);
     $this->addWhereRange('fa_name', $dir, $from, $to);
     if (isset($params['prefix'])) {
         $this->addWhere('fa_name' . $db->buildLike($this->titlePartToKey($params['prefix']), $db->anyString()));
     }
     $sha1Set = isset($params['sha1']);
     $sha1base36Set = isset($params['sha1base36']);
     if ($sha1Set || $sha1base36Set) {
         global $wgMiserMode;
         if ($wgMiserMode) {
             $this->dieUsage('Search by hash disabled in Miser Mode', 'hashsearchdisabled');
         }
         $sha1 = false;
         if ($sha1Set) {
             if (!$this->validateSha1Hash($params['sha1'])) {
                 $this->dieUsage('The SHA1 hash provided is not valid', 'invalidsha1hash');
             }
             $sha1 = wfBaseConvert($params['sha1'], 16, 36, 31);
         } elseif ($sha1base36Set) {
             if (!$this->validateSha1Base36Hash($params['sha1base36'])) {
                 $this->dieUsage('The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash');
             }
             $sha1 = $params['sha1base36'];
         }
         if ($sha1) {
             $this->addWhere('fa_storage_key ' . $db->buildLike("{$sha1}.", $db->anyString()));
         }
     }
     if (!$user->isAllowed('suppressrevision')) {
         // Filter out revisions that the user is not allowed to see. There
         // is no way to indicate that we have skipped stuff because the
         // continuation parameter is fa_name
         // Note that this field is unindexed. This should however not be
         // a big problem as files with fa_deleted are rare
         $this->addWhereFld('fa_deleted', 0);
     }
     $limit = $params['limit'];
     $this->addOption('LIMIT', $limit + 1);
     $sort = $params['dir'] == 'descending' ? ' DESC' : '';
     $this->addOption('ORDER BY', 'fa_name' . $sort);
     $res = $this->select(__METHOD__);
     $count = 0;
     $result = $this->getResult();
     foreach ($res as $row) {
         if (++$count > $limit) {
             // We've reached the one extra which shows that there are additional pages to be had. Stop here...
             $this->setContinueEnumParameter('continue', $row->fa_name);
             break;
         }
         $file = array();
         $file['name'] = $row->fa_name;
         $title = Title::makeTitle(NS_FILE, $row->fa_name);
         self::addTitleInfo($file, $title);
         if ($fld_sha1) {
             $file['sha1'] = wfBaseConvert(LocalRepo::getHashFromKey($row->fa_storage_key), 36, 16, 40);
         }
         if ($fld_timestamp) {
             $file['timestamp'] = wfTimestamp(TS_ISO_8601, $row->fa_timestamp);
         }
         if ($fld_user) {
             $file['userid'] = $row->fa_user;
             $file['user'] = $row->fa_user_text;
         }
         if ($fld_size || $fld_dimensions) {
             $file['size'] = $row->fa_size;
             $pageCount = ArchivedFile::newFromRow($row)->pageCount();
             if ($pageCount !== false) {
                 $vals['pagecount'] = $pageCount;
             }
             $file['height'] = $row->fa_height;
             $file['width'] = $row->fa_width;
         }
         if ($fld_description) {
             $file['description'] = $row->fa_description;
             if (isset($prop['parseddescription'])) {
                 $file['parseddescription'] = Linker::formatComment($row->fa_description, $title);
             }
         }
         if ($fld_mediatype) {
             $file['mediatype'] = $row->fa_media_type;
         }
         if ($fld_metadata) {
             $file['metadata'] = $row->fa_metadata ? ApiQueryImageInfo::processMetaData(unserialize($row->fa_metadata), $result) : null;
         }
         if ($fld_bitdepth) {
             $file['bitdepth'] = $row->fa_bits;
         }
         if ($fld_mime) {
             $file['mime'] = "{$row->fa_major_mime}/{$row->fa_minor_mime}";
         }
         if ($fld_archivename && !is_null($row->fa_archive_name)) {
             $file['archivename'] = $row->fa_archive_name;
         }
         if ($row->fa_deleted & File::DELETED_FILE) {
             $file['filehidden'] = '';
         }
         if ($row->fa_deleted & File::DELETED_COMMENT) {
             $file['commenthidden'] = '';
         }
         if ($row->fa_deleted & File::DELETED_USER) {
             $file['userhidden'] = '';
         }
         if ($row->fa_deleted & File::DELETED_RESTRICTED) {
             // This file is deleted for normal admins
             $file['suppressed'] = '';
         }
         $fit = $result->addValue(array('query', $this->getModuleName()), null, $file);
         if (!$fit) {
             $this->setContinueEnumParameter('continue', $row->fa_name);
             break;
         }
     }
     $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'fa');
 }
Exemplo n.º 15
0
 private function formatFileRow($row)
 {
     $file = ArchivedFile::newFromRow($row);
     $ts = wfTimestamp(TS_MW, $row->fa_timestamp);
     $user = $this->getUser();
     if ($this->mAllowed && $row->fa_storage_key) {
         $checkBox = Xml::check('fileid' . $row->fa_id);
         $key = urlencode($row->fa_storage_key);
         $pageLink = $this->getFileLink($file, $this->getTitle(), $ts, $key);
     } else {
         $checkBox = '';
         $pageLink = $this->getLanguage()->userTimeAndDate($ts, $user);
     }
     $userLink = $this->getFileUser($file);
     $data = $this->msg('widthheight')->numParams($row->fa_width, $row->fa_height)->text() . ' (' . $this->msg('nbytes')->numParams($row->fa_size)->text() . ')';
     $data = htmlspecialchars($data);
     $comment = $this->getFileComment($file);
     // Add show/hide deletion links if available
     $canHide = $user->isAllowed('deleterevision');
     if ($canHide || $file->getVisibility() && $user->isAllowed('deletedhistory')) {
         if (!$file->userCan(File::DELETED_RESTRICTED, $user)) {
             $revdlink = Linker::revDeleteLinkDisabled($canHide);
             // revision was hidden from sysops
         } else {
             $query = array('type' => 'filearchive', 'target' => $this->mTargetObj->getPrefixedDBkey(), 'ids' => $row->fa_id);
             $revdlink = Linker::revDeleteLink($query, $file->isDeleted(File::DELETED_RESTRICTED), $canHide);
         }
     } else {
         $revdlink = '';
     }
     return "<li>{$checkBox} {$revdlink} {$pageLink} . . {$userLink} {$data} {$comment}</li>\n";
 }
Exemplo n.º 16
0
 /**
  * Fetch file upload comment if it's available to this user
  *
  * @param File|ArchivedFile $file
  * @return string HTML fragment
  */
 function getFileComment($file)
 {
     if (!$file->userCan(File::DELETED_COMMENT, $this->getUser())) {
         return '<span class="history-deleted"><span class="comment">' . $this->msg('rev-deleted-comment')->escaped() . '</span></span>';
     }
     $link = Linker::commentBlock($file->getRawDescription());
     if ($file->isDeleted(File::DELETED_COMMENT)) {
         $link = '<span class="history-deleted">' . $link . '</span>';
     }
     return $link;
 }
Exemplo n.º 17
0
 /**
  * Check for non fatal problems with the file
  *
  * @return Array of warnings
  */
 public function checkWarnings()
 {
     $warnings = array();
     $localFile = $this->getLocalFile();
     $filename = $localFile->getName();
     $n = strrpos($filename, '.');
     /**
      * Check whether the resulting filename is different from the desired one,
      * but ignore things like ucfirst() and spaces/underscore things
      */
     $comparableName = str_replace(' ', '_', $this->mDesiredDestName);
     $comparableName = Title::capitalize($comparableName, NS_FILE);
     if ($this->mDesiredDestName != $filename && $comparableName != $filename) {
         $warnings['badfilename'] = $filename;
     }
     // Check whether the file extension is on the unwanted list
     global $wgCheckFileExtensions, $wgFileExtensions;
     if ($wgCheckFileExtensions) {
         if (!$this->checkFileExtension($this->mFinalExtension, $wgFileExtensions)) {
             $warnings['filetype-unwanted-type'] = $this->mFinalExtension;
         }
     }
     global $wgUploadSizeWarning;
     if ($wgUploadSizeWarning && $this->mFileSize > $wgUploadSizeWarning) {
         $warnings['large-file'] = $wgUploadSizeWarning;
     }
     if ($this->mFileSize == 0) {
         $warnings['emptyfile'] = true;
     }
     $exists = self::getExistsWarning($localFile);
     if ($exists !== false) {
         $warnings['exists'] = $exists;
     }
     // Check dupes against existing files
     $hash = File::sha1Base36($this->mTempPath);
     $dupes = RepoGroup::singleton()->findBySha1($hash);
     $title = $this->getTitle();
     // Remove all matches against self
     foreach ($dupes as $key => $dupe) {
         if ($title->equals($dupe->getTitle())) {
             unset($dupes[$key]);
         }
     }
     if ($dupes) {
         $warnings['duplicate'] = $dupes;
     }
     // Check dupes against archives
     $archivedImage = new ArchivedFile(null, 0, "{$hash}.{$this->mFinalExtension}");
     if ($archivedImage->getID() > 0) {
         $warnings['duplicate-archive'] = $archivedImage->getName();
     }
     return $warnings;
 }
 public function __construct($list, $row)
 {
     RevDel_Item::__construct($list, $row);
     $this->file = ArchivedFile::newFromRow($row);
 }
Exemplo n.º 19
0
 private function formatFileRow($row, $sk)
 {
     global $wgUser, $wgLang;
     $file = ArchivedFile::newFromRow($row);
     $ts = wfTimestamp(TS_MW, $row->fa_timestamp);
     if ($this->mAllowed && $row->fa_storage_key) {
         $checkBox = Xml::check("fileid" . $row->fa_id);
         $key = urlencode($row->fa_storage_key);
         $target = urlencode($this->mTarget);
         $titleObj = SpecialPage::getTitleFor("Undelete");
         $pageLink = $this->getFileLink($file, $titleObj, $ts, $key, $sk);
     } else {
         $checkBox = '';
         $pageLink = $wgLang->timeanddate($ts, true);
     }
     $userLink = $this->getFileUser($file, $sk);
     $data = wfMsg('widthheight', $wgLang->formatNum($row->fa_width), $wgLang->formatNum($row->fa_height)) . ' (' . wfMsg('nbytes', $wgLang->formatNum($row->fa_size)) . ')';
     $data = htmlspecialchars($data);
     $comment = $this->getFileComment($file, $sk);
     $revdlink = '';
     if ($wgUser->isAllowed('deleterevision')) {
         if (!$file->userCan(File::DELETED_RESTRICTED)) {
             // If revision was hidden from sysops
             $revdlink = Xml::tags('span', array('class' => 'mw-revdelundel-link'), '(' . wfMsgHtml('rev-delundel') . ')');
         } else {
             $query = array('target' => $this->mTargetObj->getPrefixedDBkey(), 'fileid' => $row->fa_id);
             $revdlink = $sk->revDeleteLink($query, $file->isDeleted(File::DELETED_RESTRICTED));
         }
     }
     return "<li>{$checkBox} {$revdlink} {$pageLink} . . {$userLink} {$data} {$comment}</li>\n";
 }