Beispiel #1
0
 public function __construct($path)
 {
     parent::__construct($path);
     if (self::$pathsCollect === null) {
         self::$pathsCollect = array();
         register_shutdown_function(array(__CLASS__, 'purgeAllOnShutdown'));
     }
 }
 protected function setUp()
 {
     parent::setUp();
     $filename = 'Foo.png';
     $this->tmpPrefix = $this->getNewTempDirectory();
     $backend = new FSFileBackend(['name' => 'local-migratefilerepolayouttest', 'wikiId' => wfWikiID(), 'containerPaths' => ['migratefilerepolayouttest-original' => "{$this->tmpPrefix}-original", 'migratefilerepolayouttest-public' => "{$this->tmpPrefix}-public", 'migratefilerepolayouttest-thumb' => "{$this->tmpPrefix}-thumb", 'migratefilerepolayouttest-temp' => "{$this->tmpPrefix}-temp", 'migratefilerepolayouttest-deleted' => "{$this->tmpPrefix}-deleted"]]);
     $dbMock = $this->getMockBuilder('DatabaseMysql')->disableOriginalConstructor()->getMock();
     $imageRow = new stdClass();
     $imageRow->img_name = $filename;
     $imageRow->img_sha1 = sha1($this->text);
     $dbMock->expects($this->any())->method('select')->will($this->onConsecutiveCalls(new FakeResultWrapper([$imageRow]), new FakeResultWrapper([]), new FakeResultWrapper([])));
     $repoMock = $this->getMock('LocalRepo', ['getMasterDB'], [['name' => 'migratefilerepolayouttest', 'backend' => $backend]]);
     $repoMock->expects($this->any())->method('getMasterDB')->will($this->returnValue($dbMock));
     $this->migratorMock = $this->getMock('MigrateFileRepoLayout', ['getRepo']);
     $this->migratorMock->expects($this->any())->method('getRepo')->will($this->returnValue($repoMock));
     $this->tmpFilepath = TempFSFile::factory('migratefilelayout-test-', 'png')->getPath();
     file_put_contents($this->tmpFilepath, $this->text);
     $hashPath = $repoMock->getHashPath($filename);
     $status = $repoMock->store($this->tmpFilepath, 'public', $hashPath . $filename, FileRepo::OVERWRITE);
 }
Beispiel #3
0
 /**
  * Append the final chunk and ready file for parent::performUpload()
  * @return FileRepoStatus
  */
 public function concatenateChunks()
 {
     $chunkIndex = $this->getChunkIndex();
     wfDebug(__METHOD__ . " concatenate {$this->mChunkIndex} chunks:" . $this->getOffset() . ' inx:' . $chunkIndex . "\n");
     // Concatenate all the chunks to mVirtualTempPath
     $fileList = [];
     // The first chunk is stored at the mVirtualTempPath path so we start on "chunk 1"
     for ($i = 0; $i <= $chunkIndex; $i++) {
         $fileList[] = $this->getVirtualChunkLocation($i);
     }
     // Get the file extension from the last chunk
     $ext = FileBackend::extensionFromPath($this->mVirtualTempPath);
     // Get a 0-byte temp file to perform the concatenation at
     $tmpFile = TempFSFile::factory('chunkedupload_', $ext, wfTempDir());
     $tmpPath = false;
     // fail in concatenate()
     if ($tmpFile) {
         // keep alive with $this
         $tmpPath = $tmpFile->bind($this)->getPath();
     }
     // Concatenate the chunks at the temp file
     $tStart = microtime(true);
     $status = $this->repo->concatenate($fileList, $tmpPath, FileRepo::DELETE_SOURCE);
     $tAmount = microtime(true) - $tStart;
     if (!$status->isOK()) {
         return $status;
     }
     wfDebugLog('fileconcatenate', "Combined {$i} chunks in {$tAmount} seconds.");
     // File system path of the actual full temp file
     $this->setTempFile($tmpPath);
     $ret = $this->verifyUpload();
     if ($ret['status'] !== UploadBase::OK) {
         wfDebugLog('fileconcatenate', "Verification failed for chunked upload");
         $status->fatal($this->getVerificationErrorCode($ret['status']));
         return $status;
     }
     // Update the mTempPath and mStashFile
     // (for FileUpload or normal Stash to take over)
     $tStart = microtime(true);
     // This is a re-implementation of UploadBase::tryStashFile(), we can't call it because we
     // override doStashFile() with completely different functionality in this class...
     $error = $this->runUploadStashFileHook($this->user);
     if ($error) {
         call_user_func_array([$status, 'fatal'], $error);
         return $status;
     }
     try {
         $this->mStashFile = parent::doStashFile($this->user);
     } catch (UploadStashException $e) {
         $status->fatal('uploadstash-exception', get_class($e), $e->getMessage());
         return $status;
     }
     $tAmount = microtime(true) - $tStart;
     $this->mStashFile->setLocalReference($tmpFile);
     // reuse (e.g. for getImageInfo())
     wfDebugLog('fileconcatenate', "Stashed combined file ({$i} chunks) in {$tAmount} seconds.");
     return $status;
 }
Beispiel #4
0
 /**
  * @see FileBackendStore::getLocalCopy()
  * @return null|TempFSFile
  */
 public function getLocalCopy(array $params)
 {
     list($srcCont, $srcRel) = $this->resolveStoragePathReal($params['src']);
     if ($srcRel === null) {
         return null;
     }
     // Blindly create a tmp file and stream to it, catching any exception if the file does
     // not exist. Also, doing a stat here will cause infinite loops when filling metadata.
     $tmpFile = null;
     try {
         $sContObj = $this->getContainer($srcCont);
         $obj = new CF_Object($sContObj, $srcRel, false, false);
         // skip HEAD
         // Get source file extension
         $ext = FileBackend::extensionFromPath($srcRel);
         // Create a new temporary file...
         $tmpFile = TempFSFile::factory('localcopy_', $ext);
         if ($tmpFile) {
             $handle = fopen($tmpFile->getPath(), 'wb');
             if ($handle) {
                 $obj->stream($handle, $this->headersFromParams($params));
                 fclose($handle);
             } else {
                 $tmpFile = null;
                 // couldn't open temp file
             }
         }
     } catch (NoSuchContainerException $e) {
         $tmpFile = null;
     } catch (NoSuchObjectException $e) {
         $tmpFile = null;
     } catch (CloudFilesException $e) {
         // some other exception?
         $tmpFile = null;
         $this->handleException($e, null, __METHOD__, $params);
     }
     return $tmpFile;
 }
Beispiel #5
0
 public function provider_testStore()
 {
     $cases = array();
     $tmpName = TempFSFile::factory("unittests_", 'txt')->getPath();
     $toPath = $this->baseStorePath() . '/unittest-cont1/fun/obj1.txt';
     $op = array('op' => 'store', 'src' => $tmpName, 'dst' => $toPath);
     $cases[] = array($op, $tmpName, $toPath);
     $op2 = $op;
     $op2['overwrite'] = true;
     $cases[] = array($op2, $tmpName, $toPath);
     $op2 = $op;
     $op2['overwriteSame'] = true;
     $cases[] = array($op2, $tmpName, $toPath);
     return $cases;
 }
	/**
	 * Get the target encode path for a video encode
	 *
	 * @param $file File
	 * @param $transcodeKey String
	 *
	 * @return the local target encode path
	 */
	static public function getTargetEncodePath( &$file, $transcodeKey ){
		$filePath = self::getDerivativeFilePath( $file, $transcodeKey );
		$ext = strtolower( pathinfo( "$filePath", PATHINFO_EXTENSION ) );

		// Create a temp FS file with the same extension
		$tmpFile = TempFSFile::factory( 'transcode_' . $transcodeKey, $ext);
		if ( !$tmpFile ) {
			return False;
		}
		$tmpFile->bind( $file );
		return $tmpFile->getPath(); //path with 0-byte temp file
	}
Beispiel #7
0
 public function execute()
 {
     $this->useTransactionalTimeLimit();
     $params = $this->extractRequestParams();
     $rotation = $params['rotation'];
     $continuationManager = new ApiContinuationManager($this, [], []);
     $this->setContinuationManager($continuationManager);
     $pageSet = $this->getPageSet();
     $pageSet->execute();
     $result = [];
     $result = $pageSet->getInvalidTitlesAndRevisions(['invalidTitles', 'special', 'missingIds', 'missingRevIds', 'interwikiTitles']);
     foreach ($pageSet->getTitles() as $title) {
         $r = [];
         $r['id'] = $title->getArticleID();
         ApiQueryBase::addTitleInfo($r, $title);
         if (!$title->exists()) {
             $r['missing'] = true;
             if ($title->isKnown()) {
                 $r['known'] = true;
             }
         }
         $file = wfFindFile($title, ['latest' => true]);
         if (!$file) {
             $r['result'] = 'Failure';
             $r['errormessage'] = 'File does not exist';
             $result[] = $r;
             continue;
         }
         $handler = $file->getHandler();
         if (!$handler || !$handler->canRotate()) {
             $r['result'] = 'Failure';
             $r['errormessage'] = 'File type cannot be rotated';
             $result[] = $r;
             continue;
         }
         // Check whether we're allowed to rotate this file
         $permError = $this->checkPermissions($this->getUser(), $file->getTitle());
         if ($permError !== null) {
             $r['result'] = 'Failure';
             $r['errormessage'] = $permError;
             $result[] = $r;
             continue;
         }
         $srcPath = $file->getLocalRefPath();
         if ($srcPath === false) {
             $r['result'] = 'Failure';
             $r['errormessage'] = 'Cannot get local file path';
             $result[] = $r;
             continue;
         }
         $ext = strtolower(pathinfo("{$srcPath}", PATHINFO_EXTENSION));
         $tmpFile = TempFSFile::factory('rotate_', $ext, wfTempDir());
         $dstPath = $tmpFile->getPath();
         $err = $handler->rotate($file, ['srcPath' => $srcPath, 'dstPath' => $dstPath, 'rotation' => $rotation]);
         if (!$err) {
             $comment = wfMessage('rotate-comment')->numParams($rotation)->inContentLanguage()->text();
             $status = $file->upload($dstPath, $comment, $comment, 0, false, false, $this->getUser());
             if ($status->isGood()) {
                 $r['result'] = 'Success';
             } else {
                 $r['result'] = 'Failure';
                 $r['errormessage'] = $this->getErrorFormatter()->arrayFromStatus($status);
             }
         } else {
             $r['result'] = 'Failure';
             $r['errormessage'] = $err->toText();
         }
         $result[] = $r;
     }
     $apiResult = $this->getResult();
     ApiResult::setIndexedTagName($result, 'page');
     $apiResult->addValue(null, $this->getModuleName(), $result);
     $this->setContinuationManager(null);
     $continuationManager->setContinuationIntoResult($apiResult);
 }
Beispiel #8
0
 /**
  * Transform a media file
  *
  * @param array $params an associative array of handler-specific parameters.
  *                Typical keys are width, height and page.
  * @param $flags Integer: a bitfield, may contain self::RENDER_NOW to force rendering
  * @return MediaTransformOutput|bool False on failure
  */
 function transform($params, $flags = 0)
 {
     global $wgUseSquid, $wgIgnoreImageErrors, $wgThumbnailEpoch;
     wfProfileIn(__METHOD__);
     do {
         if (!$this->canRender()) {
             $thumb = $this->iconThumb();
             break;
             // not a bitmap or renderable image, don't try
         }
         // Get the descriptionUrl to embed it as comment into the thumbnail. Bug 19791.
         $descriptionUrl = $this->getDescriptionUrl();
         if ($descriptionUrl) {
             $params['descriptionUrl'] = wfExpandUrl($descriptionUrl, PROTO_CANONICAL);
         }
         $handler = $this->getHandler();
         $script = $this->getTransformScript();
         if ($script && !($flags & self::RENDER_NOW)) {
             // Use a script to transform on client request, if possible
             $thumb = $handler->getScriptedTransform($this, $script, $params);
             if ($thumb) {
                 break;
             }
         }
         $normalisedParams = $params;
         $handler->normaliseParams($this, $normalisedParams);
         $thumbName = $this->thumbName($normalisedParams);
         $thumbUrl = $this->getThumbUrl($thumbName);
         $thumbPath = $this->getThumbPath($thumbName);
         // final thumb path
         if ($this->repo) {
             // Defer rendering if a 404 handler is set up...
             if ($this->repo->canTransformVia404() && !($flags & self::RENDER_NOW)) {
                 wfDebug(__METHOD__ . " transformation deferred.");
                 // XXX: Pass in the storage path even though we are not rendering anything
                 // and the path is supposed to be an FS path. This is due to getScalerType()
                 // getting called on the path and clobbering $thumb->getUrl() if it's false.
                 $thumb = $handler->getTransform($this, $thumbPath, $thumbUrl, $params);
                 break;
             }
             // Clean up broken thumbnails as needed
             $this->migrateThumbFile($thumbName);
             // Check if an up-to-date thumbnail already exists...
             wfDebug(__METHOD__ . ": Doing stat for {$thumbPath}\n");
             if (!($flags & self::RENDER_FORCE) && $this->repo->fileExists($thumbPath)) {
                 $timestamp = $this->repo->getFileTimestamp($thumbPath);
                 if ($timestamp !== false && $timestamp >= $wgThumbnailEpoch) {
                     // XXX: Pass in the storage path even though we are not rendering anything
                     // and the path is supposed to be an FS path. This is due to getScalerType()
                     // getting called on the path and clobbering $thumb->getUrl() if it's false.
                     $thumb = $handler->getTransform($this, $thumbPath, $thumbUrl, $params);
                     $thumb->setStoragePath($thumbPath);
                     break;
                 }
             } elseif ($flags & self::RENDER_FORCE) {
                 wfDebug(__METHOD__ . " forcing rendering per flag File::RENDER_FORCE\n");
             }
         }
         // If the backend is ready-only, don't keep generating thumbnails
         // only to return transformation errors, just return the error now.
         if ($this->repo->getReadOnlyReason() !== false) {
             $thumb = $this->transformErrorOutput($thumbPath, $thumbUrl, $params, $flags);
             break;
         }
         // Create a temp FS file with the same extension and the thumbnail
         $thumbExt = FileBackend::extensionFromPath($thumbPath);
         $tmpFile = TempFSFile::factory('transform_', $thumbExt);
         if (!$tmpFile) {
             $thumb = $this->transformErrorOutput($thumbPath, $thumbUrl, $params, $flags);
             break;
         }
         $tmpThumbPath = $tmpFile->getPath();
         // path of 0-byte temp file
         // Actually render the thumbnail...
         wfProfileIn(__METHOD__ . '-doTransform');
         $thumb = $handler->doTransform($this, $tmpThumbPath, $thumbUrl, $params);
         wfProfileOut(__METHOD__ . '-doTransform');
         $tmpFile->bind($thumb);
         // keep alive with $thumb
         if (!$thumb) {
             // bad params?
             $thumb = null;
         } elseif ($thumb->isError()) {
             // transform error
             $this->lastError = $thumb->toText();
             // Ignore errors if requested
             if ($wgIgnoreImageErrors && !($flags & self::RENDER_NOW)) {
                 $thumb = $handler->getTransform($this, $tmpThumbPath, $thumbUrl, $params);
             }
         } elseif ($this->repo && $thumb->hasFile() && !$thumb->fileIsSource()) {
             // Copy the thumbnail from the file system into storage...
             $disposition = $this->getThumbDisposition($thumbName);
             $status = $this->repo->quickImport($tmpThumbPath, $thumbPath, $disposition);
             if ($status->isOK()) {
                 $thumb->setStoragePath($thumbPath);
             } else {
                 $thumb = $this->transformErrorOutput($thumbPath, $thumbUrl, $params, $flags);
             }
             // Give extensions a chance to do something with this thumbnail...
             wfRunHooks('FileTransformed', array($this, $thumb, $tmpThumbPath, $thumbPath));
         }
         // Purge. Useful in the event of Core -> Squid connection failure or squid
         // purge collisions from elsewhere during failure. Don't keep triggering for
         // "thumbs" which have the main image URL though (bug 13776)
         if ($wgUseSquid) {
             if (!$thumb || $thumb->isError() || $thumb->getUrl() != $this->getURL()) {
                 SquidUpdate::purge(array($thumbUrl));
             }
         }
     } while (false);
     wfProfileOut(__METHOD__);
     return is_object($thumb) ? $thumb : false;
 }
 private function doTestDoOperationsPipeline()
 {
     $base = self::baseStorePath();
     $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
     $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
     $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
     $tmpNameA = TempFSFile::factory("unittests_", 'txt')->getPath();
     file_put_contents($tmpNameA, $fileAContents);
     $tmpNameB = TempFSFile::factory("unittests_", 'txt')->getPath();
     file_put_contents($tmpNameB, $fileBContents);
     $tmpNameC = TempFSFile::factory("unittests_", 'txt')->getPath();
     file_put_contents($tmpNameC, $fileCContents);
     $this->filesToPrune[] = $tmpNameA;
     # avoid file leaking
     $this->filesToPrune[] = $tmpNameB;
     # avoid file leaking
     $this->filesToPrune[] = $tmpNameC;
     # avoid file leaking
     $fileA = "{$base}/unittest-cont1/e/a/b/fileA.txt";
     $fileB = "{$base}/unittest-cont1/e/a/b/fileB.txt";
     $fileC = "{$base}/unittest-cont1/e/a/b/fileC.txt";
     $fileD = "{$base}/unittest-cont1/e/a/b/fileD.txt";
     $this->prepare(array('dir' => dirname($fileA)));
     $this->create(array('dst' => $fileA, 'content' => $fileAContents));
     $this->prepare(array('dir' => dirname($fileB)));
     $this->prepare(array('dir' => dirname($fileC)));
     $this->prepare(array('dir' => dirname($fileD)));
     $status = $this->backend->doOperations(array(array('op' => 'store', 'src' => $tmpNameA, 'dst' => $fileA, 'overwriteSame' => 1), array('op' => 'store', 'src' => $tmpNameB, 'dst' => $fileB, 'overwrite' => 1), array('op' => 'store', 'src' => $tmpNameC, 'dst' => $fileC, 'overwrite' => 1), array('op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1), array('op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1), array('op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1), array('op' => 'move', 'src' => $fileB, 'dst' => $fileC), array('op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1), array('op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1), array('op' => 'copy', 'src' => $fileA, 'dst' => $fileC), array('op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1), array('op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1), array('op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1), array('op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1), array('op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1), array('op' => 'null')));
     $this->assertGoodStatus($status, "Operation batch succeeded");
     $this->assertEquals(true, $status->isOK(), "Operation batch succeeded");
     $this->assertEquals(16, count($status->success), "Operation batch has correct success array");
     $this->assertEquals(false, $this->backend->fileExists(array('src' => $fileA)), "File does not exist at {$fileA}");
     $this->assertEquals(false, $this->backend->fileExists(array('src' => $fileB)), "File does not exist at {$fileB}");
     $this->assertEquals(false, $this->backend->fileExists(array('src' => $fileD)), "File does not exist at {$fileD}");
     $this->assertEquals(true, $this->backend->fileExists(array('src' => $fileC)), "File exists at {$fileC}");
     $this->assertEquals($fileBContents, $this->backend->getFileContents(array('src' => $fileC)), "Correct file contents of {$fileC}");
     $this->assertEquals(strlen($fileBContents), $this->backend->getFileSize(array('src' => $fileC)), "Correct file size of {$fileC}");
     $this->assertEquals(wfBaseConvert(sha1($fileBContents), 16, 36, 31), $this->backend->getFileSha1Base36(array('src' => $fileC)), "Correct file SHA-1 of {$fileC}");
 }
Beispiel #10
0
 /**
  * Create a new temporary file in the URL subdirectory of wfTempDir().
  *
  * @return string Path to the file
  */
 protected function makeTemporaryFile()
 {
     $tmpFile = TempFSFile::factory('URL', 'urlupload_', wfTempDir());
     $tmpFile->bind($this);
     return $tmpFile->getPath();
 }
Beispiel #11
0
 protected function doGetLocalCopyMulti(array $params)
 {
     $tmpFiles = array();
     // (path => TempFSFile)
     foreach ($params['srcs'] as $srcPath) {
         $src = $this->resolveHashKey($srcPath);
         if ($src === null || !isset($this->files[$src])) {
             $fsFile = null;
         } else {
             // Create a new temporary file with the same extension...
             $ext = FileBackend::extensionFromPath($src);
             $fsFile = TempFSFile::factory('localcopy_', $ext);
             if ($fsFile) {
                 $bytes = file_put_contents($fsFile->getPath(), $this->files[$src]['data']);
                 if ($bytes !== strlen($this->files[$src]['data'])) {
                     $fsFile = null;
                 }
             }
         }
         $tmpFiles[$srcPath] = $fsFile;
     }
     return $tmpFiles;
 }
Beispiel #12
0
 public function execute()
 {
     $params = $this->extractRequestParams();
     $rotation = $params['rotation'];
     $this->getResult()->beginContinuation($params['continue'], array(), array());
     $pageSet = $this->getPageSet();
     $pageSet->execute();
     $result = array();
     self::addValues($result, $pageSet->getInvalidTitles(), 'invalid', 'title');
     self::addValues($result, $pageSet->getSpecialTitles(), 'special', 'title');
     self::addValues($result, $pageSet->getMissingPageIDs(), 'missing', 'pageid');
     self::addValues($result, $pageSet->getMissingRevisionIDs(), 'missing', 'revid');
     self::addValues($result, $pageSet->getInterwikiTitlesAsResult());
     foreach ($pageSet->getTitles() as $title) {
         $r = array();
         $r['id'] = $title->getArticleID();
         ApiQueryBase::addTitleInfo($r, $title);
         if (!$title->exists()) {
             $r['missing'] = '';
         }
         $file = wfFindFile($title);
         if (!$file) {
             $r['result'] = 'Failure';
             $r['errormessage'] = 'File does not exist';
             $result[] = $r;
             continue;
         }
         $handler = $file->getHandler();
         if (!$handler || !$handler->canRotate()) {
             $r['result'] = 'Failure';
             $r['errormessage'] = 'File type cannot be rotated';
             $result[] = $r;
             continue;
         }
         // Check whether we're allowed to rotate this file
         $permError = $this->checkPermissions($this->getUser(), $file->getTitle());
         if ($permError !== null) {
             $r['result'] = 'Failure';
             $r['errormessage'] = $permError;
             $result[] = $r;
             continue;
         }
         $srcPath = $file->getLocalRefPath();
         if ($srcPath === false) {
             $r['result'] = 'Failure';
             $r['errormessage'] = 'Cannot get local file path';
             $result[] = $r;
             continue;
         }
         $ext = strtolower(pathinfo("{$srcPath}", PATHINFO_EXTENSION));
         $tmpFile = TempFSFile::factory('rotate_', $ext);
         $dstPath = $tmpFile->getPath();
         $err = $handler->rotate($file, array("srcPath" => $srcPath, "dstPath" => $dstPath, "rotation" => $rotation));
         if (!$err) {
             $comment = wfMessage('rotate-comment')->numParams($rotation)->inContentLanguage()->text();
             $status = $file->upload($dstPath, $comment, $comment, 0, false, false, $this->getUser());
             if ($status->isGood()) {
                 $r['result'] = 'Success';
             } else {
                 $r['result'] = 'Failure';
                 $r['errormessage'] = $this->getResult()->convertStatusToArray($status);
             }
         } else {
             $r['result'] = 'Failure';
             $r['errormessage'] = $err->toText();
         }
         $result[] = $r;
     }
     $apiResult = $this->getResult();
     $apiResult->setIndexedTagName($result, 'page');
     $apiResult->addValue(null, $this->getModuleName(), $result);
     $apiResult->endContinuation();
 }
Beispiel #13
0
 /**
  * @see FileBackendStore::getLocalCopy()
  */
 public function getLocalCopy(array $params)
 {
     $source = $this->resolveToFSPath($params['src']);
     if ($source === null) {
         return null;
     }
     // Create a new temporary file with the same extension...
     $ext = FileBackend::extensionFromPath($params['src']);
     $tmpFile = TempFSFile::factory(wfBaseName($source) . '_', $ext);
     if (!$tmpFile) {
         return null;
     }
     $tmpPath = $tmpFile->getPath();
     // Copy the source file over the temp file
     $ok = copy($source, $tmpPath);
     if (!$ok) {
         return null;
     }
     $this->chmod($tmpPath);
     return $tmpFile;
 }
Beispiel #14
0
/**
 * @param $timelinesrc string
 * @return string
 */
function wfRenderTimeline($timelinesrc)
{
    global $wgUploadDirectory, $wgUploadPath, $wgArticlePath, $wgTmpDirectory, $wgRenderHashAppend;
    global $wgTimelineSettings;
    // Get the backend to store plot data and pngs
    if ($wgTimelineSettings->fileBackend != '') {
        $backend = FileBackendGroup::singleton()->get($wgTimelineSettings->fileBackend);
    } else {
        $backend = new FSFileBackend(array('name' => 'timeline-backend', 'lockManager' => 'nullLockManager', 'containerPaths' => array('timeline-render' => "{$wgUploadDirectory}/timeline"), 'fileMode' => 777));
    }
    // Get a hash of the plot data
    $hash = md5($timelinesrc);
    if ($wgRenderHashAppend != '') {
        $hash = md5($hash . $wgRenderHashAppend);
    }
    // Storage destination path (excluding file extension)
    $fname = 'mwstore://' . $backend->getName() . "/timeline-render/{$hash}";
    // Wikia change - begin
    wfRunHooks('BeforeRenderTimeline', [&$backend, &$fname, $hash]);
    // Wikia change - end
    $previouslyFailed = $backend->fileExists(array('src' => "{$fname}.err"));
    $previouslyRendered = $backend->fileExists(array('src' => "{$fname}.png"));
    if ($previouslyRendered) {
        $timestamp = $backend->getFileTimestamp(array('src' => "{$fname}.png"));
        $expired = $timestamp < $wgTimelineSettings->epochTimestamp;
    } else {
        $expired = false;
    }
    // Create a new .map, .png (or .gif), and .err file as needed...
    if ($expired || !$previouslyRendered && !$previouslyFailed) {
        if (!is_dir($wgTmpDirectory)) {
            mkdir($wgTmpDirectory, 0777);
        }
        $tmpFile = TempFSFile::factory('timeline_');
        if ($tmpFile) {
            $tmpPath = $tmpFile->getPath();
            file_put_contents($tmpPath, $timelinesrc);
            // store plot data to file
            // Get command for ploticus to read the user input and output an error,
            // map, and rendering (png or gif) file under the same dir as the temp file.
            $cmdline = wfEscapeShellArg($wgTimelineSettings->perlCommand, $wgTimelineSettings->timelineFile) . " -i " . wfEscapeShellArg($tmpPath) . " -m -P " . wfEscapeShellArg($wgTimelineSettings->ploticusCommand) . " -T " . wfEscapeShellArg($wgTmpDirectory) . " -A " . wfEscapeShellArg($wgArticlePath) . " -f " . wfEscapeShellArg($wgTimelineSettings->fontFile);
            // Actually run the command...
            wfDebug("Timeline cmd: {$cmdline}\n");
            $retVal = null;
            $ret = wfShellExec($cmdline, $retVal);
            // Copy the output files into storage...
            // @TODO: store error files in another container or not at all?
            $opt = array('force' => 1, 'nonLocking' => 1, 'allowStale' => 1);
            // performance
            $backend->prepare(array('dir' => dirname($fname)));
            $backend->store(array('src' => "{$tmpPath}.map", 'dst' => "{$fname}.map"), $opt);
            $backend->store(array('src' => "{$tmpPath}.png", 'dst' => "{$fname}.png"), $opt);
            $backend->store(array('src' => "{$tmpPath}.err", 'dst' => "{$fname}.err"), $opt);
        } else {
            return "<div id=\"toc\" dir=\"ltr\"><tt>Timeline error. " . "Could not create temp file</tt></div>";
            // ugh
        }
        if ($ret == "" || $retVal > 0) {
            // Message not localized, only relevant during install
            return "<div id=\"toc\" dir=\"ltr\"><tt>Timeline error. " . "Command line was: " . htmlspecialchars($cmdline) . "</tt></div>";
        }
    }
    // Wikia change - begin
    if ($backend->fileExists(array('src' => "{$fname}.err", 'latest' => true))) {
        $err = $backend->getFileContents(array('src' => "{$fname}.err"));
    } else {
        $err = '';
    }
    // Wikia change - end
    if ($err != "") {
        // Convert the error from poorly-sanitized HTML to plain text
        $err = strtr($err, array('</p><p>' => "\n\n", '<p>' => '', '</p>' => '', '<b>' => '', '</b>' => '', '<br>' => "\n"));
        $err = Sanitizer::decodeCharReferences($err);
        // Now convert back to HTML again
        $encErr = nl2br(htmlspecialchars($err));
        $txt = "<div id=\"toc\" dir=\"ltr\"><tt>{$encErr}</tt></div>";
    } else {
        // Wikia change - begin
        if ($backend->fileExists(array('src' => "{$fname}.map", 'latest' => true))) {
            $map = $backend->getFileContents(array('src' => "{$fname}.map"));
        } else {
            $map = '';
        }
        // Wikia change - end
        $map = str_replace(' >', ' />', $map);
        $map = "<map name=\"timeline_" . htmlspecialchars($hash) . "\">{$map}</map>";
        $map = easyTimelineFixMap($map);
        $url = "{$wgUploadPath}/timeline/{$hash}.png";
        // Wikia change - begin
        $url = wfReplaceImageServer($url);
        // Wikia change - end
        $txt = $map . "<img usemap=\"#timeline_" . htmlspecialchars($hash) . "\" " . "src=\"" . htmlspecialchars($url) . "\">";
        if ($expired) {
            // Replacing an older file, we may need to purge the old one.
            global $wgUseSquid;
            if ($wgUseSquid) {
                $u = new SquidUpdate(array($url));
                $u->doUpdate();
            }
        }
    }
    return $txt;
}
	/**
	 * @see FileBackend::getLocalCopy()
	 */
	function getLocalCopy( array $params ) {
		list( $srcCont, $srcRel ) = $this->resolveStoragePath( $params['src'] );
		if ( $srcRel === null ) {
			return null;
		}

		// Get source file extension
		$ext = FileBackend::extensionFromPath( $srcRel );
		// Create a new temporary file...
		// TODO: Caution: tempfile should not write a local file.
		$tmpFile = TempFSFile::factory( wfBaseName( $srcRel ) . '_', $ext );
		if ( !$tmpFile ) {
			return null;
		}
		$tmpPath = $tmpFile->getPath();

		try {
			$this->storageClient->getBlob( $srcCont, $srcRel, $tmpPath );
		}
		catch ( Exception $e ) {
			$tmpFile = null;
		}

		return $tmpFile;
	}
Beispiel #16
0
 /**
  * Append the final chunk and ready file for parent::performUpload()
  * @return FileRepoStatus
  */
 public function concatenateChunks()
 {
     wfDebug(__METHOD__ . " concatenate {$this->mChunkIndex} chunks:" . $this->getOffset() . ' inx:' . $this->getChunkIndex() . "\n");
     // Concatenate all the chunks to mVirtualTempPath
     $fileList = array();
     // The first chunk is stored at the mVirtualTempPath path so we start on "chunk 1"
     for ($i = 0; $i <= $this->getChunkIndex(); $i++) {
         $fileList[] = $this->getVirtualChunkLocation($i);
     }
     // Get the file extension from the last chunk
     $ext = FileBackend::extensionFromPath($this->mVirtualTempPath);
     // Get a 0-byte temp file to perform the concatenation at
     $tmpFile = TempFSFile::factory('chunkedupload_', $ext);
     $tmpPath = $tmpFile ? $tmpFile->getPath() : false;
     // fail in concatenate()
     // Concatenate the chunks at the temp file
     $status = $this->repo->concatenate($fileList, $tmpPath, FileRepo::DELETE_SOURCE);
     if (!$status->isOk()) {
         return $status;
     }
     // Update the mTempPath and mLocalFile
     // ( for FileUpload or normal Stash to take over )
     $this->mTempPath = $tmpPath;
     // file system path
     $this->mLocalFile = parent::stashFile();
     return $status;
 }
Beispiel #17
0
 protected function doGetLocalCopyMulti(array $params)
 {
     $tmpFiles = array();
     $auth = $this->getAuthentication();
     $ep = array_diff_key($params, array('srcs' => 1));
     // for error logging
     // Blindly create tmp files and stream to them, catching any exception if the file does
     // not exist. Doing a stat here is useless causes infinite loops in addMissingMetadata().
     $reqs = array();
     // (path => op)
     foreach ($params['srcs'] as $path) {
         // each path in this concurrent batch
         list($srcCont, $srcRel) = $this->resolveStoragePathReal($path);
         if ($srcRel === null || !$auth) {
             $tmpFiles[$path] = null;
             continue;
         }
         // Get source file extension
         $ext = FileBackend::extensionFromPath($path);
         // Create a new temporary file...
         $tmpFile = TempFSFile::factory('localcopy_', $ext);
         if ($tmpFile) {
             $handle = fopen($tmpFile->getPath(), 'wb');
             if ($handle) {
                 $reqs[$path] = array('method' => 'GET', 'url' => $this->storageUrl($auth, $srcCont, $srcRel), 'headers' => $this->authTokenHeaders($auth) + $this->headersFromParams($params), 'stream' => $handle);
             } else {
                 $tmpFile = null;
             }
         }
         $tmpFiles[$path] = $tmpFile;
     }
     $isLatest = $this->isRGW || !empty($params['latest']);
     $opts = array('maxConnsPerHost' => $params['concurrency']);
     $reqs = $this->http->runMulti($reqs, $opts);
     foreach ($reqs as $path => $op) {
         list($rcode, $rdesc, $rhdrs, $rbody, $rerr) = $op['response'];
         fclose($op['stream']);
         // close open handle
         if ($rcode >= 200 && $rcode <= 299) {
             $size = $tmpFiles[$path] ? $tmpFiles[$path]->getSize() : 0;
             // Double check that the disk is not full/broken
             if ($size != $rhdrs['content-length']) {
                 $tmpFiles[$path] = null;
                 $rerr = "Got {$size}/{$rhdrs['content-length']} bytes";
                 $this->onError(null, __METHOD__, array('src' => $path) + $ep, $rerr, $rcode, $rdesc);
             }
             // Set the file stat process cache in passing
             $stat = $this->getStatFromHeaders($rhdrs);
             $stat['latest'] = $isLatest;
             $this->cheapCache->set($path, 'stat', $stat);
         } elseif ($rcode === 404) {
             $tmpFiles[$path] = false;
         } else {
             $tmpFiles[$path] = null;
             $this->onError(null, __METHOD__, array('src' => $path) + $ep, $rerr, $rcode, $rdesc);
         }
     }
     return $tmpFiles;
 }
Beispiel #18
0
 protected function doGetLocalCopyMulti(array $params)
 {
     $tmpFiles = array();
     // (path => TempFSFile)
     foreach ($params['srcs'] as $src) {
         $source = $this->resolveToFSPath($src);
         if ($source === null) {
             $tmpFiles[$src] = null;
             // invalid path
         } else {
             // Create a new temporary file with the same extension...
             $ext = FileBackend::extensionFromPath($src);
             $tmpFile = TempFSFile::factory('localcopy_', $ext);
             if (!$tmpFile) {
                 $tmpFiles[$src] = null;
             } else {
                 $tmpPath = $tmpFile->getPath();
                 // Copy the source file over the temp file
                 $this->trapWarnings();
                 $ok = copy($source, $tmpPath);
                 $this->untrapWarnings();
                 if (!$ok) {
                     $tmpFiles[$src] = null;
                 } else {
                     $this->chmod($tmpPath);
                     $tmpFiles[$src] = $tmpFile;
                 }
             }
         }
     }
     return $tmpFiles;
 }
Beispiel #19
0
 /**
  * @return bool
  */
 function importUpload()
 {
     # Construct a file
     $archiveName = $this->getArchiveName();
     if ($archiveName) {
         wfDebug(__METHOD__ . "Importing archived file as {$archiveName}\n");
         $file = OldLocalFile::newFromArchiveName($this->getTitle(), RepoGroup::singleton()->getLocalRepo(), $archiveName);
     } else {
         $file = wfLocalFile($this->getTitle());
         $file->load(File::READ_LATEST);
         wfDebug(__METHOD__ . 'Importing new file as ' . $file->getName() . "\n");
         if ($file->exists() && $file->getTimestamp() > $this->getTimestamp()) {
             $archiveName = $file->getTimestamp() . '!' . $file->getName();
             $file = OldLocalFile::newFromArchiveName($this->getTitle(), RepoGroup::singleton()->getLocalRepo(), $archiveName);
             wfDebug(__METHOD__ . "File already exists; importing as {$archiveName}\n");
         }
     }
     if (!$file) {
         wfDebug(__METHOD__ . ': Bad file for ' . $this->getTitle() . "\n");
         return false;
     }
     # Get the file source or download if necessary
     $source = $this->getFileSrc();
     $autoDeleteSource = $this->isTempSrc();
     if (!strlen($source)) {
         $source = $this->downloadSource();
         $autoDeleteSource = true;
     }
     if (!strlen($source)) {
         wfDebug(__METHOD__ . ": Could not fetch remote file.\n");
         return false;
     }
     $tmpFile = new TempFSFile($source);
     if ($autoDeleteSource) {
         $tmpFile->autocollect();
     }
     $sha1File = ltrim(sha1_file($source), '0');
     $sha1 = $this->getSha1();
     if ($sha1 && $sha1 !== $sha1File) {
         wfDebug(__METHOD__ . ": Corrupt file {$source}.\n");
         return false;
     }
     $user = $this->getUserObj() ?: User::newFromName($this->getUser());
     # Do the actual upload
     if ($archiveName) {
         $status = $file->uploadOld($source, $archiveName, $this->getTimestamp(), $this->getComment(), $user);
     } else {
         $flags = 0;
         $status = $file->upload($source, $this->getComment(), $this->getComment(), $flags, false, $this->getTimestamp(), $user);
     }
     if ($status->isGood()) {
         wfDebug(__METHOD__ . ": Successful\n");
         return true;
     } else {
         wfDebug(__METHOD__ . ': failed: ' . $status->getHTML() . "\n");
         return false;
     }
 }
Beispiel #20
0
 /**
  * @see FileBackendStore::getLocalCopy()
  */
 public function getLocalCopy(array $params)
 {
     list($srcCont, $srcRel) = $this->resolveStoragePathReal($params['src']);
     if ($srcRel === null) {
         return null;
     }
     /*if ( !$this->fileExists( $params ) ) {
     			return null;
     		}*/
     $tmpFile = null;
     try {
         $sContObj = $this->getContainer($srcCont);
         $obj = new CF_Object($sContObj, $srcRel, false, false);
         // skip HEAD
         // Get source file extension
         $ext = FileBackend::extensionFromPath($srcRel);
         // Create a new temporary file...
         $tmpFile = TempFSFile::factory(wfBaseName($srcRel) . '_', $ext);
         if ($tmpFile) {
             $handle = fopen($tmpFile->getPath(), 'wb');
             if ($handle) {
                 $obj->stream($handle, $this->headersFromParams($params));
                 fclose($handle);
             } else {
                 $tmpFile = null;
                 // couldn't open temp file
             }
         }
     } catch (NoSuchContainerException $e) {
         $tmpFile = null;
         $this->logException($e, __METHOD__, $params);
     } catch (NoSuchObjectException $e) {
         $tmpFile = null;
         $this->logException($e, __METHOD__, $params);
     } catch (InvalidResponseException $e) {
         $tmpFile = null;
         $this->logException($e, __METHOD__, $params);
     } catch (Exception $e) {
         // some other exception?
         $tmpFile = null;
         $this->logException($e, __METHOD__, $params);
     }
     return $tmpFile;
 }
Beispiel #21
0
 /**
  * @param string $storagePath
  * @param string|null $content
  * @param string|null $fsPath
  * @return string
  * @since 1.27
  */
 public function guessMimeInternal($storagePath, $content, $fsPath)
 {
     $magic = MimeMagic::singleton();
     // Trust the extension of the storage path (caller must validate)
     $ext = FileBackend::extensionFromPath($storagePath);
     $type = $magic->guessTypesForExtension($ext);
     // For files without a valid extension (or one at all), inspect the contents
     if (!$type && $fsPath) {
         $type = $magic->guessMimeType($fsPath, false);
     } elseif (!$type && strlen($content)) {
         $tmpFile = TempFSFile::factory('mime_');
         file_put_contents($tmpFile->getPath(), $content);
         $type = $magic->guessMimeType($tmpFile->getPath(), false);
     }
     return $type ?: 'unknown/unknown';
 }
Beispiel #22
0
 /**
  * @see FileBackendStore::doGetLocalCopyMulti()
  * @return null|TempFSFile
  */
 protected function doGetLocalCopyMulti(array $params)
 {
     $tmpFiles = array();
     $ep = array_diff_key($params, array('srcs' => 1));
     // for error logging
     // Blindly create tmp files and stream to them, catching any exception if the file does
     // not exist. Doing a stat here is useless causes infinite loops in addMissingMetadata().
     foreach (array_chunk($params['srcs'], $params['concurrency']) as $pathBatch) {
         $cfOps = array();
         // (path => CF_Async_Op)
         foreach ($pathBatch as $path) {
             // each path in this concurrent batch
             list($srcCont, $srcRel) = $this->resolveStoragePathReal($path);
             if ($srcRel === null) {
                 $tmpFiles[$path] = null;
                 continue;
             }
             $tmpFile = null;
             try {
                 $sContObj = $this->getContainer($srcCont);
                 $obj = new CF_Object($sContObj, $srcRel, false, false);
                 // skip HEAD
                 // Get source file extension
                 $ext = FileBackend::extensionFromPath($path);
                 // Create a new temporary file...
                 $tmpFile = TempFSFile::factory('localcopy_', $ext);
                 if ($tmpFile) {
                     $handle = fopen($tmpFile->getPath(), 'wb');
                     if ($handle) {
                         $headers = $this->headersFromParams($params);
                         if (count($pathBatch) > 1) {
                             $cfOps[$path] = $obj->stream_async($handle, $headers);
                             $cfOps[$path]->_file_handle = $handle;
                             // close this later
                         } else {
                             $obj->stream($handle, $headers);
                             fclose($handle);
                         }
                     } else {
                         $tmpFile = null;
                     }
                 }
             } catch (NoSuchContainerException $e) {
                 $tmpFile = null;
             } catch (NoSuchObjectException $e) {
                 $tmpFile = null;
             } catch (CloudFilesException $e) {
                 // some other exception?
                 $tmpFile = null;
                 $this->handleException($e, null, __METHOD__, array('src' => $path) + $ep);
             }
             $tmpFiles[$path] = $tmpFile;
         }
         $batch = new CF_Async_Op_Batch($cfOps);
         $cfOps = $batch->execute();
         foreach ($cfOps as $path => $cfOp) {
             try {
                 $cfOp->getLastResponse();
             } catch (NoSuchContainerException $e) {
                 $tmpFiles[$path] = null;
             } catch (NoSuchObjectException $e) {
                 $tmpFiles[$path] = null;
             } catch (CloudFilesException $e) {
                 // some other exception?
                 $tmpFiles[$path] = null;
                 $this->handleException($e, null, __METHOD__, array('src' => $path) + $ep);
             }
             fclose($cfOp->_file_handle);
             // close open handle
         }
     }
     return $tmpFiles;
 }
Beispiel #23
0
/**
 * Tries to get the system directory for temporary files. First
 * $wgTmpDirectory is checked, and then the TMPDIR, TMP, and TEMP
 * environment variables are then checked in sequence, then
 * sys_get_temp_dir(), then upload_tmp_dir from php.ini.
 *
 * NOTE: When possible, use instead the tmpfile() function to create
 * temporary files to avoid race conditions on file creation, etc.
 *
 * @return string
 */
function wfTempDir()
{
    global $wgTmpDirectory;
    if ($wgTmpDirectory !== false) {
        return $wgTmpDirectory;
    }
    return TempFSFile::getUsableTempDirectory();
}
Beispiel #24
0
 /**
  * Creates a temp FS file with the same extension and the thumbnail
  * @param string $thumbPath Thumbnail path
  * @return TempFSFile
  */
 protected function makeTransformTmpFile($thumbPath)
 {
     $thumbExt = FileBackend::extensionFromPath($thumbPath);
     return TempFSFile::factory('transform_', $thumbExt);
 }
Beispiel #25
0
 /**
  * Create a new temporary file in the URL subdirectory of wfTempDir().
  *
  * @return string Path to the file
  */
 protected function makeTemporaryFile()
 {
     $tmpFile = TempFSFile::factory('URL');
     $tmpFile->bind($this);
     return $tmpFile->getPath();
 }
Beispiel #26
0
 /**
  * Append the final chunk and ready file for parent::performUpload()
  * @return FileRepoStatus
  */
 public function concatenateChunks()
 {
     $chunkIndex = $this->getChunkIndex();
     wfDebug(__METHOD__ . " concatenate {$this->mChunkIndex} chunks:" . $this->getOffset() . ' inx:' . $chunkIndex . "\n");
     // Concatenate all the chunks to mVirtualTempPath
     $fileList = array();
     // The first chunk is stored at the mVirtualTempPath path so we start on "chunk 1"
     for ($i = 0; $i <= $chunkIndex; $i++) {
         $fileList[] = $this->getVirtualChunkLocation($i);
     }
     // Get the file extension from the last chunk
     $ext = FileBackend::extensionFromPath($this->mVirtualTempPath);
     // Get a 0-byte temp file to perform the concatenation at
     $tmpFile = TempFSFile::factory('chunkedupload_', $ext);
     $tmpPath = false;
     // fail in concatenate()
     if ($tmpFile) {
         // keep alive with $this
         $tmpPath = $tmpFile->bind($this)->getPath();
     }
     // Concatenate the chunks at the temp file
     $tStart = microtime(true);
     $status = $this->repo->concatenate($fileList, $tmpPath, FileRepo::DELETE_SOURCE);
     $tAmount = microtime(true) - $tStart;
     if (!$status->isOk()) {
         return $status;
     }
     wfDebugLog('fileconcatenate', "Combined {$i} chunks in {$tAmount} seconds.");
     // File system path
     $this->mTempPath = $tmpPath;
     // Since this was set for the last chunk previously
     $this->mFileSize = filesize($this->mTempPath);
     $ret = $this->verifyUpload();
     if ($ret['status'] !== UploadBase::OK) {
         wfDebugLog('fileconcatenate', "Verification failed for chunked upload");
         $status->fatal($this->getVerificationErrorCode($ret['status']));
         return $status;
     }
     // Update the mTempPath and mLocalFile
     // (for FileUpload or normal Stash to take over)
     $tStart = microtime(true);
     $this->mLocalFile = parent::stashFile($this->user);
     $tAmount = microtime(true) - $tStart;
     $this->mLocalFile->setLocalReference($tmpFile);
     // reuse (e.g. for getImageInfo())
     wfDebugLog('fileconcatenate', "Stashed combined file ({$i} chunks) in {$tAmount} seconds.");
     return $status;
 }
Beispiel #27
0
 public function testTrickyDomain()
 {
     global $wgDBtype;
     if ($wgDBtype === 'sqlite') {
         $tmpDir = $this->getNewTempDirectory();
         $dbPath = "{$tmpDir}/unit_test_db.sqlite";
         file_put_contents($dbPath, '');
         $tempFsFile = new TempFSFile($dbPath);
         $tempFsFile->autocollect();
     } else {
         $dbPath = null;
     }
     $dbname = 'unittest-domain';
     $factory = $this->newLBFactoryMulti(['localDomain' => $dbname], ['dbname' => $dbname, 'dbFilePath' => $dbPath]);
     $lb = $factory->getMainLB();
     /** @var Database $db */
     $db = $lb->getConnection(DB_MASTER, [], '');
     $lb->reuseConnection($db);
     // don't care
     $this->assertEquals('', $db->getDomainID());
     $this->assertEquals($this->quoteTable($db, 'page'), $db->tableName('page'), "Correct full table name");
     $this->assertEquals($this->quoteTable($db, $dbname) . '.' . $this->quoteTable($db, 'page'), $db->tableName("{$dbname}.page"), "Correct full table name");
     $this->assertEquals($this->quoteTable($db, 'nice_db') . '.' . $this->quoteTable($db, 'page'), $db->tableName('nice_db.page'), "Correct full table name");
     $factory->setDomainPrefix('my_');
     $this->assertEquals($this->quoteTable($db, 'my_page'), $db->tableName('page'), "Correct full table name");
     $this->assertEquals($this->quoteTable($db, 'other_nice_db') . '.' . $this->quoteTable($db, 'page'), $db->tableName('other_nice_db.page'), "Correct full table name");
     \MediaWiki\suppressWarnings();
     $this->assertFalse($db->selectDB('garbage-db'));
     \MediaWiki\restoreWarnings();
     $this->assertEquals($this->quoteTable($db, 'garbage-db') . '.' . $this->quoteTable($db, 'page'), $db->tableName('garbage-db.page'), "Correct full table name");
     $factory->closeAll();
     $factory->destroy();
 }