Exemple #1
0
 public function execute()
 {
     $stdin = $this->getStdin();
     $urls = array();
     while (!feof($stdin)) {
         $page = trim(fgets($stdin));
         if (substr($page, 0, 7) == 'http://') {
             $urls[] = $page;
         } elseif ($page !== '') {
             $title = Title::newFromText($page);
             if ($title) {
                 $url = $title->getFullUrl();
                 $this->output("{$url}\n");
                 $urls[] = $url;
                 if (isset($options['purge'])) {
                     $title->invalidateCache();
                 }
             } else {
                 $this->output("(Invalid title '{$page}')\n");
             }
         }
     }
     $this->output("Purging " . count($urls) . " urls...\n");
     $u = new SquidUpdate($urls);
     $u->doUpdate();
     $this->output("Done!\n");
 }
 public function execute()
 {
     global $wgUser, $wgArticleFeedbackRatingTypes, $wgArticleFeedbackSMaxage, $wgArticleFeedbackNamespaces;
     $params = $this->extractRequestParams();
     // Anon token check
     if ($wgUser->isAnon()) {
         if (!isset($params['anontoken'])) {
             $this->dieUsageMsg(array('missingparam', 'anontoken'));
         } elseif (strlen($params['anontoken']) != 32) {
             $this->dieUsage('The anontoken is not 32 characters', 'invalidtoken');
         }
         $token = $params['anontoken'];
     } else {
         $token = '';
     }
     // Load check, is this page ArticleFeedback-enabled ?
     // Keep in sync with ext.articleFeedback.startup.js
     $title = Title::newFromID($params['pageid']);
     if (is_null($title) || !in_array($title->getNamespace(), $wgArticleFeedbackNamespaces) || $title->isRedirect()) {
         // ...then error out
         $this->dieUsage('ArticleFeedback is not enabled on this page', 'invalidpage');
     }
     $dbw = wfGetDB(DB_MASTER);
     // Query the latest ratings by this user for this page,
     // possibly for an older revision
     // Select from the master to prevent replag-induced bugs
     $res = $dbw->select('article_feedback', array('aa_rating_id', 'aa_rating_value', 'aa_revision'), array('aa_user_text' => $wgUser->getName(), 'aa_page_id' => $params['pageid'], 'aa_rating_id' => array_keys($wgArticleFeedbackRatingTypes), 'aa_user_anon_token' => $token), __METHOD__, array('ORDER BY' => 'aa_revision DESC', 'LIMIT' => count($wgArticleFeedbackRatingTypes)));
     $lastRatings = array();
     foreach ($res as $row) {
         $lastRatings[$row->aa_rating_id]['value'] = $row->aa_rating_value;
         $lastRatings[$row->aa_rating_id]['revision'] = $row->aa_revision;
     }
     $pageId = $params['pageid'];
     $revisionId = $params['revid'];
     foreach ($wgArticleFeedbackRatingTypes as $ratingID => $unused) {
         $lastPageRating = false;
         $lastRevRating = false;
         if (isset($lastRatings[$ratingID])) {
             $lastPageRating = intval($lastRatings[$ratingID]['value']);
             if (intval($lastRatings[$ratingID]['revision']) == $revisionId) {
                 $lastRevRating = $lastPageRating;
             }
         }
         $thisRating = false;
         if (isset($params["r{$ratingID}"])) {
             $thisRating = intval($params["r{$ratingID}"]);
         }
         $this->insertRevisionRating($pageId, $revisionId, $ratingID, $thisRating - $lastRevRating, $thisRating, $lastRevRating);
         $this->insertPageRating($pageId, $ratingID, $thisRating - $lastPageRating, $thisRating, $lastPageRating);
         $this->insertUserRatings($pageId, $revisionId, $wgUser, $token, $ratingID, $thisRating, $params['bucket']);
     }
     $this->insertProperties($revisionId, $wgUser, $token, $params);
     $squidUpdate = new SquidUpdate(array(wfAppendQuery(wfScript('api'), array('action' => 'query', 'format' => 'json', 'list' => 'articlefeedback', 'afpageid' => $pageId, 'afanontoken' => '', 'afuserrating' => 0, 'maxage' => 0, 'smaxage' => $wgArticleFeedbackSMaxage))));
     $squidUpdate->doUpdate();
     wfRunHooks('ArticleFeedbackChangeRating', array($params));
     $r = array('result' => 'Success');
     $this->getResult()->addValue(null, $this->getModuleName(), $r);
 }
Exemple #3
0
 public function purgeVarnish()
 {
     global $wgHubRssFeeds, $wgServer;
     echo "| Purging varnishen..." . PHP_EOL;
     $urls = [];
     foreach ($wgHubRssFeeds as $feedEndpoint) {
         $urls[] = SpecialPage::getTitleFor(HubRssFeedSpecialController::SPECIAL_NAME)->getFullUrl() . '/' . $feedEndpoint;
         $urls[] = implode('/', [$wgServer, 'rss', $feedEndpoint]);
     }
     $u = new SquidUpdate($urls);
     $u->doUpdate();
 }
Exemple #4
0
function renderTimeline($timelinesrc)
{
    global $wgUploadDirectory, $wgUploadPath, $IP, $wgTimelineSettings, $wgArticlePath, $wgTmpDirectory;
    $hash = md5($timelinesrc);
    $dest = $wgUploadDirectory . "/timeline/";
    if (!is_dir($dest)) {
        mkdir($dest, 0777);
    }
    if (!is_dir($wgTmpDirectory)) {
        mkdir($wgTmpDirectory, 0777);
    }
    $fname = $dest . $hash;
    $previouslyFailed = file_exists($fname . ".err");
    $previouslyRendered = file_exists($fname . ".png");
    $expired = $previouslyRendered && filemtime($fname . ".png") < wfTimestamp(TS_UNIX, $wgTimelineSettings->epochTimestamp);
    if ($expired || !$previouslyRendered && !$previouslyFailed) {
        $handle = fopen($fname, "w");
        fwrite($handle, $timelinesrc);
        fclose($handle);
        $cmdline = wfEscapeShellArg($wgTimelineSettings->perlCommand, $wgTimelineSettings->timelineFile) . " -i " . wfEscapeShellArg($fname) . " -m -P " . wfEscapeShellArg($wgTimelineSettings->ploticusCommand) . " -T " . wfEscapeShellArg($wgTmpDirectory) . " -A " . wfEscapeShellArg($wgArticlePath);
        $ret = `{$cmdline}`;
        unlink($fname);
        if ($ret == "") {
            // Message not localized, only relevant during install
            return "<div id=\"toc\"><tt>Timeline error: Executable not found. Command line was: {$cmdline}</tt></div>";
        }
    }
    @($err = file_get_contents($fname . ".err"));
    if ($err != "") {
        $txt = "<div id=\"toc\"><tt>{$err}</tt></div>";
    } else {
        @($map = file_get_contents($fname . ".map"));
        if (substr(php_uname(), 0, 7) == "Windows") {
            $ext = "gif";
        } else {
            $ext = "png";
        }
        $url = "{$wgUploadPath}/timeline/{$hash}.{$ext}";
        $txt = "<map name=\"{$hash}\">{$map}</map>" . "<img usemap=\"#{$hash}\" src=\"{$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;
}
 /**
  * Purge the cache for backlinking pages (that is, pages containing
  * a reference to the Title associated with this task)
  *
  * @param string|array $tables
  */
 public function purge($tables)
 {
     global $wgUseFileCache, $wgUseSquid;
     $affectedTitles = $this->getAffectedTitles((array) $tables);
     $affectedCount = count($affectedTitles);
     $this->info("Purge Request", ['title' => $this->title->getPrefixedText(), 'count' => $affectedCount, 'tables' => $tables]);
     // abort if no pages link to the associated Title
     if ($affectedCount == 0) {
         return 0;
     }
     $dbw = wfGetDB(DB_MASTER);
     (new \WikiaSQL())->UPDATE('page')->SET('page_touched', $dbw->timestamp())->WHERE('page_id')->IN(array_map(function ($t) {
         return $t->getArticleID();
     }, $affectedTitles))->run($dbw);
     // Update squid/varnish
     if ($wgUseSquid) {
         \SquidUpdate::newFromTitles($affectedTitles)->doUpdate();
     }
     // Update file cache
     if ($wgUseFileCache) {
         foreach ($affectedTitles as $title) {
             \HTMLFileCache::clearFileCache($title);
         }
     }
     return $affectedCount;
 }
Exemple #6
0
 /**
  * Invalidate a set of pages, right now
  */
 public function invalidate($startId = false, $endId = false)
 {
     global $wgUseFileCache, $wgUseSquid;
     $titleArray = $this->mCache->getLinks($this->mTable, $startId, $endId);
     if ($titleArray->count() == 0) {
         return;
     }
     $dbw = wfGetDB(DB_MASTER);
     $timestamp = $dbw->timestamp();
     # Get all IDs in this query into an array
     $ids = array();
     foreach ($titleArray as $title) {
         $ids[] = $title->getArticleID();
     }
     # Update page_touched
     $dbw->update('page', array('page_touched' => $timestamp), array('page_id IN (' . $dbw->makeList($ids) . ')'), __METHOD__);
     # Update squid
     if ($wgUseSquid) {
         $u = SquidUpdate::newFromTitles($titleArray);
         $u->doUpdate();
     }
     # Update file cache
     if ($wgUseFileCache) {
         foreach ($titleArray as $title) {
             HTMLFileCache::clearFileCache($title);
         }
     }
 }
 /**
  * Record a file upload in the upload log and the image table
  */
 function recordUpload2($oldver, $comment, $pageText, $props = false, $timestamp = false, $user = null)
 {
     if (is_null($user)) {
         global $wgUser;
         $user = $wgUser;
     }
     $dbw = $this->repo->getMasterDB();
     $dbw->begin();
     if (!$props) {
         $props = $this->repo->getFileProps($this->getVirtualUrl());
     }
     $props['description'] = $comment;
     $props['user'] = $user->getId();
     $props['user_text'] = $user->getName();
     $props['timestamp'] = wfTimestamp(TS_MW);
     $this->setProps($props);
     // Delete thumbnails and refresh the metadata cache
     $this->purgeThumbnails();
     $this->saveToCache();
     SquidUpdate::purge(array($this->getURL()));
     /* Wikia change begin - @author: Marooned, see RT#44185 */
     global $wgLogo;
     if ($this->url == $wgLogo) {
         SquidUpdate::purge(array($this->url));
     }
     /* Wikia change end */
     // Fail now if the file isn't there
     if (!$this->fileExists) {
         wfDebug(__METHOD__ . ": File " . $this->getPath() . " went missing!\n");
         return false;
     }
     $reupload = false;
     if ($timestamp === false) {
         $timestamp = $dbw->timestamp();
     }
     # Test to see if the row exists using INSERT IGNORE
     # This avoids race conditions by locking the row until the commit, and also
     # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition.
     $dbw->insert('image', array('img_name' => $this->getName(), 'img_size' => $this->size, 'img_width' => intval($this->width), 'img_height' => intval($this->height), 'img_bits' => $this->bits, 'img_media_type' => $this->media_type, 'img_major_mime' => $this->major_mime, 'img_minor_mime' => $this->minor_mime, 'img_timestamp' => $timestamp, 'img_description' => $comment, 'img_user' => $user->getId(), 'img_user_text' => $user->getName(), 'img_metadata' => $this->metadata, 'img_sha1' => $this->sha1), __METHOD__, 'IGNORE');
     if ($dbw->affectedRows() == 0) {
         $reupload = true;
         # Collision, this is an update of a file
         # Insert previous contents into oldimage
         $dbw->insertSelect('oldimage', 'image', array('oi_name' => 'img_name', 'oi_archive_name' => $dbw->addQuotes($oldver), 'oi_size' => 'img_size', 'oi_width' => 'img_width', 'oi_height' => 'img_height', 'oi_bits' => 'img_bits', 'oi_timestamp' => 'img_timestamp', 'oi_description' => 'img_description', 'oi_user' => 'img_user', 'oi_user_text' => 'img_user_text', 'oi_metadata' => 'img_metadata', 'oi_media_type' => 'img_media_type', 'oi_major_mime' => 'img_major_mime', 'oi_minor_mime' => 'img_minor_mime', 'oi_sha1' => 'img_sha1'), array('img_name' => $this->getName()), __METHOD__);
         # Update the current image row
         $dbw->update('image', array('img_size' => $this->size, 'img_width' => intval($this->width), 'img_height' => intval($this->height), 'img_bits' => $this->bits, 'img_media_type' => $this->media_type, 'img_major_mime' => $this->major_mime, 'img_minor_mime' => $this->minor_mime, 'img_timestamp' => $timestamp, 'img_description' => $comment, 'img_user' => $user->getId(), 'img_user_text' => $user->getName(), 'img_metadata' => $this->metadata, 'img_sha1' => $this->sha1), array('img_name' => $this->getName()), __METHOD__);
     } else {
         # This is a new file
         # Update the image count
         $site_stats = $dbw->tableName('site_stats');
         $dbw->query("UPDATE {$site_stats} SET ss_images=ss_images+1", __METHOD__);
     }
     # Commit the transaction now, in case something goes wrong later
     # The most important thing is that files don't get lost, especially archives
     $dbw->commit();
     # Invalidate cache for all pages using this file
     $update = new HTMLCacheUpdate($this->getTitle(), 'imagelinks');
     $update->doUpdate();
     return true;
 }
 private function purge($url, $var, $typeVal, $val, $likeVal)
 {
     $wikis = $this->getListOfWikisWithVar($var, $typeVal, $val, $likeVal);
     $purgeUrls = array();
     foreach ($wikis as $cityId => $wikiData) {
         $purgeUrls[] = $wikiData['u'] . $url;
     }
     SquidUpdate::purge($purgeUrls);
     return $purgeUrls;
 }
/** @todo document */
function benchSquid($urls, $trials = 1)
{
    $start = wfTime();
    for ($i = 0; $i < $trials; $i++) {
        SquidUpdate::purge($urls);
    }
    $delta = wfTime() - $start;
    $pertrial = $delta / $trials;
    $pertitle = $pertrial / count($urls);
    return sprintf("%4d titles in %6.2fms (%6.2fms each)", count($urls), $pertrial * 1000.0, $pertitle * 1000.0);
}
Exemple #10
0
 /**
  * Remove the thumb from DFS and purge it from CDN
  *
  * @param string $thumb
  */
 private function purgeThumb($thumb)
 {
     $url = sprintf("http://images.wikia.com/%s%s/%s", $this->storage->getContainerName(), $this->storage->getPathPrefix(), $thumb);
     #$this->output(sprintf("%s: %s <%s>...", __METHOD__, $thumb, $url));
     $this->output(sprintf("%s: '%s'... ", __METHOD__, $thumb));
     if ($this->isDryRun) {
         $this->output("dry run!\n");
     } else {
         $this->storage->remove($thumb);
         SquidUpdate::purge([$url]);
         $this->output("done\n");
     }
 }
 public function execute()
 {
     $this->dryRun = $this->hasOption('dry-run');
     $this->verbose = $this->hasOption('verbose');
     $wikiId = $this->getOption('wikiId', '');
     if (empty($wikiId)) {
         die("Error: Empty wiki id.\n");
     }
     $dbname = WikiFactory::IDtoDB($wikiId);
     if (empty($dbname)) {
         die("Error: Cannot find dbname.\n");
     }
     $pageLimit = 20000;
     $totalLimit = $this->getOption('limit', $pageLimit);
     if (empty($totalLimit) || $totalLimit < -1) {
         die("Error: invalid limit.\n");
     }
     if ($totalLimit == -1) {
         $totalLimit = $this->getTotalPages($dbname);
     }
     $maxSet = ceil($totalLimit / $pageLimit);
     $limit = $totalLimit > $pageLimit ? $pageLimit : $totalLimit;
     $totalPages = 0;
     for ($set = 1; $set <= $maxSet; $set++) {
         $cnt = 0;
         if ($set == $maxSet) {
             $limit = $totalLimit - $pageLimit * ($set - 1);
         }
         $offset = ($set - 1) * $pageLimit;
         $pages = $this->getAllPages($dbname, $limit, $offset);
         $total = count($pages);
         foreach ($pages as $page) {
             $cnt++;
             echo "Wiki {$wikiId} - Page {$page['id']} [{$cnt} of {$total}, set {$set} of {$maxSet}]: ";
             $title = GlobalTitle::newFromId($page['id'], $wikiId);
             if ($title instanceof GlobalTitle) {
                 $url = $title->getFullURL();
                 echo "{$url}\n";
                 if (!$this->dryRun) {
                     SquidUpdate::purge([$url]);
                 }
                 $this->success++;
             } else {
                 echo "ERROR: Cannot find global title for {$page['title']}\n";
             }
         }
         $totalPages = $totalPages + $total;
     }
     echo "\nWiki {$wikiId}: Total pages: {$totalPages}, Success: {$this->success}, Failed: " . ($totalPages - $this->success) . "\n\n";
 }
 /**
  * Add array of URLs to the purger queue
  *
  * @param Array $urlArr list of URLs to purge
  * @throws WikiaException
  */
 static function purge($urlArr)
 {
     global $wgEnableScribeReport;
     wfProfileIn(__METHOD__);
     if (empty($wgEnableScribeReport)) {
         wfProfileOut(__METHOD__);
         return;
     }
     foreach ($urlArr as $url) {
         if (!is_string($url)) {
             throw new WikiaException('Bad purge URL');
         }
         $url = SquidUpdate::expand($url);
         $method = self::getPurgeCaller();
         wfDebug("Purging URL {$url} from {$method} via Scribe\n");
         wfDebug("Purging backtrace: " . wfGetAllCallers(false) . "\n");
         // add to the queue, will be sent by onRestInPeace method
         self::$urls[$url] = ['url' => $url, 'time' => time(), 'method' => $method];
         self::$urlsCount++;
     }
     wfProfileOut(__METHOD__);
 }
 /**
  * Invalidate an array (or iterator) of Title objects, right now
  * @param $titleArray array
  */
 protected function invalidateTitles($titleArray)
 {
     global $wgUseFileCache, $wgUseSquid;
     $dbw = wfGetDB(DB_MASTER);
     $timestamp = $dbw->timestamp();
     # Get all IDs in this query into an array
     $ids = array();
     foreach ($titleArray as $title) {
         $ids[] = $title->getArticleID();
     }
     if (!$ids) {
         return;
     }
     # Update page_touched
     $batches = array_chunk($ids, $this->mRowsPerQuery);
     foreach ($batches as $batch) {
         $dbw->update('page', array('page_touched' => $timestamp), array('page_id' => $batch), __METHOD__);
     }
     # Update squid
     if ($wgUseSquid) {
         $u = SquidUpdate::newFromTitles($titleArray);
         $u->doUpdate();
     }
     # Update file cache
     if ($wgUseFileCache) {
         foreach ($titleArray as $title) {
             HTMLFileCache::clearFileCache($title);
         }
     }
 }
Exemple #14
0
 /**
  * Helper to purge an array of $urls
  * @param array $urls List of URLS to purge from squids
  */
 private function sendPurgeRequest($urls)
 {
     if ($this->hasOption('delay')) {
         $delay = floatval($this->getOption('delay'));
         foreach ($urls as $url) {
             if ($this->hasOption('verbose')) {
                 $this->output($url . "\n");
             }
             $u = new SquidUpdate(array($url));
             $u->doUpdate();
             usleep($delay * 1000000.0);
         }
     } else {
         if ($this->hasOption('verbose')) {
             $this->output(implode("\n", $urls) . "\n");
         }
         $u = new SquidUpdate($urls);
         $u->doUpdate();
     }
 }
Exemple #15
0
 function recordUpload($oldver, $desc, $copyStatus = '', $source = '', $watch = false)
 {
     global $wgUser, $wgLang, $wgTitle, $wgDeferredUpdateList;
     global $wgUseCopyrightUpload, $wgUseSquid, $wgPostCommitUpdateList;
     $img = Image::newFromName($this->mUploadSaveName);
     $fname = 'Image::recordUpload';
     $dbw =& wfGetDB(DB_MASTER);
     Image::checkDBSchema($dbw);
     // Delete thumbnails and refresh the metadata cache
     $img->purgeCache();
     // Fail now if the image isn't there
     if (!$img->fileExists || $img->fromSharedDirectory) {
         wfDebug("Image::recordUpload: File " . $img->imagePath . " went missing!\n");
         return false;
     }
     if ($wgUseCopyrightUpload) {
         $textdesc = '== ' . wfMsg('filedesc') . " ==\n" . $desc . "\n" . '== ' . wfMsg('filestatus') . " ==\n" . $copyStatus . "\n" . '== ' . wfMsg('filesource') . " ==\n" . $source;
     } else {
         $textdesc = $desc;
     }
     $now = $dbw->timestamp();
     #split mime type
     if (strpos($img->mime, '/') !== false) {
         list($major, $minor) = explode('/', $img->mime, 2);
     } else {
         $major = $img->mime;
         $minor = "unknown";
     }
     # Test to see if the row exists using INSERT IGNORE
     # This avoids race conditions by locking the row until the commit, and also
     # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition.
     $dbw->insert('image', array('img_name' => $img->name, 'img_size' => $img->size, 'img_width' => IntVal($img->width), 'img_height' => IntVal($img->height), 'img_bits' => $img->bits, 'img_media_type' => $img->type, 'img_major_mime' => $major, 'img_minor_mime' => $minor, 'img_timestamp' => $now, 'img_description' => $desc, 'img_user' => $wgUser->getID(), 'img_user_text' => $wgUser->getName(), 'img_metadata' => $img->metadata), $fname, 'IGNORE');
     $descTitle = $img->getTitle();
     $purgeURLs = array();
     $article = new Article($descTitle);
     $minor = false;
     $watch = $watch || $wgUser->isWatched($descTitle);
     $suppressRC = true;
     // There's already a log entry, so don't double the RC load
     if ($descTitle->exists()) {
         // TODO: insert a null revision into the page history for this update.
         if ($watch) {
             $wgUser->addWatch($descTitle);
         }
         # Invalidate the cache for the description page
         $descTitle->invalidateCache();
         $purgeURLs[] = $descTitle->getInternalURL();
     } else {
         $this->insertNewArticle($article, $textdesc, $desc, $minor, $watch, $suppressRC);
     }
     # Invalidate cache for all pages using this image
     $linksTo = $img->getLinksTo();
     if ($wgUseSquid) {
         $u = SquidUpdate::newFromTitles($linksTo, $purgeURLs);
         array_push($wgPostCommitUpdateList, $u);
     }
     Title::touchArray($linksTo);
     $log = new LogPage('upload');
     $log->addEntry('upload', $descTitle, $desc);
     return true;
 }
Exemple #16
0
 /**
  * Transform a media file
  *
  * @param array $params An associative array of handler-specific parameters. Typical
  *                      keys are width, height and page.
  * @param integer $flags A bitfield, may contain self::RENDER_NOW to force rendering
  * @return MediaTransformOutput
  */
 function transform($params, $flags = 0)
 {
     global $wgUseSquid, $wgIgnoreImageErrors;
     wfProfileIn(__METHOD__);
     do {
         if (!$this->canRender()) {
             // not a bitmap or renderable image, don't try.
             $thumb = $this->iconThumb();
             break;
         }
         $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);
         $thumbPath = $this->getThumbPath($thumbName);
         $thumbUrl = $this->getThumbUrl($thumbName);
         if ($this->repo->canTransformVia404() && !($flags & self::RENDER_NOW)) {
             $thumb = $this->handler->getTransform($this, $thumbPath, $thumbUrl, $params);
             break;
         }
         wfDebug(__METHOD__ . ": Doing stat for {$thumbPath}\n");
         $this->migrateThumbFile($thumbName);
         if (file_exists($thumbPath)) {
             $thumb = $this->handler->getTransform($this, $thumbPath, $thumbUrl, $params);
             break;
         }
         $thumb = $this->handler->doTransform($this, $thumbPath, $thumbUrl, $params);
         // Ignore errors if requested
         if (!$thumb) {
             $thumb = null;
         } elseif ($thumb->isError()) {
             $this->lastError = $thumb->toText();
             if ($wgIgnoreImageErrors && !($flags & self::RENDER_NOW)) {
                 $thumb = $this->handler->getTransform($this, $thumbPath, $thumbUrl, $params);
             }
         }
         // 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 && (!$thumb || $thumb->isError() || $thumb->getUrl() != $this->getURL())) {
             SquidUpdate::purge(array($thumbUrl));
         }
     } while (false);
     wfProfileOut(__METHOD__);
     return $thumb;
 }
Exemple #17
0
 /**
  * Delete an old version of the file.
  *
  * Moves the file into an archive directory (or deletes it)
  * and removes the database row.
  *
  * Cache purging is done; logging is caller's responsibility.
  *
  * @param string $archiveName
  * @param string $reason
  * @param bool $suppress
  * @throws MWException Exception on database or file store failure
  * @return FileRepoStatus
  */
 function deleteOld($archiveName, $reason, $suppress = false)
 {
     global $wgUseSquid;
     if ($this->getRepo()->getReadOnlyReason() !== false) {
         return $this->readOnlyFatalStatus();
     }
     $batch = new LocalFileDeleteBatch($this, $reason, $suppress);
     $this->lock();
     // begin
     $batch->addOld($archiveName);
     $status = $batch->execute();
     $this->unlock();
     // done
     $this->purgeOldThumbnails($archiveName);
     if ($status->isOK()) {
         $this->purgeDescription();
         $this->purgeHistory();
     }
     if ($wgUseSquid) {
         // Purge the squid
         SquidUpdate::purge(array($this->getArchiveUrl($archiveName)));
     }
     return $status;
 }
Exemple #18
0
 /**
  * Run the transaction
  */
 function execute()
 {
     global $wgUseSquid;
     wfProfileIn(__METHOD__);
     $this->file->lock();
     // Leave private files alone
     $privateFiles = array();
     list($oldRels, $deleteCurrent) = $this->getOldRels();
     $dbw = $this->file->repo->getMasterDB();
     if (!empty($oldRels)) {
         $res = $dbw->select('oldimage', array('oi_archive_name'), array('oi_name' => $this->file->getName(), 'oi_archive_name IN (' . $dbw->makeList(array_keys($oldRels)) . ')', $dbw->bitAnd('oi_deleted', File::DELETED_FILE) => File::DELETED_FILE), __METHOD__);
         foreach ($res as $row) {
             $privateFiles[$row->oi_archive_name] = 1;
         }
     }
     // Prepare deletion batch
     $hashes = $this->getHashes();
     $this->deletionBatch = array();
     $ext = $this->file->getExtension();
     $dotExt = $ext === '' ? '' : ".{$ext}";
     foreach ($this->srcRels as $name => $srcRel) {
         // Skip files that have no hash (missing source).
         // Keep private files where they are.
         if (isset($hashes[$name]) && !array_key_exists($name, $privateFiles)) {
             $hash = $hashes[$name];
             $key = $hash . $dotExt;
             $dstRel = $this->file->repo->getDeletedHashPath($key) . $key;
             $this->deletionBatch[$name] = array($srcRel, $dstRel);
         }
     }
     // Lock the filearchive rows so that the files don't get deleted by a cleanup operation
     // We acquire this lock by running the inserts now, before the file operations.
     //
     // This potentially has poor lock contention characteristics -- an alternative
     // scheme would be to insert stub filearchive entries with no fa_name and commit
     // them in a separate transaction, then run the file ops, then update the fa_name fields.
     $this->doDBInserts();
     // Removes non-existent file from the batch, so we don't get errors.
     $this->deletionBatch = $this->removeNonexistentFiles($this->deletionBatch);
     // Execute the file deletion batch
     $status = $this->file->repo->deleteBatch($this->deletionBatch);
     if (!$status->isGood()) {
         $this->status->merge($status);
     }
     if (!$this->status->ok) {
         // Critical file deletion error
         // Roll back inserts, release lock and abort
         // TODO: delete the defunct filearchive rows if we are using a non-transactional DB
         $this->file->unlockAndRollback();
         wfProfileOut(__METHOD__);
         return $this->status;
     }
     // Purge squid
     if ($wgUseSquid) {
         $urls = array();
         foreach ($this->srcRels as $srcRel) {
             $urlRel = str_replace('%2F', '/', rawurlencode($srcRel));
             $urls[] = $this->file->repo->getZoneUrl('public') . '/' . $urlRel;
         }
         SquidUpdate::purge($urls);
     }
     // Delete image/oldimage rows
     $this->doDBDeletes();
     // Commit and return
     $this->file->unlock();
     wfProfileOut(__METHOD__);
     return $this->status;
 }
Exemple #19
0
 /**
  * Perform the actions of a page purging
  */
 public function doPurge()
 {
     global $wgUseSquid;
     // Invalidate the cache
     $this->mTitle->invalidateCache();
     if ($wgUseSquid) {
         // Commit the transaction before the purge is sent
         $dbw = wfGetDB(DB_MASTER);
         $dbw->commit();
         // Send purge
         $update = SquidUpdate::newSimplePurge($this->mTitle);
         $update->doUpdate();
     }
     if ($this->mTitle->getNamespace() == NS_MEDIAWIKI) {
         global $wgMessageCache;
         if ($this->getID() == 0) {
             $text = false;
         } else {
             $text = $this->getRawText();
         }
         $wgMessageCache->replace($this->mTitle->getDBkey(), $text);
     }
 }
 /**
  * Queue a purge operation
  *
  * @param string $url
  */
 public function queuePurge($url)
 {
     global $wgSquidPurgeUseHostHeader;
     $url = SquidUpdate::expand(str_replace("\n", '', $url));
     $request = array();
     if ($wgSquidPurgeUseHostHeader) {
         $url = wfParseUrl($url);
         $host = $url['host'];
         if (isset($url['port']) && strlen($url['port']) > 0) {
             $host .= ":" . $url['port'];
         }
         $path = $url['path'];
         if (isset($url['query']) && is_string($url['query'])) {
             $path = wfAppendQuery($path, $url['query']);
         }
         $request[] = "PURGE {$path} HTTP/1.1";
         $request[] = "Host: {$host}";
     } else {
         $request[] = "PURGE {$url} HTTP/1.0";
     }
     $request[] = "Connection: Keep-Alive";
     $request[] = "Proxy-Connection: Keep-Alive";
     $request[] = "User-Agent: " . Http::userAgent() . ' ' . __CLASS__;
     // Two ''s to create \r\n\r\n
     $request[] = '';
     $request[] = '';
     $this->requests[] = implode("\r\n", $request);
     if ($this->currentRequestIndex === null) {
         $this->nextRequest();
     }
 }
<?php

/**
 * Send purge requests for listed pages to squid
 */
require_once "commandLine.inc";
$stdin = fopen("php://stdin", "rt");
$urls = array();
while (!feof($stdin)) {
    $page = trim(fgets($stdin));
    if (substr($page, 0, 7) == 'http://') {
        $urls[] = $page;
    } elseif ($page !== '') {
        $title = Title::newFromText($page);
        if ($title) {
            $url = $title->getFullUrl();
            echo "{$url}\n";
            $urls[] = $url;
            if (isset($options['purge'])) {
                $title->invalidateCache();
            }
        } else {
            echo "(Invalid title '{$page}')\n";
        }
    }
}
echo "Purging " . count($urls) . " urls...\n";
$u = new SquidUpdate($urls);
$u->doUpdate();
echo "Done!\n";
Exemple #22
0
 /**
  * Record a file upload in the upload log and the image table
  */
 function recordUpload2($oldver, $comment, $pageText, $props = false, $timestamp = false, $user = null)
 {
     if (is_null($user)) {
         global $wgUser;
         $user = $wgUser;
     }
     $dbw = $this->repo->getMasterDB();
     $dbw->begin();
     if (!$props) {
         $props = $this->repo->getFileProps($this->getVirtualUrl());
     }
     $props['description'] = $comment;
     $props['user'] = $user->getId();
     $props['user_text'] = $user->getName();
     $props['timestamp'] = wfTimestamp(TS_MW);
     $this->setProps($props);
     // Delete thumbnails and refresh the metadata cache
     $this->purgeThumbnails();
     $this->saveToCache();
     SquidUpdate::purge(array($this->getURL()));
     // Fail now if the file isn't there
     if (!$this->fileExists) {
         wfDebug(__METHOD__ . ": File " . $this->getPath() . " went missing!\n");
         return false;
     }
     $reupload = false;
     if ($timestamp === false) {
         $timestamp = $dbw->timestamp();
     }
     # Test to see if the row exists using INSERT IGNORE
     # This avoids race conditions by locking the row until the commit, and also
     # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition.
     $dbw->insert('image', array('img_name' => $this->getName(), 'img_size' => $this->size, 'img_width' => intval($this->width), 'img_height' => intval($this->height), 'img_bits' => $this->bits, 'img_media_type' => $this->media_type, 'img_major_mime' => $this->major_mime, 'img_minor_mime' => $this->minor_mime, 'img_timestamp' => $timestamp, 'img_description' => $comment, 'img_user' => $user->getId(), 'img_user_text' => $user->getName(), 'img_metadata' => $this->metadata, 'img_sha1' => $this->sha1), __METHOD__, 'IGNORE');
     if ($dbw->affectedRows() == 0) {
         $reupload = true;
         # Collision, this is an update of a file
         # Insert previous contents into oldimage
         $dbw->insertSelect('oldimage', 'image', array('oi_name' => 'img_name', 'oi_archive_name' => $dbw->addQuotes($oldver), 'oi_size' => 'img_size', 'oi_width' => 'img_width', 'oi_height' => 'img_height', 'oi_bits' => 'img_bits', 'oi_timestamp' => 'img_timestamp', 'oi_description' => 'img_description', 'oi_user' => 'img_user', 'oi_user_text' => 'img_user_text', 'oi_metadata' => 'img_metadata', 'oi_media_type' => 'img_media_type', 'oi_major_mime' => 'img_major_mime', 'oi_minor_mime' => 'img_minor_mime', 'oi_sha1' => 'img_sha1'), array('img_name' => $this->getName()), __METHOD__);
         # Update the current image row
         $dbw->update('image', array('img_size' => $this->size, 'img_width' => intval($this->width), 'img_height' => intval($this->height), 'img_bits' => $this->bits, 'img_media_type' => $this->media_type, 'img_major_mime' => $this->major_mime, 'img_minor_mime' => $this->minor_mime, 'img_timestamp' => $timestamp, 'img_description' => $comment, 'img_user' => $user->getId(), 'img_user_text' => $user->getName(), 'img_metadata' => $this->metadata, 'img_sha1' => $this->sha1), array('img_name' => $this->getName()), __METHOD__);
     } else {
         # This is a new file
         # Update the image count
         $site_stats = $dbw->tableName('site_stats');
         $dbw->query("UPDATE {$site_stats} SET ss_images=ss_images+1", __METHOD__);
     }
     $descTitle = $this->getTitle();
     $wikiPage = new WikiFilePage($descTitle);
     $wikiPage->setFile($this);
     # Add the log entry...
     $action = $reupload ? 'overwrite' : 'upload';
     $logEntry = new ManualLogEntry('upload', $action);
     $logEntry->setTimestamp($this->timestamp);
     $logEntry->setPerformer($user);
     $logEntry->setComment($comment);
     $logEntry->setTarget($descTitle);
     // Allow people using the api to associate log entries with the upload.
     // Log has a timestamp, but sometimes different from upload timestamp.
     $logEntry->setParameters(array('img_sha1' => $this->sha1, 'img_timestamp' => $timestamp));
     // Note we keep $logId around since during new image
     // creation, page doesn't exist yet, so log_page = 0
     // but we want it to point to the page we're making,
     // so we later modify the log entry.
     // For a similar reason, we avoid making an RC entry
     // now and wait until the page exists.
     $logId = $logEntry->insert();
     $exists = $descTitle->exists();
     if ($exists) {
         // Page exists, do RC entry now (otherwise we wait for later).
         $logEntry->publish($logId);
         // TODO: same if statement twice? pointless?
         //}
         //if ( $exists ) {
         // Create a null revision
         $latest = $descTitle->getLatestRevID();
         // Use own context to get the action text in content language
         $formatter = LogFormatter::newFromEntry($logEntry);
         $formatter->setContext(RequestContext::newExtraneousContext($descTitle));
         $editSummary = $formatter->getPlainActionText();
         $nullRevision = Revision::newNullRevision($dbw, $descTitle->getArticleID(), $editSummary, false, $user);
         if (!is_null($nullRevision)) {
             $nullRevision->insertOn($dbw);
             Hooks::run('NewRevisionFromEditComplete', array($wikiPage, $nullRevision, $nullRevision->getParentId(), $user));
             $wikiPage->updateRevisionOn($dbw, $nullRevision);
         }
     }
     # Commit the transaction now, in case something goes wrong later
     # The most important thing is that files don't get lost, especially archives
     # NOTE: once we have support for nested transactions, the commit may be moved
     #       to after $wikiPage->doEdit has been called.
     $dbw->commit(__METHOD__);
     # Update memcache after the commit
     $this->invalidateCache();
     if ($exists) {
         # Invalidate the cache for the description page
         $descTitle->invalidateCache();
         $descTitle->purgeSquid();
     } else {
         # New file; create the description page.
         # There's already a log entry, so don't make a second RC entry
         # Squid and file cache for the description page are purged by doEditContent.
         $content = ContentHandler::makeContent($pageText, $descTitle);
         $status = $wikiPage->doEditContent($content, $comment, EDIT_NEW | EDIT_SUPPRESS_RC, false, $user);
         $dbw->begin(__METHOD__);
         // XXX; doEdit() uses a transaction
         // Now that the page exists, make an RC entry.
         $logEntry->publish($logId);
         if (isset($status->value['revision'])) {
             $dbw->update('logging', array('log_page' => $status->value['revision']->getPage()), array('log_id' => $logId), __METHOD__);
         }
         $dbw->commit(__METHOD__);
         // commit before anything bad can happen
     }
     if ($reupload) {
         # Delete old thumbnails
         $this->purgeThumbnails();
         # Remove the old file from the squid cache
         SquidUpdate::purge(array($this->getURL()));
     }
     # Hooks, hooks, the magic of hooks...
     Hooks::run('FileUpload', array($this, $reupload, $descTitle->exists()));
     # Invalidate cache for all pages using this file
     $update = new HTMLCacheUpdate($this->getTitle(), 'imagelinks');
     $update->doUpdate();
     if (!$reupload) {
         LinksUpdate::queueRecursiveJobsForTable($this->getTitle(), 'imagelinks');
     }
     return true;
 }
 /**
  * Invalidate a set of IDs, right now
  */
 function invalidateIDs(ResultWrapper $res)
 {
     global $wgUseFileCache, $wgUseSquid;
     if ($res->numRows() == 0) {
         return;
     }
     $dbw =& wfGetDB(DB_MASTER);
     $timestamp = $dbw->timestamp();
     $done = false;
     while (!$done) {
         # Get all IDs in this query into an array
         $ids = array();
         for ($i = 0; $i < $this->mRowsPerQuery; $i++) {
             $row = $res->fetchRow();
             if ($row) {
                 $ids[] = $row[0];
             } else {
                 $done = true;
                 break;
             }
         }
         if (!count($ids)) {
             break;
         }
         # Update page_touched
         $dbw->update('page', array('page_touched' => $timestamp), array('page_id IN (' . $dbw->makeList($ids) . ')'), __METHOD__);
         # Update squid
         if ($wgUseSquid || $wgUseFileCache) {
             $titles = Title::newFromIDs($ids);
             if ($wgUseSquid) {
                 $u = SquidUpdate::newFromTitles($titles);
                 $u->doUpdate();
             }
             # Update file cache
             if ($wgUseFileCache) {
                 foreach ($titles as $title) {
                     $cm = new CacheManager($title);
                     @unlink($cm->fileCacheName());
                 }
             }
         }
     }
 }
Exemple #24
0
 /**
  * Perform the actions of a page purging
  * @return bool
  */
 public function doPurge()
 {
     if (!Hooks::run('ArticlePurge', array(&$this))) {
         return false;
     }
     $title = $this->mTitle;
     wfGetDB(DB_MASTER)->onTransactionIdle(function () use($title) {
         global $wgUseSquid;
         // Invalidate the cache in auto-commit mode
         $title->invalidateCache();
         if ($wgUseSquid) {
             // Send purge now that page_touched update was committed above
             $update = new SquidUpdate($title->getSquidURLs());
             $update->doUpdate();
         }
     });
     if ($this->mTitle->getNamespace() == NS_MEDIAWIKI) {
         // @todo move this logic to MessageCache
         if ($this->exists()) {
             // NOTE: use transclusion text for messages.
             //       This is consistent with  MessageCache::getMsgFromNamespace()
             $content = $this->getContent();
             $text = $content === null ? null : $content->getWikitextForTransclusion();
             if ($text === null) {
                 $text = false;
             }
         } else {
             $text = false;
         }
         MessageCache::singleton()->replace($this->mTitle->getDBkey(), $text);
     }
     return true;
 }
Exemple #25
0
 /**
  * Purge all applicable Squid URLs
  */
 public function purgeSquid()
 {
     global $wgUseSquid;
     if ($wgUseSquid) {
         $urls = $this->getSquidURLs();
         $u = new SquidUpdate($urls);
         $u->doUpdate();
     }
 }
 /**
  * Invalidate an array (or iterator) of Title objects, right now
  * @param $titleArray array
  */
 protected function invalidateTitles($titleArray)
 {
     global $wgUseFileCache, $wgUseSquid;
     $dbw = wfGetDB(DB_MASTER);
     $timestamp = $dbw->timestamp();
     # Get all IDs in this query into an array
     $ids = array();
     foreach ($titleArray as $title) {
         $ids[] = $title->getArticleID();
     }
     if (!$ids) {
         return;
     }
     # Don't invalidated pages that were already invalidated
     $touchedCond = isset($this->params['rootJobTimestamp']) ? array("page_touched < " . $dbw->addQuotes($dbw->timestamp($this->params['rootJobTimestamp']))) : array();
     # Update page_touched
     $batches = array_chunk($ids, $this->rowsPerQuery);
     foreach ($batches as $batch) {
         $dbw->update('page', array('page_touched' => $timestamp), array('page_id' => $batch) + $touchedCond, __METHOD__);
     }
     # Update squid
     if ($wgUseSquid) {
         $u = SquidUpdate::newFromTitles($titleArray);
         $u->doUpdate();
     }
     # Update file cache
     if ($wgUseFileCache) {
         foreach ($titleArray as $title) {
             HTMLFileCache::clearFileCache($title);
         }
     }
 }
Exemple #27
0
	/**
	 * Perform the actions of a page purging
	 * @return bool
	 */
	public function doPurge() {
		global $wgUseSquid;

		if ( !wfRunHooks( 'ArticlePurge', array( &$this ) ) ) {
			return false;
		}

		// Invalidate the cache
		$this->mTitle->invalidateCache();

		if ( $wgUseSquid ) {
			// Commit the transaction before the purge is sent
			$dbw = wfGetDB( DB_MASTER );
			$dbw->commit( __METHOD__ );

			// Send purge
			$update = SquidUpdate::newSimplePurge( $this->mTitle );
			$update->doUpdate();
		}

		if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
			// @todo move this logic to MessageCache

			if ( $this->exists() ) {
				// NOTE: use transclusion text for messages.
				//       This is consistent with  MessageCache::getMsgFromNamespace()

				$content = $this->getContent();
				$text = $content === null ? null : $content->getWikitextForTransclusion();

				if ( $text === null ) {
					$text = false;
				}
			} else {
				$text = false;
			}

			MessageCache::singleton()->replace( $this->mTitle->getDBkey(), $text );
		}
		return true;
	}
Exemple #28
0
 /**
  * Move page to a title which is at present a redirect to the
  * source page
  *
  * @param Title &$nt the page to move to, which should currently
  * 	be a redirect
  */
 private function moveOverExistingRedirect(&$nt, $reason = '')
 {
     global $wgUseSquid;
     $fname = 'Title::moveOverExistingRedirect';
     $comment = wfMsgForContent('1movedto2_redir', $this->getPrefixedText(), $nt->getPrefixedText());
     if ($reason) {
         $comment .= ": {$reason}";
     }
     $now = wfTimestampNow();
     $newid = $nt->getArticleID();
     $oldid = $this->getArticleID();
     $dbw = wfGetDB(DB_MASTER);
     $linkCache =& LinkCache::singleton();
     # Delete the old redirect. We don't save it to history since
     # by definition if we've got here it's rather uninteresting.
     # We have to remove it so that the next step doesn't trigger
     # a conflict on the unique namespace+title index...
     $dbw->delete('page', array('page_id' => $newid), $fname);
     # Save a null revision in the page's history notifying of the move
     $nullRevision = Revision::newNullRevision($dbw, $oldid, $comment, true);
     $nullRevId = $nullRevision->insertOn($dbw);
     # Change the name of the target page:
     $dbw->update('page', array('page_touched' => $dbw->timestamp($now), 'page_namespace' => $nt->getNamespace(), 'page_title' => $nt->getDBkey(), 'page_latest' => $nullRevId), array('page_id' => $oldid), $fname);
     $linkCache->clearLink($nt->getPrefixedDBkey());
     # Recreate the redirect, this time in the other direction.
     $mwRedir = MagicWord::get('redirect');
     $redirectText = $mwRedir->getSynonym(0) . ' [[' . $nt->getPrefixedText() . "]]\n";
     $redirectArticle = new Article($this);
     $newid = $redirectArticle->insertOn($dbw);
     $redirectRevision = new Revision(array('page' => $newid, 'comment' => $comment, 'text' => $redirectText));
     $redirectRevision->insertOn($dbw);
     $redirectArticle->updateRevisionOn($dbw, $redirectRevision, 0);
     $linkCache->clearLink($this->getPrefixedDBkey());
     # Log the move
     $log = new LogPage('move');
     $log->addEntry('move_redir', $this, $reason, array(1 => $nt->getPrefixedText()));
     # Now, we record the link from the redirect to the new title.
     # It should have no other outgoing links...
     $dbw->delete('pagelinks', array('pl_from' => $newid), $fname);
     $dbw->insert('pagelinks', array('pl_from' => $newid, 'pl_namespace' => $nt->getNamespace(), 'pl_title' => $nt->getDbKey()), $fname);
     # Purge squid
     if ($wgUseSquid) {
         $urls = array_merge($nt->getSquidURLs(), $this->getSquidURLs());
         $u = new SquidUpdate($urls);
         $u->doUpdate();
     }
 }
Exemple #29
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;
 }
Exemple #30
0
 function render()
 {
     global $wgTmpDirectory, $wgInputEncoding;
     global $wgTexvc, $wgMathCheckFiles, $wgTexvcBackgroundColor;
     if ($this->mode == MW_MATH_SOURCE) {
         # No need to render or parse anything more!
         # New lines are replaced with spaces, which avoids confusing our parser (bugs 23190, 22818)
         return '<span class="tex">$ ' . str_replace("\n", " ", htmlspecialchars($this->tex)) . ' $</span>';
     }
     if ($this->tex == '') {
         return;
         # bug 8372
     }
     if (!$this->_recall()) {
         if ($wgMathCheckFiles) {
             # Ensure that the temp and output directories are available before continuing...
             if (!file_exists($wgTmpDirectory)) {
                 if (!wfMkdirParents($wgTmpDirectory)) {
                     return $this->_error('math_bad_tmpdir');
                 }
             } elseif (!is_dir($wgTmpDirectory) || !is_writable($wgTmpDirectory)) {
                 return $this->_error('math_bad_tmpdir');
             }
         }
         if (!is_executable($wgTexvc)) {
             return $this->_error('math_notexvc');
         }
         $cmd = $wgTexvc . ' ' . escapeshellarg($wgTmpDirectory) . ' ' . escapeshellarg($wgTmpDirectory) . ' ' . escapeshellarg($this->tex) . ' ' . escapeshellarg($wgInputEncoding) . ' ' . escapeshellarg($wgTexvcBackgroundColor);
         if (wfIsWindows()) {
             # Invoke it within cygwin sh, because texvc expects sh features in its default shell
             $cmd = 'sh -c ' . wfEscapeShellArg($cmd);
         }
         wfDebug("TeX: {$cmd}\n");
         $contents = wfShellExec($cmd);
         wfDebug("TeX output:\n {$contents}\n---\n");
         if (strlen($contents) == 0) {
             return $this->_error('math_unknown_error');
         }
         $retval = substr($contents, 0, 1);
         $errmsg = '';
         if ($retval == 'C' || $retval == 'M' || $retval == 'L') {
             if ($retval == 'C') {
                 $this->conservativeness = 2;
             } else {
                 if ($retval == 'M') {
                     $this->conservativeness = 1;
                 } else {
                     $this->conservativeness = 0;
                 }
             }
             $outdata = substr($contents, 33);
             $i = strpos($outdata, "");
             $this->html = substr($outdata, 0, $i);
             $this->mathml = substr($outdata, $i + 1);
         } else {
             if ($retval == 'c' || $retval == 'm' || $retval == 'l') {
                 $this->html = substr($contents, 33);
                 if ($retval == 'c') {
                     $this->conservativeness = 2;
                 } else {
                     if ($retval == 'm') {
                         $this->conservativeness = 1;
                     } else {
                         $this->conservativeness = 0;
                     }
                 }
                 $this->mathml = null;
             } else {
                 if ($retval == 'X') {
                     $this->html = null;
                     $this->mathml = substr($contents, 33);
                     $this->conservativeness = 0;
                 } else {
                     if ($retval == '+') {
                         $this->html = null;
                         $this->mathml = null;
                         $this->conservativeness = 0;
                     } else {
                         $errbit = htmlspecialchars(substr($contents, 1));
                         switch ($retval) {
                             case 'E':
                                 $errmsg = $this->_error('math_lexing_error', $errbit);
                                 break;
                             case 'S':
                                 $errmsg = $this->_error('math_syntax_error', $errbit);
                                 break;
                             case 'F':
                                 $errmsg = $this->_error('math_unknown_function', $errbit);
                                 break;
                             default:
                                 $errmsg = $this->_error('math_unknown_error', $errbit);
                         }
                     }
                 }
             }
         }
         if (!$errmsg) {
             $this->hash = substr($contents, 1, 32);
         }
         wfRunHooks('MathAfterTexvc', array(&$this, &$errmsg));
         if ($errmsg) {
             return $errmsg;
         }
         if (!preg_match("/^[a-f0-9]{32}\$/", $this->hash)) {
             return $this->_error('math_unknown_error');
         }
         if (!file_exists("{$wgTmpDirectory}/{$this->hash}.png")) {
             return $this->_error('math_image_error');
         }
         if (filesize("{$wgTmpDirectory}/{$this->hash}.png") == 0) {
             return $this->_error('math_image_error');
         }
         $hashpath = $this->_getHashPath();
         if (!file_exists($hashpath)) {
             wfSuppressWarnings();
             $ret = wfMkdirParents($hashpath, 0755);
             wfRestoreWarnings();
             if (!$ret) {
                 return $this->_error('math_bad_output');
             }
         } elseif (!is_dir($hashpath) || !is_writable($hashpath)) {
             return $this->_error('math_bad_output');
         }
         if (!rename("{$wgTmpDirectory}/{$this->hash}.png", "{$hashpath}/{$this->hash}.png")) {
             return $this->_error('math_output_error');
         }
         # Now save it back to the DB:
         if (!wfReadOnly()) {
             $outmd5_sql = pack('H32', $this->hash);
             $md5_sql = pack('H32', $this->md5);
             # Binary packed, not hex
             $dbw = wfGetDB(DB_MASTER);
             $dbw->replace('math', array('math_inputhash'), array('math_inputhash' => $dbw->encodeBlob($md5_sql), 'math_outputhash' => $dbw->encodeBlob($outmd5_sql), 'math_html_conservativeness' => $this->conservativeness, 'math_html' => $this->html, 'math_mathml' => $this->mathml), __METHOD__);
         }
         // If we're replacing an older version of the image, make sure it's current.
         global $wgUseSquid;
         if ($wgUseSquid) {
             $urls = array($this->_mathImageUrl());
             $u = new SquidUpdate($urls);
             $u->doUpdate();
         }
     }
     return $this->_doRender();
 }