/**
  * Try to set session.serialize_handler to a supported format
  *
  * This may change the format even if the current format is also supported.
  *
  * @return string Format set
  * @throws \\DomainException
  */
 public static function setSerializeHandler()
 {
     $formats = array('php_serialize', 'php', 'php_binary');
     // First, try php_serialize since that's the only one that doesn't suck in some way.
     \MediaWiki\suppressWarnings();
     ini_set('session.serialize_handler', 'php_serialize');
     \MediaWiki\restoreWarnings();
     if (ini_get('session.serialize_handler') === 'php_serialize') {
         return 'php_serialize';
     }
     // Next, just use the current format if it's supported.
     $format = ini_get('session.serialize_handler');
     if (in_array($format, $formats, true)) {
         return $format;
     }
     // Last chance, see if any of our supported formats are accepted.
     foreach ($formats as $format) {
         \MediaWiki\suppressWarnings();
         ini_set('session.serialize_handler', $format);
         \MediaWiki\restoreWarnings();
         if (ini_get('session.serialize_handler') === $format) {
             return $format;
         }
     }
     throw new \DomainException('Failed to set serialize handler to a supported format.' . ' Supported formats are: ' . join(', ', $formats) . '.');
 }
Example #2
0
 public function execute()
 {
     if ($this->hasArg()) {
         $files = $this->mArgs;
     } else {
         $this->maybeHelp(true);
         // @todo fixme this is a lame API :)
         exit(1);
         // it should exit from the above first...
     }
     $parser = new JSParser();
     foreach ($files as $filename) {
         MediaWiki\suppressWarnings();
         $js = file_get_contents($filename);
         MediaWiki\restoreWarnings();
         if ($js === false) {
             $this->output("{$filename} ERROR: could not read file\n");
             $this->errs++;
             continue;
         }
         try {
             $parser->parse($js, $filename, 1);
         } catch (Exception $e) {
             $this->errs++;
             $this->output("{$filename} ERROR: " . $e->getMessage() . "\n");
             continue;
         }
         $this->output("{$filename} OK\n");
     }
     if ($this->errs > 0) {
         exit(1);
     }
 }
 public function run()
 {
     $done = false;
     $startTime = microtime(true);
     while (!$done) {
         $readSockets = $writeSockets = array();
         /**
          * @var $client SquidPurgeClient
          */
         foreach ($this->clients as $clientIndex => $client) {
             $sockets = $client->getReadSocketsForSelect();
             foreach ($sockets as $i => $socket) {
                 $readSockets["{$clientIndex}/{$i}"] = $socket;
             }
             $sockets = $client->getWriteSocketsForSelect();
             foreach ($sockets as $i => $socket) {
                 $writeSockets["{$clientIndex}/{$i}"] = $socket;
             }
         }
         if (!count($readSockets) && !count($writeSockets)) {
             break;
         }
         $exceptSockets = null;
         $timeout = min($startTime + $this->timeout - microtime(true), 1);
         MediaWiki\suppressWarnings();
         $numReady = socket_select($readSockets, $writeSockets, $exceptSockets, $timeout);
         MediaWiki\restoreWarnings();
         if ($numReady === false) {
             wfDebugLog('squid', __METHOD__ . ': Error in stream_select: ' . socket_strerror(socket_last_error()) . "\n");
             break;
         }
         // Check for timeout, use 1% tolerance since we aimed at having socket_select()
         // exit at precisely the overall timeout
         if (microtime(true) - $startTime > $this->timeout * 0.99) {
             wfDebugLog('squid', __CLASS__ . ": timeout ({$this->timeout}s)\n");
             break;
         } elseif (!$numReady) {
             continue;
         }
         foreach ($readSockets as $key => $socket) {
             list($clientIndex, ) = explode('/', $key);
             $client = $this->clients[$clientIndex];
             $client->doReads();
         }
         foreach ($writeSockets as $key => $socket) {
             list($clientIndex, ) = explode('/', $key);
             $client = $this->clients[$clientIndex];
             $client->doWrites();
         }
         $done = true;
         foreach ($this->clients as $client) {
             if (!$client->isIdle()) {
                 $done = false;
             }
         }
     }
     foreach ($this->clients as $client) {
         $client->close();
     }
 }
 public function testGetUnknownTemplate()
 {
     $registry = new TemplateRegistry(array());
     \MediaWiki\suppressWarnings();
     $html = $registry->getTemplate('unknown');
     \MediaWiki\restoreWarnings();
     $this->assertNull($html);
 }
Example #5
0
 protected function getSourceSha1Base36()
 {
     MediaWiki\suppressWarnings();
     $hash = sha1_file($this->params['src']);
     MediaWiki\restoreWarnings();
     if ($hash !== false) {
         $hash = Wikimedia\base_convert($hash, 16, 36, 31);
     }
     return $hash;
 }
 /**
  * @param string $filename
  * @return Status
  */
 static function newFromFile($filename)
 {
     MediaWiki\suppressWarnings();
     $file = fopen($filename, 'rt');
     MediaWiki\restoreWarnings();
     if (!$file) {
         return Status::newFatal("importcantopen");
     }
     return Status::newGood(new ImportStreamSource($file));
 }
 public function testOtherProjectSiteIds_unknownSite()
 {
     $siteStore = $this->getSiteStoreMock();
     $otherProjectsSitesProvider = new OtherProjectsSitesGenerator($siteStore, 'kittenswiki', array('wikidata'));
     // getOtherProjectsSiteIds does wfWarn in case it's being called with a siteid
     // it doesn't know about. That's fine, we can just ignore that.
     \MediaWiki\suppressWarnings();
     $result = $otherProjectsSitesProvider->getOtherProjectsSiteIds(array('wikipedia', 'wikisource'));
     \MediaWiki\restoreWarnings();
     $this->assertSame(array(), $result);
 }
 /**
  * @dataProvider provideCases
  * @covers JavaScriptMinifier::minify
  */
 public function testJavaScriptMinifierOutput($code, $expectedOutput)
 {
     $minified = JavaScriptMinifier::minify($code);
     // JSMin+'s parser will throw an exception if output is not valid JS.
     // suppression of warnings needed for stupid crap
     MediaWiki\suppressWarnings();
     $parser = new JSParser();
     MediaWiki\restoreWarnings();
     $parser->parse($minified, 'minify-test.js', 1);
     $this->assertEquals($expectedOutput, $minified, "Minified output should be in the form expected.");
 }
Example #9
0
 /**
  * Build the list of files we'll check for syntax errors
  */
 private function buildFileList()
 {
     global $IP;
     $this->mIgnorePaths = [];
     $this->mNoStyleCheckPaths = ["/activemq_stomp/", "EmailPage/PHPMailer", "FCKeditor/fckeditor/", '\\bphplot-', "/svggraph/", "\\bjsmin.php\$", "PEAR/File_Ogg/", "QPoll/Excel/", "/geshi/", "/smarty/"];
     if ($this->hasOption('path')) {
         $path = $this->getOption('path');
         if (!$this->addPath($path)) {
             $this->error("Error: can't find file or directory {$path}\n", true);
         }
         return;
         // process only this path
     } elseif ($this->hasOption('list-file')) {
         $file = $this->getOption('list-file');
         MediaWiki\suppressWarnings();
         $f = fopen($file, 'r');
         MediaWiki\restoreWarnings();
         if (!$f) {
             $this->error("Can't open file {$file}\n", true);
         }
         $path = trim(fgets($f));
         while ($path) {
             $this->addPath($path);
         }
         fclose($f);
         return;
     } elseif ($this->hasOption('modified')) {
         $this->output("Retrieving list from Git... ");
         $files = $this->getGitModifiedFiles($IP);
         $this->output("done\n");
         foreach ($files as $file) {
             if ($this->isSuitableFile($file) && !is_dir($file)) {
                 $this->mFiles[] = $file;
             }
         }
         return;
     }
     $this->output('Building file list...', 'listfiles');
     // Only check files in these directories.
     // Don't just put $IP, because the recursive dir thingie goes into all subdirs
     $dirs = [$IP . '/includes', $IP . '/mw-config', $IP . '/languages', $IP . '/maintenance', $IP . '/skins'];
     if ($this->hasOption('with-extensions')) {
         $dirs[] = $IP . '/extensions';
     }
     foreach ($dirs as $d) {
         $this->addDirectoryContent($d);
     }
     // Manually add two user-editable files that are usually sources of problems
     if (file_exists("{$IP}/LocalSettings.php")) {
         $this->mFiles[] = "{$IP}/LocalSettings.php";
     }
     $this->output('done.', 'listfiles');
 }
 /**
  * @dataProvider projectLinkSidebarHookProvider
  */
 public function testBuildProjectLinkSidebar_hook($handler, array $siteIdsToOutput, array $result, $suppressErrors = false)
 {
     $this->setMwGlobals('wgHooks', array('WikibaseClientOtherProjectsSidebar' => array($handler)));
     $otherProjectSidebarGenerator = new OtherProjectsSidebarGenerator('enwiki', $this->getSiteLinkLookup(), $this->getSiteStore(), $siteIdsToOutput);
     if ($suppressErrors) {
         \MediaWiki\suppressWarnings();
     }
     $this->assertEquals($result, $otherProjectSidebarGenerator->buildProjectLinkSidebar(Title::makeTitle(NS_MAIN, 'Nyan Cat')));
     if ($suppressErrors) {
         \MediaWiki\restoreWarnings();
     }
 }
 /**
  * @dataProvider wikiIdProvider
  */
 public function testPidLock($wikiId)
 {
     $pidLock = new PidLock('PidLockTest', $wikiId);
     $this->assertTrue($pidLock->getLock(), 'Get an initial log');
     $this->assertFalse($pidLock->getLock(), 'Try to get the lock, although some already has it');
     $this->assertTrue($pidLock->getLock(true), 'Force getting the lock');
     $this->assertTrue($pidLock->removeLock());
     // Make sure that the given file has actually been removed.
     // unlink gives a warning if you use it a file that doesn't exist, suppress that
     \MediaWiki\suppressWarnings();
     $this->assertFalse($pidLock->removeLock());
     \MediaWiki\restoreWarnings();
 }
 public function testSchemaNotAvailableReturnValue()
 {
     $formatter = new AvroFormatter([]);
     $noticeEnabled = PHPUnit_Framework_Error_Notice::$enabled;
     // disable conversion of notices
     PHPUnit_Framework_Error_Notice::$enabled = false;
     // have to keep the user notice from being output
     \MediaWiki\suppressWarnings();
     $res = $formatter->format(['channel' => 'marty']);
     \MediaWiki\restoreWarnings();
     PHPUnit_Framework_Error_Notice::$enabled = $noticeEnabled;
     $this->assertNull($res);
 }
 protected function __construct($text)
 {
     $this->doc = new DOMDocument('1.0', 'utf-8');
     // Note: parsing a supposedly XHTML document with an XML parser is not
     // guaranteed to give accurate results. For example, it may introduce
     // differences in the number of line breaks in <pre> tags.
     MediaWiki\suppressWarnings();
     if (!$this->doc->loadXML('<html><body>' . $text . '</body></html>')) {
         $this->invalid = true;
     }
     MediaWiki\restoreWarnings();
     $this->xpath = new DOMXPath($this->doc);
     $this->body = $this->xpath->query('//body')->item(0);
 }
Example #14
0
 public function onSubmit(array $data)
 {
     if (!$data['Confirm']) {
         return Status::newFatal('locknoconfirm');
     }
     $readOnlyFile = $this->getConfig()->get('ReadOnlyFile');
     MediaWiki\suppressWarnings();
     $res = unlink($readOnlyFile);
     MediaWiki\restoreWarnings();
     if ($res) {
         return Status::newGood();
     } else {
         return Status::newFatal('filedeleteerror', $readOnlyFile);
     }
 }
Example #15
0
 function translate($value)
 {
     // Hack for i18n:attributes in PHPTAL 1.0.0 dev version as of 2004-10-23
     $value = preg_replace('/^string:/', '', $value);
     $value = wfMessage($value)->text();
     // interpolate variables
     $m = [];
     while (preg_match('/\\$([0-9]*?)/sm', $value, $m)) {
         list($src, $var) = $m;
         MediaWiki\suppressWarnings();
         $varValue = $this->context[$var];
         MediaWiki\restoreWarnings();
         $value = str_replace($src, $varValue, $value);
     }
     return $value;
 }
Example #16
0
 protected function doStoreInternal(array $params)
 {
     $status = Status::newGood();
     $dst = $this->resolveHashKey($params['dst']);
     if ($dst === null) {
         $status->fatal('backend-fail-invalidpath', $params['dst']);
         return $status;
     }
     MediaWiki\suppressWarnings();
     $data = file_get_contents($params['src']);
     MediaWiki\restoreWarnings();
     if ($data === false) {
         // source doesn't exist?
         $status->fatal('backend-fail-store', $params['src'], $params['dst']);
         return $status;
     }
     $this->files[$dst] = array('data' => $data, 'mtime' => wfTimestamp(TS_MW, time()));
     return $status;
 }
Example #17
0
 /**
  * Stream a file to the browser, adding all the headings and fun stuff.
  * Headers sent include: Content-type, Content-Length, Last-Modified,
  * and Content-Disposition.
  *
  * @param string $fname Full name and path of the file to stream
  * @param array $headers Any additional headers to send
  * @param bool $sendErrors Send error messages if errors occur (like 404)
  * @throws MWException
  * @return bool Success
  */
 public static function stream($fname, $headers = array(), $sendErrors = true)
 {
     if (FileBackend::isStoragePath($fname)) {
         // sanity
         throw new MWException(__FUNCTION__ . " given storage path '{$fname}'.");
     }
     MediaWiki\suppressWarnings();
     $stat = stat($fname);
     MediaWiki\restoreWarnings();
     $res = self::prepareForStream($fname, $stat, $headers, $sendErrors);
     if ($res == self::NOT_MODIFIED) {
         $ok = true;
         // use client cache
     } elseif ($res == self::READY_STREAM) {
         $ok = readfile($fname);
     } else {
         $ok = false;
         // failed
     }
     return $ok;
 }
Example #18
0
 public function onSubmit(array $data)
 {
     global $wgContLang;
     if (!$data['Confirm']) {
         return Status::newFatal('locknoconfirm');
     }
     MediaWiki\suppressWarnings();
     $fp = fopen($this->getConfig()->get('ReadOnlyFile'), 'w');
     MediaWiki\restoreWarnings();
     if (false === $fp) {
         # This used to show a file not found error, but the likeliest reason for fopen()
         # to fail at this point is insufficient permission to write to the file...good old
         # is_writable() is plain wrong in some cases, it seems...
         return Status::newFatal('lockfilenotwritable');
     }
     fwrite($fp, $data['Reason']);
     $timestamp = wfTimestampNow();
     fwrite($fp, "\n<p>" . $this->msg('lockedbyandtime', $this->getUser()->getName(), $wgContLang->date($timestamp, false, false), $wgContLang->time($timestamp, false, false))->inContentLanguage()->text() . "</p>\n");
     fclose($fp);
     return Status::newGood();
 }
Example #19
0
 protected function __construct()
 {
     $this->nodeIdFile = wfTempDir() . '/mw-' . __CLASS__ . '-UID-nodeid';
     $nodeId = '';
     if (is_file($this->nodeIdFile)) {
         $nodeId = file_get_contents($this->nodeIdFile);
     }
     // Try to get some ID that uniquely identifies this machine (RFC 4122)...
     if (!preg_match('/^[0-9a-f]{12}$/i', $nodeId)) {
         MediaWiki\suppressWarnings();
         if (wfIsWindows()) {
             // http://technet.microsoft.com/en-us/library/bb490913.aspx
             $csv = trim(wfShellExec('getmac /NH /FO CSV'));
             $line = substr($csv, 0, strcspn($csv, "\n"));
             $info = str_getcsv($line);
             $nodeId = isset($info[0]) ? str_replace('-', '', $info[0]) : '';
         } elseif (is_executable('/sbin/ifconfig')) {
             // Linux/BSD/Solaris/OS X
             // See http://linux.die.net/man/8/ifconfig
             $m = array();
             preg_match('/\\s([0-9a-f]{2}(:[0-9a-f]{2}){5})\\s/', wfShellExec('/sbin/ifconfig -a'), $m);
             $nodeId = isset($m[1]) ? str_replace(':', '', $m[1]) : '';
         }
         MediaWiki\restoreWarnings();
         if (!preg_match('/^[0-9a-f]{12}$/i', $nodeId)) {
             $nodeId = MWCryptRand::generateHex(12, true);
             $nodeId[1] = dechex(hexdec($nodeId[1]) | 0x1);
             // set multicast bit
         }
         file_put_contents($this->nodeIdFile, $nodeId);
         // cache
     }
     $this->nodeId32 = Wikimedia\base_convert(substr(sha1($nodeId), 0, 8), 16, 2, 32);
     $this->nodeId48 = Wikimedia\base_convert($nodeId, 16, 2, 48);
     // If different processes run as different users, they may have different temp dirs.
     // This is dealt with by initializing the clock sequence number and counters randomly.
     $this->lockFile88 = wfTempDir() . '/mw-' . __CLASS__ . '-UID-88';
     $this->lockFile128 = wfTempDir() . '/mw-' . __CLASS__ . '-UID-128';
     $this->lockFileUUID = wfTempDir() . '/mw-' . __CLASS__ . '-UUID-128';
 }
Example #20
0
 function numRows($res)
 {
     if ($res instanceof ResultWrapper) {
         $res = $res->result;
     }
     MediaWiki\suppressWarnings();
     $n = pg_num_rows($res);
     MediaWiki\restoreWarnings();
     if (pg_last_error($this->mConn)) {
         throw new DBUnexpectedError($this, 'SQL error: ' . htmlspecialchars(pg_last_error($this->mConn)));
     }
     return $n;
 }
Example #21
0
 /**
  * @return string
  */
 function lastError()
 {
     if ($this->mConn) {
         # Even if it's non-zero, it can still be invalid
         MediaWiki\suppressWarnings();
         $error = $this->mysqlError($this->mConn);
         if (!$error) {
             $error = $this->mysqlError();
         }
         MediaWiki\restoreWarnings();
     } else {
         $error = $this->mysqlError();
     }
     if ($error) {
         $error .= ' (' . $this->mServer . ')';
     }
     return $error;
 }
Example #22
0
 /**
  * Convert metadata version.
  *
  * By default just returns $metadata, but can be used to allow
  * media handlers to convert between metadata versions.
  *
  * @param string|array $metadata Metadata array (serialized if string)
  * @param int $version Target version
  * @return array Serialized metadata in specified version, or $metadata on fail.
  */
 function convertMetadataVersion($metadata, $version = 1)
 {
     if (!is_array($metadata)) {
         // unserialize to keep return parameter consistent.
         MediaWiki\suppressWarnings();
         $ret = unserialize($metadata);
         MediaWiki\restoreWarnings();
         return $ret;
     }
     return $metadata;
 }
 /**
  * Parses and returns the rc_params attribute
  *
  * @since 1.26
  *
  * @return array|null
  */
 public function parseParams()
 {
     $rcParams = $this->getAttribute('rc_params');
     MediaWiki\suppressWarnings();
     $unserializedParams = unserialize($rcParams);
     MediaWiki\restoreWarnings();
     return $unserializedParams;
 }
Example #24
0
 function getInfo()
 {
     MediaWiki\suppressWarnings();
     $file = fopen($this->mFilename, 'rb');
     MediaWiki\restoreWarnings();
     if ($file === false) {
         wfDebug(__METHOD__ . ": missing or failed file read\n");
         return false;
     }
     $header = fread($file, 16);
     $info = false;
     if (strlen($header) < 16) {
         wfDebug(__METHOD__ . ": too short file header\n");
     } else {
         $arr = unpack('a4magic/a4form/NformLength/a4subtype', $header);
         $subtype = $arr['subtype'];
         if ($arr['magic'] != 'AT&T') {
             wfDebug(__METHOD__ . ": not a DjVu file\n");
         } elseif ($subtype == 'DJVU') {
             // Single-page document
             $info = $this->getPageInfo($file);
         } elseif ($subtype == 'DJVM') {
             // Multi-page document
             $info = $this->getMultiPageInfo($file, $arr['formLength']);
         } else {
             wfDebug(__METHOD__ . ": unrecognized DJVU file type '{$arr['subtype']}'\n");
         }
     }
     fclose($file);
     return $info;
 }
Example #25
0
 /**
  * checkLastModified tells the client to use the client-cached page if
  * possible. If successful, the OutputPage is disabled so that
  * any future call to OutputPage->output() have no effect.
  *
  * Side effect: sets mLastModified for Last-Modified header
  *
  * @param string $timestamp
  *
  * @return bool True if cache-ok headers was sent.
  */
 public function checkLastModified($timestamp)
 {
     if (!$timestamp || $timestamp == '19700101000000') {
         wfDebug(__METHOD__ . ": CACHE DISABLED, NO TIMESTAMP\n");
         return false;
     }
     $config = $this->getConfig();
     if (!$config->get('CachePages')) {
         wfDebug(__METHOD__ . ": CACHE DISABLED\n");
         return false;
     }
     $timestamp = wfTimestamp(TS_MW, $timestamp);
     $modifiedTimes = array('page' => $timestamp, 'user' => $this->getUser()->getTouched(), 'epoch' => $config->get('CacheEpoch'));
     if ($config->get('UseSquid')) {
         // bug 44570: the core page itself may not change, but resources might
         $modifiedTimes['sepoch'] = wfTimestamp(TS_MW, time() - $config->get('SquidMaxage'));
     }
     Hooks::run('OutputPageCheckLastModified', array(&$modifiedTimes));
     $maxModified = max($modifiedTimes);
     $this->mLastModified = wfTimestamp(TS_RFC2822, $maxModified);
     $clientHeader = $this->getRequest()->getHeader('If-Modified-Since');
     if ($clientHeader === false) {
         wfDebug(__METHOD__ . ": client did not send If-Modified-Since header\n", 'log');
         return false;
     }
     # IE sends sizes after the date like this:
     # Wed, 20 Aug 2003 06:51:19 GMT; length=5202
     # this breaks strtotime().
     $clientHeader = preg_replace('/;.*$/', '', $clientHeader);
     MediaWiki\suppressWarnings();
     // E_STRICT system time bitching
     $clientHeaderTime = strtotime($clientHeader);
     MediaWiki\restoreWarnings();
     if (!$clientHeaderTime) {
         wfDebug(__METHOD__ . ": unable to parse the client's If-Modified-Since header: {$clientHeader}\n");
         return false;
     }
     $clientHeaderTime = wfTimestamp(TS_MW, $clientHeaderTime);
     # Make debug info
     $info = '';
     foreach ($modifiedTimes as $name => $value) {
         if ($info !== '') {
             $info .= ', ';
         }
         $info .= "{$name}=" . wfTimestamp(TS_ISO_8601, $value);
     }
     wfDebug(__METHOD__ . ": client sent If-Modified-Since: " . wfTimestamp(TS_ISO_8601, $clientHeaderTime) . "\n", 'log');
     wfDebug(__METHOD__ . ": effective Last-Modified: " . wfTimestamp(TS_ISO_8601, $maxModified) . "\n", 'log');
     if ($clientHeaderTime < $maxModified) {
         wfDebug(__METHOD__ . ": STALE, {$info}\n", 'log');
         return false;
     }
     # Not modified
     # Give a 304 Not Modified response code and disable body output
     wfDebug(__METHOD__ . ": NOT MODIFIED, {$info}\n", 'log');
     ini_set('zlib.output_compression', 0);
     $this->getRequest()->response()->statusHeader(304);
     $this->sendCacheControl();
     $this->disable();
     // Don't output a compressed blob when using ob_gzhandler;
     // it's technically against HTTP spec and seems to confuse
     // Firefox when the response gets split over two packets.
     wfClearOutputBuffers();
     return true;
 }
Example #26
0
 /**
  * Preprocess some wikitext and return the document tree.
  * This is the ghost of Parser::replace_variables().
  *
  * @param string $text The text to parse
  * @param int $flags Bitwise combination of:
  *     Parser::PTD_FOR_INCLUSION  Handle "<noinclude>" and "<includeonly>"
  *                                as if the text is being included. Default
  *                                is to assume a direct page view.
  *
  * The generated DOM tree must depend only on the input text and the flags.
  * The DOM tree must be the same in OT_HTML and OT_WIKI mode, to avoid a regression of bug 4899.
  *
  * Any flag added to the $flags parameter here, or any other parameter liable to cause a
  * change in the DOM tree for a given text, must be passed through the section identifier
  * in the section edit link and thus back to extractSections().
  *
  * The output of this function is currently only cached in process memory, but a persistent
  * cache may be implemented at a later date which takes further advantage of these strict
  * dependency requirements.
  *
  * @throws MWException
  * @return PPNode_DOM
  */
 public function preprocessToObj($text, $flags = 0)
 {
     $xml = $this->cacheGetTree($text, $flags);
     if ($xml === false) {
         $xml = $this->preprocessToXml($text, $flags);
         $this->cacheSetTree($text, $flags, $xml);
     }
     // Fail if the number of elements exceeds acceptable limits
     // Do not attempt to generate the DOM
     $this->parser->mGeneratedPPNodeCount += substr_count($xml, '<');
     $max = $this->parser->mOptions->getMaxGeneratedPPNodeCount();
     if ($this->parser->mGeneratedPPNodeCount > $max) {
         // if ( $cacheable ) { ... }
         throw new MWException(__METHOD__ . ': generated node count limit exceeded');
     }
     $dom = new DOMDocument();
     MediaWiki\suppressWarnings();
     $result = $dom->loadXML($xml);
     MediaWiki\restoreWarnings();
     if (!$result) {
         // Try running the XML through UtfNormal to get rid of invalid characters
         $xml = UtfNormal\Validator::cleanUp($xml);
         // 1 << 19 == XML_PARSE_HUGE, needed so newer versions of libxml2
         // don't barf when the XML is >256 levels deep.
         $result = $dom->loadXML($xml, 1 << 19);
     }
     if ($result) {
         $obj = new PPNode_DOM($dom->documentElement);
     }
     // if ( $cacheable ) { ... }
     if (!$result) {
         throw new MWException(__METHOD__ . ' generated invalid XML');
     }
     return $obj;
 }
Example #27
0
 /**
  * Log to a file without getting "file size exceeded" signals.
  *
  * Can also log to UDP with the syntax udp://host:port/prefix. This will send
  * lines to the specified port, prefixed by the specified prefix and a space.
  *
  * @param string $text
  * @param string $file Filename
  */
 public static function emit($text, $file)
 {
     if (substr($file, 0, 4) == 'udp:') {
         $transport = UDPTransport::newFromString($file);
         $transport->emit($text);
     } else {
         \MediaWiki\suppressWarnings();
         $exists = file_exists($file);
         $size = $exists ? filesize($file) : false;
         if (!$exists || $size !== false && $size + strlen($text) < 0x7fffffff) {
             file_put_contents($file, $text, FILE_APPEND);
         }
         \MediaWiki\restoreWarnings();
     }
 }
Example #28
0
 /**
  * @dataProvider importProvider
  */
 public function testImportHandleRevisionXMLTag_hook($xml, $allowImport, $expectedException = null)
 {
     // WikiImporter tried to register this protocol every time, so unregister first to avoid errors.
     \MediaWiki\suppressWarnings();
     stream_wrapper_unregister('uploadsource');
     \MediaWiki\restoreWarnings();
     WikibaseRepo::getDefaultInstance()->getSettings()->setSetting('allowEntityImport', $allowImport);
     $source = new ImportStringSource($xml);
     $importer = new WikiImporter($source, ConfigFactory::getDefaultInstance()->makeConfig('main'));
     $importer->setNoticeCallback(function () {
         // Do nothing for now. Could collect and compare notices.
     });
     $importer->setPageOutCallback(function () {
     });
     if ($expectedException !== null) {
         $this->setExpectedException($expectedException);
     }
     $importer->doImport();
     $this->assertTrue(true);
     // make PHPUnit happy
 }
Example #29
0
 /**
  * Check selected RFC 7232 precondition headers
  *
  * RFC 7232 envisions a particular model where you send your request to "a
  * resource", and for write requests that you can read "the resource" by
  * changing the method to GET. When the API receives a GET request, it
  * works out even though "the resource" from RFC 7232's perspective might
  * be many resources from MediaWiki's perspective. But it totally fails for
  * a POST, since what HTTP sees as "the resource" is probably just
  * "/api.php" with all the interesting bits in the body.
  *
  * Therefore, we only support RFC 7232 precondition headers for GET (and
  * HEAD). That means we don't need to bother with If-Match and
  * If-Unmodified-Since since they only apply to modification requests.
  *
  * And since we don't support Range, If-Range is ignored too.
  *
  * @since 1.26
  * @param ApiBase $module Api module being used
  * @return bool True on success, false should exit immediately
  */
 protected function checkConditionalRequestHeaders($module)
 {
     if ($this->mInternalMode) {
         // No headers to check in internal mode
         return true;
     }
     if ($this->getRequest()->getMethod() !== 'GET' && $this->getRequest()->getMethod() !== 'HEAD') {
         // Don't check POSTs
         return true;
     }
     $return304 = false;
     $ifNoneMatch = array_diff($this->getRequest()->getHeader('If-None-Match', WebRequest::GETHEADER_LIST) ?: array(), array(''));
     if ($ifNoneMatch) {
         if ($ifNoneMatch === array('*')) {
             // API responses always "exist"
             $etag = '*';
         } else {
             $etag = $module->getConditionalRequestData('etag');
         }
     }
     if ($ifNoneMatch && $etag !== null) {
         $test = substr($etag, 0, 2) === 'W/' ? substr($etag, 2) : $etag;
         $match = array_map(function ($s) {
             return substr($s, 0, 2) === 'W/' ? substr($s, 2) : $s;
         }, $ifNoneMatch);
         $return304 = in_array($test, $match, true);
     } else {
         $value = trim($this->getRequest()->getHeader('If-Modified-Since'));
         // Some old browsers sends sizes after the date, like this:
         //  Wed, 20 Aug 2003 06:51:19 GMT; length=5202
         // Ignore that.
         $i = strpos($value, ';');
         if ($i !== false) {
             $value = trim(substr($value, 0, $i));
         }
         if ($value !== '') {
             try {
                 $ts = new MWTimestamp($value);
                 if ($ts->getTimestamp(TS_RFC2822) === $value || $ts->format('l, d-M-y H:i:s') . ' GMT' === $value || $ts->format('D M j H:i:s Y') === $value || $ts->format('D M  j H:i:s Y') === $value) {
                     $lastMod = $module->getConditionalRequestData('last-modified');
                     if ($lastMod !== null) {
                         // Mix in some MediaWiki modification times
                         $modifiedTimes = array('page' => $lastMod, 'user' => $this->getUser()->getTouched(), 'epoch' => $this->getConfig()->get('CacheEpoch'));
                         if ($this->getConfig()->get('UseSquid')) {
                             // T46570: the core page itself may not change, but resources might
                             $modifiedTimes['sepoch'] = wfTimestamp(TS_MW, time() - $this->getConfig()->get('SquidMaxage'));
                         }
                         Hooks::run('OutputPageCheckLastModified', array(&$modifiedTimes));
                         $lastMod = max($modifiedTimes);
                         $return304 = wfTimestamp(TS_MW, $lastMod) <= $ts->getTimestamp(TS_MW);
                     }
                 }
             } catch (TimestampException $e) {
                 // Invalid timestamp, ignore it
             }
         }
     }
     if ($return304) {
         $this->getRequest()->response()->statusHeader(304);
         // Avoid outputting the compressed representation of a zero-length body
         MediaWiki\suppressWarnings();
         ini_set('zlib.output_compression', 0);
         MediaWiki\restoreWarnings();
         wfClearOutputBuffers();
         return false;
     }
     return true;
 }
Example #30
0
 /**
  * Transform an image using ImageMagick
  *
  * @param File $image File associated with this thumbnail
  * @param array $params Array with scaler params
  *
  * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
  */
 protected function transformImageMagick($image, $params)
 {
     # use ImageMagick
     global $wgSharpenReductionThreshold, $wgSharpenParameter, $wgMaxAnimatedGifArea, $wgImageMagickTempDir, $wgImageMagickConvertCommand, $wgJpegPixelFormat;
     $quality = [];
     $sharpen = [];
     $scene = false;
     $animation_pre = [];
     $animation_post = [];
     $decoderHint = [];
     $subsampling = [];
     if ($params['mimeType'] == 'image/jpeg') {
         $qualityVal = isset($params['quality']) ? (string) $params['quality'] : null;
         $quality = ['-quality', $qualityVal ?: '80'];
         // 80%
         if ($params['interlace']) {
             $animation_post = ['-interlace', 'JPEG'];
         }
         # Sharpening, see bug 6193
         if (($params['physicalWidth'] + $params['physicalHeight']) / ($params['srcWidth'] + $params['srcHeight']) < $wgSharpenReductionThreshold) {
             $sharpen = ['-sharpen', $wgSharpenParameter];
         }
         if (version_compare($this->getMagickVersion(), "6.5.6") >= 0) {
             // JPEG decoder hint to reduce memory, available since IM 6.5.6-2
             $decoderHint = ['-define', "jpeg:size={$params['physicalDimensions']}"];
         }
         if ($wgJpegPixelFormat) {
             $factors = $this->imageMagickSubsampling($wgJpegPixelFormat);
             $subsampling = ['-sampling-factor', implode(',', $factors)];
         }
     } elseif ($params['mimeType'] == 'image/png') {
         $quality = ['-quality', '95'];
         // zlib 9, adaptive filtering
         if ($params['interlace']) {
             $animation_post = ['-interlace', 'PNG'];
         }
     } elseif ($params['mimeType'] == 'image/webp') {
         $quality = ['-quality', '95'];
         // zlib 9, adaptive filtering
     } elseif ($params['mimeType'] == 'image/gif') {
         if ($this->getImageArea($image) > $wgMaxAnimatedGifArea) {
             // Extract initial frame only; we're so big it'll
             // be a total drag. :P
             $scene = 0;
         } elseif ($this->isAnimatedImage($image)) {
             // Coalesce is needed to scale animated GIFs properly (bug 1017).
             $animation_pre = ['-coalesce'];
             // We optimize the output, but -optimize is broken,
             // use optimizeTransparency instead (bug 11822)
             if (version_compare($this->getMagickVersion(), "6.3.5") >= 0) {
                 $animation_post = ['-fuzz', '5%', '-layers', 'optimizeTransparency'];
             }
         }
         if ($params['interlace'] && version_compare($this->getMagickVersion(), "6.3.4") >= 0 && !$this->isAnimatedImage($image)) {
             // interlacing animated GIFs is a bad idea
             $animation_post[] = '-interlace';
             $animation_post[] = 'GIF';
         }
     } elseif ($params['mimeType'] == 'image/x-xcf') {
         // Before merging layers, we need to set the background
         // to be transparent to preserve alpha, as -layers merge
         // merges all layers on to a canvas filled with the
         // background colour. After merging we reset the background
         // to be white for the default background colour setting
         // in the PNG image (which is used in old IE)
         $animation_pre = ['-background', 'transparent', '-layers', 'merge', '-background', 'white'];
         MediaWiki\suppressWarnings();
         $xcfMeta = unserialize($image->getMetadata());
         MediaWiki\restoreWarnings();
         if ($xcfMeta && isset($xcfMeta['colorType']) && $xcfMeta['colorType'] === 'greyscale-alpha' && version_compare($this->getMagickVersion(), "6.8.9-3") < 0) {
             // bug 66323 - Greyscale images not rendered properly.
             // So only take the "red" channel.
             $channelOnly = ['-channel', 'R', '-separate'];
             $animation_pre = array_merge($animation_pre, $channelOnly);
         }
     }
     // Use one thread only, to avoid deadlock bugs on OOM
     $env = ['OMP_NUM_THREADS' => 1];
     if (strval($wgImageMagickTempDir) !== '') {
         $env['MAGICK_TMPDIR'] = $wgImageMagickTempDir;
     }
     $rotation = isset($params['disableRotation']) ? 0 : $this->getRotation($image);
     list($width, $height) = $this->extractPreRotationDimensions($params, $rotation);
     $cmd = call_user_func_array('wfEscapeShellArg', array_merge([$wgImageMagickConvertCommand], $quality, ['-background', 'white'], $decoderHint, [$this->escapeMagickInput($params['srcPath'], $scene)], $animation_pre, ['-thumbnail', "{$width}x{$height}!"], $params['comment'] !== '' ? ['-set', 'comment', $this->escapeMagickProperty($params['comment'])] : [], ['+set', 'Thumb::URI'], ['-depth', 8], $sharpen, ['-rotate', "-{$rotation}"], $subsampling, $animation_post, [$this->escapeMagickOutput($params['dstPath'])]));
     wfDebug(__METHOD__ . ": running ImageMagick: {$cmd}\n");
     $retval = 0;
     $err = wfShellExecWithStderr($cmd, $retval, $env);
     if ($retval !== 0) {
         $this->logErrorForExternalProcess($retval, $err, $cmd);
         return $this->getMediaTransformError($params, "{$err}\nError code: {$retval}");
     }
     return false;
     # No error
 }