/** * Delete all previously generated thumbnails, refresh metadata in memcached and purge the squid */ function purgeCache($archiveFiles = array(), $shared = false) { global $wgInternalServer, $wgUseSquid; // Refresh metadata cache clearstatcache(); $this->loadFromFile(); $this->saveToCache(); // Delete thumbnails $files = $this->getThumbnails($shared); $dir = wfImageThumbDir($this->name, $shared); $urls = array(); foreach ($files as $file) { if (preg_match('/^(\\d+)px/', $file, $m)) { $urls[] = $wgInternalServer . $this->thumbUrl($m[1], $this->fromSharedDirectory); @unlink("{$dir}/{$file}"); } } // Purge the squid if ($wgUseSquid) { $urls[] = $wgInternalServer . $this->getViewURL(); foreach ($archiveFiles as $file) { $urls[] = $wgInternalServer . wfImageArchiveUrl($file); } wfPurgeSquidServers($urls); } }
/** * Delete an old version of the image. * * 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 $reason * @throws MWException or FSException on database or filestore failure * @return true on success, false on some kind of failure */ function deleteOld($archiveName, $reason, $suppress = false) { $transaction = new FSTransaction(); $urlArr = array(); if (!FileStore::lock()) { wfDebug(__METHOD__ . ": failed to acquire file store lock, aborting\n"); return false; } $transaction = new FSTransaction(); try { $dbw = wfGetDB(DB_MASTER); $dbw->begin(); $transaction->add($this->prepareDeleteOld($archiveName, $reason, $suppress)); $dbw->immediateCommit(); } catch (MWException $e) { wfDebug(__METHOD__ . ": db error, rolling back file transaction\n"); $transaction->rollback(); FileStore::unlock(); throw $e; } wfDebug(__METHOD__ . ": deleted db items, applying file transaction\n"); $transaction->commit(); FileStore::unlock(); $this->purgeDescription(); // Squid purging global $wgUseSquid; if ($wgUseSquid) { $urlArr = array(wfImageArchiveUrl($archiveName)); wfPurgeSquidServers($urlArr); } return true; }
break; case 'history': if ($_SERVER['REQUEST_URI'] == $wgTitle->getInternalURL('action=history')) { $wgOut->setSquidMaxage($wgSquidMaxage); } require_once 'includes/PageHistory.php'; $history = new PageHistory($wgArticle); $history->history(); break; case 'raw': require_once 'includes/RawPage.php'; $raw = new RawPage($wgArticle); $raw->view(); break; case 'purge': wfPurgeSquidServers(array($wgTitle->getInternalURL())); $wgOut->setSquidMaxage($wgSquidMaxage); $wgTitle->invalidateCache(); $wgArticle->view(); break; default: if (wfRunHooks('UnknownAction', array($action, $wgArticle))) { $wgOut->errorpage('nosuchaction', 'nosuchactiontext'); } } } } } } } }
/** * Record a file upload in the upload log and the image table */ function recordUpload2($oldver, $comment, $pageText, $props = false, $timestamp = false) { global $wgUser; $dbw = $this->repo->getMasterDB(); if (!$props) { $props = $this->repo->getFileProps($this->getVirtualUrl()); } $props['description'] = $comment; $props['user'] = $wgUser->getID(); $props['user_text'] = $wgUser->getName(); $props['timestamp'] = wfTimestamp(TS_MW); $this->setProps($props); // Delete thumbnails and refresh the metadata cache $this->purgeThumbnails(); $this->saveToCache(); wfPurgeSquidServers(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' => $wgUser->getID(), 'img_user_text' => $wgUser->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' => $wgUser->getID(), 'img_user_text' => $wgUser->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(); $article = new Article($descTitle); # Add the log entry $log = new LogPage('upload'); $action = $reupload ? 'overwrite' : 'upload'; $log->addEntry($action, $descTitle, $comment); if ($descTitle->exists()) { # Create a null revision $nullRevision = Revision::newNullRevision($dbw, $descTitle->getArticleId(), $log->getRcComment(), false); $nullRevision->insertOn($dbw); $article->updateRevisionOn($dbw, $nullRevision); # 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 $article->doEdit($pageText, $comment, EDIT_NEW | EDIT_SUPPRESS_RC); } # Hooks, hooks, the magic of hooks... wfRunHooks('FileUpload', array($this)); # Commit the transaction now, in case something goes wrong later # The most important thing is that files don't get lost, especially archives $dbw->immediateCommit(); # Invalidate cache for all pages using this file $update = new HTMLCacheUpdate($this->getTitle(), 'imagelinks'); $update->doUpdate(); return true; }
/** * 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); } } if ($wgUseSquid) { wfPurgeSquidServers(array($thumbUrl)); } } while (false); wfProfileOut(__METHOD__); return $thumb; }
function doDelete() { global $wgOut, $wgUser, $wgContLang, $wgRequest; global $wgUseSquid, $wgInternalServer, $wgPostCommitUpdateList; $fname = 'ImagePage::doDelete'; $reason = $wgRequest->getVal('wpReason'); $oldimage = $wgRequest->getVal('oldimage'); $dbw =& wfGetDB(DB_MASTER); if (!is_null($oldimage)) { if (strlen($oldimage) < 16) { $wgOut->unexpectedValueError('oldimage', htmlspecialchars($oldimage)); return; } if (strstr($oldimage, "/") || strstr($oldimage, "\\")) { $wgOut->unexpectedValueError('oldimage', htmlspecialchars($oldimage)); return; } # Invalidate description page cache $this->mTitle->invalidateCache(); # Squid purging if ($wgUseSquid) { $urlArr = array($wgInternalServer . wfImageArchiveUrl($oldimage), $wgInternalServer . $this->mTitle->getFullURL()); wfPurgeSquidServers($urlArr); } $this->doDeleteOldImage($oldimage); $dbw->delete('oldimage', array('oi_archive_name' => $oldimage)); $deleted = $oldimage; } else { $image = $this->mTitle->getDBkey(); $dest = wfImageDir($image); $archive = wfImageDir($image); # Delete the image file if it exists; due to sync problems # or manual trimming sometimes the file will be missing. $targetFile = "{$dest}/{$image}"; if (file_exists($targetFile) && !@unlink($targetFile)) { # If the deletion operation actually failed, bug out: $wgOut->fileDeleteError($targetFile); return; } $dbw->delete('image', array('img_name' => $image)); $res = $dbw->select('oldimage', array('oi_archive_name'), array('oi_name' => $image)); # Purge archive URLs from the squid $urlArr = array(); while ($s = $dbw->fetchObject($res)) { $this->doDeleteOldImage($s->oi_archive_name); $urlArr[] = $wgInternalServer . wfImageArchiveUrl($s->oi_archive_name); } # And also the HTML of all pages using this image $linksTo = $this->img->getLinksTo(); if ($wgUseSquid) { $u = SquidUpdate::newFromTitles($linksTo, $urlArr); array_push($wgPostCommitUpdateList, $u); } $dbw->delete('oldimage', array('oi_name' => $image)); # Image itself is now gone, and database is cleaned. # Now we remove the image description page. $article = new Article($this->mTitle); $article->doDeleteArticle($reason); # ignore errors # Invalidate parser cache and client cache for pages using this image # This is left until relatively late to reduce lock time Title::touchArray($linksTo); /* Delete thumbnails and refresh image metadata cache */ $this->img->purgeCache(); $deleted = $image; } $wgOut->setPagetitle(wfMsg('actioncomplete')); $wgOut->setRobotpolicy('noindex,nofollow'); $loglink = '[[Special:Log/delete|' . wfMsg('deletionlog') . ']]'; $text = wfMsg('deletedtext', $deleted, $loglink); $wgOut->addWikiText($text); $wgOut->returnToMain(false, $this->mTitle->getPrefixedText()); }