/** * Output the chunk to disk * * @param string $chunkPath * @throws UploadChunkFileException * @return FileRepoStatus */ private function outputChunk($chunkPath) { // Key is fileKey + chunk index $fileKey = $this->getChunkFileKey(); // Store the chunk per its indexed fileKey: $hashPath = $this->repo->getHashPath($fileKey); $storeStatus = $this->repo->quickImport($chunkPath, $this->repo->getZonePath('temp') . "/{$hashPath}{$fileKey}"); // Check for error in stashing the chunk: if (!$storeStatus->isOK()) { $error = $storeStatus->getErrorsArray(); $error = reset($error); if (!count($error)) { $error = $storeStatus->getWarningsArray(); $error = reset($error); if (!count($error)) { $error = array('unknown', 'no error recorded'); } } throw new UploadChunkFileException("Error storing file in '{$chunkPath}': " . implode('; ', $error)); } return $storeStatus; }
/** * Transform a media file * * @param array $params an associative array of handler-specific parameters. * Typical keys are width, height and page. * @param int $flags 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.\n"); // 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; }
/** * Generates a thumbnail according to the given parameters and saves it to storage * @param TempFSFile $tmpFile Temporary file where the rendered thumbnail will be saved * @param array $transformParams * @param int $flags * @return bool|MediaTransformOutput */ public function generateAndSaveThumb($tmpFile, $transformParams, $flags) { global $wgIgnoreImageErrors; $stats = RequestContext::getMain()->getStats(); $handler = $this->getHandler(); $normalisedParams = $transformParams; $handler->normaliseParams($this, $normalisedParams); $thumbName = $this->thumbName($normalisedParams); $thumbUrl = $this->getThumbUrl($thumbName); $thumbPath = $this->getThumbPath($thumbName); // final thumb path $tmpThumbPath = $tmpFile->getPath(); if ($handler->supportsBucketing()) { $this->generateBucketsIfNeeded($normalisedParams, $flags); } $starttime = microtime(true); // Actually render the thumbnail... $thumb = $handler->doTransform($this, $tmpThumbPath, $thumbUrl, $transformParams); $tmpFile->bind($thumb); // keep alive with $thumb $statTiming = microtime(true) - $starttime; $stats->timing('media.thumbnail.generate.transform', 1000 * $statTiming); if (!$thumb) { // bad params? $thumb = false; } elseif ($thumb->isError()) { // transform error /** @var $thumb MediaTransformError */ $this->lastError = $thumb->toText(); // Ignore errors if requested if ($wgIgnoreImageErrors && !($flags & self::RENDER_NOW)) { $thumb = $handler->getTransform($this, $tmpThumbPath, $thumbUrl, $transformParams); } } elseif ($this->repo && $thumb->hasFile() && !$thumb->fileIsSource()) { // Copy the thumbnail from the file system into storage... $starttime = microtime(true); $disposition = $this->getThumbDisposition($thumbName); $status = $this->repo->quickImport($tmpThumbPath, $thumbPath, $disposition); if ($status->isOK()) { $thumb->setStoragePath($thumbPath); } else { $thumb = $this->transformErrorOutput($thumbPath, $thumbUrl, $transformParams, $flags); } $statTiming = microtime(true) - $starttime; $stats->timing('media.thumbnail.generate.store', 1000 * $statTiming); // Give extensions a chance to do something with this thumbnail... Hooks::run('FileTransformed', array($this, $thumb, $tmpThumbPath, $thumbPath)); } return $thumb; }
/** * Generates a thumbnail according to the given parameters and saves it to storage * @param TempFSFile $tmpFile Temporary file where the rendered thumbnail will be saved * @param array $transformParams * @param int $flags * @return bool|MediaTransformOutput */ public function generateAndSaveThumb($tmpFile, $transformParams, $flags) { global $wgUseSquid, $wgIgnoreImageErrors; $handler = $this->getHandler(); $normalisedParams = $transformParams; $handler->normaliseParams($this, $normalisedParams); $thumbName = $this->thumbName($normalisedParams); $thumbUrl = $this->getThumbUrl($thumbName); $thumbPath = $this->getThumbPath($thumbName); // final thumb path $tmpThumbPath = $tmpFile->getPath(); if ($handler->supportsBucketing()) { $this->generateBucketsIfNeeded($normalisedParams, $flags); } // Actually render the thumbnail... $thumb = $handler->doTransform($this, $tmpThumbPath, $thumbUrl, $transformParams); $tmpFile->bind($thumb); // keep alive with $thumb if (!$thumb) { // bad params? $thumb = false; } 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, $transformParams); } } 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, $transformParams, $flags); } // Give extensions a chance to do something with this thumbnail... Hooks::run('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)); } } return $thumb; }