/** * Perform a cleanup for a set of wikis * * @param DatabaseBase $db database handler * @param string $table name of table to clean up * @param string $wiki_id_column table column name to use when querying for wiki ID * @param Array $city_ids IDs of wikis to remove from the table */ private function doTableCleanup(DatabaseBase $db, $table, array $city_ids, $wiki_id_column = 'wiki_id') { $start = microtime(true); $db->delete($table, [$wiki_id_column => $city_ids], __METHOD__); $rows = $db->affectedRows(); // just in case MW decides to start a transaction automagically $db->commit(__METHOD__); Wikia\Logger\WikiaLogger::instance()->info(__METHOD__, ['table' => $table, 'cities' => join(', ', $city_ids), 'count' => count($city_ids), 'took' => round(microtime(true) - $start, 4), 'rows' => $rows]); $this->output(sprintf("%s: %s - removed %d rows\n", date('Y-m-d H:i:s'), $table, $rows)); // throttle delete queries if ($rows > 0) { sleep(5); } }
/** * LoginHistoryHook * * store information about when & where user logged in, for stats * purposes, called by Hook UserLoginComplete and UserLoadFromSessionInfo * Data is stored in external storage archive1 * * @author Krzysztof Krzyżaniak (eloy) <*****@*****.**> * @access public * @static * * @param Integer $from -- which hook call this * @param User $user -- User class instance * @param String $type -- UserLoadFromSessionInfo set this to 'cookie' or 'session' * * @return bool true process other hooks */ public static function LoginHistoryHook($from, $user, $type = false) { global $wgCityId; #--- private wikia identifier, you can use wgDBname global $wgEnableScribeReport, $wgSpecialsDB; if (wfReadOnly()) { return true; } wfProfileIn(__METHOD__); /** * if user id is empty it means that user object is not loaded * store information only for registered users */ if (!empty($user) && is_object($user)) { $id = $user->getId(); if ($id) { if ($from == self::LOGIN_AUTO && $type == "session") { # ignore } else { $params = array("user_id" => $id, "city_id" => $wgCityId, "ulh_from" => $from, "ulh_rememberme" => $user->getGlobalPreference('rememberpassword')); if (!empty($wgEnableScribeReport)) { # use scribe try { $message = array('method' => 'login', 'params' => $params); $data = json_encode($message); WScribeClient::singleton('trigger')->send($data); } catch (TException $e) { Wikia\Logger\WikiaLogger::instance()->error(__METHOD__ . ' - scribeClient exception', ['exception' => $e]); } } else { // user_login_history_summary is used in joins with specials.events_local_users table // @see PLATFORM-1309 $dbw_specials = wfGetDB(DB_MASTER, array(), $wgSpecialsDB); $dbw_specials->insert("user_login_history", $params, __METHOD__, array('IGNORE')); $dbw_specials->replace("user_login_history_summary", array('user_id'), array('ulh_timestamp' => wfTimestampOrNull(), 'user_id' => $id), __METHOD__); $dbw_specials->commit(__METHOD__); } } } } wfProfileOut(__METHOD__); return true; }
/** * Script entry point */ public function execute() { global $wgUser; $wgUser = User::newFromName('WikiaBot'); // get options $oldName = $this->getOption('old-username'); $newName = $this->getOption('new-username'); $reason = $this->getOption('reason', 'User rename'); // set up the logger $logger = Wikia\Logger\WikiaLogger::instance(); $logger->pushContext(['old-name' => $oldName, 'new-name' => $newName, 'reason' => $reason]); $logger->info(__CLASS__ . ': start'); $renameProcess = new RenameUserProcess($oldName, $newName, true, $reason); $res = $renameProcess->run(); if ($res !== true) { $logger->info(__CLASS__ . ': error', ['errors' => $renameProcess->getErrors(), 'warnings' => $renameProcess->getWarnings()]); $this->output("RenameUserProcess::run failed for {$oldName}\n"); $this->output(json_encode(['errors' => $renameProcess->getErrors(), 'warnings' => $renameProcess->getWarnings()])); die(1); } $logger->info(__CLASS__ . ': done', ['task_id' => $renameProcess->getUserRenameTaskId()]); $this->output(sprintf("Renaming of '%s' to '%s' done, task_id is '%s'\n", $oldName, $newName, $renameProcess->getUserRenameTaskId())); }
protected function save() { global $wgOut, $wgUser, $wgContLang, $wgRequest; // CategorySelect compatibility (add categories to article body) if ($this->mCategorySelectEnabled) { CategorySelectHooksHelper::onEditPageImportFormData($this->mEditPage, $wgRequest); } $sPostBody = $this->mEditPage->textbox1; $editPage = new EditPage($this->mPostArticle); $editPage->initialiseForm(); $editPage->textbox1 = $sPostBody; $editPage->summary = isset($this->mFormData['postEditSummary']) ? $this->mFormData['postEditSummary'] : ''; $editPage->recreate = true; $result = false; $status = $editPage->internalAttemptSave($result); switch ($status->value) { case EditPage::AS_SUCCESS_UPDATE: case EditPage::AS_SUCCESS_NEW_ARTICLE: case EditPage::AS_ARTICLE_WAS_DELETED: $wgOut->redirect($this->mPostArticle->getTitle()->getFullUrl()); break; default: /** * PLATFORM-1160: Log the entire $status to ELK * * Recommendation: use $status->value for comparisons and messages rather than $status in the following block. */ Wikia\Logger\WikiaLogger::instance()->warning('PLATFORM-1160', ['method' => __METHOD__, 'status_object' => $status]); if ($status->value == EditPage::AS_READ_ONLY_PAGE_LOGGED || $status->value == EditPage::AS_READ_ONLY_PAGE_ANON) { $sMsg = wfMsg('createpage_cant_edit'); } else { $sMsg = wfMsg('createpage_spam'); } $this->mFormErrors[] = $sMsg . " ({$status->value})"; global $wgCreatePageCaptchaTriggered; // do not display form - there is already one invoked from Captcha [RT#21902] - Marooned if (empty($wgCreatePageCaptchaTriggered)) { $this->renderForm(); } break; } }
/** * Wait for a given slave to catch up to the master pos stored in $this * @param $index * @param $open bool * @param $wiki * @return bool */ function doWait($index, $open = false, $wiki = false) { # Find a connection to wait on $conn = $this->getAnyOpenConnection($index); if (!$conn) { if (!$open) { wfDebug(__METHOD__ . ": no connection open\n"); return false; } else { $conn = $this->openConnection($index, $wiki); if (!$conn) { wfDebug(__METHOD__ . ": failed to open connection\n"); return false; } } } $then = microtime(true); // Wikia change wfDebug(__METHOD__ . ": Waiting for slave #{$index} to catch up...\n"); $result = $conn->masterPosWait($this->mWaitForPos, $this->mWaitTimeout); if ($result == -1 || is_null($result)) { # Timed out waiting for slave, use master instead wfDebug(__METHOD__ . ": Timed out waiting for slave #{$index} pos {$this->mWaitForPos}\n"); // Wikia change - begin // log failed wfWaitForSlaves // @see PLATFORM-1219 Wikia\Logger\WikiaLogger::instance()->error('LoadBalancer::doWait timed out', ['exception' => new Exception(), 'db' => $conn->getDBname(), 'host' => $conn->getServer(), 'pos' => (string) $this->mWaitForPos, 'result' => $result, 'waited' => microtime(true) - $then]); // Wikia change - end return false; } else { wfDebug(__METHOD__ . ": Done\n"); return true; } }
/** * Initialise php session * * @param $sessionId Bool */ function wfSetupSession($sessionId = false) { global $wgSessionsInMemcached, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookieHttpOnly, $wgSessionHandler; if ($wgSessionsInMemcached) { if (!defined('MW_COMPILED')) { global $IP; require_once "{$IP}/includes/cache/MemcachedSessions.php"; } session_set_save_handler('memsess_open', 'memsess_close', 'memsess_read', 'memsess_write', 'memsess_destroy', 'memsess_gc'); // It's necessary to register a shutdown function to call session_write_close(), // because by the time the request shutdown function for the session module is // called, $wgMemc has already been destroyed. Shutdown functions registered // this way are called before object destruction. register_shutdown_function('memsess_write_close'); } elseif ($wgSessionHandler && $wgSessionHandler != ini_get('session.save_handler')) { # Only set this if $wgSessionHandler isn't null and session.save_handler # hasn't already been set to the desired value (that causes errors) ini_set('session.save_handler', $wgSessionHandler); } $httpOnlySafe = wfHttpOnlySafe() && $wgCookieHttpOnly; wfDebugLog('cookie', 'session_set_cookie_params: "' . implode('", "', array(0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $httpOnlySafe)) . '"'); session_set_cookie_params(0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $httpOnlySafe); session_cache_limiter('private, must-revalidate'); if ($sessionId) { session_id($sessionId); } else { wfFixSessionID(); } wfSuppressWarnings(); session_start(); wfRestoreWarnings(); // Wikia change - start // log all sessions started with 1% sampling (PLATFORM-1266) if ((new Wikia\Util\Statistics\BernoulliTrial(0.01))->shouldSample()) { Wikia\Logger\WikiaLogger::instance()->info(__METHOD__, ['caller' => wfGetAllCallers(), 'exception' => new Exception()]); } // Wikia change - end }
private function _send_request($conn_type, $url_path, $hdrs = NULL, $method = "GET", $force_new = False) { $retriesLeft = self::MAX_RETRIES; $res = false; while ($retriesLeft >= 0) { $res = $this->_do_send_request($conn_type, $url_path, $hdrs, $method, $force_new); if (!in_array($res, [500, 503, false])) { // request was successful, return break; } Wikia\Logger\WikiaLogger::instance()->error('SwiftStorage: retry', ['exception' => new Exception($this->error_str, is_numeric($res) ? $res : 0), 'retries-left' => $retriesLeft, 'headers' => $hdrs, 'conn-type' => $conn_type, 'path' => $url_path]); // wait a bit before retrying the request usleep(self::RETRY_DELAY * 1000); $retriesLeft--; } return $res; }
private function queueRefreshTasks($batches) { global $wgCityId; foreach ($batches as $batch) { list($start, $end) = $batch; $task = new BatchRefreshLinksForTemplate(); $task->title($this->mTitle); $task->wikiId($wgCityId); $task->call('refreshTemplateLinks', $start, $end); $task->queue(); Wikia\Logger\WikiaLogger::instance()->info('LinksUpdate::queueRefreshTasks', ['title' => $this->mTitle->getPrefixedDBkey(), 'start' => $start, 'end' => $end]); } }
/** * Log helper * * @param string $msg * @param array $context */ private function info($msg, array $context = []) { Wikia\Logger\WikiaLogger::instance()->info($msg, $context); }
/** * check if item type is supported and logs unsupported types * * @param string $type - template type * @return bool */ private function validateType($type) { $isValid = true; if (!isset($this->templates[$type])) { Wikia\Logger\WikiaLogger::instance()->info(self::LOGGER_LABEL, ['type' => $type]); $isValid = false; } return $isValid; }
/** * Delete image from destination path * * @return Boolean|null returns false for recoverable error and null for permanent error and true in the unlikely event of success */ private function delete() { $this->output("\tDelete {$this->imageSyncQueueItem->dst} image\n"); /* connect to source Ceph/Swift */ $srcStorage = $this->srcConn(); /* read source file to string (src here is tmp file, so dst should be set here) */ $remoteFile = $this->getRemotePath($this->imageSyncQueueItem->dst); $this->output("\tRemote file: {$remoteFile} (Swift: " . $srcStorage->getSwiftServer() . " ) \n"); if (!$srcStorage->exists($remoteFile)) { /* connect to destination Ceph/Swift */ $dstStorage = $this->destConn(); $this->output("\tConnect to dest Swift server: " . $dstStorage->getSwiftServer() . " \n"); /* store image in destination path */ if ($dstStorage->exists($remoteFile)) { $result = $dstStorage->remove($remoteFile)->isOK(); } else { $result = null; } } else { $this->output("\tImage still exists in source DC \n"); $this->imageSyncQueueItem->setError(self::ERROR_FILE_EXISTS_IN_SOURCE_DC); Wikia\Logger\WikiaLogger::instance()->warning('MigrateImagesBetweenSwiftDC: file still exists in source DC', ['id' => $this->imageSyncQueueItem->id, 'action' => $this->imageSyncQueueItem->action, 'city_id' => $this->imageSyncQueueItem->city_id, 'src' => $this->imageSyncQueueItem->src, 'dst' => $this->imageSyncQueueItem->dst]); $result = null; } return $result; }
public function execute() { global $IP, $wgSpecialPageCacheUpdates, $wgQueryPages, $wgQueryCacheLimit, $wgDisableQueryPageUpdate; $dbw = wfGetDB(DB_MASTER); foreach ($wgSpecialPageCacheUpdates as $special => $call) { if (!is_callable($call)) { $this->error("Uncallable function {$call}!"); continue; } $t1 = explode(' ', microtime()); call_user_func($call, $dbw); $t2 = explode(' ', microtime()); $this->output(sprintf('%-30s ', $special)); $elapsed = $t2[0] - $t1[0] + ($t2[1] - $t1[1]); $hours = intval($elapsed / 3600); $minutes = intval($elapsed % 3600 / 60); $seconds = $elapsed - $hours * 3600 - $minutes * 60; if ($hours) { $this->output($hours . 'h '); } if ($minutes) { $this->output($minutes . 'm '); } $this->output(sprintf("completed in %.2fs\n", $seconds)); # Wait for the slave to catch up wfWaitForSlaves(); } // This is needed to initialise $wgQueryPages require_once "{$IP}/includes/QueryPage.php"; foreach ($wgQueryPages as $page) { list($class, $special) = $page; $limit = isset($page[2]) ? $page[2] : null; # --list : just show the name of pages if ($this->hasOption('list')) { $this->output("{$special}\n"); continue; } if (!$this->hasOption('override') && $wgDisableQueryPageUpdate && in_array($special, $wgDisableQueryPageUpdate)) { $this->output(sprintf("%-30s disabled\n", $special)); continue; } $specialObj = SpecialPageFactory::getPage($special); if (!$specialObj) { $this->output("No such special page: {$special}\n"); exit; } if ($specialObj instanceof QueryPage) { $queryPage = $specialObj; } else { if (!class_exists($class)) { $file = $specialObj->getFile(); require_once $file; } $queryPage = new $class(); } if (!$this->hasOption('only') || $this->getOption('only') == $queryPage->getName()) { $this->output(sprintf('%-30s ', $special)); if ($queryPage->isExpensive()) { $t1 = explode(' ', microtime()); # Do the query $num = $queryPage->recache($limit === null ? $wgQueryCacheLimit : $limit); $t2 = explode(' ', microtime()); if ($num === false) { $this->output("FAILED: database error\n"); } else { $this->output("got {$num} rows in "); $elapsed = $t2[0] - $t1[0] + ($t2[1] - $t1[1]); $hours = intval($elapsed / 3600); $minutes = intval($elapsed % 3600 / 60); $seconds = $elapsed - $hours * 3600 - $minutes * 60; if ($hours) { $this->output($hours . 'h '); } if ($minutes) { $this->output($minutes . 'm '); } $this->output(sprintf("%.2fs\n", $seconds)); } # Commit the results $res = $dbw->commit(__METHOD__); # try to reconnect to the master if ($res === false) { Wikia\Logger\WikiaLogger::instance()->error('updateSpecialPages - commit failed, reconnecting...'); $this->output("\n"); do { $this->error("Connection failed, reconnecting in 10 seconds..."); sleep(10); } while (!$dbw->ping()); $this->output("Reconnected\n\n"); } # Wait for the slave to catch up wfWaitForSlaves(); } else { $this->output("cheap, skipped\n"); } } } }
} if (!empty($wgEnableNirvanaAPI)) { // temporarily force ApiDocs extension regardless of config require_once $IP . "/extensions/wikia/ApiDocs/ApiDocs.setup.php"; // same for JsonFormat require_once $IP . "/extensions/wikia/JsonFormat/JsonFormat.setup.php"; $app = F::app(); // Ensure that we have a title stub, otherwise parser does not work BugId: 12901 $app->wg->title = Wikia::createTitleFromRequest($app->wg->Request); // support "mcache" URL parameter to ease debugging Wikia::setUpMemcachePurge($app->wg->Request, $app->wg->User); // initialize skin if requested $app->initSkin((bool) $app->wg->Request->getVal("skin", false)); $response = $app->sendRequest(null, null, null, false); // commit any open transactions just in case the controller forgot to $app->commit(); //if cache policy wasn't explicitly set (e.g. WikiaResponse::setCacheValidity) //then force no cache to reflect api.php default behavior $cacheControl = $response->getHeader('Cache-Control'); if (empty($cacheControl)) { $response->setHeader('Cache-Control', 'private', true); Wikia\Logger\WikiaLogger::instance()->info('wikia-php.caching-disabled', ['controller' => $response->getControllerName(), 'method' => $response->getMethodName()]); } $response->sendHeaders(); wfRunHooks('NirvanaAfterRespond', [$app, $response]); $response->render(); wfLogProfilingData(); wfRunHooks('RestInPeace'); } else { header("HTTP/1.1 503 Service Unavailable", true, 503); }
/** * Error log helper * * @param string $msg * @param array $context */ protected function err($msg, array $context = []) { Wikia\Logger\WikiaLogger::instance()->error($msg, $context); }
/** * Set a flag in the output object indicating that the content is dynamic and * shouldn't be cached. */ function disableCache() { wfDebug("Parser output marked as uncacheable.\n"); if (!$this->mOutput) { throw new MWException(__METHOD__ . " can only be called when actually parsing something"); } $this->mOutput->setCacheTime(-1); // old style, for compatibility $this->mOutput->updateCacheExpiry(0); // new style, for consistency // Wikia change - begin Wikia\Logger\WikiaLogger::instance()->info(__METHOD__, ['exception' => new Exception()]); Transaction::setAttribute(Transaction::PARAM_PARSER_CACHE_DISABLED, true); // Wikia change - end }
private function getUserFromMemCacheById($id) { $cacheIdKey = wfSharedMemcKey("UserCache:" . $id); $value = F::app()->wg->memc->get($cacheIdKey); if ($value instanceof User) { try { //cache locally $this->cacheLocalUser($value); return $value; } catch (Exception $e) { Wikia\Logger\WikiaLogger::instance()->debug('HG-519 MemCache returned invalid value from UserCache', ['id' => $id, 'cacheIdKey' => $cacheIdKey, 'value' => $value, 'stack' => $e->getTraceAsString()]); } } return false; }
/** * Check given value against the token value stored in the session. * A match should confirm that the form was submitted from the * user's own login session, not a form submission from a third-party * site. * * @param $val String Input value to compare * @param $salt String Optional function-specific data for hashing * @param $request WebRequest object to use or null to use $wgRequest * @return Boolean: Whether the token matches */ public function matchEditToken($val, $salt = '', $request = null) { $sessionToken = $this->getEditToken($salt, $request); if ($val != $sessionToken) { wfDebug("User::matchEditToken: broken session data\n"); // Wikia change - begin // @see MAIN-4660 log edit tokens mismatches if ($val != '') { Wikia\Logger\WikiaLogger::instance()->error(__METHOD__ . '::tokenMismatch', ['client_val' => $val, 'session_val' => $sessionToken, 'session_id' => session_id(), 'salt' => $salt, 'user_id' => $this->getId(), 'user_name' => $this->getName(), 'exception' => new Exception()]); } // Wikia change - end } return $val == $sessionToken; }
/** * Get total video view count from DB, given video title * * @param string $title Video title * @return integer */ public static function getTotalVideoViewsByTitleFromDb($title) { $db = wfGetDB(DB_SLAVE); $totalViews = (new WikiaSQL())->SELECT('views_total')->FROM('video_info')->WHERE('video_title')->EQUAL_TO($title)->run($db, function ($result) { $row = $result->fetchObject($result); return $row->views_total; }); Wikia\Logger\WikiaLogger::instance()->info('Video view query to db', ['method' => __METHOD__, 'title' => $title, 'totalViews' => $totalViews]); return $totalViews; }