/** * @param IDatabase $db * @return mixed */ public function doQuery($db) { $archiveNames = array(); foreach ($this->ids as $timestamp) { $archiveNames[] = $timestamp . '!' . $this->title->getDBkey(); } return $db->select('oldimage', OldLocalFile::selectFields(), array('oi_name' => $this->title->getDBkey(), 'oi_archive_name' => $archiveNames), __METHOD__, array('ORDER BY' => 'oi_timestamp DESC')); }
public function findFiles(array $items, $flags = 0) { $finalFiles = array(); // map of (DB key => corresponding File) for matches $searchSet = array(); // map of (normalized DB key => search params) foreach ($items as $item) { if (is_array($item)) { $title = File::normalizeTitle($item['title']); if ($title) { $searchSet[$title->getDBkey()] = $item; } } else { $title = File::normalizeTitle($item); if ($title) { $searchSet[$title->getDBkey()] = array(); } } } $fileMatchesSearch = function (File $file, array $search) { // Note: file name comparison done elsewhere (to handle redirects) $user = !empty($search['private']) && $search['private'] instanceof User ? $search['private'] : null; return $file->exists() && (empty($search['time']) && !$file->isOld() || !empty($search['time']) && $search['time'] === $file->getTimestamp()) && (!empty($search['private']) || !$file->isDeleted(File::DELETED_FILE)) && $file->userCan(File::DELETED_FILE, $user); }; $that = $this; $applyMatchingFiles = function (ResultWrapper $res, &$searchSet, &$finalFiles) use($that, $fileMatchesSearch, $flags) { global $wgContLang; $info = $that->getInfo(); foreach ($res as $row) { $file = $that->newFileFromRow($row); // There must have been a search for this DB key, but this has to handle the // cases were title capitalization is different on the client and repo wikis. $dbKeysLook = array(strtr($file->getName(), ' ', '_')); if (!empty($info['initialCapital'])) { // Search keys for "hi.png" and "Hi.png" should use the "Hi.png file" $dbKeysLook[] = $wgContLang->lcfirst($file->getName()); } foreach ($dbKeysLook as $dbKey) { if (isset($searchSet[$dbKey]) && $fileMatchesSearch($file, $searchSet[$dbKey])) { $finalFiles[$dbKey] = $flags & FileRepo::NAME_AND_TIME_ONLY ? array('title' => $dbKey, 'timestamp' => $file->getTimestamp()) : $file; unset($searchSet[$dbKey]); } } } }; $dbr = $this->getSlaveDB(); // Query image table $imgNames = array(); foreach (array_keys($searchSet) as $dbKey) { $imgNames[] = $this->getNameFromTitle(File::normalizeTitle($dbKey)); } if (count($imgNames)) { $res = $dbr->select('image', LocalFile::selectFields(), array('img_name' => $imgNames), __METHOD__); $applyMatchingFiles($res, $searchSet, $finalFiles); } // Query old image table $oiConds = array(); // WHERE clause array for each file foreach ($searchSet as $dbKey => $search) { if (isset($search['time'])) { $oiConds[] = $dbr->makeList(array('oi_name' => $this->getNameFromTitle(File::normalizeTitle($dbKey)), 'oi_timestamp' => $dbr->timestamp($search['time'])), LIST_AND); } } if (count($oiConds)) { $res = $dbr->select('oldimage', OldLocalFile::selectFields(), $dbr->makeList($oiConds, LIST_OR), __METHOD__); $applyMatchingFiles($res, $searchSet, $finalFiles); } // Check for redirects... foreach ($searchSet as $dbKey => $search) { if (!empty($search['ignoreRedirect'])) { continue; } $title = File::normalizeTitle($dbKey); $redir = $this->checkRedirect($title); // hopefully hits memcached if ($redir && $redir->getNamespace() == NS_FILE) { $file = $this->newFile($redir); if ($file && $fileMatchesSearch($file, $search)) { $file->redirectedFrom($title->getDBkey()); if ($flags & FileRepo::NAME_AND_TIME_ONLY) { $finalFiles[$dbKey] = array('title' => $file->getTitle()->getDBkey(), 'timestamp' => $file->getTimestamp()); } else { $finalFiles[$dbKey] = $file; } } } } return $finalFiles; }
/** * @param int $limit Optional: Limit to number of results * @param int $start Optional: Timestamp, start from * @param int $end Optional: Timestamp, end at * @param bool $inc * @return array */ function getHistory($limit = null, $start = null, $end = null, $inc = true) { $dbr = $this->repo->getSlaveDB(); $tables = array('oldimage'); $fields = OldLocalFile::selectFields(); $conds = $opts = $join_conds = array(); $eq = $inc ? '=' : ''; $conds[] = "oi_name = " . $dbr->addQuotes($this->title->getDBkey()); if ($start) { $conds[] = "oi_timestamp <{$eq} " . $dbr->addQuotes($dbr->timestamp($start)); } if ($end) { $conds[] = "oi_timestamp >{$eq} " . $dbr->addQuotes($dbr->timestamp($end)); } if ($limit) { $opts['LIMIT'] = $limit; } // Search backwards for time > x queries $order = !$start && $end !== null ? 'ASC' : 'DESC'; $opts['ORDER BY'] = "oi_timestamp {$order}"; $opts['USE INDEX'] = array('oldimage' => 'oi_name_timestamp'); wfRunHooks('LocalFile::getHistory', array(&$this, &$tables, &$fields, &$conds, &$opts, &$join_conds)); $res = $dbr->select($tables, $fields, $conds, __METHOD__, $opts, $join_conds); $r = array(); foreach ($res as $row) { $r[] = $this->repo->newFileFromRow($row); } if ($order == 'ASC') { $r = array_reverse($r); // make sure it ends up descending } return $r; }
function deletePermanently($title) { global $wgOut; $ns = $title->getNamespace(); $t = $title->getDBkey(); $id = $title->getArticleID(); $cats = $title->getParentCategories(); $dbw = wfGetDB(DB_MASTER); $dbw->begin(); #### ## First delete entries, which are in direct relation with the page: #### # delete redirect... $dbw->delete('redirect', array('rd_from' => $id), __METHOD__); # delete external link... $dbw->delete('externallinks', array('el_from' => $id), __METHOD__); # delete language link... $dbw->delete('langlinks', array('ll_from' => $id), __METHOD__); # delete search index... $dbw->delete('searchindex', array('si_page' => $id), __METHOD__); # Delete restrictions for the page $dbw->delete('page_restrictions', array('pr_page' => $id), __METHOD__); # Delete page Links $dbw->delete('pagelinks', array('pl_from' => $id), __METHOD__); # delete category links $dbw->delete('categorylinks', array('cl_from' => $id), __METHOD__); # delete template links $dbw->delete('templatelinks', array('tl_from' => $id), __METHOD__); # read text entries for all revisions and delete them. $res = $dbw->select('revision', 'rev_text_id', "rev_page={$id}"); while ($row = $dbw->fetchObject($res)) { $value = $row->rev_text_id; $dbw->delete('text', array('old_id' => $value), __METHOD__); } # In the table 'revision' : Delete all the revision of the page where 'rev_page' = $id $dbw->delete('revision', array('rev_page' => $id), __METHOD__); # delete image links $dbw->delete('imagelinks', array('il_from' => $id), __METHOD__); #### ## then delete entries which are not in direct relation with the page: #### # Clean up recentchanges entries... $dbw->delete('recentchanges', array('rc_namespace' => $ns, 'rc_title' => $t), __METHOD__); # read text entries for all archived pages and delete them. $res = $dbw->select('archive', 'ar_text_id', array('ar_namespace' => $ns, 'ar_title' => $t)); while ($row = $dbw->fetchObject($res)) { $value = $row->ar_text_id; $dbw->delete('text', array('old_id' => $value), __METHOD__); } # Clean archive entries... $dbw->delete('archive', array('ar_namespace' => $ns, 'ar_title' => $t), __METHOD__); # Clean up log entries... $dbw->delete('logging', array('log_namespace' => $ns, 'log_title' => $t), __METHOD__); # Clean up watchlist... $dbw->delete('watchlist', array('wl_namespace' => $ns, 'wl_title' => $t), __METHOD__); # In the table 'page' : Delete the page entry $dbw->delete('page', array('page_id' => $id), __METHOD__); #### ## If the article belongs to a category, update category counts #### if (!empty($cats)) { foreach ($cats as $parentcat => $currentarticle) { $catname = split(':', $parentcat, 2); $cat = Category::newFromName($catname[1]); $cat->refreshCounts(); } } #### ## If an image is beeing deleted, some extra work needs to be done #### if ($ns == NS_IMAGE) { $file = wfFindFile($t); if ($file) { # Get all filenames of old versions: $fields = OldLocalFile::selectFields(); $res = $dbw->select('oldimage', $fields, array('oi_name' => $t)); while ($row = $dbw->fetchObject($res)) { $oldLocalFile = OldLocalFile::newFromRow($row, $file->repo); $path = $oldLocalFile->getArchivePath() . '/' . $oldLocalFile->getArchiveName(); try { # Using the FileStore to delete the file $transaction = FileStore::deleteFile($path); $transaction->commit(); } catch (Exception $e) { $wgOut->addHTML($e->getMessage()); } } $path = $file->getPath(); try { # Using the FileStore to delete the file itself $transaction = FileStore::deleteFile($path); $transaction->commit(); } catch (Exception $e) { $wgOut->addHTML($e->getMessage()); } } # clean the filearchive for the given filename: $fa_archive_name = array(); $res = $dbw->select('filearchive', 'fa_storage_key', array('fa_name' => $t)); while ($row = $dbw->fetchObject($res)) { $key = $row->fa_storage_key; # Using the FileStore to delete the file $store = FileStore::get('deleted'); $transaction = $store->delete($key); $transaction->commit(); } # Delete old db entries of the image: $dbw->delete('oldimage', array('oi_name' => $t), __METHOD__); # Delete archive entries of the image: $dbw->delete('filearchive', array('fa_name' => $t), __METHOD__); # Delete image entry: $dbw->delete('image', array('img_name' => $t), __METHOD__); $dbw->commit(); $linkCache = LinkCache::singleton(); $linkCache->clear(); } }
protected function doDBInserts() { $now = time(); $dbw = $this->file->repo->getMasterDB(); $encTimestamp = $dbw->addQuotes($dbw->timestamp($now)); $encUserId = $dbw->addQuotes($this->user->getId()); $encReason = $dbw->addQuotes($this->reason); $encGroup = $dbw->addQuotes('deleted'); $ext = $this->file->getExtension(); $dotExt = $ext === '' ? '' : ".{$ext}"; $encExt = $dbw->addQuotes($dotExt); list($oldRels, $deleteCurrent) = $this->getOldRels(); // Bitfields to further suppress the content if ($this->suppress) { $bitfield = Revision::SUPPRESSED_ALL; } else { $bitfield = 'oi_deleted'; } if ($deleteCurrent) { $dbw->insertSelect('filearchive', 'image', ['fa_storage_group' => $encGroup, 'fa_storage_key' => $dbw->conditional(['img_sha1' => ''], $dbw->addQuotes(''), $dbw->buildConcat(["img_sha1", $encExt])), 'fa_deleted_user' => $encUserId, 'fa_deleted_timestamp' => $encTimestamp, 'fa_deleted_reason' => $encReason, 'fa_deleted' => $this->suppress ? $bitfield : 0, 'fa_name' => 'img_name', 'fa_archive_name' => 'NULL', 'fa_size' => 'img_size', 'fa_width' => 'img_width', 'fa_height' => 'img_height', 'fa_metadata' => 'img_metadata', 'fa_bits' => 'img_bits', 'fa_media_type' => 'img_media_type', 'fa_major_mime' => 'img_major_mime', 'fa_minor_mime' => 'img_minor_mime', 'fa_description' => 'img_description', 'fa_user' => 'img_user', 'fa_user_text' => 'img_user_text', 'fa_timestamp' => 'img_timestamp', 'fa_sha1' => 'img_sha1'], ['img_name' => $this->file->getName()], __METHOD__); } if (count($oldRels)) { $res = $dbw->select('oldimage', OldLocalFile::selectFields(), ['oi_name' => $this->file->getName(), 'oi_archive_name' => array_keys($oldRels)], __METHOD__, ['FOR UPDATE']); $rowsInsert = []; foreach ($res as $row) { $rowsInsert[] = ['fa_storage_group' => 'deleted', 'fa_storage_key' => $row->oi_sha1 === '' ? '' : "{$row->oi_sha1}{$dotExt}", 'fa_deleted_user' => $this->user->getId(), 'fa_deleted_timestamp' => $dbw->timestamp($now), 'fa_deleted_reason' => $this->reason, 'fa_deleted' => $this->suppress ? $bitfield : $row->oi_deleted, 'fa_name' => $row->oi_name, 'fa_archive_name' => $row->oi_archive_name, 'fa_size' => $row->oi_size, 'fa_width' => $row->oi_width, 'fa_height' => $row->oi_height, 'fa_metadata' => $row->oi_metadata, 'fa_bits' => $row->oi_bits, 'fa_media_type' => $row->oi_media_type, 'fa_major_mime' => $row->oi_major_mime, 'fa_minor_mime' => $row->oi_minor_mime, 'fa_description' => $row->oi_description, 'fa_user' => $row->oi_user, 'fa_user_text' => $row->oi_user_text, 'fa_timestamp' => $row->oi_timestamp, 'fa_sha1' => $row->oi_sha1]; } $dbw->insert('filearchive', $rowsInsert, __METHOD__); } }
public static function addToFileHistQuery(File $file, array &$tables, array &$fields, &$conds, array &$opts, array &$join_conds) { if (!$file->isLocal()) { return true; // local files only } $flaggedArticle = FlaggableWikiPage::getTitleInstance($file->getTitle()); # Non-content pages cannot be validated. Stable version must exist. if ($flaggedArticle->isReviewable() && $flaggedArticle->getStableRev()) { $tables[] = 'flaggedrevs'; $fields[] = 'MAX(fr_quality) AS fr_quality'; # Avoid duplicate rows due to multiple revs with the same sha-1 key # This is a stupid hack to get all the field names in our GROUP BY # clause. Postgres yells at you for not including all of the selected # columns, so grab the full list, unset the two we actually want to # order by, then append the rest of them to our two. It would be # REALLY nice if we handled this automagically in makeSelectOptions() # or something *sigh* $groupBy = OldLocalFile::selectFields(); unset($groupBy[array_search('oi_name', $groupBy)]); unset($groupBy[array_search('oi_timestamp', $groupBy)]); $opts['GROUP BY'] = 'oi_name,oi_timestamp,' . implode(',', $groupBy); $join_conds['flaggedrevs'] = array('LEFT JOIN', 'oi_sha1 = fr_img_sha1 AND oi_timestamp = fr_img_timestamp'); } return true; }