public function execute() { // FIXME: This is horrible, no good, very bad hack. Only for testing, // and probably should be eventually replaced with something more sane. $updaterScript = "extensions/CirrusSearch/maintenance/updateSuggesterIndex.php"; $this->getResult()->addValue(null, 'result', wfShellExecWithStderr("unset REQUEST_METHOD; /usr/local/bin/mwscript {$updaterScript} --wiki " . wfWikiID())); }
/** * @param File $file * @param array $params Rotate parameters. * 'rotation' clockwise rotation in degrees, allowed are multiples of 90 * @since 1.21 * @return bool */ public function rotate($file, $params) { global $wgJpegTran; $rotation = ($params['rotation'] + $this->getRotation($file)) % 360; if ($wgJpegTran && is_file($wgJpegTran)) { $cmd = wfEscapeShellArg($wgJpegTran) . " -rotate " . wfEscapeShellArg($rotation) . " -outfile " . wfEscapeShellArg($params['dstPath']) . " " . wfEscapeShellArg($params['srcPath']); wfDebug(__METHOD__ . ": running jpgtran: {$cmd}\n"); wfProfileIn('jpegtran'); $retval = 0; $err = wfShellExecWithStderr($cmd, $retval); wfProfileOut('jpegtran'); if ($retval !== 0) { $this->logErrorForExternalProcess($retval, $err, $cmd); return new MediaTransformError('thumbnail_error', 0, 0, $err); } return false; } else { return parent::rotate($file, $params); } }
/** * @param File $file * @param array $params Rotate parameters. * 'rotation' clockwise rotation in degrees, allowed are multiples of 90 * @since 1.21 * @return bool */ public function rotate($file, $params) { global $wgImageMagickConvertCommand; $rotation = ($params['rotation'] + $this->getRotation($file)) % 360; $scene = false; $scaler = $this->getScalerType(null, false); switch ($scaler) { case 'im': $cmd = wfEscapeShellArg($wgImageMagickConvertCommand) . " " . wfEscapeShellArg($this->escapeMagickInput($params['srcPath'], $scene)) . " -rotate " . wfEscapeShellArg("-{$rotation}") . " " . wfEscapeShellArg($this->escapeMagickOutput($params['dstPath'])); wfDebug(__METHOD__ . ": running ImageMagick: {$cmd}\n"); $retval = 0; $err = wfShellExecWithStderr($cmd, $retval); if ($retval !== 0) { $this->logErrorForExternalProcess($retval, $err, $cmd); return new MediaTransformError('thumbnail_error', 0, 0, $err); } return false; case 'imext': $im = new Imagick(); $im->readImage($params['srcPath']); if (!$im->rotateImage(new ImagickPixel('white'), 360 - $rotation)) { return new MediaTransformError('thumbnail_error', 0, 0, "Error rotating {$rotation} degrees"); } $result = $im->writeImage($params['dstPath']); if (!$result) { return new MediaTransformError('thumbnail_error', 0, 0, "Unable to write image to {$params['dstPath']}"); } return false; default: return new MediaTransformError('thumbnail_error', 0, 0, "{$scaler} rotation not implemented"); } }
/** * Generic wrapper function for a virus scanner program. * This relies on the $wgAntivirus and $wgAntivirusSetup variables. * $wgAntivirusRequired may be used to deny upload if the scan fails. * * @param string $file pathname to the temporary upload file * @return mixed false if not virus is found, NULL if the scan fails or is disabled, * or a string containing feedback from the virus scanner if a virus was found. * If textual feedback is missing but a virus was found, this function returns true. */ public static function detectVirus($file) { global $wgAntivirus, $wgAntivirusSetup, $wgAntivirusRequired, $wgOut; wfProfileIn(__METHOD__); if (!$wgAntivirus) { wfDebug(__METHOD__ . ": virus scanner disabled\n"); wfProfileOut(__METHOD__); return null; } if (!$wgAntivirusSetup[$wgAntivirus]) { wfDebug(__METHOD__ . ": unknown virus scanner: {$wgAntivirus}\n"); $wgOut->wrapWikiMsg("<div class=\"error\">\n\$1\n</div>", array('virus-badscanner', $wgAntivirus)); wfProfileOut(__METHOD__); return wfMessage('virus-unknownscanner')->text() . " {$wgAntivirus}"; } # look up scanner configuration $command = $wgAntivirusSetup[$wgAntivirus]['command']; $exitCodeMap = $wgAntivirusSetup[$wgAntivirus]['codemap']; $msgPattern = isset($wgAntivirusSetup[$wgAntivirus]['messagepattern']) ? $wgAntivirusSetup[$wgAntivirus]['messagepattern'] : null; if (strpos($command, "%f") === false) { # simple pattern: append file to scan $command .= " " . wfEscapeShellArg($file); } else { # complex pattern: replace "%f" with file to scan $command = str_replace("%f", wfEscapeShellArg($file), $command); } wfDebug(__METHOD__ . ": running virus scan: {$command} \n"); # execute virus scanner $exitCode = false; # NOTE: there's a 50 line workaround to make stderr redirection work on windows, too. # that does not seem to be worth the pain. # Ask me (Duesentrieb) about it if it's ever needed. $output = wfShellExecWithStderr($command, $exitCode); # map exit code to AV_xxx constants. $mappedCode = $exitCode; if ($exitCodeMap) { if (isset($exitCodeMap[$exitCode])) { $mappedCode = $exitCodeMap[$exitCode]; } elseif (isset($exitCodeMap["*"])) { $mappedCode = $exitCodeMap["*"]; } } /* NB: AV_NO_VIRUS is 0 but AV_SCAN_FAILED is false, * so we need the strict equalities === and thus can't use a switch here */ if ($mappedCode === AV_SCAN_FAILED) { # scan failed (code was mapped to false by $exitCodeMap) wfDebug(__METHOD__ . ": failed to scan {$file} (code {$exitCode}).\n"); $output = $wgAntivirusRequired ? wfMessage('virus-scanfailed', array($exitCode))->text() : null; } elseif ($mappedCode === AV_SCAN_ABORTED) { # scan failed because filetype is unknown (probably imune) wfDebug(__METHOD__ . ": unsupported file type {$file} (code {$exitCode}).\n"); $output = null; } elseif ($mappedCode === AV_NO_VIRUS) { # no virus found wfDebug(__METHOD__ . ": file passed virus scan.\n"); $output = false; } else { $output = trim($output); if (!$output) { $output = true; #if there's no output, return true } elseif ($msgPattern) { $groups = array(); if (preg_match($msgPattern, $output, $groups)) { if ($groups[1]) { $output = $groups[1]; } } } wfDebug(__METHOD__ . ": FOUND VIRUS! scanner feedback: {$output} \n"); } wfProfileOut(__METHOD__); return $output; }
/** * Swaps an embedded ICC profile for another, if found. Depends on exiftool, no-op if not installed. * @param string $filepath File to be manipulated (will be overwritten) * @param string $oldProfileString Exact name of color profile to look for (the one that will be replaced) * @param string $profileFilepath ICC profile file to apply to the file * @since 1.26 * @return bool */ public function swapICCProfile($filepath, $oldProfileString, $profileFilepath) { global $wgExiftool; if (!$wgExiftool || !is_executable($wgExiftool)) { return false; } $cmd = wfEscapeShellArg($wgExiftool, '-DeviceModelDesc', '-S', '-T', $filepath); $output = wfShellExecWithStderr($cmd, $retval); if ($retval !== 0 || strcasecmp(trim($output), $oldProfileString) !== 0) { // We can't establish that this file has the expected ICC profile, don't process it return false; } $cmd = wfEscapeShellArg($wgExiftool, '-overwrite_original', '-icc_profile<=' . $profileFilepath, $filepath); $output = wfShellExecWithStderr($cmd, $retval); if ($retval !== 0) { $this->logErrorForExternalProcess($retval, $output, $cmd); return false; } return true; }
/** * Transform an SVG file to PNG * This function can be called outside of thumbnail contexts * @param string $srcPath * @param string $dstPath * @param string $width * @param string $height * @param bool|string $lang Language code of the language to render the SVG in * @throws MWException * @return bool|MediaTransformError */ public function rasterize($srcPath, $dstPath, $width, $height, $lang = false) { global $wgSVGConverters, $wgSVGConverter, $wgSVGConverterPath; $err = false; $retval = ''; if (isset($wgSVGConverters[$wgSVGConverter])) { if (is_array($wgSVGConverters[$wgSVGConverter])) { // This is a PHP callable $func = $wgSVGConverters[$wgSVGConverter][0]; $args = array_merge(array($srcPath, $dstPath, $width, $height, $lang), array_slice($wgSVGConverters[$wgSVGConverter], 1)); if (!is_callable($func)) { throw new MWException("{$func} is not callable"); } $err = call_user_func_array($func, $args); $retval = (bool) $err; } else { // External command $cmd = str_replace(array('$path/', '$width', '$height', '$input', '$output'), array($wgSVGConverterPath ? wfEscapeShellArg("{$wgSVGConverterPath}/") : "", intval($width), intval($height), wfEscapeShellArg($srcPath), wfEscapeShellArg($dstPath)), $wgSVGConverters[$wgSVGConverter]); $env = array(); if ($lang !== false) { $env['LANG'] = $lang; } wfProfileIn('rsvg'); wfDebug(__METHOD__ . ": {$cmd}\n"); $err = wfShellExecWithStderr($cmd, $retval, $env); wfProfileOut('rsvg'); } } $removed = $this->removeBadFile($dstPath, $retval); if ($retval != 0 || $removed) { $this->logErrorForExternalProcess($retval, $err, $cmd); return new MediaTransformError('thumbnail_error', $width, $height, $err); } return true; }
/** * @param $image File * @param $dstPath string * @param $dstUrl string * @param $params array * @param $flags int * @return MediaTransformError|MediaTransformOutput|ThumbnailImage|TransformParameterError */ function doTransform($image, $dstPath, $dstUrl, $params, $flags = 0) { global $wgPdfProcessor, $wgPdfPostProcessor, $wgPdfHandlerDpi, $wgPdfHandlerJpegQuality; $metadata = $image->getMetadata(); if (!$metadata) { return $this->doThumbError(isset($params['width']) ? $params['width'] : null, isset($params['height']) ? $params['height'] : null, 'pdf_no_metadata'); } if (!$this->normaliseParams($image, $params)) { return new TransformParameterError($params); } $width = $params['width']; $height = $params['height']; $page = $params['page']; if ($page > $this->pageCount($image)) { return $this->doThumbError($width, $height, 'pdf_page_error'); } if ($flags & self::TRANSFORM_LATER) { return new ThumbnailImage($image, $dstUrl, $width, $height, false, $page); } if (!wfMkdirParents(dirname($dstPath), null, __METHOD__)) { return $this->doThumbError($width, $height, 'thumbnail_dest_directory'); } // Thumbnail extraction is very inefficient for large files. // Provide a way to pool count limit the number of downloaders. if ($image->getSize() >= 10000000.0) { // 10MB $work = new PoolCounterWorkViaCallback('GetLocalFileCopy', sha1($image->getName()), array('doWork' => function () use($image) { return $image->getLocalRefPath(); })); $srcPath = $work->execute(); } else { $srcPath = $image->getLocalRefPath(); } if ($srcPath === false) { // could not download original return $this->doThumbError($width, $height, 'filemissing'); } $cmd = '(' . wfEscapeShellArg($wgPdfProcessor, "-sDEVICE=jpeg", "-sOutputFile=-", "-dFirstPage={$page}", "-dLastPage={$page}", "-r{$wgPdfHandlerDpi}", "-dBATCH", "-dNOPAUSE", "-q", $srcPath); $cmd .= " | " . wfEscapeShellArg($wgPdfPostProcessor, "-depth", "8", "-quality", $wgPdfHandlerJpegQuality, "-resize", $width, "-", $dstPath); $cmd .= ")"; wfProfileIn('PdfHandler'); wfDebug(__METHOD__ . ": {$cmd}\n"); $retval = ''; $err = wfShellExecWithStderr($cmd, $retval); wfProfileOut('PdfHandler'); $removed = $this->removeBadFile($dstPath, $retval); if ($retval != 0 || $removed) { wfDebugLog('thumbnail', sprintf('thumbnail failed on %s: error %d "%s" from "%s"', wfHostname(), $retval, trim($err), $cmd)); return new MediaTransformError('thumbnail_error', $width, $height, $err); } else { return new ThumbnailImage($image, $dstUrl, $width, $height, $dstPath, $page); } }