/** * Sanitize data to avoid tag replacement * * @param mixed data * * @return string * */ public static function sanitizeOutput($data) { return self::sanitize(Utilities::sanitizeOutput($data)); }
/** * Placeholder replacement * * @param mixed $placeholder placeholder id as string or array of placholders and values * @param mixed $value value if 1st param is a placeholder id * * OR * * @param mixed $* arrays of placeholders and values or data objects * * @return Lang */ public function replace() { // Do not replace anything unless allowed if (!$this->allow_replace) { return $this; } $args = func_get_args(); // Forward call to any sub-Translations if (!is_string($this->translation)) { $t = array(); foreach ($this->translation as $k => $v) { $t[$k] = call_user_func_array(array($v, 'replace'), $args); } return new self($t); } // Transform function arguments into placeholders values array $placeholders = array(); while ($arg = array_shift($args)) { if (is_string($arg)) { $placeholders[$arg] = array_shift($args); } else { if (is_array($arg)) { foreach ($arg as $k => $v) { if (!is_numeric($k)) { $placeholders[$k] = $v; } } } else { if (is_object($arg)) { $placeholders[strtolower(get_class($arg))] = $arg; } } } } // base translation $translation = $this->translation; // Placeholder value getter $placeholder_resolver = function ($path, $raw = false) use($placeholders) { // Need value casting ? $path = explode(':', $path); $cast = count($path) > 1 ? array_shift($path) : null; $path = array_shift($path); // Path parts $path = array_filter(array_map('trim', explode('.', $path))); $name = array_shift($path); // Return empty if placeholder does not exist if (!array_key_exists($name, $placeholders)) { return null; } $value = $placeholders[$name]; // Follow path if any while (!is_null($entry = array_shift($path))) { if (is_object($value)) { $value = $value->{$entry}; } else { if (is_array($value)) { if (is_numeric($entry) && !is_float($entry)) { $entry = (int) $entry; } if (preg_match('`^(first|nth|last)\\(([0-9]*\\))`', $entry, $m)) { $keys = array_keys($value); switch ($m[1]) { case 'first': $entry = reset($keys); break; case 'last': $entry = end($keys); break; case 'nth': $i = $m[2] ? (int) $m[2] : 0; $entry = array_slice($keys, $i, 1); $entry = array_shift($entry); break; } } $value = !is_null($entry) && array_key_exists($entry, $value) ? $value[$entry] : null; } } } // Cast if needed if ($cast) { switch ($cast) { case 'date': $value = Utilities::formatDate($value); break; case 'datetime': $value = Utilities::formatDate($value, true); break; case 'time': $value = Utilities::formatTime($value); break; case 'size': $value = Utilities::formatBytes($value); break; } } // Convert non-scalar to scalar unless raw required if (!$raw) { if (is_array($value)) { $value = count($value); } if (is_object($value)) { $value = true; } } return $value; }; // Replace each loops $translation = preg_replace_callback('`\\{each:([^\\}]+)\\}(.+)\\{endeach\\}`msiU', function ($m) use($placeholders, $placeholder_resolver) { // Source variable $src = $m[1]; // Inner body $content = new Translation($m[2]); // Whole each statment $raw = $m[0]; // Inner loop variable name $itemname = 'item'; if (preg_match('`^(.+)\\s+as\\s+([a-z0-9_]+)$`i', $src, $m)) { $itemname = $m[2]; $src = $m[1]; } // Resolve source variable and get raw value $src = $placeholder_resolver($src, true); // Placeholder not (yet) defined, do not replace if (is_null($src)) { return $raw; } // Source variable is notan array, cannot replace if (!is_array($src)) { return ''; } // Loop and replace inner variables $out = array(); foreach ($src as $item) { $out[] = $content->replace(array_merge($placeholders, array($itemname => $item)))->out(); } // Return serialized content return implode('', $out); }, $translation); // Replace if statments $translation = preg_replace_callback('`\\{if:([^\\}]+)\\}(.+)(?:\\{else\\}(.+))?\\{endif\\}`msiU', function ($m) use($placeholder_resolver) { // Get test $condition = $m[1]; // Get "if true" content $ifcontent = $m[2]; // Get "if false" content $elsecontent = count($m) > 3 ? $m[3] : ''; // Evaluate test (and before or fashion) $match = false; $leftor = array(); foreach (array_map('trim', array_filter(explode('|', $condition))) as $orpart) { $smatch = true; $leftand = array(); foreach (array_map('trim', array_filter(explode('&', $orpart))) as $andpart) { $op = 'bool'; $ov = true; $neg = false; // Is there a comparison operator if (preg_match('`^(.+)(==|!=|<|<=|>|>=)(.+)$`', $andpart, $m)) { $andpart = trim($m[1]); $op = $m[2]; $ov = trim($m[3]); } // Is there any negation ? $andpart = trim($andpart); if (substr($andpart, 0, 1) == '!') { $neg = true; $andpart = trim(substr($andpart, 1)); } // Resolve compared value $value = $placeholder_resolver($andpart); // Placeholder not (yet) available, cannot choose, leave part as is if (is_null($value)) { $leftand[] = ($neg ? '!' : '') . $andpart . ($op != 'bool' ? $op . $ov : ''); $smatch = false; break; } // Cast value to scalar if (is_object($value)) { $value = true; } if (is_array($value)) { $value = count($value); } // Cast value to compare to if ($ov == 'true') { $ov = true; } else { if ($ov == 'false') { $ov = false; } else { if (is_float($ov)) { $ov = (double) $ov; } else { if (is_numeric($ov)) { $ov = (int) $ov; } else { if (is_string($ov)) { if (preg_match('`^(["\'])(.*)\\1$`', $ov, $m)) { $ov = $m[2]; } } } } } } // Run the test switch ($op) { case '==': $smatch &= $value == $ov; break; case '!=': $smatch &= $value != $ov; break; case '<': $smatch &= $value < $ov; break; case '<=': $smatch &= $value <= $ov; break; case '>': $smatch &= $value > $ov; break; case '>=': $smatch &= $value >= $ov; break; case 'bool': default: $smatch &= (bool) $value; } } // Any test that we couldn't run ? Then leave what's not resolved for later, reduce value otherwise if (count($leftand)) { $leftor[] = implode('&', $leftand); } else { if ($smatch) { $match = true; break; } } } // Part of the test remains, set it for next replace if (!$match && count($leftor)) { return '{if:' . implode('|', $leftor) . '}' . $ifcontent . ($elsecontent ? '{else}' . $elsecontent : '') . '{endif}'; } // Return fitting content return $match ? $ifcontent : $elsecontent; }, $translation); // Basic placeholder replacement foreach ($placeholders as $k => $v) { $translation = preg_replace_callback('`\\{(([^:\\}]+:)?' . $k . '(\\.[a-z0-9_\\(\\)]+)*)\\}`iU', function ($m) use($placeholder_resolver) { if (substr($m[0], 0, 4) == '{if:') { return $m[0]; } // Remaining ifs $v = $placeholder_resolver($m[1]); return substr($m[0], 0, 5) == '{raw:' ? $v : Utilities::sanitizeOutput($v); // Ensure sanity }, $translation); } // Return new translation object for further replacements return new self($translation); }
if (!Utilities::isValidUID($token)) { throw new TokenHasBadFormatException($token); } $lang = array_key_exists('lang', $_REQUEST) ? $_REQUEST['lang'] : null; $available = Lang::getAvailableLanguages(); if (!array_key_exists($lang, $available)) { $lang = Lang::getCode(); } $url = '?s=translate_email&token=' . $token . '&lang='; if (count($available) > 1) { echo '<div class="buttons">'; foreach ($available as $id => $dfn) { if ($id == $lang) { echo '<span class="selected">' . Utilities::sanitizeOutput($dfn['name']) . '</span>'; } else { echo '<a href="' . $url . $id . '">' . Utilities::sanitizeOutput($dfn['name']) . '</a>'; } } echo '</div>'; } $translatable = TranslatableEmail::fromToken($token); $translation = $translatable->translate($lang); /* * Do not call Template::sanitizeOutput on email contents after that because * TranslatableEmail::translate calls Translation::replace which itself calls * Utilities::sanitizeOutput, use Template::sanitize instead ! */ $subject = array_filter($translation->subject->out()); ?> <dl>
?> </pre> <?php } ?> <div class="report"> <?php if (Config::get('support_email')) { ?> {tr:you_can_report_exception_by_email} : <a href="mailto:<?php echo Config::get('support_email'); ?> ?subject=Exception <?php echo method_exists($exception, 'getUid') ? Utilities::sanitizeOutput($exception->getUid()) : ''; ?> ">{tr:report_exception}</a> <?php } else { if (method_exists($exception, 'getUid')) { ?> {tr:you_can_report_exception} : <?php echo Utilities::sanitizeOutput($exception->getUid()); ?> <?php } } ?> </div> </div>