protected function purgeFromArchiveTable(LocalFile $file) { $db = $file->getRepo()->getSlaveDB(); $res = $db->select('filearchive', array('fa_archive_name'), array('fa_name' => $file->getName()), __METHOD__); foreach ($res as $row) { $file->purgeOldThumbnails($row->fa_archive_name); } }
/** * Handle image upload * * Returns array with uploaded files details or error details */ public function uploadImage($uploadFieldName = self::DEFAULT_FILE_FIELD_NAME, $destFileName = null, $forceOverwrite = false) { global $IP, $wgRequest, $wgUser; wfProfileIn(__METHOD__); $ret = false; // check whether upload is enabled (RT #53714) if (!WikiaPhotoGalleryHelper::isUploadAllowed()) { $ret = array('error' => true, 'message' => wfMsg('uploaddisabled')); wfProfileOut(__METHOD__); return $ret; } $imageName = stripslashes(!empty($destFileName) ? $destFileName : $wgRequest->getFileName($uploadFieldName)); // validate name and content of uploaded photo $nameValidation = $this->checkImageName($imageName, $uploadFieldName); if ($nameValidation == UploadBase::SUCCESS) { // get path to uploaded image $imagePath = $wgRequest->getFileTempName($uploadFieldName); // check if image with this name is already uploaded if ($this->imageExists($imageName) && !$forceOverwrite) { // upload as temporary file $this->log(__METHOD__, "image '{$imageName}' already exists!"); $tempName = $this->tempFileName($wgUser); $title = Title::makeTitle(NS_FILE, $tempName); $localRepo = RepoGroup::singleton()->getLocalRepo(); $file = new FakeLocalFile($title, $localRepo); $file->upload($wgRequest->getFileTempName($uploadFieldName), '', ''); // store uploaded image in GarbageCollector (image will be removed if not used) $tempId = $this->tempFileStoreInfo($tempName); // generate thumbnail (to fit 200x200 box) of temporary file $width = min(WikiaPhotoGalleryHelper::thumbnailMaxWidth, $file->width); $height = min(WikiaPhotoGalleryHelper::thumbnailMaxHeight, $file->height); $thumbnail = $file->transform(array('height' => $height, 'width' => $width)); // split uploaded file name into name + extension (foo-bar.png => foo-bar + png) list($fileName, $extensionsName) = UploadBase::splitExtensions($imageName); $extensionName = !empty($extensionsName) ? end($extensionsName) : ''; $this->log(__METHOD__, 'upload successful'); $ret = array('conflict' => true, 'name' => $imageName, 'nameParts' => array($fileName, $extensionName), 'tempId' => $tempId, 'size' => array('height' => $file->height, 'width' => $file->width), 'thumbnail' => array('height' => $thumbnail->height, 'url' => $thumbnail->url, 'width' => $thumbnail->width)); } else { // use regular MW upload $this->log(__METHOD__, "image '{$imageName}' is new one - uploading as MW file"); $this->log(__METHOD__, "uploading '{$imagePath}' as File:{$imageName}"); // create title and file objects for MW image to create $imageTitle = Title::newFromText($imageName, NS_FILE); $imageFile = new LocalFile($imageTitle, RepoGroup::singleton()->getLocalRepo()); // perform upload $result = $imageFile->upload($imagePath, '', ''); $this->log(__METHOD__, !empty($result->ok) ? 'upload successful' : 'upload failed'); $ret = array('success' => !empty($result->ok), 'name' => $imageName, 'size' => array('height' => !empty($result->ok) ? $imageFile->getHeight() : 0, 'width' => !empty($result->ok) ? $imageFile->getWidth() : 0)); } } else { $reason = $nameValidation; $this->log(__METHOD__, "upload failed - file name is not valid (error #{$reason})"); $ret = array('error' => true, 'reason' => $reason, 'message' => $this->translateError($reason)); } wfProfileOut(__METHOD__); return $ret; }
/** * Clear cache of video info specific to given file * @param LocalFile $file * @return bool */ public static function purgeVideoInfoCache(\LocalFile $file) { $mediaService = new MediaQueryService(); $mediaService->clearCacheTotalVideos(); if (!$file->isLocal()) { $mediaService->clearCacheTotalPremiumVideos(); } if (!empty(F::app()->wg->UseVideoVerticalFilters)) { VideoInfoHooksHelper::clearCategories($file->getTitle()); } return true; }
/** * Do the upload. * Checks are made in SpecialUpload::execute() */ protected function processUpload() { // Fetch the file if required $status = $this->mUpload->fetchFile(); if (!$status->isOK()) { $this->showUploadError($this->getOutput()->parse($status->getWikiText())); return; } if (!Hooks::run('UploadForm:BeforeProcessing', array(&$this))) { wfDebug("Hook 'UploadForm:BeforeProcessing' broke processing the file.\n"); // This code path is deprecated. If you want to break upload processing // do so by hooking into the appropriate hooks in UploadBase::verifyUpload // and UploadBase::verifyFile. // If you use this hook to break uploading, the user will be returned // an empty form with no error message whatsoever. return; } // Upload verification $details = $this->mUpload->verifyUpload(); if ($details['status'] != UploadBase::OK) { $this->processVerificationError($details); return; } // Verify permissions for this title $permErrors = $this->mUpload->verifyTitlePermissions($this->getUser()); if ($permErrors !== true) { $code = array_shift($permErrors[0]); $this->showRecoverableUploadError($this->msg($code, $permErrors[0])->parse()); return; } $this->mLocalFile = $this->mUpload->getLocalFile(); // Check warnings if necessary if (!$this->mIgnoreWarning) { $warnings = $this->mUpload->checkWarnings(); if ($this->showUploadWarning($warnings)) { return; } } // This is as late as we can throttle, after expected issues have been handled if (UploadBase::isThrottled($this->getUser())) { $this->showRecoverableUploadError($this->msg('actionthrottledtext')->escaped()); return; } // Get the page text if this is not a reupload if (!$this->mForReUpload) { $pageText = self::getInitialPageText($this->mComment, $this->mLicense, $this->mCopyrightStatus, $this->mCopyrightSource, $this->getConfig()); } else { $pageText = false; } $status = $this->mUpload->performUpload($this->mComment, $pageText, $this->mWatchthis, $this->getUser()); if (!$status->isGood()) { $this->showUploadError($this->getOutput()->parse($status->getWikiText())); return; } // Success, redirect to description page $this->mUploadSuccessful = true; Hooks::run('SpecialUploadComplete', array(&$this)); $this->getOutput()->redirect($this->mLocalFile->getTitle()->getFullURL()); }
/** * Constructor. * Do not call this except from inside a repo class. */ function __construct( $title, $repo ) { if ( !is_object( $title ) ) { throw new MWException( __CLASS__ . ' constructor given bogus title.' ); } parent::__construct( $title, $repo ); $this->tempPaths = array(); // Hash from rel to local copy. }
function newFileFromRow($row) { if (isset($row->img_name)) { return LocalFile::newFromRow($row, $this); } elseif (isset($row->oi_name)) { return OldLocalFile::newFromRow($row, $this); } else { throw new MWException(__METHOD__ . ': invalid row'); } }
private function executeImage() { if (empty($this->mParams['tempName'])) { $this->dieUsageMsg('The tempName parameter must be set'); } $tempFile = new FakeLocalFile(Title::newFromText($this->mParams['tempName'], 6), RepoGroup::singleton()->getLocalRepo()); $duplicate = $this->getFileDuplicate($tempFile->getLocalRefPath()); if ($duplicate) { return array('title' => $duplicate->getTitle()->getText()); } else { $title = $this->getUniqueTitle(wfStripIllegalFilenameChars($this->mParams['title'])); if (isset($this->mParams['license'])) { $pageText = SpecialUpload::getInitialPageText('', $this->mParams['license']); } $file = new LocalFile($title, RepoGroup::singleton()->getLocalRepo()); $file->upload($tempFile->getPath(), '', $pageText ? $pageText : ''); return array('title' => $file->getTitle()->getText()); } }
/** * Validate the user parameters and set $this->archiveName and $this->file. * Throws an error if validation fails */ protected function validateParameters() { // Validate the input title $title = Title::makeTitleSafe(NS_FILE, $this->params['filename']); if (is_null($title)) { $this->dieUsageMsg(array('invalidtitle', $this->params['filename'])); } $localRepo = RepoGroup::singleton()->getLocalRepo(); // Check if the file really exists $this->file = $localRepo->newFile($title); if (!$this->file->exists()) { $this->dieUsageMsg('notanarticle'); } // Check if the archivename is valid for this file $this->archiveName = $this->params['archivename']; $oldFile = $localRepo->newFromArchiveName($title, $this->archiveName); if (!$oldFile->exists()) { $this->dieUsageMsg('filerevert-badversion'); } }
/** * @param LocalFile $file * @param string $url * @param string $comment * @return FileRepoStatus */ private function uploadFromUrl($file, $url, $comment) { $tmpFile = tempnam(wfTempDir(), 'upload'); // fetch an asset $res = Http::get($url, 'default', ['noProxy' => true]); $this->assertTrue($res !== false, 'File from <' . $url . '> should be uploaded'); file_put_contents($tmpFile, $res); $this->assertTrue(is_readable($tmpFile), 'Temp file for HTTP upload should be created and readable'); Wikia::log(__METHOD__, false, sprintf('uploading %s (%.2f kB) as %s', $tmpFile, filesize($tmpFile) / 1024, $file->getName()), true); $res = $file->upload($tmpFile, $comment, ''); #unlink( $tmpFile ); return $res; }
/** * Store info in the db to enable the script to pick it up later during the day (via an automated cleaning routine) */ public function tempFileStoreInfo($filename) { global $wgExternalSharedDB, $wgCityId; wfProfileIn(__METHOD__); $title = Title::makeTitle(NS_FILE, $filename); $localRepo = RepoGroup::singleton()->getLocalRepo(); $path = LocalFile::newFromTitle($title, $localRepo)->getPath(); $dbw = wfGetDB(DB_MASTER, array(), $wgExternalSharedDB); $dbw->insert('garbage_collector', array('gc_filename' => $path, 'gc_timestamp' => $dbw->timestamp(), 'gc_wiki_id' => $wgCityId), __METHOD__); $id = $dbw->insertId(); $this->log(__METHOD__, "image stored as #{$id}"); $dbw->commit(); wfProfileOut(__METHOD__); return $id; }
function findFiles($titles) { // FIXME: Only accepts a $titles array where the keys are the sanitized // file names. if (count($titles) == 0) { return array(); } $dbr = $this->getSlaveDB(); $res = $dbr->select('image', LocalFile::selectFields(), array('img_name' => array_keys($titles))); $result = array(); while ($row = $res->fetchObject()) { $result[$row->img_name] = $this->newFileFromRow($row); } $res->free(); return $result; }
public function saveSettings($settings, $cityId = null) { global $wgCityId, $wgUser; $cityId = empty($cityId) ? $wgCityId : $cityId; // Verify wordmark length ( CONN-116 ) if (!empty($settings['wordmark-text'])) { $settings['wordmark-text'] = trim($settings['wordmark-text']); } if (empty($settings['wordmark-text'])) { // Do not save wordmark if its empty. unset($settings['wordmark-text']); } else { if (mb_strlen($settings['wordmark-text']) > 50) { $settings['wordmark-text'] = mb_substr($settings['wordmark-text'], 0, 50); } } if (isset($settings['favicon-image-name']) && strpos($settings['favicon-image-name'], 'Temp_file_') === 0) { $temp_file = new LocalFile(Title::newFromText($settings['favicon-image-name'], 6), RepoGroup::singleton()->getLocalRepo()); $file = new LocalFile(Title::newFromText(self::FaviconImageName, 6), RepoGroup::singleton()->getLocalRepo()); $file->upload($temp_file->getPath(), '', ''); $temp_file->delete(''); Wikia::invalidateFavicon(); $settings['favicon-image-url'] = $file->getURL(); $settings['favicon-image-name'] = $file->getName(); $file->repo->forceMaster(); $history = $file->getHistory(1); if (count($history) == 1) { $oldFaviconFile = array('url' => $history[0]->getURL(), 'name' => $history[0]->getArchiveName()); } } if (isset($settings['wordmark-image-name']) && strpos($settings['wordmark-image-name'], 'Temp_file_') === 0) { $temp_file = new LocalFile(Title::newFromText($settings['wordmark-image-name'], 6), RepoGroup::singleton()->getLocalRepo()); $file = new LocalFile(Title::newFromText(self::WordmarkImageName, 6), RepoGroup::singleton()->getLocalRepo()); $file->upload($temp_file->getPath(), '', ''); $temp_file->delete(''); $settings['wordmark-image-url'] = $file->getURL(); $settings['wordmark-image-name'] = $file->getName(); $file->repo->forceMaster(); $history = $file->getHistory(1); if (count($history) == 1) { $oldFile = array('url' => $history[0]->getURL(), 'name' => $history[0]->getArchiveName()); } } if (isset($settings['background-image-name']) && strpos($settings['background-image-name'], 'Temp_file_') === 0) { $temp_file = new LocalFile(Title::newFromText($settings['background-image-name'], 6), RepoGroup::singleton()->getLocalRepo()); $file = new LocalFile(Title::newFromText(self::BackgroundImageName, 6), RepoGroup::singleton()->getLocalRepo()); $file->upload($temp_file->getPath(), '', ''); $temp_file->delete(''); $settings['background-image'] = $file->getURL(); $settings['background-image-name'] = $file->getName(); $settings['background-image-width'] = $file->getWidth(); $settings['background-image-height'] = $file->getHeight(); $imageServing = new ImageServing(null, 120, array("w" => "120", "h" => "65")); $settings['user-background-image'] = $file->getURL(); $settings['user-background-image-thumb'] = wfReplaceImageServer($file->getThumbUrl($imageServing->getCut($file->getWidth(), $file->getHeight(), "origin") . "-" . $file->getName())); $file->repo->forceMaster(); $history = $file->getHistory(1); if (count($history) == 1) { $oldBackgroundFile = array('url' => $history[0]->getURL(), 'name' => $history[0]->getArchiveName()); } } $reason = wfMsg('themedesigner-reason', $wgUser->getName()); // update history if (!empty($GLOBALS[self::WikiFactoryHistory])) { $history = $GLOBALS[self::WikiFactoryHistory]; $lastItem = end($history); $revisionId = intval($lastItem['revision']) + 1; } else { $history = array(); $revisionId = 1; } // #140758 - Jakub // validation // default color values foreach (ThemeDesignerHelper::getColorVars() as $sColorVar => $sDefaultValue) { if (!isset($settings[$sColorVar]) || !ThemeDesignerHelper::isValidColor($settings[$sColorVar])) { $settings[$sColorVar] = $sDefaultValue; } } // update WF variable with current theme settings WikiFactory::setVarByName(self::WikiFactorySettings, $cityId, $settings, $reason); // add entry $history[] = array('settings' => $settings, 'author' => $wgUser->getName(), 'timestamp' => wfTimestampNow(), 'revision' => $revisionId); // limit history size to last 10 changes $history = array_slice($history, -self::HistoryItemsLimit); if (count($history) > 1) { for ($i = 0; $i < count($history) - 1; $i++) { if (isset($oldFaviconFile) && isset($history[$i]['settings']['favicon-image-name'])) { if ($history[$i]['settings']['favicon-image-name'] == self::FaviconImageName) { $history[$i]['settings']['favicon-image-name'] = $oldFaviconFile['name']; $history[$i]['settings']['favicon-image-url'] = $oldFaviconFile['url']; } } if (isset($oldFile) && isset($history[$i]['settings']['wordmark-image-name'])) { if ($history[$i]['settings']['wordmark-image-name'] == self::WordmarkImageName) { $history[$i]['settings']['wordmark-image-name'] = $oldFile['name']; $history[$i]['settings']['wordmark-image-url'] = $oldFile['url']; } } if (isset($oldBackgroundFile) && isset($history[$i]['settings']['background-image-name'])) { if ($history[$i]['settings']['background-image-name'] == self::BackgroundImageName) { $history[$i]['settings']['background-image-name'] = $oldBackgroundFile['name']; } } } } WikiFactory::setVarByName(self::WikiFactoryHistory, $cityId, $history, $reason); }
/** * Generate triplets for FileRepo::storeBatch(). * @return array */ function getMoveTriplets() { $moves = array_merge(array($this->cur), $this->olds); $triplets = array(); // The format is: (srcUrl, destZone, destUrl) foreach ($moves as $move) { // $move: (oldRelativePath, newRelativePath) $srcUrl = $this->file->repo->getVirtualUrl() . '/public/' . rawurlencode($move[0]); $triplets[] = array($srcUrl, 'public', $move[1]); wfDebugLog('imagemove', "Generated move triplet for {$this->file->getName()}: {$srcUrl} :: public :: {$move[1]}"); } return $triplets; }
protected function getDeletedPath(LocalRepo $repo, LocalFile $file) { $hash = $repo->getFileSha1($file->getPath()); $key = "{$hash}.{$file->getExtension()}"; return $repo->getDeletedHashPath($key) . $key; }
/** * Get an array of arrays or iterators of file objects for files that * have the given SHA-1 content hashes. * * Overrides generic implementation in FileRepo for performance reason * * @param $hashes array An array of hashes * @return array An Array of arrays or iterators of file objects and the hash as key */ function findBySha1s(array $hashes) { if (!count($hashes)) { return array(); //empty parameter } $dbr = $this->getSlaveDB(); $res = $dbr->select('image', LocalFile::selectFields(), array('img_sha1' => $hashes), __METHOD__, array('ORDER BY' => 'img_name')); $result = array(); foreach ($res as $row) { $file = $this->newFileFromRow($row); $result[$file->getSha1()][] = $file; } $res->free(); return $result; }
/** * Return an array of files where the name starts with $prefix. * * @param string $prefix The prefix to search for * @param int $limit The maximum amount of files to return * @return array */ public function findFilesByPrefix($prefix, $limit) { $selectOptions = array('ORDER BY' => 'img_name', 'LIMIT' => intval($limit)); // Query database $dbr = $this->getSlaveDB(); $res = $dbr->select('image', LocalFile::selectFields(), 'img_name ' . $dbr->buildLike($prefix, $dbr->anyString()), __METHOD__, $selectOptions); // Build file objects $files = array(); foreach ($res as $row) { $files[] = $this->newFileFromRow($row); } return $files; }
public function testMoveTo() { //existing file $this->assertTrue(is_file(TESTS_FSI_LOCALFILE_TMP_PATH . '/myFile.ext')); $this->assertFalse(is_file(TESTS_FSI_LOCALFILE_TMP_PATH . '/myDir/myFile.ext')); $originalContent = file_get_contents(TESTS_FSI_LOCALFILE_TMP_PATH . '/myFile.ext'); $this->assertTrue($this->fixture_file->moveTo($this->fixture_dir)); $this->assertFalse(is_file(TESTS_FSI_LOCALFILE_TMP_PATH . '/myFile.ext')); $this->assertTrue(is_file(TESTS_FSI_LOCALFILE_TMP_PATH . '/myDir/myFile.ext')); $this->assertEquals($originalContent, file_get_contents(TESTS_FSI_LOCALFILE_TMP_PATH . '/myDir/myFile.ext')); unlink(TESTS_FSI_LOCALFILE_TMP_PATH . '/myDir/myFile.ext'); //non-existing file $this->assertFalse(is_file(TESTS_FSI_LOCALFILE_TMP_PATH . '/myFile.ext')); try { $this->fixture_file->moveTo($this->fixture_dir); $fail->fail(); } catch (EyeFileNotFoundException $e) { // normal situation } //existing directory containing files mkdir(TESTS_FSI_LOCALFILE_TMP_PATH . '/dir1'); $dir = new LocalFile(TESTS_FSI_LOCALFILE_TMP_PATH . '/dir1'); $originalContent = '## test - content ##'; file_put_contents(TESTS_FSI_LOCALFILE_TMP_PATH . '/dir1/mySubFile.ext', $originalContent); $this->assertTrue(is_dir(TESTS_FSI_LOCALFILE_TMP_PATH . '/dir1')); $this->assertTrue(is_file(TESTS_FSI_LOCALFILE_TMP_PATH . '/dir1/mySubFile.ext')); $this->assertTrue($dir->moveTo($this->fixture_dir)); $this->assertFalse(is_dir(TESTS_FSI_LOCALFILE_TMP_PATH . '/dir1')); $this->assertTrue(is_dir(TESTS_FSI_LOCALFILE_TMP_PATH . '/myDir/dir1')); $this->assertTrue(is_file(TESTS_FSI_LOCALFILE_TMP_PATH . '/myDir/dir1/mySubFile.ext')); $this->assertEquals($originalContent, file_get_contents(TESTS_FSI_LOCALFILE_TMP_PATH . '/myDir/dir1/mySubFile.ext')); unlink(TESTS_FSI_LOCALFILE_TMP_PATH . '/myDir/dir1/mySubFile.ext'); rmdir(TESTS_FSI_LOCALFILE_TMP_PATH . '/myDir/dir1'); }
function getCacheFields($prefix = 'img_') { $fields = parent::getCacheFields($prefix); $fields[] = $prefix . 'archive_name'; $fields[] = $prefix . 'deleted'; return $fields; }
/** * @param $resultPageSet ApiPageSet * @return void */ private function run($resultPageSet = null) { $repo = $this->mRepo; if (!$repo instanceof LocalRepo) { $this->dieUsage('Local file repository does not support querying all images', 'unsupportedrepo'); } $db = $this->getDB(); $params = $this->extractRequestParams(); 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("img_name {$op}= {$cont_from}"); } // Image filters $dir = $params['dir'] == 'descending' ? 'older' : 'newer'; $from = is_null($params['from']) ? null : $this->titlePartToKey($params['from']); $to = is_null($params['to']) ? null : $this->titlePartToKey($params['to']); $this->addWhereRange('img_name', $dir, $from, $to); if (isset($params['prefix'])) { $this->addWhere('img_name' . $db->buildLike($this->titlePartToKey($params['prefix']), $db->anyString())); } if (isset($params['minsize'])) { $this->addWhere('img_size>=' . intval($params['minsize'])); } if (isset($params['maxsize'])) { $this->addWhere('img_size<=' . intval($params['maxsize'])); } $sha1 = false; if (isset($params['sha1'])) { if (!$this->validateSha1Hash($params['sha1'])) { $this->dieUsage('The SHA1 hash provided is not valid', 'invalidsha1hash'); } $sha1 = wfBaseConvert($params['sha1'], 16, 36, 31); } elseif (isset($params['sha1base36'])) { $sha1 = $params['sha1base36']; if (!$this->validateSha1Base36Hash($sha1)) { $this->dieUsage('The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash'); } } if ($sha1) { $this->addWhereFld('img_sha1', $sha1); } if (!is_null($params['mime'])) { global $wgMiserMode; if ($wgMiserMode) { $this->dieUsage('MIME search disabled in Miser Mode', 'mimesearchdisabled'); } list($major, $minor) = File::splitMime($params['mime']); $this->addWhereFld('img_major_mime', $major); $this->addWhereFld('img_minor_mime', $minor); } $this->addTables('image'); $prop = array_flip($params['prop']); $this->addFields(LocalFile::selectFields()); $limit = $params['limit']; $this->addOption('LIMIT', $limit + 1); $sort = $params['dir'] == 'descending' ? ' DESC' : ''; $this->addOption('ORDER BY', 'img_name' . $sort); $res = $this->select(__METHOD__); $titles = array(); $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->img_name); break; } if (is_null($resultPageSet)) { $file = $repo->newFileFromRow($row); $info = array_merge(array('name' => $row->img_name), ApiQueryImageInfo::getInfo($file, $prop, $result)); self::addTitleInfo($info, $file->getTitle()); $fit = $result->addValue(array('query', $this->getModuleName()), null, $info); if (!$fit) { $this->setContinueEnumParameter('continue', $row->img_name); break; } } else { $titles[] = Title::makeTitle(NS_FILE, $row->img_name); } } if (is_null($resultPageSet)) { $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'img'); } else { $resultPageSet->populateFromTitles($titles); } }
protected function insertImage($name, $mwname, $result) { global $wgRequest, $wgImageMagickConvertCommand, $wgServer; if (!$result) { $result = array(); } elseif ($result['error']) { return $result; } $fromPage = $wgRequest->getVal('viapage'); if (!empty($mwname) && !empty($name)) { $name = trim(urldecode($name)); $dateTime = new DateTime(); $mwDate = wfTimestamp(TS_MW); // Mediawiki timestamp: 'YmdHis' list($first, $ext) = self::splitFilenameExt($name); $ext = strtolower($ext); $validExts = array('GIF', 'JPG', 'JPEG', 'PNG'); if (!in_array(strtoupper($ext), $validExts)) { $result['error'] = 'Error: Invalid file extension ' . strtoupper($ext) . '. Valid extensions are:'; foreach ($validExts as $validExt) { $result['error'] .= ' ' . strtoupper($validExt); } $result['error'] .= '.'; return $result; } $saveName = false; $titleExists = false; $suffixNum = 1; while (!$saveName || $titleExists) { $saveName = 'User Completed Image ' . $fromPage . ' ' . $dateTime->format('Y.m.d H.i.s') . ' ' . $suffixNum . '.' . $ext; $title = Title::makeTitleSafe(NS_IMAGE, $saveName); $newFile = true; $titleExists = $title->exists(); $suffixNum++; } $temp_file = new TempLocalImageFile(Title::newFromText($mwname, NS_IMAGE), RepoGroup::singleton()->getLocalRepo()); if (!$temp_file || !$temp_file->exists()) { $result['error'] = 'Error: A server error has occurred. Please try again.'; return $result; } // Image orientation is a bit wonky on some mobile devices; use ImageMagick's auto-orient to try fixing it. $tempFilePath = $temp_file->getPath(); $cmd = $wgImageMagickConvertCommand . ' ' . $tempFilePath . ' -auto-orient ' . $tempFilePath; exec($cmd); // Use a CC license $comment = '{{Self}}'; $file = new LocalFile($title, RepoGroup::singleton()->getLocalRepo()); $file->upload($tempFilePath, $comment, $comment); if (!$file || !$file->exists()) { $result['error'] = 'Error: A server error has occurred. Please try again.'; return $result; } $temp_file->delete(''); $fileTitle = $file->getTitle(); $fileURL = $file->url; $thumbURL = ''; $thumb = $file->getThumbnail(200, -1, true, true); if (!$thumb) { $result['error'] = 'Error: A server error has occurred. Please try again.'; $file->delete(''); return $result; } $thumbURL = $thumb->url; $result['titleText'] = $fileTitle->getText(); $result['titleDBkey'] = substr($fileTitle->getDBkey(), 21); // Only keep important info $result['titlePreText'] = '/' . $fileTitle->getPrefixedText(); $result['titleArtID'] = $fileTitle->getArticleID(); $result['timestamp'] = $mwDate; $result['fromPage'] = $wgRequest->getVal('viapage'); $result['thumbURL'] = $thumbURL; $result['fileURL'] = $wgServer . $fileURL; } return $result; }
function __construct($title) { wfDeprecated(__METHOD__); $repo = RepoGroup::singleton()->getLocalRepo(); parent::__construct($title, $repo); }
function execute($par) { global $wgOut, $wgUser, $wgRequest; global $wgUseAjax, $wgAjaxUploadDestCheck, $wgAjaxLicensePreview; if ($wgUser->isBlocked()) { $wgOut->blockedPage(); return; } if ($wgUser->getID() == 0) { $wgOut->setRobotpolicy('noindex,nofollow'); $wgOut->showErrorPage('nosuchspecialpage', 'nospecialpagetext'); return; } if (!in_array('staff', $wgUser->getGroups())) { $wgOut->setRobotpolicy('noindex,nofollow'); $wgOut->showErrorPage('nosuchspecialpage', 'nospecialpagetext'); return; } $this->errorFile = ""; $this->errorTitle = ""; if ($wgRequest->getVal('delete')) { $wgOut->setArticleBodyOnly(true); $hpid = str_replace('delete_', '', $wgRequest->getVal('delete')); $html = self::deleteHPImage($hpid); $wgOut->addHTML($html); return; } $this->postSuccessful = true; if ($wgRequest->wasPosted()) { if ($wgRequest->getVal("updateActive")) { $dbw = wfGetDB(DB_MASTER); //first clear them all $dbw->update(WikihowHomepageAdmin::HP_TABLE, array('hp_active' => 0, 'hp_order' => 0), '*', __METHOD__); $images = $wgRequest->getArray("hp_images"); $count = 1; foreach ($images as $image) { if (!$image) { continue; } $dbw->update(WikihowHomepageAdmin::HP_TABLE, array('hp_active' => 1, 'hp_order' => $count), array('hp_id' => $image)); $count++; } } else { $title = WikiPhoto::getArticleTitleNoCheck($wgRequest->getVal('articleName')); if (!$title->exists()) { $this->postSuccessful = false; $this->errorTitle = "* That article does not exist."; } if ($this->postSuccessful) { //keep going $imageTitle = Title::newFromText($wgRequest->getVal('wpDestFile'), NS_IMAGE); $file = new LocalFile($imageTitle, RepoGroup::singleton()->getLocalRepo()); $file->upload($wgRequest->getFileTempName('wpUploadFile'), '', ''); $filesize = $file->getSize(); if ($filesize > 0) { $dbw = wfGetDB(DB_MASTER); $dbw->insert(WikihowHomepageAdmin::HP_TABLE, array('hp_page' => $title->getArticleID(), 'hp_image' => $imageTitle->getArticleID())); $article = new Article($imageTitle); $limit = array(); $limit['move'] = "sysop"; $limit['edit'] = "sysop"; $protectResult = $article->updateRestrictions($limit, "Used on homepage"); } else { $this->postSuccessful = false; $this->errorFile = "* We encountered an error uploading that file."; } } } } $useAjaxDestCheck = $wgUseAjax && $wgAjaxUploadDestCheck; $useAjaxLicensePreview = $wgUseAjax && $wgAjaxLicensePreview; $adc = wfBoolToStr($useAjaxDestCheck); $alp = wfBoolToStr($useAjaxLicensePreview); $wgOut->setPageTitle('WikiHow Homepage Admin'); $wgOut->addScript("<script type=\"text/javascript\">\nwgAjaxUploadDestCheck = {$adc};\nwgAjaxLicensePreview = {$alp};\n</script>"); $wgOut->addScript(HtmlSnips::makeUrlTags('js', array('jquery-ui-1.8.custom.min.js'), 'extensions/wikihow/common/ui/js', false)); $wgOut->addScript(HtmlSnips::makeUrlTags('js', array('wikihowhomepageadmin.js'), 'extensions/wikihow/homepage', false)); $wgOut->addScript(HtmlSnips::makeUrlTags('css', array('wikihowhomepageadmin.css'), 'extensions/wikihow/homepage', false)); $wgOut->addScript(HtmlSnips::makeUrlTags('js', array('upload.js'), 'skins/common', false)); $this->displayHomepageData(); $this->displayForm(); }
/** * Add a new image file into the mediawiki infrastructure so that it can * be accessed as [[Image:filename.jpg]] */ private static function addMediawikiImage($articleID, &$image) { // Download the preview image and set the filename to the temporarary location $err = self::downloadImagePreview($image); if ($err) { return $err; } // check if we've already uploaded this image $dupTitle = DupImage::checkDupImage($image['filename']); // if we've already uploaded this image, just return that filename if ($dupTitle) { //$image['dupTitle'] = true; $image['mediawikiName'] = $dupTitle; return ''; } // find name for image; change filename to Filename 1.jpg if // Filename.jpg already existed $regexp = '/[^' . Title::legalChars() . ']+/'; $first = preg_replace($regexp, '', $image['first']); $ext = $image['ext']; $newName = $first . '-preview.' . $ext; $i = 1; do { $title = Title::newFromText($newName, NS_IMAGE); if ($title && !$title->exists()) { break; } $newName = $first . '-preview Version ' . ++$i . '.' . $ext; } while ($i <= 1000); // insert image into wikihow mediawiki repos $comment = '{{' . self::PHOTO_LICENSE . '}}'; // next 6 lines taken and modified from // extensions/wikihow/eiu/Easyimageupload.body.php $title = Title::makeTitleSafe(NS_IMAGE, $newName); if (!$title) { return "Couln't Make a title"; } $file = new LocalFile($title, RepoGroup::singleton()->getLocalRepo()); if (!$file) { return "Couldn't make a local file"; } $ret = $file->upload($image['filename'], $comment, $comment); if (!$ret->ok) { return "Couldn't upload file " . $image['filename']; } // instruct later processing about which mediawiki name was used $image['mediawikiName'] = $newName; // Add our uploaded image to the dup table so it's no uploaded again DupImage::addDupImage($image['filename'], $image['mediawikiName']); return ''; }
public static function copyFile($params) { $apiManager = new ApiManager(); $user = ProcManager::getInstance()->getCurrentProcess()->getLoginContext()->getEyeosUser(); $cloudspace = false; $cloudOrig = isset($params['cloud']['origin']) && strlen($params['cloud']['origin']) > 0 ? $params['cloud']['origin'] : null; $cloudDestination = isset($params['cloud']['destination']) && strlen($params['cloud']['destination']) > 0 ? $params['cloud']['destination'] : null; $pathCloud = "home://~" . $user->getName() . "/Cloudspaces/"; $pathOrig = null; if ($cloudOrig) { if ($pathCloud . $cloudOrig == $params['orig']) { $pathOrig = "/"; } else { $pathOrig = substr($params['orig'], strlen($pathCloud . $cloudOrig)) . "/"; } } if ($cloudDestination) { $cloudspace = true; } $file = null; $isFolder = true; $tmpFile = null; $filename = null; $pathinfo = null; $pathAbsolute = null; if (!$params['file']['is_folder']) { $isFolder = false; $tmpFile = new LocalFile('/var/tmp/' . date('Y_m_d_H_i_s') . '_' . $user->getId()); $pathAbsolute = AdvancedPathLib::getPhpLocalHackPath($tmpFile->getAbsolutePath()); if (array_key_exists('id', $params['file'])) { $token = $_SESSION['access_token_' . $cloudOrig . '_v2']; $resourceUrl = null; if (isset($params['file']['resource_url'])) { $token = new stdClass(); $token->key = $params['access_token_key']; $token->secret = $params['access_token_secret']; $resourceUrl = $params['resource_url']; } $metadata = $apiManager->downloadMetadata($token, $params['file']['id'], $pathAbsolute, $user->getId(), true, $cloudOrig, $resourceUrl); if ($metadata['status'] == 'KO') { if ($metadata['error'] == 403) { $denied = self::permissionDeniedCloud($cloudOrig); $metadata['path'] = $denied['path']; } return $metadata; } else { if (isset($metadata['local'])) { $file = FSI::getFile($params['file']['pathEyeos']); $tmpFile->putContents($file->getContents()); } } } else { $file = FSI::getFile($params['file']['path']); $tmpFile->putContents($file->getContents()); } } if ($pathOrig) { if ($params['file']['path'] == $pathOrig) { $pathinfo = pathinfo($params['file']['filename']); } } else { if ($params['file']['parent'] == null) { $pathinfo = pathinfo($params['file']['filename']); } } if ($pathinfo) { $nameForCheck = $pathinfo['filename']; $extension = null; if (isset($pathinfo['extension'])) { $extension = $pathinfo['extension']; $nameForCheck .= '.' . $extension; } $number = 1; $newFile = FSI::getFile($params['dest'] . "/" . $nameForCheck); while ($newFile->exists()) { $futureName = array($pathinfo['filename'], $number); $nameForCheck = implode(' ', $futureName); if ($extension) { $nameForCheck .= '.' . $extension; } $number++; $newFile = FSI::getFile($params['dest'] . "/" . $nameForCheck); $params['filenameChange'] = $nameForCheck; if (!array_key_exists('parent', $params['file'])) { $params['pathChange'] = substr($params['orig'], strlen($pathCloud . $cloudOrig)); } } $filename = $newFile->getName(); } else { $filename = $params['file']['filename']; } if ($cloudspace) { $pathParent = substr($params['dest'], strlen($pathCloud . $cloudDestination)); if (array_key_exists('parent', $params['file'])) { if (strlen($pathParent) == 0 && !$params['file']['parent']) { $pathParent = '/'; } if ($params['file']['parent']) { $pathParent .= $params['file']['parent']; } } else { $pathParent .= '/' . substr($params['file']['path'], strlen($pathOrig)); if (strlen($pathParent) > 1) { $pathParent = substr($pathParent, 0, -1); } } $folder = NULL; if ($pathParent !== '/') { $pos = strrpos($pathParent, '/'); $folder = substr($pathParent, $pos + 1); $pathParent = substr($pathParent, 0, $pos + 1); } $parentId = false; if ($folder) { $path = $pathParent . $folder . '/'; $lista = new stdClass(); $lista->cloud = $cloudDestination; $lista->path = $pathParent; $lista->filename = $folder; $lista->user_eyeos = $user->getId(); $u1db = json_decode($apiManager->callProcessU1db('parent', $lista)); if ($u1db !== NULL && count($u1db) > 0) { $parentId = $u1db[0]->id; if ($parentId === 'null') { $parentId = '0'; } } } else { $parentId = '0'; $path = $pathParent; } if ($parentId !== false) { $token = $_SESSION['access_token_' . $cloudDestination . '_v2']; $resourceUrl = null; if (isset($params['resource_url'])) { $token = new stdClass(); $token->key = $params['access_token_key']; $token->secret = $params['access_token_secret']; $resourceUrl = $params['resource_url']; } $metadata = $apiManager->createMetadata($cloudDestination, $token, $user->getId(), !$isFolder, $filename, $parentId, $path, $pathAbsolute, $resourceUrl); if ($metadata['status'] == 'KO') { if ($metadata['error'] == 403) { $denied = self::permissionDeniedCloud($cloudDestination); $metadata['path'] = $denied['path']; } return $metadata; } } } $pathDest = null; if (array_key_exists('parent', $params['file'])) { if ($params['file']['parent']) { $pathDest = $params['dest'] . $params['file']['parent'] . '/'; } else { $pathDest = $params['dest'] . '/'; } } else { if ($pathOrig == $params['file']['path']) { $pathDest = $params['dest'] . '/'; } else { $pathDest = $params['dest'] . '/' . substr($params['file']['path'], strlen($pathOrig)); } } $pathDest .= $filename; $newFile = FSI::getFile($pathDest); if ($isFolder) { $newFile->mkdir(); } else { $tmpFile->copyTo($newFile); } if ($tmpFile) { $tmpFile->delete(); } return $params; }
/** * @param ApiPageSet $resultPageSet * @return void */ private function run($resultPageSet = null) { $repo = $this->mRepo; if (!$repo instanceof LocalRepo) { $this->dieUsage('Local file repository does not support querying all images', 'unsupportedrepo'); } $prefix = $this->getModulePrefix(); $db = $this->getDB(); $params = $this->extractRequestParams(); // Table and return fields $this->addTables('image'); $prop = array_flip($params['prop']); $this->addFields(LocalFile::selectFields()); $ascendingOrder = true; if ($params['dir'] == 'descending' || $params['dir'] == 'older') { $ascendingOrder = false; } if ($params['sort'] == 'name') { // Check mutually exclusive params $disallowed = ['start', 'end', 'user']; foreach ($disallowed as $pname) { if (isset($params[$pname])) { $this->dieUsage("Parameter '{$prefix}{$pname}' can only be used with {$prefix}sort=timestamp", 'badparams'); } } if ($params['filterbots'] != 'all') { $this->dieUsage("Parameter '{$prefix}filterbots' can only be used with {$prefix}sort=timestamp", 'badparams'); } // Pagination if (!is_null($params['continue'])) { $cont = explode('|', $params['continue']); $this->dieContinueUsageIf(count($cont) != 1); $op = $ascendingOrder ? '>' : '<'; $continueFrom = $db->addQuotes($cont[0]); $this->addWhere("img_name {$op}= {$continueFrom}"); } // Image filters $from = $params['from'] === null ? null : $this->titlePartToKey($params['from'], NS_FILE); $to = $params['to'] === null ? null : $this->titlePartToKey($params['to'], NS_FILE); $this->addWhereRange('img_name', $ascendingOrder ? 'newer' : 'older', $from, $to); if (isset($params['prefix'])) { $this->addWhere('img_name' . $db->buildLike($this->titlePartToKey($params['prefix'], NS_FILE), $db->anyString())); } } else { // Check mutually exclusive params $disallowed = ['from', 'to', 'prefix']; foreach ($disallowed as $pname) { if (isset($params[$pname])) { $this->dieUsage("Parameter '{$prefix}{$pname}' can only be used with {$prefix}sort=name", 'badparams'); } } if (!is_null($params['user']) && $params['filterbots'] != 'all') { // Since filterbots checks if each user has the bot right, it // doesn't make sense to use it with user $this->dieUsage("Parameters '{$prefix}user' and '{$prefix}filterbots' cannot be used together", 'badparams'); } // Pagination $this->addTimestampWhereRange('img_timestamp', $ascendingOrder ? 'newer' : 'older', $params['start'], $params['end']); // Include in ORDER BY for uniqueness $this->addWhereRange('img_name', $ascendingOrder ? 'newer' : 'older', null, null); if (!is_null($params['continue'])) { $cont = explode('|', $params['continue']); $this->dieContinueUsageIf(count($cont) != 2); $op = $ascendingOrder ? '>' : '<'; $continueTimestamp = $db->addQuotes($db->timestamp($cont[0])); $continueName = $db->addQuotes($cont[1]); $this->addWhere("img_timestamp {$op} {$continueTimestamp} OR " . "(img_timestamp = {$continueTimestamp} AND " . "img_name {$op}= {$continueName})"); } // Image filters if (!is_null($params['user'])) { $this->addWhereFld('img_user_text', $params['user']); } if ($params['filterbots'] != 'all') { $this->addTables('user_groups'); $this->addJoinConds(['user_groups' => ['LEFT JOIN', ['ug_group' => User::getGroupsWithPermission('bot'), 'ug_user = img_user']]]); $groupCond = $params['filterbots'] == 'nobots' ? 'NULL' : 'NOT NULL'; $this->addWhere("ug_group IS {$groupCond}"); } } // Filters not depending on sort if (isset($params['minsize'])) { $this->addWhere('img_size>=' . intval($params['minsize'])); } if (isset($params['maxsize'])) { $this->addWhere('img_size<=' . intval($params['maxsize'])); } $sha1 = false; if (isset($params['sha1'])) { $sha1 = strtolower($params['sha1']); if (!$this->validateSha1Hash($sha1)) { $this->dieUsage('The SHA1 hash provided is not valid', 'invalidsha1hash'); } $sha1 = Wikimedia\base_convert($sha1, 16, 36, 31); } elseif (isset($params['sha1base36'])) { $sha1 = strtolower($params['sha1base36']); if (!$this->validateSha1Base36Hash($sha1)) { $this->dieUsage('The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash'); } } if ($sha1) { $this->addWhereFld('img_sha1', $sha1); } if (!is_null($params['mime'])) { if ($this->getConfig()->get('MiserMode')) { $this->dieUsage('MIME search disabled in Miser Mode', 'mimesearchdisabled'); } $mimeConds = []; foreach ($params['mime'] as $mime) { list($major, $minor) = File::splitMime($mime); $mimeConds[] = $db->makeList(['img_major_mime' => $major, 'img_minor_mime' => $minor], LIST_AND); } // safeguard against internal_api_error_DBQueryError if (count($mimeConds) > 0) { $this->addWhere($db->makeList($mimeConds, LIST_OR)); } else { // no MIME types, no files $this->getResult()->addValue('query', $this->getModuleName(), []); return; } } $limit = $params['limit']; $this->addOption('LIMIT', $limit + 1); $sortFlag = ''; if (!$ascendingOrder) { $sortFlag = ' DESC'; } if ($params['sort'] == 'timestamp') { $this->addOption('ORDER BY', 'img_timestamp' . $sortFlag); if (!is_null($params['user'])) { $this->addOption('USE INDEX', ['image' => 'img_usertext_timestamp']); } else { $this->addOption('USE INDEX', ['image' => 'img_timestamp']); } } else { $this->addOption('ORDER BY', 'img_name' . $sortFlag); } $res = $this->select(__METHOD__); $titles = []; $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... if ($params['sort'] == 'name') { $this->setContinueEnumParameter('continue', $row->img_name); } else { $this->setContinueEnumParameter('continue', "{$row->img_timestamp}|{$row->img_name}"); } break; } if (is_null($resultPageSet)) { $file = $repo->newFileFromRow($row); $info = array_merge(['name' => $row->img_name], ApiQueryImageInfo::getInfo($file, $prop, $result)); self::addTitleInfo($info, $file->getTitle()); $fit = $result->addValue(['query', $this->getModuleName()], null, $info); if (!$fit) { if ($params['sort'] == 'name') { $this->setContinueEnumParameter('continue', $row->img_name); } else { $this->setContinueEnumParameter('continue', "{$row->img_timestamp}|{$row->img_name}"); } break; } } else { $titles[] = Title::makeTitle(NS_FILE, $row->img_name); } } if (is_null($resultPageSet)) { $result->addIndexedTagName(['query', $this->getModuleName()], 'img'); } else { $resultPageSet->populateFromTitles($titles); } }
public static function submitFile($path) { try { if (!isset($_FILES['Filedata'])) { echo '<div style="font-size:20px;font-family:Helvetica, Arial, Verdana, Sans, FreeSans;margin-top:80px;margin-right:15px;"><center> <img style="position:relative;top:15px"src="index.php?extern=/images/48x48/actions/dialog-close.png" />Error uploading files</center>'; exit; } $Logger = Logger::getLogger('application.upload'); foreach ($_FILES['Filedata']['name'] as $k => $v) { if (!empty($v)) { $filename = $_FILES['Filedata']['name'][$k]; if (!isset($_POST['UPLOAD_IDENTIFIER'])) { $filename = utf8_encode($filename); } $tmpPath = $_FILES['Filedata']['tmp_name'][$k]; $Logger->debug("Filename: " . $filename); if (!is_uploaded_file($tmpPath)) { throw new EyeFileNotFoundException('Uploaded file not found at "' . $tmpPath . '".'); } $request = MMapManager::getCurrentRequest(); $destPath = $path; $filename = str_replace('?', '_', $filename); $filename = str_replace('#', '_', $filename); $tmp = pathinfo($filename); if (isset($tmp['extension']) && "lnk" == $tmp['extension']) { throw new EyeFileNotFoundException('This file cannot be uploaded (file type banned)'); } /* if ( '?' == $filename{0} ) { $filename{0} = "_"; } */ $destFile = FSI::getFile($destPath . '/' . $filename); //The uploaded file is necessarily on the local filesystem and we want to avoid any //permission check through EyeLocalFile, so we use LocalFile directly $tmpFile = new LocalFile($tmpPath); $num = 1; $extension = AdvancedPathLib::pathinfo($filename, PATHINFO_EXTENSION); $filename = AdvancedPathLib::pathinfo($filename, PATHINFO_FILENAME); $Logger->debug("CLASS: " . get_class($destFile)); $Logger->debug("Exists: " . $destFile->exists()); //exit(); while ($destFile->exists()) { $newBasename = $filename . ' (' . $num++ . ')' . ($extension ? '.' . $extension : ''); $destFile = FSI::getFile($destPath . '/' . $newBasename); } $destFile->checkWritePermission(); $tmpFile->moveTo($destFile); $currentUser = ProcManager::getInstance()->getCurrentProcess()->getLoginContext()->getEyeosUser(); $settings = MetaManager::getInstance()->retrieveMeta($currentUser); $message = new ClientBusMessage('file', 'uploadComplete', self::getFileInfo($destFile, $settings)); ClientMessageBusController::getInstance()->queueMessage($message); $event = new FileEvent($destFile); $destFile->fireEvent('fileWritten', $event); } } register_shutdown_function('endRequestUpload'); } catch (EyeException $e) { echo '<div style="font-size:20px;font-family:Helvetica, Arial, Verdana, Sans, FreeSans;margin-top:80px;margin-right:15px;"><center> <img style="position:relative;top:15px"src="index.php?extern=/images/48x48/actions/dialog-close.png" />Error uploading files: ' . $e->getMessage() . '</center>'; exit; } }
private function run($resultPageSet = null) { $repo = RepoGroup::singleton()->getLocalRepo(); if (!$repo instanceof LocalRepo) { $this->dieUsage('Local file repository does not support querying all images', 'unsupportedrepo'); } $db = $this->getDB(); $params = $this->extractRequestParams(); // Image filters $dir = $params['dir'] == 'descending' ? 'older' : 'newer'; $from = is_null($params['from']) ? null : $this->titlePartToKey($params['from']); $this->addWhereRange('img_name', $dir, $from, null); if (isset($params['prefix'])) { $this->addWhere("img_name LIKE '" . $db->escapeLike($this->titlePartToKey($params['prefix'])) . "%'"); } if (isset($params['minsize'])) { $this->addWhere('img_size>=' . intval($params['minsize'])); } if (isset($params['maxsize'])) { $this->addWhere('img_size<=' . intval($params['maxsize'])); } $sha1 = false; if (isset($params['sha1'])) { $sha1 = wfBaseConvert($params['sha1'], 16, 36, 31); } elseif (isset($params['sha1base36'])) { $sha1 = $params['sha1base36']; } if ($sha1) { $this->addWhere('img_sha1=' . $db->addQuotes($sha1)); } $this->addTables('image'); $prop = array_flip($params['prop']); $this->addFields(LocalFile::selectFields()); $limit = $params['limit']; $this->addOption('LIMIT', $limit + 1); $this->addOption('ORDER BY', 'img_name' . ($params['dir'] == 'descending' ? ' DESC' : '')); $res = $this->select(__METHOD__); $titles = array(); $count = 0; $result = $this->getResult(); while ($row = $db->fetchObject($res)) { if (++$count > $limit) { // We've reached the one extra which shows that there are additional pages to be had. Stop here... // TODO: Security issue - if the user has no right to view next title, it will still be shown $this->setContinueEnumParameter('from', $this->keyToTitle($row->img_name)); break; } if (is_null($resultPageSet)) { $file = $repo->newFileFromRow($row); $info = array_merge(array('name' => $row->img_name), ApiQueryImageInfo::getInfo($file, $prop, $result)); $fit = $result->addValue(array('query', $this->getModuleName()), null, $info); if (!$fit) { $this->setContinueEnumParameter('from', $this->keyToTitle($row->img_name)); break; } } else { $titles[] = Title::makeTitle(NS_IMAGE, $row->img_name); } } $db->freeResult($res); if (is_null($resultPageSet)) { $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'img'); } else { $resultPageSet->populateFromTitles($titles); } }
/** * 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() */ 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 IN (' . $dbw->makeList($this->ids) . ')'; } $result = $dbw->select('filearchive', '*', $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; $sha1 = substr($row->fa_storage_key, 0, strcspn($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) { $storeBatch[] = array($deletedUrl, 'public', $destRel); $this->cleanupBatch[] = $row->fa_storage_key; } } 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 IN (' . $dbw->makeList($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"); // Update site_stats $site_stats = $dbw->tableName('site_stats'); $dbw->query("UPDATE {$site_stats} SET ss_images=ss_images+1", __METHOD__); $this->file->purgeEverything(); } else { wfDebug(__METHOD__ . " restored {$status->successCount} as archived versions\n"); $this->file->purgeDescription(); $this->file->purgeHistory(); } } $this->file->unlock(); return $status; }
/** * Get an array or iterator of file objects for files that have a given * SHA-1 content hash. */ function findBySha1($hash) { $dbr = $this->getSlaveDB(); $res = $dbr->select('image', LocalFile::selectFields(), array('img_sha1' => $hash)); $result = array(); while ($row = $res->fetchObject()) { $result[] = $this->newFileFromRow($row); } $res->free(); return $result; }
/** * Insert an image upload into the mediawiki database tables. If the * image insert was successful, a page showing the wiki text for their * image is shown. Otherwise, if the image file name already exists in * the database, a conflict page is returned to the user. * * @param $type string with either 'overwrite' or blank -- specifies * whether to force-overwrite an existing image * @param $name filename chosen by user for uploaded image * @param $mwname filename of the file in mediawiki DB * @param $fromIIA true iff source of call is Special:IntroImageAdder * @param $image_comment a comment attached to the image upload (only * used if $fromIIA == true) * @return outputs either a wikitext results page (if image filename * didn't exist or force overwrite was selected) or a conflict page. * Returns an error string or empty string if no error. */ private function insertImage($type, $name, $mwname, $fromIIA = false, $image_comment = '') { global $wgRequest, $wgUser, $wgOut, $wgFileExtensions; if (!$fromIIA) { $license = $wgRequest->getVal('wpLicense', ''); if (!empty($license)) { $attrib = $wgRequest->getVal('attribution'); $comment = '{{' . $license . (!empty($attrib) ? '|' . $attrib : '') . '}}'; if ($license != '') { $wgUser->setOption('image_license', $license); $wgUser->saveSettings(); } } else { $comment = $wgRequest->getVal('ImageAttribution', ''); } } else { $comment = $image_comment; } if (wfReadOnly()) { return wfMsg('eiu-readonly'); } if (!empty($mwname) && !empty($name)) { $name = urldecode($name); $name = preg_replace('/[^' . Title::legalChars() . ']|[:\\/\\\\]|\\?/', '-', $name); $name = preg_replace('@&@', '&', $name); $name = trim($name); // did they give no extension at all when they changed the name? list($first, $ext) = self::splitFilenameExt($name); $ext = strtolower($ext); $title = Title::makeTitleSafe(NS_IMAGE, $name); if (is_null($title) || !in_array($ext, $wgFileExtensions)) { return wfMsg('eiu-filetype-incorrect'); } $newFile = true; $titleExists = $title->exists(); if (!$titleExists || $fromIIA) { // // DB entry for file doesn't exist. User renamed their // upload or it never existed. // if ($titleExists) { $suggestedName = self::generateNewFilename($name); $title = Title::makeTitleSafe(NS_IMAGE, $suggestedName); } // is the target protected? $permErrors = $title->getUserPermissionsErrors('edit', $wgUser); $permErrorsUpload = $title->getUserPermissionsErrors('upload', $wgUser); if ($permErrors || $permErrorsUpload) { return wfMsg('This image is protected'); } $temp_file = new LocalFile(Title::newFromText($mwname, NS_IMAGE), RepoGroup::singleton()->getLocalRepo()); $file = new LocalFile($title, RepoGroup::singleton()->getLocalRepo()); $file->upload($temp_file->getPath(), $comment, $comment); $temp_file->delete(''); } elseif ($type == 'overwrite') { // // DB entry exists and user selected to overwrite it // $title = Title::newFromText($name, NS_IMAGE); // is the target protected? $permErrors = $title->getUserPermissionsErrors('edit', $wgUser); $permErrorsUpload = $title->getUserPermissionsErrors('upload', $wgUser); $permErrorsCreate = $title->exists() ? array() : $title->getUserPermissionsErrors('create', $wgUser); if ($permErrors || $permErrorsUpload || $permErrorsCreate) { return wfMsg('This image is protected'); } $file_name = new LocalFile($title, RepoGroup::singleton()->getLocalRepo()); $file_mwname = new TempLocalFile(Title::newFromText($mwname, NS_IMAGE), RepoGroup::singleton()->getLocalRepo()); $file_name->upload($file_mwname->getPath(), $comment, $comment); $file_mwname->delete(''); $newFile = false; } elseif ($type == 'existing') { // // DB entry exists and user doesn't want to overwrite or // rename, so they use the existing file from the DB. // $title = Title::newFromText($name, NS_IMAGE); } else { // // There was a conflict with an existing file in the // DB. Title exists and overwrite action not taken yet. // $data = array('wpUpload' => 1, 'wpSourceType' => 'web', 'wpUploadFileURL' => ''); $form = new UploadForm(new FauxRequest($data, true)); // generate title if current one is taken $suggestedName = self::generateNewFilename($name); // extensions check list($first, $ext) = self::splitFilenameExt($suggestedName); $title = Title::newFromText($name, NS_IMAGE); $file = wfFindFile($title); $vars = array('suggestedFirstPart' => $first, 'extension' => strtolower($ext), 'name' => $name, 'mwname' => $mwname, 'file' => $file, 'image_comment' => $comment); $wgOut->setStatusCode(200); $wgOut->addHTML(EasyTemplate::html('eiu_conflict.tmpl.php', $vars)); // return no error return ''; } // add watch to file is user needs it if ($wgUser->getOption('watchdefault') || $newFile && $wgUser->getOption('watchcreations')) { $wgUser->addWatch($title); } $db =& wfGetDB(DB_MASTER); $db->commit(); } elseif (empty($mwname)) { $title = Title::makeTitleSafe(NS_IMAGE, $name); } elseif ($name !== null) { return WfMsg('eiu-warn3'); } else { // name === null $title = Title::newFromText($mwname, NS_IMAGE); } $file = wfFindFile($title); if (!is_object($file)) { return wfMsg('File not found'); } $details = self::splitValuePairs($wgRequest->getVal('image-details')); $tag = self::makeImageWikiTag($title, $file, $details); $vars = array('tag' => $tag, 'file' => $file, 'width' => $details['chosen-width'], 'height' => $details['chosen-height'], 'imageFilename' => $title->getText()); if (!$fromIIA) { $vars['details'] = $details; $html = EasyTemplate::html('eiu_upload_summary.tmpl.php', $vars); } else { $html = IntroImageAdder::addIntroImage($vars); } $wgOut->setStatusCode(200); $wgOut->addHTML($html); // return no error return ''; }