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); }
/** * 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; }
/** * @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; }
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 }
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); }
/** * 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}"); }
/** * 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(); }
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; }
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(); }
/** * @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; }
/** * @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; }
/** * 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; }
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; }
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; }
/** * @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; } }
/** * @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; }
/** * @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'; }
/** * @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; }
/** * 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(); }
/** * 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); }
/** * 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(); }
/** * 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; }
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(); }