/**
  * Evaluate a compiled set of rules returned by compile(). Do not allow
  * the user to edit the compiled form, or else PHP errors may result.
  */
 public static function evaluateCompiled($number, array $rules)
 {
     // The compiled form is RPN, with tokens strictly delimited by
     // spaces, so this is a simple RPN evaluator.
     foreach ($rules as $i => $rule) {
         $stack = array();
         $zero = ord('0');
         $nine = ord('9');
         foreach (StringUtils::explode(' ', $rule) as $token) {
             $ord = ord($token);
             if ($token === 'n') {
                 $stack[] = $number;
             } elseif ($ord >= $zero && $ord <= $nine) {
                 $stack[] = intval($token);
             } else {
                 $right = array_pop($stack);
                 $left = array_pop($stack);
                 $result = self::doOperation($token, $left, $right);
                 $stack[] = $result;
             }
         }
         if ($stack[0]) {
             return $i;
         }
     }
     // None of the provided rules match. The number belongs to caregory
     // 'other' which comes last.
     return count($rules);
 }
 /**
  * @desc Parse data from <hubspopularvideos /> tag
  * 
  * @param String $input data within <hubspopularvideos /> tag
  */
 protected function pullData($input)
 {
     wfProfileIn(__METHOD__);
     //use images passed inside <gallery> tag
     $lines = StringUtils::explode("\n", $input);
     foreach ($lines as $line) {
         if ($line == '') {
             continue;
         }
         //title|user|||wikiurl
         $parts = (array) StringUtils::explode('|', $line);
         $videoTitleText = !empty($parts[0]) ? $parts[0] : null;
         $username = !empty($parts[1]) ? $parts[1] : null;
         $wikiUrl = !empty($parts[4]) ? $parts[4] : null;
         if (in_array(true, array(is_null($videoTitleText), is_null($username), is_null($wikiUrl)))) {
             //we want all data given
             continue;
         }
         $this->data[] = array('videoTitleText' => $videoTitleText, 'username' => $username, 'wikiUrl' => $wikiUrl);
     }
     wfProfileOut(__METHOD__);
 }
 /**
  * Parse flags with syntax -{FLAG| ... }-
  * @private
  */
 function parseFlags()
 {
     $text = $this->mText;
     $flags = array();
     $variantFlags = array();
     $sepPos = strpos($text, '|');
     if ($sepPos !== false) {
         $validFlags = $this->mConverter->mFlags;
         $f = StringUtils::explode(';', substr($text, 0, $sepPos));
         foreach ($f as $ff) {
             $ff = trim($ff);
             if (isset($validFlags[$ff])) {
                 $flags[$validFlags[$ff]] = true;
             }
         }
         $text = strval(substr($text, $sepPos + 1));
     }
     if (!$flags) {
         $flags['S'] = true;
     } elseif (isset($flags['R'])) {
         $flags = array('R' => true);
         // remove other flags
     } elseif (isset($flags['N'])) {
         $flags = array('N' => true);
         // remove other flags
     } elseif (isset($flags['-'])) {
         $flags = array('-' => true);
         // remove other flags
     } elseif (count($flags) == 1 && isset($flags['T'])) {
         $flags['H'] = true;
     } elseif (isset($flags['H'])) {
         // replace A flag, and remove other flags except T
         $temp = array('+' => true, 'H' => true);
         if (isset($flags['T'])) {
             $temp['T'] = true;
         }
         if (isset($flags['D'])) {
             $temp['D'] = true;
         }
         $flags = $temp;
     } else {
         if (isset($flags['A'])) {
             $flags['+'] = true;
             $flags['S'] = true;
         }
         if (isset($flags['D'])) {
             unset($flags['S']);
         }
         // try to find flags like "zh-hans", "zh-hant"
         // allow syntaxes like "-{zh-hans;zh-hant|XXXX}-"
         $variantFlags = array_intersect(array_keys($flags), $this->mConverter->mVariants);
         if ($variantFlags) {
             $variantFlags = array_flip($variantFlags);
             $flags = array();
         }
     }
     $this->mVariantFlags = $variantFlags;
     $this->mRules = $text;
     $this->mFlags = $flags;
 }
 /**
  * Parse the conversion table stored in the cache.
  *
  * The tables should be in blocks of the following form:
  *		-{
  *			word => word ;
  *			word => word ;
  *			...
  *		}-
  *
  * To make the tables more manageable, subpages are allowed
  * and will be parsed recursively if $recursive == true.
  *
  * @param string $code Language code
  * @param string $subpage Subpage name
  * @param bool $recursive Parse subpages recursively? Defaults to true.
  *
  * @return array
  */
 function parseCachedTable($code, $subpage = '', $recursive = true)
 {
     static $parsed = [];
     $key = 'Conversiontable/' . $code;
     if ($subpage) {
         $key .= '/' . $subpage;
     }
     if (array_key_exists($key, $parsed)) {
         return [];
     }
     $parsed[$key] = true;
     if ($subpage === '') {
         $txt = MessageCache::singleton()->getMsgFromNamespace($key, $code);
     } else {
         $txt = false;
         $title = Title::makeTitleSafe(NS_MEDIAWIKI, $key);
         if ($title && $title->exists()) {
             $revision = Revision::newFromTitle($title);
             if ($revision) {
                 if ($revision->getContentModel() == CONTENT_MODEL_WIKITEXT) {
                     $txt = $revision->getContent(Revision::RAW)->getNativeData();
                 }
                 // @todo in the future, use a specialized content model, perhaps based on json!
             }
         }
     }
     # Nothing to parse if there's no text
     if ($txt === false || $txt === null || $txt === '') {
         return [];
     }
     // get all subpage links of the form
     // [[MediaWiki:Conversiontable/zh-xx/...|...]]
     $linkhead = $this->mLangObj->getNsText(NS_MEDIAWIKI) . ':Conversiontable';
     $subs = StringUtils::explode('[[', $txt);
     $sublinks = [];
     foreach ($subs as $sub) {
         $link = explode(']]', $sub, 2);
         if (count($link) != 2) {
             continue;
         }
         $b = explode('|', $link[0], 2);
         $b = explode('/', trim($b[0]), 3);
         if (count($b) == 3) {
             $sublink = $b[2];
         } else {
             $sublink = '';
         }
         if ($b[0] == $linkhead && $b[1] == $code) {
             $sublinks[] = $sublink;
         }
     }
     // parse the mappings in this page
     $blocks = StringUtils::explode('-{', $txt);
     $ret = [];
     $first = true;
     foreach ($blocks as $block) {
         if ($first) {
             // Skip the part before the first -{
             $first = false;
             continue;
         }
         $mappings = explode('}-', $block, 2)[0];
         $stripped = str_replace(["'", '"', '*', '#'], '', $mappings);
         $table = StringUtils::explode(';', $stripped);
         foreach ($table as $t) {
             $m = explode('=>', $t, 3);
             if (count($m) != 2) {
                 continue;
             }
             // trim any trailling comments starting with '//'
             $tt = explode('//', $m[1], 2);
             $ret[trim($m[0])] = trim($tt[0]);
         }
     }
     // recursively parse the subpages
     if ($recursive) {
         foreach ($sublinks as $link) {
             $s = $this->parseCachedTable($code, $link, $recursive);
             $ret = $s + $ret;
         }
     }
     if ($this->mUcfirst) {
         foreach ($ret as $k => $v) {
             $ret[$this->mLangObj->ucfirst($k)] = $this->mLangObj->ucfirst($v);
         }
     }
     return $ret;
 }
Exemple #5
0
 /**
  * Parse image options text and use it to make an image
  *
  * @param $title Title
  * @param $options String
  * @param $holders LinkHolderArray|bool
  * @return string HTML
  */
 function makeImage($title, $options, $holders = false)
 {
     # Check if the options text is of the form "options|alt text"
     # Options are:
     #  * thumbnail  make a thumbnail with enlarge-icon and caption, alignment depends on lang
     #  * left       no resizing, just left align. label is used for alt= only
     #  * right      same, but right aligned
     #  * none       same, but not aligned
     #  * ___px      scale to ___ pixels width, no aligning. e.g. use in taxobox
     #  * center     center the image
     #  * frame      Keep original image size, no magnify-button.
     #  * framed     Same as "frame"
     #  * frameless  like 'thumb' but without a frame. Keeps user preferences for width
     #  * upright    reduce width for upright images, rounded to full __0 px
     #  * border     draw a 1px border around the image
     #  * alt        Text for HTML alt attribute (defaults to empty)
     #  * class      Set a class for img node
     #  * link       Set the target of the image link. Can be external, interwiki, or local
     # vertical-align values (no % or length right now):
     #  * baseline
     #  * sub
     #  * super
     #  * top
     #  * text-top
     #  * middle
     #  * bottom
     #  * text-bottom
     $parts = StringUtils::explode("|", $options);
     # Give extensions a chance to select the file revision for us
     $options = array();
     $descQuery = false;
     wfRunHooks('BeforeParserFetchFileAndTitle', array($this, $title, &$options, &$descQuery));
     # Fetch and register the file (file title may be different via hooks)
     list($file, $title) = $this->fetchFileAndTitle($title, $options);
     # Get parameter map
     $handler = $file ? $file->getHandler() : false;
     list($paramMap, $mwArray) = $this->getImageParams($handler);
     if (!$file) {
         $this->addTrackingCategory('broken-file-category');
     }
     # Process the input parameters
     $caption = '';
     $params = array('frame' => array(), 'handler' => array(), 'horizAlign' => array(), 'vertAlign' => array());
     foreach ($parts as $part) {
         $part = trim($part);
         list($magicName, $value) = $mwArray->matchVariableStartToEnd($part);
         $validated = false;
         if (isset($paramMap[$magicName])) {
             list($type, $paramName) = $paramMap[$magicName];
             # Special case; width and height come in one variable together
             if ($type === 'handler' && $paramName === 'width') {
                 $parsedWidthParam = $this->parseWidthParam($value);
                 if (isset($parsedWidthParam['width'])) {
                     $width = $parsedWidthParam['width'];
                     if ($handler->validateParam('width', $width)) {
                         $params[$type]['width'] = $width;
                         $validated = true;
                     }
                 }
                 if (isset($parsedWidthParam['height'])) {
                     $height = $parsedWidthParam['height'];
                     if ($handler->validateParam('height', $height)) {
                         $params[$type]['height'] = $height;
                         $validated = true;
                     }
                 }
                 # else no validation -- bug 13436
             } else {
                 if ($type === 'handler') {
                     # Validate handler parameter
                     $validated = $handler->validateParam($paramName, $value);
                 } else {
                     # Validate internal parameters
                     switch ($paramName) {
                         case 'manualthumb':
                         case 'alt':
                         case 'class':
                             # @todo FIXME: Possibly check validity here for
                             # manualthumb? downstream behavior seems odd with
                             # missing manual thumbs.
                             $validated = true;
                             $value = $this->stripAltText($value, $holders);
                             break;
                         case 'link':
                             $chars = self::EXT_LINK_URL_CLASS;
                             $prots = $this->mUrlProtocols;
                             if ($value === '') {
                                 $paramName = 'no-link';
                                 $value = true;
                                 $validated = true;
                             } elseif (preg_match("/^(?i){$prots}/", $value)) {
                                 if (preg_match("/^((?i){$prots}){$chars}+\$/u", $value, $m)) {
                                     $paramName = 'link-url';
                                     $this->mOutput->addExternalLink($value);
                                     if ($this->mOptions->getExternalLinkTarget()) {
                                         $params[$type]['link-target'] = $this->mOptions->getExternalLinkTarget();
                                     }
                                     $validated = true;
                                 }
                             } else {
                                 $linkTitle = Title::newFromText($value);
                                 if ($linkTitle) {
                                     $paramName = 'link-title';
                                     $value = $linkTitle;
                                     $this->mOutput->addLink($linkTitle);
                                     $validated = true;
                                 }
                             }
                             break;
                         default:
                             # Most other things appear to be empty or numeric...
                             $validated = $value === false || is_numeric(trim($value));
                     }
                 }
                 if ($validated) {
                     $params[$type][$paramName] = $value;
                 }
             }
         }
         if (!$validated) {
             $caption = $part;
         }
     }
     # Process alignment parameters
     if ($params['horizAlign']) {
         $params['frame']['align'] = key($params['horizAlign']);
     }
     if ($params['vertAlign']) {
         $params['frame']['valign'] = key($params['vertAlign']);
     }
     $params['frame']['caption'] = $caption;
     # Will the image be presented in a frame, with the caption below?
     $imageIsFramed = isset($params['frame']['frame']) || isset($params['frame']['framed']) || isset($params['frame']['thumbnail']) || isset($params['frame']['manualthumb']);
     # In the old days, [[Image:Foo|text...]] would set alt text.  Later it
     # came to also set the caption, ordinary text after the image -- which
     # makes no sense, because that just repeats the text multiple times in
     # screen readers.  It *also* came to set the title attribute.
     #
     # Now that we have an alt attribute, we should not set the alt text to
     # equal the caption: that's worse than useless, it just repeats the
     # text.  This is the framed/thumbnail case.  If there's no caption, we
     # use the unnamed parameter for alt text as well, just for the time be-
     # ing, if the unnamed param is set and the alt param is not.
     #
     # For the future, we need to figure out if we want to tweak this more,
     # e.g., introducing a title= parameter for the title; ignoring the un-
     # named parameter entirely for images without a caption; adding an ex-
     # plicit caption= parameter and preserving the old magic unnamed para-
     # meter for BC; ...
     if ($imageIsFramed) {
         # Framed image
         if ($caption === '' && !isset($params['frame']['alt'])) {
             # No caption or alt text, add the filename as the alt text so
             # that screen readers at least get some description of the image
             $params['frame']['alt'] = $title->getText();
         }
         # Do not set $params['frame']['title'] because tooltips don't make sense
         # for framed images
     } else {
         # Inline image
         if (!isset($params['frame']['alt'])) {
             # No alt text, use the "caption" for the alt text
             if ($caption !== '') {
                 $params['frame']['alt'] = $this->stripAltText($caption, $holders);
             } else {
                 # No caption, fall back to using the filename for the
                 # alt text
                 $params['frame']['alt'] = $title->getText();
             }
         }
         # Use the "caption" for the tooltip text
         $params['frame']['title'] = $this->stripAltText($caption, $holders);
     }
     wfRunHooks('ParserMakeImageParams', array($title, $file, &$params, $this));
     # Linker does the rest
     $time = isset($options['time']) ? $options['time'] : false;
     $ret = Linker::makeImageLink($this, $title, $file, $params['frame'], $params['handler'], $time, $descQuery, $this->mOptions->getThumbSize());
     # Give the handler a chance to modify the parser object
     if ($handler) {
         $handler->parserTransformHook($this, $file);
     }
     return $ret;
 }
 /**
  * Evaluate a compiled set of rules returned by compile(). Do not allow
  * the user to edit the compiled form, or else PHP errors may result.
  *
  * @param string $number The number to be evaluated against the rules, in English, or it
  *   may be a type convertible to string.
  * @param array $rules The associative array of plural rules in pluralform => rule format.
  * @return int The index of the plural form which passed the evaluation
  */
 public static function evaluateCompiled($number, array $rules)
 {
     // Calculate the values of the operand symbols
     $number = strval($number);
     if (!preg_match('/^ -? ( ([0-9]+) (?: \\. ([0-9]+) )? )$/x', $number, $m)) {
         wfDebug(__METHOD__ . ": invalid number input, returning 'other'\n");
         return count($rules);
     }
     if (!isset($m[3])) {
         $operandSymbols = array('n' => intval($m[1]), 'i' => intval($m[1]), 'v' => 0, 'w' => 0, 'f' => 0, 't' => 0);
     } else {
         $absValStr = $m[1];
         $intStr = $m[2];
         $fracStr = $m[3];
         $operandSymbols = array('n' => floatval($absValStr), 'i' => intval($intStr), 'v' => strlen($fracStr), 'w' => strlen(rtrim($fracStr, '0')), 'f' => intval($fracStr), 't' => intval(rtrim($fracStr, '0')));
     }
     // The compiled form is RPN, with tokens strictly delimited by
     // spaces, so this is a simple RPN evaluator.
     foreach ($rules as $i => $rule) {
         $stack = array();
         $zero = ord('0');
         $nine = ord('9');
         foreach (StringUtils::explode(' ', $rule) as $token) {
             $ord = ord($token);
             if (isset($operandSymbols[$token])) {
                 $stack[] = $operandSymbols[$token];
             } elseif ($ord >= $zero && $ord <= $nine) {
                 $stack[] = intval($token);
             } else {
                 $right = array_pop($stack);
                 $left = array_pop($stack);
                 $result = self::doOperation($token, $left, $right);
                 $stack[] = $result;
             }
         }
         if ($stack[0]) {
             return $i;
         }
     }
     // None of the provided rules match. The number belongs to category
     // 'other', which comes last.
     return count($rules);
 }
 function generateFirstChars()
 {
     $file = fopen("{$this->dataDir}/allkeys.txt", 'r');
     if (!$file) {
         $this->error("Unable to open allkeys.txt");
         exit(1);
     }
     global $IP;
     $outFile = fopen("{$IP}/serialized/first-letters-root.ser", 'w');
     if (!$outFile) {
         $this->error("Unable to open output file first-letters-root.ser");
         exit(1);
     }
     $goodTertiaryChars = array();
     // For each character with an entry in allkeys.txt, overwrite the implicit
     // entry in $this->weights that came from the UCD.
     // Also gather a list of tertiary weights, for use in selecting the group header
     while (false !== ($line = fgets($file))) {
         // We're only interested in single-character weights, pick them out with a regex
         $line = trim($line);
         if (!preg_match('/^([0-9A-F]+)\\s*;\\s*([^#]*)/', $line, $m)) {
             continue;
         }
         $cp = hexdec($m[1]);
         $allWeights = trim($m[2]);
         $primary = '';
         $tertiary = '';
         if (!isset($this->weights[$cp])) {
             // Non-printable, ignore
             continue;
         }
         foreach (StringUtils::explode('[', $allWeights) as $weightStr) {
             preg_match_all('/[*.]([0-9A-F]+)/', $weightStr, $m);
             if (!empty($m[1])) {
                 if ($m[1][0] !== '0000') {
                     $primary .= '.' . $m[1][0];
                 }
                 if ($m[1][2] !== '0000') {
                     $tertiary .= '.' . $m[1][2];
                 }
             }
         }
         $this->weights[$cp] = $primary;
         if ($tertiary === '.0008' || $tertiary === '.000E') {
             $goodTertiaryChars[$cp] = true;
         }
     }
     fclose($file);
     // Identify groups of characters with the same primary weight
     $this->groups = array();
     asort($this->weights, SORT_STRING);
     $prevWeight = reset($this->weights);
     $group = array();
     foreach ($this->weights as $cp => $weight) {
         if ($weight !== $prevWeight) {
             $this->groups[$prevWeight] = $group;
             $prevWeight = $weight;
             if (isset($this->groups[$weight])) {
                 $group = $this->groups[$weight];
             } else {
                 $group = array();
             }
         }
         $group[] = $cp;
     }
     if ($group) {
         $this->groups[$prevWeight] = $group;
     }
     // If one character has a given primary weight sequence, and a second
     // character has a longer primary weight sequence with an initial
     // portion equal to the first character, then remove the second
     // character. This avoids having characters like U+A732 (double A)
     // polluting the basic latin sort area.
     foreach ($this->groups as $weight => $group) {
         if (preg_match('/(\\.[0-9A-F]*)\\./', $weight, $m)) {
             if (isset($this->groups[$m[1]])) {
                 unset($this->groups[$weight]);
             }
         }
     }
     ksort($this->groups, SORT_STRING);
     // Identify the header character in each group
     $headerChars = array();
     $prevChar = "";
     $tertiaryCollator = new Collator('root');
     $primaryCollator = new Collator('root');
     $primaryCollator->setStrength(Collator::PRIMARY);
     $numOutOfOrder = 0;
     foreach ($this->groups as $weight => $group) {
         $uncomposedChars = array();
         $goodChars = array();
         foreach ($group as $cp) {
             if (isset($goodTertiaryChars[$cp])) {
                 $goodChars[] = $cp;
             }
             if (!isset($this->mappedChars[$cp])) {
                 $uncomposedChars[] = $cp;
             }
         }
         $x = array_intersect($goodChars, $uncomposedChars);
         if (!$x) {
             $x = $uncomposedChars;
             if (!$x) {
                 $x = $group;
             }
         }
         // Use ICU to pick the lowest sorting character in the selection
         $tertiaryCollator->sort($x);
         $cp = $x[0];
         $char = UtfNormal\Utils::codepointToUtf8($cp);
         $headerChars[] = $char;
         if ($primaryCollator->compare($char, $prevChar) <= 0) {
             $numOutOfOrder++;
             /*
             				printf( "Out of order: U+%05X > U+%05X\n",
             					utf8ToCodepoint( $prevChar ),
             					utf8ToCodepoint( $char ) );
             */
         }
         $prevChar = $char;
         if ($this->debugOutFile) {
             fwrite($this->debugOutFile, sprintf("%05X %s %s (%s)\n", $cp, $weight, $char, implode(' ', array_map('UtfNormal\\Utils::codepointToUtf8', $group))));
         }
     }
     print "Out of order: {$numOutOfOrder} / " . count($headerChars) . "\n";
     fwrite($outFile, serialize($headerChars));
 }
Exemple #8
0
 /**
  * Parse image options text and use it to make an image
  * @param Title $title
  * @param string $options
  * @param LinkHolderArray $holders
  */
 function makeImage($title, $options, $holders = false)
 {
     # Check if the options text is of the form "options|alt text"
     # Options are:
     #  * thumbnail  make a thumbnail with enlarge-icon and caption, alignment depends on lang
     #  * left       no resizing, just left align. label is used for alt= only
     #  * right      same, but right aligned
     #  * none       same, but not aligned
     #  * ___px      scale to ___ pixels width, no aligning. e.g. use in taxobox
     #  * center     center the image
     #  * framed     Keep original image size, no magnify-button.
     #  * frameless  like 'thumb' but without a frame. Keeps user preferences for width
     #  * upright    reduce width for upright images, rounded to full __0 px
     #  * border     draw a 1px border around the image
     #  * alt        Text for HTML alt attribute (defaults to empty)
     # vertical-align values (no % or length right now):
     #  * baseline
     #  * sub
     #  * super
     #  * top
     #  * text-top
     #  * middle
     #  * bottom
     #  * text-bottom
     $parts = StringUtils::explode("|", $options);
     $sk = $this->mOptions->getSkin();
     # Give extensions a chance to select the file revision for us
     $skip = $time = $descQuery = false;
     wfRunHooks('BeforeParserMakeImageLinkObj', array(&$this, &$title, &$skip, &$time, &$descQuery));
     if ($skip) {
         return $sk->link($title);
     }
     # Get the file
     $imagename = $title->getDBkey();
     if (isset($this->mFileCache[$imagename][$time])) {
         $file = $this->mFileCache[$imagename][$time];
     } else {
         $file = wfFindFile($title, $time);
         if (count($this->mFileCache) > 1000) {
             $this->mFileCache = array();
         }
         $this->mFileCache[$imagename][$time] = $file;
     }
     # Get parameter map
     $handler = $file ? $file->getHandler() : false;
     list($paramMap, $mwArray) = $this->getImageParams($handler);
     # Process the input parameters
     $caption = '';
     $params = array('frame' => array(), 'handler' => array(), 'horizAlign' => array(), 'vertAlign' => array());
     foreach ($parts as $part) {
         $part = trim($part);
         list($magicName, $value) = $mwArray->matchVariableStartToEnd($part);
         $validated = false;
         if (isset($paramMap[$magicName])) {
             list($type, $paramName) = $paramMap[$magicName];
             // Special case; width and height come in one variable together
             if ($type === 'handler' && $paramName === 'width') {
                 $m = array();
                 # (bug 13500) In both cases (width/height and width only),
                 # permit trailing "px" for backward compatibility.
                 if (preg_match('/^([0-9]*)x([0-9]*)\\s*(?:px)?\\s*$/', $value, $m)) {
                     $width = intval($m[1]);
                     $height = intval($m[2]);
                     if ($handler->validateParam('width', $width)) {
                         $params[$type]['width'] = $width;
                         $validated = true;
                     }
                     if ($handler->validateParam('height', $height)) {
                         $params[$type]['height'] = $height;
                         $validated = true;
                     }
                 } elseif (preg_match('/^[0-9]*\\s*(?:px)?\\s*$/', $value)) {
                     $width = intval($value);
                     if ($handler->validateParam('width', $width)) {
                         $params[$type]['width'] = $width;
                         $validated = true;
                     }
                 }
                 // else no validation -- bug 13436
             } else {
                 if ($type === 'handler') {
                     # Validate handler parameter
                     $validated = $handler->validateParam($paramName, $value);
                 } else {
                     # Validate internal parameters
                     switch ($paramName) {
                         case 'manualthumb':
                         case 'alt':
                             // @fixme - possibly check validity here for
                             // manualthumb? downstream behavior seems odd with
                             // missing manual thumbs.
                             $validated = true;
                             $value = $this->stripAltText($value, $holders);
                             break;
                         case 'link':
                             $chars = self::EXT_LINK_URL_CLASS;
                             $prots = $this->mUrlProtocols;
                             if ($value === '') {
                                 $paramName = 'no-link';
                                 $value = true;
                                 $validated = true;
                             } elseif (preg_match("/^{$prots}/", $value)) {
                                 if (preg_match("/^({$prots}){$chars}+\$/", $value, $m)) {
                                     $paramName = 'link-url';
                                     $this->mOutput->addExternalLink($value);
                                     $validated = true;
                                 }
                             } else {
                                 $linkTitle = Title::newFromText($value);
                                 if ($linkTitle) {
                                     $paramName = 'link-title';
                                     $value = $linkTitle;
                                     $this->mOutput->addLink($linkTitle);
                                     $validated = true;
                                 }
                             }
                             break;
                         default:
                             // Most other things appear to be empty or numeric...
                             $validated = $value === false || is_numeric(trim($value));
                     }
                 }
                 if ($validated) {
                     $params[$type][$paramName] = $value;
                 }
             }
         }
         if (!$validated) {
             $caption = $part;
         }
     }
     # Process alignment parameters
     if ($params['horizAlign']) {
         $params['frame']['align'] = key($params['horizAlign']);
     }
     if ($params['vertAlign']) {
         $params['frame']['valign'] = key($params['vertAlign']);
     }
     $params['frame']['caption'] = $caption;
     $params['frame']['title'] = $this->stripAltText($caption, $holders);
     # In the old days, [[Image:Foo|text...]] would set alt text.  Later it
     # came to also set the caption, ordinary text after the image -- which
     # makes no sense, because that just repeats the text multiple times in
     # screen readers.  It *also* came to set the title attribute.
     #
     # Now that we have an alt attribute, we should not set the alt text to
     # equal the caption: that's worse than useless, it just repeats the
     # text.  This is the framed/thumbnail case.  If there's no caption, we
     # use the unnamed parameter for alt text as well, just for the time be-
     # ing, if the unnamed param is set and the alt param is not.
     #
     # For the future, we need to figure out if we want to tweak this more,
     # e.g., introducing a title= parameter for the title; ignoring the un-
     # named parameter entirely for images without a caption; adding an ex-
     # plicit caption= parameter and preserving the old magic unnamed para-
     # meter for BC; ...
     if ($caption !== '' && !isset($params['frame']['alt']) && !isset($params['frame']['framed']) && !isset($params['frame']['thumbnail']) && !isset($params['frame']['manualthumb'])) {
         $params['frame']['alt'] = $params['frame']['title'];
     }
     wfRunHooks('ParserMakeImageParams', array($title, $file, &$params));
     # Linker does the rest
     $ret = $sk->makeImageLink2($title, $file, $params['frame'], $params['handler'], $time, $descQuery);
     # Give the handler a chance to modify the parser object
     if ($handler) {
         $handler->parserTransformHook($this, $file);
     }
     return $ret;
 }
 function highlight($text)
 {
     $lines = StringUtils::explode("\n", $text);
     foreach ($lines as $lineNum => $line) {
         if ($lineNum == $this->lineNum - 1) {
             return "{$line}\n" . str_repeat(' ', $this->colNum - 1) . "^\n";
         }
     }
     return '';
 }
 /**
  * Parse content of <gallery> tag (add images with captions and links provided)
  */
 public function parse(&$parser = null)
 {
     wfProfileIn(__METHOD__);
     //use images passed inside <gallery> tag
     $lines = StringUtils::explode("\n", $this->mText);
     foreach ($lines as $line) {
         if ($line == '') {
             continue;
         }
         $parts = (array) StringUtils::explode('|', $line);
         // get name of an image from current line and remove it from list of params
         $imageName = array_shift($parts);
         if (strpos($line, '%') !== false) {
             $imageName = urldecode($imageName);
         }
         // Allow <gallery> to accept image names without an Image: prefix
         $tp = Title::newFromText($imageName, NS_FILE);
         $nt =& $tp;
         if (is_null($nt)) {
             // Bogus title. Ignore these so we don't bomb out later.
             continue;
         }
         // search for caption and link= param
         $captionParts = array();
         $link = $linktext = $shorttext = '';
         foreach ($parts as $part) {
             if (substr($part, 0, 5) == 'link=') {
                 $link = substr($part, 5);
             } else {
                 if (substr($part, 0, 9) == 'linktext=') {
                     $linktext = substr($part, 9);
                 } else {
                     if (substr($part, 0, 10) == 'shorttext=') {
                         $shorttext = substr($part, 10);
                     } else {
                         $tempPart = trim($part);
                         //If it looks like Gallery param don't treat it as a caption part
                         if (!in_array($tempPart, $this->mAvailableUniqueParams)) {
                             $captionParts[] = $tempPart;
                         }
                     }
                 }
             }
         }
         // support captions with internal links with pipe (Foo.jpg|link=Bar|[[test|link]])
         $caption = implode('|', $captionParts);
         $imageItem = array('name' => $imageName, 'caption' => $caption, 'link' => $link, 'linktext' => $linktext, 'shorttext' => $shorttext, 'data-caption' => Sanitizer::removeHTMLtags($caption));
         // Get article link if it exists. If the href attribute is identical to the local
         // file URL, then there is no article URL.
         $localUrl = $tp->getLocalUrl();
         $linkAttributes = $this->parseLink($localUrl, $tp->getText(), $link);
         if ($linkAttributes['href'] !== $localUrl) {
             $imageItem['linkhref'] = $linkAttributes['href'];
         }
         // store list of images from inner content of tag (to be used by front-end)
         $this->mData['images'][] = $imageItem;
         // store list of images actually shown (to be used by front-end)
         $this->mData['imagesShown'][] = $imageItem;
         $this->add($nt, $this->mParser->recursiveTagParse($caption), $link, $caption);
         // Only add real images (bug #5586)
         if ($nt->getNamespace() == NS_FILE) {
             $this->mParser->mOutput->addImage($nt->getDBkey());
         }
     }
     // support "showrecentuploads" attribute (add 20 recently uploaded images at the end of slideshow)
     if (!empty($this->mShowRecentUploads)) {
         $this->addRecentlyUploaded(self::RECENT_UPLOADS_IMAGES);
     }
     // store ID of gallery
     if (empty($this->mData['id'])) {
         $this->mData['id'] = self::$galleriesCounter++;
     }
     if (!empty($parser)) {
         $this->recordParserOption($parser);
     }
     wfProfileOut(__METHOD__);
 }
Exemple #11
0
 /**
  * @param  $in
  * @param array $param
  * @param Parser $parser
  * @param bool $frame
  * @return string
  */
 public static function renderSlideshowTag($in, $param = array(), $parser = null, $frame = false)
 {
     $s = new CarZamSlideshow();
     $s->setParser($parser);
     $s->setContextTitle($parser->getTitle());
     $s->setHideBadImages();
     if (isset($param['height'])) {
         $explosion = explode('px', strtolower($param['height']));
         $s->setPhotoHeight($explosion[0]);
     }
     if (isset($param['width'])) {
         $explosion = explode('px', strtolower($param['width']));
         $s->setPhotoWidth($explosion[0]);
     }
     if (isset($param['float'])) {
         $s->setFloat($param['float']);
     }
     # Reading inside the tag, right now takes arguments by order
     /** @todo make less ugly */
     $lines = StringUtils::explode("\n", $in);
     foreach ($lines as $line) {
         $parameters = self::parseLine($line, $parser, $frame);
         if ($parameters === false) {
             continue;
         } else {
             $s->add($parameters['title'], $parameters['caption'], $parameters['alt'], $parameters['titleLink']);
         }
     }
     return $s->toHTML();
 }
 /**
  * Execute the pass.
  * @return string
  */
 private function execute()
 {
     $text = $this->text;
     # Parsing through the text line by line.  The main thing
     # happening here is handling of block-level elements p, pre,
     # and making lists from lines starting with * # : etc.
     $textLines = StringUtils::explode("\n", $text);
     $lastPrefix = $output = '';
     $this->DTopen = $inBlockElem = false;
     $prefixLength = 0;
     $pendingPTag = false;
     $inBlockquote = false;
     foreach ($textLines as $inputLine) {
         # Fix up $lineStart
         if (!$this->lineStart) {
             $output .= $inputLine;
             $this->lineStart = true;
             continue;
         }
         # * = ul
         # # = ol
         # ; = dt
         # : = dd
         $lastPrefixLength = strlen($lastPrefix);
         $preCloseMatch = preg_match('/<\\/pre/i', $inputLine);
         $preOpenMatch = preg_match('/<pre/i', $inputLine);
         # If not in a <pre> element, scan for and figure out what prefixes are there.
         if (!$this->inPre) {
             # Multiple prefixes may abut each other for nested lists.
             $prefixLength = strspn($inputLine, '*#:;');
             $prefix = substr($inputLine, 0, $prefixLength);
             # eh?
             # ; and : are both from definition-lists, so they're equivalent
             #  for the purposes of determining whether or not we need to open/close
             #  elements.
             $prefix2 = str_replace(';', ':', $prefix);
             $t = substr($inputLine, $prefixLength);
             $this->inPre = (bool) $preOpenMatch;
         } else {
             # Don't interpret any other prefixes in preformatted text
             $prefixLength = 0;
             $prefix = $prefix2 = '';
             $t = $inputLine;
         }
         # List generation
         if ($prefixLength && $lastPrefix === $prefix2) {
             # Same as the last item, so no need to deal with nesting or opening stuff
             $output .= $this->nextItem(substr($prefix, -1));
             $pendingPTag = false;
             if (substr($prefix, -1) === ';') {
                 # The one nasty exception: definition lists work like this:
                 # ; title : definition text
                 # So we check for : in the remainder text to split up the
                 # title and definition, without b0rking links.
                 $term = $t2 = '';
                 if ($this->findColonNoLinks($t, $term, $t2) !== false) {
                     $t = $t2;
                     $output .= $term . $this->nextItem(':');
                 }
             }
         } elseif ($prefixLength || $lastPrefixLength) {
             # We need to open or close prefixes, or both.
             # Either open or close a level...
             $commonPrefixLength = $this->getCommon($prefix, $lastPrefix);
             $pendingPTag = false;
             # Close all the prefixes which aren't shared.
             while ($commonPrefixLength < $lastPrefixLength) {
                 $output .= $this->closeList($lastPrefix[$lastPrefixLength - 1]);
                 --$lastPrefixLength;
             }
             # Continue the current prefix if appropriate.
             if ($prefixLength <= $commonPrefixLength && $commonPrefixLength > 0) {
                 $output .= $this->nextItem($prefix[$commonPrefixLength - 1]);
             }
             # Open prefixes where appropriate.
             if ($lastPrefix && $prefixLength > $commonPrefixLength) {
                 $output .= "\n";
             }
             while ($prefixLength > $commonPrefixLength) {
                 $char = substr($prefix, $commonPrefixLength, 1);
                 $output .= $this->openList($char);
                 if (';' === $char) {
                     # @todo FIXME: This is dupe of code above
                     if ($this->findColonNoLinks($t, $term, $t2) !== false) {
                         $t = $t2;
                         $output .= $term . $this->nextItem(':');
                     }
                 }
                 ++$commonPrefixLength;
             }
             if (!$prefixLength && $lastPrefix) {
                 $output .= "\n";
             }
             $lastPrefix = $prefix2;
         }
         # If we have no prefixes, go to paragraph mode.
         if (0 == $prefixLength) {
             # No prefix (not in list)--go to paragraph mode
             # @todo consider using a stack for nestable elements like span, table and div
             $openMatch = preg_match('/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|' . '<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)/iS', $t);
             $closeMatch = preg_match('/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|' . '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|' . Parser::MARKER_PREFIX . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS', $t);
             if ($openMatch || $closeMatch) {
                 $pendingPTag = false;
                 # @todo bug 5718: paragraph closed
                 $output .= $this->closeParagraph();
                 if ($preOpenMatch && !$preCloseMatch) {
                     $this->inPre = true;
                 }
                 $bqOffset = 0;
                 while (preg_match('/<(\\/?)blockquote[\\s>]/i', $t, $bqMatch, PREG_OFFSET_CAPTURE, $bqOffset)) {
                     $inBlockquote = !$bqMatch[1][0];
                     // is this a close tag?
                     $bqOffset = $bqMatch[0][1] + strlen($bqMatch[0][0]);
                 }
                 $inBlockElem = !$closeMatch;
             } elseif (!$inBlockElem && !$this->inPre) {
                 if (' ' == substr($t, 0, 1) && ($this->lastSection === 'pre' || trim($t) != '') && !$inBlockquote) {
                     # pre
                     if ($this->lastSection !== 'pre') {
                         $pendingPTag = false;
                         $output .= $this->closeParagraph() . '<pre>';
                         $this->lastSection = 'pre';
                     }
                     $t = substr($t, 1);
                 } else {
                     # paragraph
                     if (trim($t) === '') {
                         if ($pendingPTag) {
                             $output .= $pendingPTag . '<br />';
                             $pendingPTag = false;
                             $this->lastSection = 'p';
                         } else {
                             if ($this->lastSection !== 'p') {
                                 $output .= $this->closeParagraph();
                                 $this->lastSection = '';
                                 $pendingPTag = '<p>';
                             } else {
                                 $pendingPTag = '</p><p>';
                             }
                         }
                     } else {
                         if ($pendingPTag) {
                             $output .= $pendingPTag;
                             $pendingPTag = false;
                             $this->lastSection = 'p';
                         } elseif ($this->lastSection !== 'p') {
                             $output .= $this->closeParagraph() . '<p>';
                             $this->lastSection = 'p';
                         }
                     }
                 }
             }
         }
         # somewhere above we forget to get out of pre block (bug 785)
         if ($preCloseMatch && $this->inPre) {
             $this->inPre = false;
         }
         if ($pendingPTag === false) {
             $output .= $t;
             if ($prefixLength === 0) {
                 $output .= "\n";
             }
         }
     }
     while ($prefixLength) {
         $output .= $this->closeList($prefix2[$prefixLength - 1]);
         --$prefixLength;
         if (!$prefixLength) {
             $output .= "\n";
         }
     }
     if ($this->lastSection !== '') {
         $output .= '</' . $this->lastSection . '>';
         $this->lastSection = '';
     }
     return $output;
 }
Exemple #13
0
 /**
  * convert text to different variants of a language. the automatic
  * conversion is done in autoConvert(). here we parse the text
  * marked with -{}-, which specifies special conversions of the
  * text that can not be accomplished in autoConvert()
  *
  * syntax of the markup:
  * -{code1:text1;code2:text2;...}-  or
  * -{flags|code1:text1;code2:text2;...}-  or
  * -{text}- in which case no conversion should take place for text
  *
  * @param string $text text to be converted
  * @param bool $isTitle whether this conversion is for the article title
  * @return string converted text
  * @public
  */
 function convert($text, $isTitle = false)
 {
     $mw =& MagicWord::get('notitleconvert');
     if ($mw->matchAndRemove($text)) {
         $this->mDoTitleConvert = false;
     }
     $mw =& MagicWord::get('nocontentconvert');
     if ($mw->matchAndRemove($text)) {
         $this->mDoContentConvert = false;
     }
     // no conversion if redirecting
     $mw =& MagicWord::get('redirect');
     if ($mw->matchStart($text)) {
         return $text;
     }
     $plang = $this->getPreferredVariant();
     // for title convertion
     if ($isTitle) {
         return $this->convertTitle($text, $plang);
     }
     $tarray = StringUtils::explode($this->mMarkup['end'], $text);
     $text = '';
     $marks = array();
     foreach ($tarray as $txt) {
         $marked = explode($this->mMarkup['begin'], $txt, 2);
         if (array_key_exists(1, $marked)) {
             $crule = new ConverterRule($marked[1], $this);
             $crule->parse($plang);
             $marked[1] = $crule->getDisplay();
             $this->prepareManualConv($crule);
         } else {
             $marked[0] .= $this->mMarkup['end'];
         }
         array_push($marks, $marked);
     }
     $this->applyManualConv();
     foreach ($marks as $marked) {
         if ($this->mDoContentConvert) {
             $text .= $this->autoConvert($marked[0], $plang);
         } else {
             $text .= $marked[0];
         }
         if (array_key_exists(1, $marked)) {
             $text .= $marked[1];
         }
     }
     // Remove the last delimiter (wasn't real)
     $text = substr($text, 0, -strlen($this->mMarkup['end']));
     return $text;
 }
 /**
  * Returns lines of text contained inside mosaic slider gallery tag
  * @param $articleText
  * @return array
  */
 protected function extractMosaicGalleryImages($articleText)
 {
     $lines = array();
     if (preg_match('/\\<gallery.+mosaic.+\\>([\\s\\S]+)\\<\\/gallery\\>/', $articleText, $matches)) {
         $lines = StringUtils::explode("\n", $matches[1]);
     }
     return $lines;
 }
 /**
  * Parse content of <gallery> tag (add images with captions and links provided)
  */
 public function parse(&$parser = null)
 {
     wfProfileIn(__METHOD__);
     //use images passed inside <gallery> tag
     $lines = StringUtils::explode("\n", $this->mText);
     foreach ($lines as $line) {
         if ($line == '') {
             continue;
         }
         $parts = (array) StringUtils::explode('|', $line);
         // get name of an image from current line and remove it from list of params
         $imageName = array_shift($parts);
         if (strpos($line, '%') !== false) {
             $imageName = urldecode($imageName);
         }
         // Allow <gallery> to accept image names without an Image: prefix
         $tp = Title::newFromText($imageName, NS_FILE);
         $nt =& $tp;
         if (is_null($nt)) {
             // Bogus title. Ignore these so we don't bomb out later.
             continue;
         }
         // search for caption and link= param
         $captionParts = array();
         $link = $linktext = $shorttext = '';
         foreach ($parts as $part) {
             if (substr($part, 0, 5) == 'link=') {
                 $link = substr($part, 5);
             } else {
                 if (substr($part, 0, 9) == 'linktext=') {
                     $linktext = substr($part, 9);
                 } else {
                     if (substr($part, 0, 10) == 'shorttext=') {
                         $shorttext = substr($part, 10);
                     } else {
                         $captionParts[] = trim($part);
                     }
                 }
             }
         }
         // support captions with internal links with pipe (Foo.jpg|link=Bar|[[test|link]])
         $caption = implode('|', $captionParts);
         $imageItem = array('name' => $imageName, 'caption' => $caption, 'link' => $link, 'linktext' => $linktext, 'shorttext' => $shorttext, 'data-caption' => htmlspecialchars($caption));
         // store list of images from inner content of tag (to be used by front-end)
         $this->mData['images'][] = $imageItem;
         // store list of images actually shown (to be used by front-end)
         $this->mData['imagesShown'][] = $imageItem;
         // use global instance of parser (RT #44689 / RT #44712)
         $caption = $this->mParser->recursiveTagParse($caption);
         $this->add($nt, $caption, $link);
         // Only add real images (bug #5586)
         if ($nt->getNamespace() == NS_FILE) {
             $this->mParser->mOutput->addImage($nt->getDBkey());
         }
     }
     // support "showrecentuploads" attribute (add 20 recently uploaded images at the end of slideshow)
     if (!empty($this->mShowRecentUploads)) {
         $this->addRecentlyUploaded(self::RECENT_UPLOADS_IMAGES);
     }
     if (!empty($this->mFeedURL)) {
         $data = WikiaPhotoGalleryRSS::parseFeed($this->mFeedURL);
         //title of the feed - used by Lightbox
         $this->mData['feedTitle'] = $data['feedTitle'];
         //use images from feed
         $this->mExternalImages = $data['images'];
         // store list of images from inner content of tag (to be used by front-end)
         $this->mData['externalImages'] = $this->mExternalImages;
         // store list of images actually shown (to be used by front-end)
         $this->mData['imagesShown'] = $this->mExternalImages;
     }
     // store ID of gallery
     if (empty($this->mData['id'])) {
         $this->mData['id'] = self::$galleriesCounter++;
     }
     if (!empty($parser)) {
         $this->recordParserOption($parser);
     }
     wfProfileOut(__METHOD__);
 }
 /**
  * convert text to different variants of a language. the automatic
  * conversion is done in autoConvert(). here we parse the text
  * marked with -{}-, which specifies special conversions of the
  * text that can not be accomplished in autoConvert()
  *
  * syntax of the markup:
  * -{code1:text1;code2:text2;...}-  or
  * -{flags|code1:text1;code2:text2;...}-  or
  * -{text}- in which case no conversion should take place for text
  *
  * @param string $text text to be converted
  * @param bool $isTitle whether this conversion is for the article title
  * @return string converted text
  * @public
  */
 function convert($text, $isTitle = false)
 {
     $mw =& MagicWord::get('notitleconvert');
     if ($mw->matchAndRemove($text)) {
         $this->mDoTitleConvert = false;
     }
     $mw =& MagicWord::get('nocontentconvert');
     if ($mw->matchAndRemove($text)) {
         $this->mDoContentConvert = false;
     }
     // no conversion if redirecting
     $mw =& MagicWord::get('redirect');
     if ($mw->matchStart($text)) {
         return $text;
     }
     // for title convertion
     if ($isTitle) {
         return $this->convertTitle($text);
     }
     $plang = $this->getPreferredVariant();
     $tarray = StringUtils::explode($this->mMarkup['end'], $text);
     $text = '';
     $lastDelim = false;
     foreach ($tarray as $txt) {
         $marked = explode($this->mMarkup['begin'], $txt, 2);
         if ($this->mDoContentConvert) {
             $text .= $this->autoConvert($marked[0], $plang);
         } else {
             $text .= $marked[0];
         }
         if (array_key_exists(1, $marked)) {
             // strip the flags from syntax like -{T| ... }-
             $crule = new ConverterRule($marked[1], $this);
             $crule->parse($plang);
             $text .= $crule->getDisplay();
             $this->applyManualConv($crule);
             $lastDelim = false;
         } else {
             // Reinsert the }- which wasn't part of anything
             $text .= $this->mMarkup['end'];
             $lastDelim = true;
         }
     }
     if ($lastDelim) {
         // Remove the last delimiter (wasn't real)
         $text = substr($text, 0, -strlen($this->mMarkup['end']));
     }
     return $text;
 }