function _getBinary($collection, $id, $field) { loader_import('saf.File.Store'); $fs = new FileStore($this->filestore_path); $data = $fs->get($id . '_' . $field . '_' . $collection); if (!$data) { $this->error = $fs->error; return false; } return $data; }
/** * Show a deleted file version requested by the visitor. */ function showFile($key) { global $wgOut; $wgOut->disable(); $store = FileStore::get('deleted'); $store->stream($key); }
/** * Moves an image from a safe private location * Caller is responsible for clearing caches * @param File $oimage * @returns mixed, string timestamp on success, false on failure */ function makeOldImagePublic($oimage) { $transaction = new FSTransaction(); if (!FileStore::lock()) { wfDebug(__METHOD__ . " could not acquire filestore lock\n"); return false; } $store = FileStore::get('deleted'); if (!$store) { wfDebug(__METHOD__ . ": skipping row with no file.\n"); return false; } $key = $oimage->sha1 . '.' . $oimage->getExtension(); $destDir = $oimage->getArchivePath(); if (!is_dir($destDir)) { wfMkdirParents($destDir); } $destPath = $destDir . DIRECTORY_SEPARATOR . $oimage->archive_name; // Check if any other stored revisions use this file; // if so, we shouldn't remove the file from the hidden // archives so they will still work. Check hidden files first. $useCount = $this->dbw->selectField('oldimage', '1', array('oi_sha1' => $oimage->sha1, 'oi_deleted & ' . File::DELETED_FILE => File::DELETED_FILE), __METHOD__, array('FOR UPDATE')); // Check the rest of the deleted archives too. // (these are the ones that don't show in the image history) if (!$useCount) { $useCount = $this->dbw->selectField('filearchive', '1', array('fa_storage_group' => 'deleted', 'fa_storage_key' => $key), __METHOD__, array('FOR UPDATE')); } if ($useCount == 0) { wfDebug(__METHOD__ . ": nothing else using {$oimage->sha1}, will deleting after\n"); $flags = FileStore::DELETE_ORIGINAL; } else { $flags = 0; } $transaction->add($store->export($key, $destPath, $flags)); wfDebug(__METHOD__ . ": set db items, applying file transactions\n"); $transaction->commit(); FileStore::unlock(); $m = explode('!', $oimage->archive_name, 2); $timestamp = $m[0]; return $timestamp; }
/** * Restore all or specified deleted revisions to the given file. * Permissions and logging are left to the caller. * * May throw database exceptions on error. * * @param $versions set of record ids of deleted items to restore, * or empty to restore all revisions. * @return the number of file revisions restored if successful, * or false on failure */ function restore($versions = array(), $Unsuppress = false) { global $wgUser; if (!FileStore::lock()) { wfDebug(__METHOD__ . " could not acquire filestore lock\n"); return false; } $transaction = new FSTransaction(); try { $dbw = wfGetDB(DB_MASTER); $dbw->begin(); // Re-confirm whether this image presently exists; // if no we'll need to create an image record for the // first item we restore. $exists = $dbw->selectField('image', '1', array('img_name' => $this->name), __METHOD__); // Fetch all or selected archived revisions for the file, // sorted from the most recent to the oldest. $conditions = array('fa_name' => $this->name); if ($versions) { $conditions['fa_id'] = $versions; } $result = $dbw->select('filearchive', '*', $conditions, __METHOD__, array('ORDER BY' => 'fa_timestamp DESC')); if ($dbw->numRows($result) < count($versions)) { // There's some kind of conflict or confusion; // we can't restore everything we were asked to. wfDebug(__METHOD__ . ": couldn't find requested items\n"); $dbw->rollback(); FileStore::unlock(); return false; } if ($dbw->numRows($result) == 0) { // Nothing to do. wfDebug(__METHOD__ . ": nothing to do\n"); $dbw->rollback(); FileStore::unlock(); return true; } $revisions = 0; while ($row = $dbw->fetchObject($result)) { if ($Unsuppress) { // Currently, fa_deleted flags fall off upon restore, lets be careful about this } else { if ($row->fa_deleted & Revision::DELETED_RESTRICTED && !$wgUser->isAllowed('hiderevision')) { // Skip restoring file revisions that the user cannot restore continue; } } $revisions++; $store = FileStore::get($row->fa_storage_group); if (!$store) { wfDebug(__METHOD__ . ": skipping row with no file.\n"); continue; } if ($revisions == 1 && !$exists) { $destDir = wfImageDir($row->fa_name); if (!is_dir($destDir)) { wfMkdirParents($destDir); } $destPath = $destDir . DIRECTORY_SEPARATOR . $row->fa_name; // We may have to fill in data if this was originally // an archived file revision. if (is_null($row->fa_metadata)) { $tempFile = $store->filePath($row->fa_storage_key); $magic = MimeMagic::singleton(); $mime = $magic->guessMimeType($tempFile, true); $media_type = $magic->getMediaType($tempFile, $mime); list($major_mime, $minor_mime) = self::splitMime($mime); $handler = MediaHandler::getHandler($mime); if ($handler) { $metadata = $handler->getMetadata($image, $tempFile); } else { $metadata = ''; } } else { $metadata = $row->fa_metadata; $major_mime = $row->fa_major_mime; $minor_mime = $row->fa_minor_mime; $media_type = $row->fa_media_type; } $table = 'image'; $fields = array('img_name' => $row->fa_name, 'img_size' => $row->fa_size, 'img_width' => $row->fa_width, 'img_height' => $row->fa_height, 'img_metadata' => $metadata, 'img_bits' => $row->fa_bits, 'img_media_type' => $media_type, 'img_major_mime' => $major_mime, 'img_minor_mime' => $minor_mime, 'img_description' => $row->fa_description, 'img_user' => $row->fa_user, 'img_user_text' => $row->fa_user_text, 'img_timestamp' => $row->fa_timestamp); } 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> $archiveName = wfTimestamp(TS_MW, $row->fa_deleted_timestamp) . '!' . $row->fa_name; } $destDir = wfImageArchiveDir($row->fa_name); if (!is_dir($destDir)) { wfMkdirParents($destDir); } $destPath = $destDir . DIRECTORY_SEPARATOR . $archiveName; $table = 'oldimage'; $fields = 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); } $dbw->insert($table, $fields, __METHOD__); // @todo this delete is not totally safe, potentially $dbw->delete('filearchive', array('fa_id' => $row->fa_id), __METHOD__); // Check if any other stored revisions use this file; // if so, we shouldn't remove the file from the deletion // archives so they will still work. $useCount = $dbw->selectField('filearchive', 'COUNT(*)', array('fa_storage_group' => $row->fa_storage_group, 'fa_storage_key' => $row->fa_storage_key), __METHOD__); if ($useCount == 0) { wfDebug(__METHOD__ . ": nothing else using {$row->fa_storage_key}, will deleting after\n"); $flags = FileStore::DELETE_ORIGINAL; } else { $flags = 0; } $transaction->add($store->export($row->fa_storage_key, $destPath, $flags)); } $dbw->immediateCommit(); } catch (MWException $e) { wfDebug(__METHOD__ . " caught error, aborting\n"); $transaction->rollback(); throw $e; } $transaction->commit(); FileStore::unlock(); if ($revisions > 0) { if (!$exists) { wfDebug(__METHOD__ . " restored {$revisions} items, creating a new current\n"); // Update site_stats $site_stats = $dbw->tableName('site_stats'); $dbw->query("UPDATE {$site_stats} SET ss_images=ss_images+1", __METHOD__); $this->purgeEverything(); } else { wfDebug(__METHOD__ . " restored {$revisions} as archived versions\n"); $this->purgeDescription(); } } return $revisions; }
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(); } }
/** * Show a deleted file version requested by the visitor. */ function showFile($key) { global $wgOut, $wgRequest; $wgOut->disable(); # We mustn't allow the output to be Squid cached, otherwise # if an admin previews a deleted image, and it's cached, then # a user without appropriate permissions can toddle off and # nab the image, and Squid will serve it $wgRequest->response()->header('Expires: ' . gmdate('D, d M Y H:i:s', 0) . ' GMT'); $wgRequest->response()->header('Cache-Control: no-cache, no-store, max-age=0, must-revalidate'); $wgRequest->response()->header('Pragma: no-cache'); $store = FileStore::get('deleted'); $store->stream($key); }