/** * Get an associative array containing information about * a file with the given storage path. * * Resulting array fields include: * - fileExists * - size (filesize in bytes) * - mime (as major/minor) * - media_type (value to be used with the MEDIATYPE_xxx constants) * - metadata (handler specific) * - sha1 (in base 36) * - width * - height * - bits (bitrate) * - file-mime * - major_mime * - minor_mime * * @param string $path Filesystem path to a file * @param string|bool $ext The file extension, or true to extract it from the filename. * Set it to false to ignore the extension. * @return array * @since 1.28 */ public function getPropsFromPath($path, $ext) { $fsFile = new FSFile($path); $info = $this->newPlaceholderProps(); $info['fileExists'] = $fsFile->exists(); if ($info['fileExists']) { $info['size'] = $fsFile->getSize(); // bytes $info['sha1'] = $fsFile->getSha1Base36(); # MIME type according to file contents $info['file-mime'] = $this->magic->guessMimeType($path, false); # Logical MIME type $ext = $ext === true ? FileBackend::extensionFromPath($path) : $ext; $info['mime'] = $this->magic->improveTypeFromExtension($info['file-mime'], $ext); list($info['major_mime'], $info['minor_mime']) = File::splitMime($info['mime']); $info['media_type'] = $this->magic->getMediaType($path, $info['mime']); # Height, width and metadata $handler = MediaHandler::getHandler($info['mime']); if ($handler) { $info['metadata'] = $handler->getMetadata($fsFile, $path); /** @noinspection PhpMethodParametersCountMismatchInspection */ $gis = $handler->getImageSize($fsFile, $path, $info['metadata']); if (is_array($gis)) { $info = $this->extractImageSizeInfo($gis) + $info; } } } return $info; }
/** * @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; }
/** * @dataProvider provider_testExtensionFromPath */ public function testExtensionFromPath($path, $res) { $this->assertEquals($res, FileBackend::extensionFromPath($path), "FileBackend::extensionFromPath on path '{$path}'"); }
/** * 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; }
/** * Get the portion of the file that contains the origin file name. * If that name is too long, then the name "thumbnail.<ext>" will be given. * * @param string $name * @return string */ public function nameForThumb($name) { if (strlen($name) > $this->abbrvThreshold) { $ext = FileBackend::extensionFromPath($name); $name = $ext == '' ? 'thumbnail' : "thumbnail.{$ext}"; } return $name; }
/** * @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; }
/** * @param string $thumbName Thumbnail name * @return string Content-Disposition header value */ function getThumbDisposition($thumbName) { $fileName = $this->name; // file name to suggest $thumbExt = FileBackend::extensionFromPath($thumbName); if ($thumbExt != '' && $thumbExt !== $this->getExtension()) { $fileName .= ".{$thumbExt}"; } return FileBackend::makeContentDisposition('inline', $fileName); }
/** * Transform a media file * * @param $params Array: 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|false */ 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); } $script = $this->getTransformScript(); if ($script && !($flags & self::RENDER_NOW)) { // Use a script to transform on client request, if possible $thumb = $this->handler->getScriptedTransform($this, $script, $params); if ($thumb) { break; } } $normalisedParams = $params; $this->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 = $this->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 ($this->repo->fileExists($thumbPath) && !($flags & self::RENDER_FORCE)) { $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 = $this->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"); } } // 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... $thumb = $this->handler->doTransform($this, $tmpThumbPath, $thumbUrl, $params); $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 = $this->handler->getTransform($this, $tmpThumbPath, $thumbUrl, $params); } } elseif ($this->repo && $thumb->hasFile() && !$thumb->fileIsSource()) { $backend = $this->repo->getBackend(); // Copy the thumbnail from the file system into storage. This avoids using // FileRepo::store(); getThumbPath() uses a different zone in some subclasses. $backend->prepare(array('dir' => dirname($thumbPath))); $status = $backend->store(array('src' => $tmpThumbPath, 'dst' => $thumbPath, 'overwrite' => 1), array('force' => 1, 'nonLocking' => 1, 'allowStale' => 1)); if ($status->isOK()) { $thumb->setStoragePath($thumbPath); } else { $thumb = $this->transformErrorOutput($thumbPath, $thumbUrl, $params, $flags); } } // 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; }
/** * @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'; }
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; }
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; }
/** * @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; }
/** * @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; }
function wfImageAuthMain() { global $wgImgAuthUrlPathMap; $request = RequestContext::getMain()->getRequest(); $publicWiki = in_array('read', User::getGroupPermissions(array('*')), true); // Get the requested file path (source file or thumbnail) $matches = WebRequest::getPathInfo(); if (!isset($matches['title'])) { wfForbidden('img-auth-accessdenied', 'img-auth-nopathinfo'); return; } $path = $matches['title']; if ($path && $path[0] !== '/') { // Make sure $path has a leading / $path = "/" . $path; } // Check for bug 28235: QUERY_STRING overriding the correct extension $whitelist = array(); $extension = FileBackend::extensionFromPath($path, 'rawcase'); if ($extension != '') { $whitelist[] = $extension; } if (!$request->checkUrlExtension($whitelist)) { return; } // Various extensions may have their own backends that need access. // Check if there is a special backend and storage base path for this file. foreach ($wgImgAuthUrlPathMap as $prefix => $storageDir) { $prefix = rtrim($prefix, '/') . '/'; // implicit trailing slash if (strpos($path, $prefix) === 0) { $be = FileBackendGroup::singleton()->backendFromPath($storageDir); $filename = $storageDir . substr($path, strlen($prefix)); // strip prefix // Check basic user authorization if (!RequestContext::getMain()->getUser()->isAllowed('read')) { wfForbidden('img-auth-accessdenied', 'img-auth-noread', $path); return; } if ($be->fileExists(array('src' => $filename))) { wfDebugLog('img_auth', "Streaming `" . $filename . "`."); $be->streamFile(array('src' => $filename), array('Cache-Control: private', 'Vary: Cookie')); } else { wfForbidden('img-auth-accessdenied', 'img-auth-nofile', $path); } return; } } // Get the local file repository $repo = RepoGroup::singleton()->getRepo('local'); $zone = strstr(ltrim($path, '/'), '/', true); // Get the full file storage path and extract the source file name. // (e.g. 120px-Foo.png => Foo.png or page2-120px-Foo.png => Foo.png). // This only applies to thumbnails/transcoded, and each of them should // be under a folder that has the source file name. if ($zone === 'thumb' || $zone === 'transcoded') { $name = wfBaseName(dirname($path)); $filename = $repo->getZonePath($zone) . substr($path, strlen("/" . $zone)); // Check to see if the file exists if (!$repo->fileExists($filename)) { wfForbidden('img-auth-accessdenied', 'img-auth-nofile', $filename); return; } } else { $name = wfBaseName($path); // file is a source file $filename = $repo->getZonePath('public') . $path; // Check to see if the file exists and is not deleted $bits = explode('!', $name, 2); if (substr($path, 0, 9) === '/archive/' && count($bits) == 2) { $file = $repo->newFromArchiveName($bits[1], $name); } else { $file = $repo->newFile($name); } if (!$file->exists() || $file->isDeleted(File::DELETED_FILE)) { wfForbidden('img-auth-accessdenied', 'img-auth-nofile', $filename); return; } } $headers = array(); // extra HTTP headers to send if (!$publicWiki) { // For private wikis, run extra auth checks and set cache control headers $headers[] = 'Cache-Control: private'; $headers[] = 'Vary: Cookie'; $title = Title::makeTitleSafe(NS_FILE, $name); if (!$title instanceof Title) { // files have valid titles wfForbidden('img-auth-accessdenied', 'img-auth-badtitle', $name); return; } // Run hook for extension authorization plugins /** @var $result array */ $result = null; if (!wfRunHooks('ImgAuthBeforeStream', array(&$title, &$path, &$name, &$result))) { wfForbidden($result[0], $result[1], array_slice($result, 2)); return; } // Check user authorization for this title // Checks Whitelist too if (!$title->userCan('read')) { wfForbidden('img-auth-accessdenied', 'img-auth-noread', $name); return; } } if ($request->getCheck('download')) { $headers[] = 'Content-Disposition: attachment'; } // Stream the requested file wfDebugLog('img_auth', "Streaming `" . $filename . "`."); $repo->streamFile($filename, $headers); }
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; }
/** * 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::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; }
/** * Get the final extension of the thumbnail. * Returns false for scripted transformations. * @return string|bool */ public function getExtension() { return $this->path ? FileBackend::extensionFromPath($this->path) : false; }
/** * 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; }
function wfImageAuthMain() { global $wgImgAuthPublicTest, $wgImgAuthUrlPathMap, $wgRequest; // See if this is a public Wiki (no protections). if ($wgImgAuthPublicTest && in_array('read', User::getGroupPermissions(array('*')), true)) { // This is a public wiki, so disable this script (for private wikis only) wfForbidden('img-auth-accessdenied', 'img-auth-public'); return; } // Get the requested file path (source file or thumbnail) $matches = WebRequest::getPathInfo(); if (!isset($matches['title'])) { wfForbidden('img-auth-accessdenied', 'img-auth-nopathinfo'); return; } $path = $matches['title']; if ($path && $path[0] !== '/') { // Make sure $path has a leading / $path = "/" . $path; } // Check for bug 28235: QUERY_STRING overriding the correct extension $whitelist = array(); $extension = FileBackend::extensionFromPath($path, 'rawcase'); if ($extension != '') { $whitelist[] = $extension; } if (!$wgRequest->checkUrlExtension($whitelist)) { return; } // Various extensions may have their own backends that need access. // Check if there is a special backend and storage base path for this file. foreach ($wgImgAuthUrlPathMap as $prefix => $storageDir) { $prefix = rtrim($prefix, '/') . '/'; // implicit trailing slash if (strpos($path, $prefix) === 0) { $be = FileBackendGroup::singleton()->backendFromPath($storageDir); $filename = $storageDir . substr($path, strlen($prefix)); // strip prefix // Check basic user authorization if (!RequestContext::getMain()->getUser()->isAllowed('read')) { wfForbidden('img-auth-accessdenied', 'img-auth-noread', $path); return; } if ($be->fileExists(array('src' => $filename))) { wfDebugLog('img_auth', "Streaming `" . $filename . "`."); $be->streamFile(array('src' => $filename), array('Cache-Control: private', 'Vary: Cookie')); } else { wfForbidden('img-auth-accessdenied', 'img-auth-nofile', $path); } return; } } // Get the local file repository $repo = RepoGroup::singleton()->getRepo('local'); // Get the full file storage path and extract the source file name. // (e.g. 120px-Foo.png => Foo.png or page2-120px-Foo.png => Foo.png). // This only applies to thumbnails, and all thumbnails should // be under a folder that has the source file name. if (strpos($path, '/thumb/') === 0) { $name = wfBaseName(dirname($path)); // file is a thumbnail $filename = $repo->getZonePath('thumb') . substr($path, 6); // strip "/thumb" } else { $name = wfBaseName($path); // file is a source file $filename = $repo->getZonePath('public') . $path; } // Check to see if the file exists if (!$repo->fileExists($filename)) { wfForbidden('img-auth-accessdenied', 'img-auth-nofile', $filename); return; } $title = Title::makeTitleSafe(NS_FILE, $name); if (!$title instanceof Title) { // files have valid titles wfForbidden('img-auth-accessdenied', 'img-auth-badtitle', $name); return; } // Run hook for extension authorization plugins /** @var $result array */ $result = null; if (!wfRunHooks('ImgAuthBeforeStream', array(&$title, &$path, &$name, &$result))) { wfForbidden($result[0], $result[1], array_slice($result, 2)); return; } // Check user authorization for this title // Checks Whitelist too if (!$title->userCan('read')) { wfForbidden('img-auth-accessdenied', 'img-auth-noread', $name); return; } if ($wgRequest->getCheck('download')) { header('Content-Disposition: attachment'); } // Stream the requested file wfDebugLog('img_auth', "Streaming `" . $filename . "`."); $repo->streamFile($filename, array('Cache-Control: private', 'Vary: Cookie')); }