Example #1
0
/**
 * Actually try to generate a new thumbnail
 *
 * @param File $file
 * @param array $params
 * @param string $thumbName
 * @param string $thumbPath
 * @return array (MediaTransformOutput|bool, string|bool error message HTML)
 */
function wfGenerateThumbnail(File $file, array $params, $thumbName, $thumbPath)
{
    global $wgMemc, $wgAttemptFailureEpoch;
    $key = wfMemcKey('attempt-failures', $wgAttemptFailureEpoch, $file->getRepo()->getName(), $file->getSha1(), md5($thumbName));
    // Check if this file keeps failing to render
    if ($wgMemc->get($key) >= 4) {
        return array(false, wfMessage('thumbnail_image-failure-limit', 4));
    }
    $done = false;
    // Record failures on PHP fatals in addition to caching exceptions
    register_shutdown_function(function () use(&$done, $key) {
        if (!$done) {
            // transform() gave a fatal
            global $wgMemc;
            // Randomize TTL to reduce stampedes
            $wgMemc->incrWithInit($key, 3600 + mt_rand(0, 300));
        }
    });
    $thumb = false;
    $errorHtml = false;
    // guard thumbnail rendering with PoolCounter to avoid stampedes
    // expensive files use a separate PoolCounter config so it is possible
    // to set up a global limit on them
    if ($file->isExpensiveToThumbnail()) {
        $poolCounterType = 'FileRenderExpensive';
    } else {
        $poolCounterType = 'FileRender';
    }
    // Thumbnail isn't already there, so create the new thumbnail...
    try {
        $work = new PoolCounterWorkViaCallback($poolCounterType, sha1($file->getName()), array('doWork' => function () use($file, $params) {
            return $file->transform($params, File::RENDER_NOW);
        }, 'getCachedWork' => function () use($file, $params, $thumbPath) {
            // If the worker that finished made this thumbnail then use it.
            // Otherwise, it probably made a different thumbnail for this file.
            return $file->getRepo()->fileExists($thumbPath) ? $file->transform($params, File::RENDER_NOW) : false;
            // retry once more in exclusive mode
        }, 'fallback' => function () {
            return wfMessage('generic-pool-error')->parse();
        }, 'error' => function (Status $status) {
            return $status->getHTML();
        }));
        $result = $work->execute();
        if ($result instanceof MediaTransformOutput) {
            $thumb = $result;
        } elseif (is_string($result)) {
            // error
            $errorHtml = $result;
        }
    } catch (Exception $e) {
        // Tried to select a page on a non-paged file?
    }
    /** @noinspection PhpUnusedLocalVariableInspection */
    $done = true;
    // no PHP fatal occured
    if (!$thumb || $thumb->isError()) {
        // Randomize TTL to reduce stampedes
        $wgMemc->incrWithInit($key, 3600 + mt_rand(0, 300));
    }
    return array($thumb, $errorHtml);
}