public function validate($target) { if (!is_string($target)) { throw new InvalidDataTypeException("Target is not a string, and cannot be validated according to string length!"); } $len = UTF8::strlen($target, $this->encoding); if ($len < $this->minLength) { throw new StringTooShortException("Length of target is too short, min = " . $this->minLength); } elseif ($len > $this->maxLength) { if (!$this->chopDown) { throw new StringTooLongException("Length of target is too long, max = " . $this->maxLength); } else { $target = UTF8::substr($target, 0, $this->maxLength, $this->encoding); } } return $target; }
/** * Convert the current array to JSON. * * @param null $options e.g. JSON_PRETTY_PRINT * * @return string */ public function toJson($options = null) { return UTF8::json_encode($this->array, $options); }
/** * Helper function called by preg_replace() on link replacement. * * Maintains an internal list of links to be displayed at the end of the * text, with numeric indices to the original point in the text they * appeared. Also makes an effort at identifying and handling absolute * and relative links. * * @param string $link URL of the link * @param string $display Part of the text to associate number with * @param string|null $linkOverride * * @return string */ protected function buildLinkList($link, $display, $linkOverride = null) { if ($linkOverride) { $linkMethod = $linkOverride; } else { $linkMethod = $this->options['do_links']; } // ignored link types if (preg_match('!^(:?' . $this->options['do_links_ignore'] . ')!i', $link)) { return $display; } if ($linkMethod === 'none') { return ' ' . $display . ' '; } if (preg_match('!^(:?[a-z][a-z0-9.+-]+:)!i', $link)) { $url = $link; } else { $url = $this->baseUrl; if (UTF8::substr($link, 0, 1) !== '/') { $url .= '/'; } $url .= $link; } if ($linkMethod === 'table') { // // table // if (($index = array_search($url, $this->linkList, true)) === false) { $index = count($this->linkList); $this->linkList[] = $url; } return ' ' . $display . ' [' . ($index + 1) . '] '; } elseif ($linkMethod === 'nextline') { // // nextline // return ' ' . $display . "\n" . '[' . $url . '] '; } elseif ($linkMethod === 'markdown') { // // markdown // return ' [' . $display . '](' . $url . ') '; } elseif ($linkMethod === 'bbcode') { // // bbcode // return ' [url=' . $url . ']' . $display . '[/url] '; } else { // // inline (default) // return ' ' . $display . ' [' . $url . '] '; } }
/** * @param string $str payload * * @return int length of payload in bytes */ public function _determineLength($str) { return UTF8::strlen($str, '8bit'); }
public function profileUtf8StrShuffleMediumString() { UTF8::str_shuffle("abcdefghijklmnopqrstuvwxyz"); }
/** * @param $body * * @return string */ protected function stripBom($body) { return UTF8::removeBOM($body); }
/** * Check if the email is valid. * * @param string $email * @param bool $useExampleDomainCheck * @param bool $useTypoInDomainCheck * @param bool $useTemporaryDomainCheck * @param bool $useDnsCheck (do not use, if you don't need it) * * @return bool */ public static function isValid($email, $useExampleDomainCheck = false, $useTypoInDomainCheck = false, $useTemporaryDomainCheck = false, $useDnsCheck = false) { // must be a string if (!is_string($email)) { return false; } // make sure string length is limited to avoid DOS attacks $emailStringLength = strlen($email); if ($emailStringLength >= 320 || $emailStringLength <= 2) { return false; } unset($emailStringLength); $email = str_replace(array('.', '@'), array('.', '@'), $email); if (strpos($email, '@') === false || strpos($email, '.') === false && strpos($email, ':') === false) { return false; } if (!preg_match('/^(?<local>.*<?)(?:.*)@(?<domain>.*)(?:>?)$/', $email, $parts)) { return false; } else { $local = $parts['local']; $domain = $parts['domain']; // Escaped spaces are allowed in the "local"-part. $local = str_replace('\\ ', '', $local); // Spaces in quotes e.g. "firstname lastname"@foo.bar are also allowed in the "local"-part. $quoteHelperForIdn = false; if (preg_match('/^"(?<inner>[^"]*)"$/mU', $local, $parts)) { $quoteHelperForIdn = true; $local = trim(str_replace($parts['inner'], str_replace(' ', '', $parts['inner']), $local), '"'); } if (strpos($local, ' ') !== false || strpos($local, '".') !== false) { return false; } if (function_exists('idn_to_ascii') && UTF8::max_chr_width($email) <= 3) { $localTmp = idn_to_ascii($local); if ($localTmp) { $local = $localTmp; } unset($localTmp); $domainTmp = idn_to_ascii($domain); if ($domainTmp) { $domain = $domainTmp; } unset($domainTmp); } else { static $punycode = null; if ($punycode === null) { $punycode = new Punycode(); } $local = $punycode->encode($local); $domain = $punycode->encode($domain); } if ($quoteHelperForIdn === true) { $local = '"' . $local . '"'; } $email = $local . '@' . $domain; if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { return false; } else { $valid = true; } if ($useExampleDomainCheck === true && self::isExampleDomain($domain) === true) { return false; } if ($useTypoInDomainCheck === true && self::isTypoInDomain($domain) === true) { return false; } if ($useTemporaryDomainCheck === true && self::isTemporaryDomain($domain) === true) { return false; } if ($useDnsCheck === true && self::isDnsError($domain) === true) { return false; } } return $valid; }
/** * Load HTML from file * * @param string $filePath * @param int|null $libXMLExtraOptions * * @return HtmlDomParser */ public function loadHtmlFile($filePath, $libXMLExtraOptions = null) { if (!is_string($filePath)) { throw new InvalidArgumentException(__METHOD__ . ' expects parameter 1 to be string.'); } if (!preg_match("/^https?:\\/\\//i", $filePath) && !file_exists($filePath)) { throw new RuntimeException("File {$filePath} not found"); } try { $html = UTF8::file_get_contents($filePath); } catch (\Exception $e) { throw new RuntimeException("Could not load file {$filePath}"); } if ($html === false) { throw new RuntimeException("Could not load file {$filePath}"); } $this->loadHtml($html, $libXMLExtraOptions); return $this; }
/** * _logQuery * * @param String $sql sql-query * @param int $duration * @param int $results result counter * * @return bool */ private function _logQuery($sql, $duration, $results) { $logLevelUse = strtolower($this->logger_level); if ($logLevelUse != 'trace' && $logLevelUse != 'debug') { return false; } $info = 'time => ' . round($duration, 5) . ' - ' . 'results => ' . $results . ' - ' . 'SQL => ' . UTF8::htmlentities($sql); $fileInfo = $this->getFileAndLineFromSql(); $this->logger(array('debug', '<strong>' . date('d. m. Y G:i:s') . ' (' . $fileInfo['file'] . ' line: ' . $fileInfo['line'] . '):</strong> ' . $info . '<br>', 'sql')); return true; }
/** * Convert a String to URL, e.g., "Petty<br>theft" to "Petty-theft" * * @param String $text * @param Int $length length of the output string * @param String $language * @param Boolean $file_name keep the "." from the extension e.g.: "imaäe.jpg" => "image.jpg" * @param Boolean $removeWords remove some "words" -> set via "remove_words()" * @param Boolean $strtolower use strtolower() at the end * @param String $seperator define a new seperator for the words * * @return String */ public static function filter($text, $length = 200, $language = 'de', $file_name = false, $removeWords = false, $strtolower = false, $seperator = '-') { // seperator-fallback if (!$seperator) { $seperator = '-'; } $text = preg_replace(self::$arrayToSeperator, $seperator, $text); // 1) replace with $seperator $text = UTF8::strip_tags($text); // 2) remove all other html-tags $text = self::downcode($text, $language); // 3) use special language replacer $text = preg_replace(self::$arrayToSeperator, $seperator, $text); // 4) replace with $seperator, again // remove all these words from the string before urlifying if ($removeWords === true) { $removeWordsSearch = '/\\b(' . join('|', self::get_remove_list($language)) . ')\\b/i'; } else { $removeWordsSearch = '//'; } // keep the "." from e.g.: a file-extension? if ($file_name) { $remove_pattern = '/[^' . $seperator . '.\\-a-zA-Z0-9\\s]/u'; } else { $remove_pattern = '/[^' . $seperator . '\\-a-zA-Z0-9\\s]/u'; } $text = preg_replace(array('`[' . $seperator . ']+`', '[^A-Za-z0-9]', $remove_pattern, '/[' . $seperator . '\\s]+/', '/^\\s+|\\s+$/', $removeWordsSearch), array($seperator, '', '', $seperator, '', ''), $text); // convert to lowercase if ($strtolower === true) { $text = strtolower($text); } // trim "$seperator" from beginning and end of the string $text = trim($text, $seperator); // "substr" only if "$length" is set if ($length && $length > 0) { $text = (string) substr($text, 0, $length); } return $text; }
function render() { if (count($this->results) > 0) { $max = max(array_map(function ($result) { return $result['count']; }, $this->results)); } else { $max = 0; } // see http://bost.ocks.org/mike/bar/2/ return h()->div->class('ui fluid card')->div->class('content')->div->class('header')->c($this->label)->end->end->div->class('content')->svg->viewBox('0 0 700 ' . count($this->results) * 30)->style('background:#fff;width:100%;')->c(array_map(function ($result) use($max) { $barWidth = $result['count'] / $max * 500; $labelAtRight = $barWidth < 40; $key = $result['_id']; $color = RandomColor::one(['luminosity' => 'bright', 'prng' => function ($min, $max) use($key) { # Get the color by hashing the text # So it stays the same when the page is refreshed return hexdec(UTF8::substr(md5($key), 0, 2)) / pow(16, 2) * ($max - $min) + $min; }]); if ($key === true) { $key = 'Yes'; $color = '#21ba45'; } elseif ($key === false) { $key = 'No'; $color = '#db2828'; } elseif ($key === null) { $key = '(None)'; $color = '#777'; } return h()->g->transform('translate(0, ' . $result['index'] * 30 . ')')->text->style('dominant-baseline:middle;text-anchor:end;')->x(140)->y(15)->c($key)->end->rect->width($barWidth)->y(5)->x(150)->height(20)->fill($color)->end->text->x(150 + $barWidth + ($labelAtRight ? 2 : -5))->y(15)->fill($labelAtRight ? 'black' : 'white')->style('dominant-baseline:middle;' . 'text-anchor:' . ($labelAtRight ? 'start;' : 'end;'))->c($result['count'])->end->end; }, $this->results))->end->end->end; }
/** * Personal names such as "Marcus Aurelius" are sometimes typed incorrectly using lowercase ("marcus aurelius"). * * @param string $names * @param string $delimiter * * @return string */ private function capitalizePersonalNameByDelimiter($names, $delimiter) { // init $names = explode($delimiter, $names); $encoding = $this->encoding; $specialCases = array('names' => array('ab', 'af', 'al', 'and', 'ap', 'bint', 'binte', 'da', 'de', 'del', 'den', 'der', 'di', 'dit', 'ibn', 'la', 'mac', 'nic', 'of', 'ter', 'the', 'und', 'van', 'von', 'y', 'zu'), 'prefixes' => array('al-', "d'", 'ff', "l'", 'mac', 'mc', 'nic')); foreach ($names as &$name) { if (in_array($name, $specialCases['names'], true)) { continue; } $continue = false; if ($delimiter == '-') { foreach ($specialCases['names'] as $beginning) { if (UTF8::strpos($name, $beginning, null, $encoding) === 0) { $continue = true; } } } foreach ($specialCases['prefixes'] as $beginning) { if (UTF8::strpos($name, $beginning, null, $encoding) === 0) { $continue = true; } } if ($continue) { continue; } $name = $this->capitalizeWord($name); } return new static(implode($delimiter, $names), $encoding); }
function makeCSVPart($v) { if ($v === null) { return null; } # Format the phone number with pretty unicode spaces # before displaying it in a table if (preg_match('/^[0-9]{10}$/', $v)) { $showValue = '(' . UTF8::substr($v, 0, 3) . ') ' . UTF8::substr($v, 3, 3) . ' ' . UTF8::substr($v, 6, 4); } else { $showValue = $v; } return $showValue; }
/** * Render formatting options onto text */ public function render() { $offset = 0; foreach ($this->formats as $format) { $attrs = $this->attributes($format->type, !empty($format->attrs) ? $format->attrs : null); $opening = '<' . $format->type . "{$attrs}>"; $closing = '</' . $format->type . '>'; $this->text = UTF8::substr_replace($this->text, $opening, $format->from + $offset, 0); $offset += strlen($opening); $this->text = UTF8::substr_replace($this->text, $closing, $format->to + $offset, 0); $offset += strlen($closing); } // create a temporary document and load the plain html $tmpDoc = new DOMDocument(); // purify HTML to convert HTML chars in text nodes etc. $config = HTMLPurifier_Config::createDefault(); $config->set('HTML.Trusted', true); $this->text = (new HTMLPurifier($config))->purify($this->text); $tmpDoc->loadHTML('<?xml encoding="UTF-8"><html><body>' . $this->text . '</body></html>'); $tmpDoc->encoding = 'UTF-8'; // import and attach the created nodes to the paragraph foreach ($tmpDoc->getElementsByTagName('body')->item(0)->childNodes as $node) { $node = $this->dom->importNode($node, true); $this->paragraph->appendChild($node); } return $this->paragraph; }
/** * @param $s * @param int $normalization_form * @param string $leading_combining * * @return array|bool|mixed|string */ public static function filterString($s, $normalization_form = 4, $leading_combining = 'â—Œ') { if (false !== strpos($s, "\r")) { // Workaround https://bugs.php.net/65732 $s = str_replace(array("\r\n", "\r"), "\n", $s); } if (preg_match('/[\\x80-\\xFF]/', $s)) { if (Normalizer::isNormalized($s, $normalization_form)) { $n = '-'; } else { $n = Normalizer::normalize($s, $normalization_form); if (isset($n[0])) { $s = $n; } else { $s = UTF8::encode('UTF-8', $s); } } if ($s[0] >= "€" && isset($n[0], $leading_combining[0]) && preg_match('/^\\p{Mn}/u', $s)) { // Prevent leading combining chars // for NFC-safe concatenations. $s = $leading_combining . $s; } } return $s; }
function render() { return h()->div->class('item')->div->class('header')->a->href('forms/' . $this->data->id)->c($this->data->name)->end->div->class('ui horizontal right floated label')->c($this->data->count)->c(UTF8::chr(0x2004) . 'submissions')->end->end->c(count($this->data->views) === 0 ? null : h()->div->class('ui horizontal list low-line-height')->div->class('item header')->c('Views: ')->end->c(array_map(function ($view) { return new ViewInfoView($view, $this->data); }, $this->data->views))->end)->end; }
/** * Parses host part of url. * * @param string $host Host part of url * * @return Host Object representation of host portion of url */ public function parseHost($host) { $host = UTF8::strtolower($host); return new Host($this->getSubdomain($host), $this->getRegistrableDomain($host), $this->getPublicSuffix($host), $host); }
/** * Log the current query via "$this->logger". * * @param string $sql sql-query * @param int $duration * @param int $results field_count | insert_id | affected_rows * @param bool $sql_error * * @return bool */ public function logQuery($sql, $duration, $results, $sql_error = false) { $logLevelUse = strtolower($this->logger_level); if ($sql_error === false && ($logLevelUse !== 'trace' && $logLevelUse !== 'debug')) { return false; } // set log-level if ($sql_error === true) { $logLevel = 'error'; } else { $logLevel = $logLevelUse; } // get extra info $infoExtra = \mysqli_info($this->_db->getLink()); if ($infoExtra) { $infoExtra = ' | info => ' . $infoExtra; } // // logging // $info = 'time => ' . round($duration, 5) . ' | results => ' . (int) $results . $infoExtra . ' | SQL => ' . UTF8::htmlentities($sql); $fileInfo = $this->getFileAndLineFromSql(); return $this->logger(array($logLevel, '<strong>' . date('d. m. Y G:i:s') . ' (' . $fileInfo['file'] . ' line: ' . $fileInfo['line'] . '):</strong> ' . $info . '<br>', 'sql')); }
/** * @param mixed $value * @param null|false|string $encoding * * @return string|null */ public static function escape(&$value, $encoding = null) { if (empty($value)) { return $value; } $kintEnabled = Kint::enabled(); if ($kintEnabled === Kint::MODE_CLI) { $value = str_replace("", '\\x1b', $value); } if ($kintEnabled === Kint::MODE_CLI || $kintEnabled === Kint::MODE_WHITESPACE) { return $value; } if (!$encoding) { $encoding = self::_detectEncoding($value); } $value = htmlspecialchars($value, ENT_NOQUOTES, $encoding === 'ASCII' ? 'UTF-8' : $encoding); // TODO: we could make the symbols hover-title show the code for the invisible symbol if ($encoding === 'UTF-8') { # when possible force invisible characters to have some sort of display (experimental) $value = UTF8::remove_invisible_characters($value, false, '?'); } # this call converts all non-ASCII characters into html chars of format $value = UTF8::html_encode($value, true, $encoding); return $value; }
public function testUtf8Query() { $sql = "INSERT INTO " . $this->tableName . "\n SET\n page_template = '" . $this->db->escape(UTF8::urldecode('D%26%23xFC%3Bsseldorf')) . "',\n page_type = '" . UTF8::urldecode('Düsseldorf') . "'\n "; $return = $this->db->execSQL($sql); self::assertEquals(true, is_int($return)); self::assertEquals(true, $return > 0); $data = $this->db->select($this->tableName, 'page_id=' . (int) $return); $dataArray = $data->fetchArray(); self::assertEquals('Düsseldorf', $dataArray['page_template']); self::assertEquals('Düsseldorf', $dataArray['page_type']); }
/** * Return the index of begin/end delimiters. * * @param string $begin befin delimiter * @param string $end end delimiter * * @return integer position index */ protected function getDelimitersIndex($begin, $end) { $string = $this->input; $nbegin = 0; $nend = 0; $position = 0; $sbrac = false; $dbrac = false; for ($i = 0, $length = UTF8::strlen($string); $i < $length; ++$i) { if ('"' === $string[$i]) { $dbrac = !$dbrac; } elseif ('\'' === $string[$i]) { $sbrac = !$sbrac; } if (!$sbrac && !$dbrac && $begin === $string[$i]) { ++$nbegin; } elseif (!$sbrac && !$dbrac && $end === $string[$i]) { if (++$nend === $nbegin) { $position = $i; break; } } } return $position; }
function minMaxLength($minLength, $maxLength) { return $this->ifOk(function ($x) use($minLength, $maxLength) { if (UTF8::strlen($x) > $maxLength) { return Result::error('The input is too long. Maximum is ' . $maxLength . ' characters.'); } elseif (UTF8::strlen($x) < $minLength) { return Result::error('The input is too short. Minimum is ' . $minLength . ' characters.'); } else { return Result::ok($x); } }); }
/** * @param string $value * * @return string */ protected static function _detectEncoding(&$value) { return UTF8::str_detect_encoding($value); }
/** * Escape: Use "mysqli_real_escape_string" and clean non UTF-8 chars + some extra optional stuff. * * @param mixed $var boolean: convert into "integer"<br /> * int: int (don't change it)<br /> * float: float (don't change it)<br /> * null: null (don't change it)<br /> * array: run escape() for every key => value<br /> * string: run UTF8::cleanup() and mysqli_real_escape_string()<br /> * @param bool $stripe_non_utf8 * @param bool $html_entity_decode * @param bool|null $convert_array <strong>false</strong> => Keep the array.<br /> * <strong>true</strong> => Convert to string var1,var2,var3...<br /> * <strong>null</strong> => Convert the array into null, every time. * * @return mixed */ public function escape($var = '', $stripe_non_utf8 = true, $html_entity_decode = false, $convert_array = false) { if ($var === null) { return null; } // save the current value as int (for later usage) if (!is_object($var)) { $varInt = (int) $var; } /** @noinspection TypeUnsafeComparisonInspection */ if (is_int($var) || is_bool($var) || isset($varInt, $var[0]) && $var[0] != '0' && "{$varInt}" == $var) { // "int" || int || bool return (int) $var; } elseif (is_float($var)) { // float return $var; } elseif (is_array($var)) { // array if ($convert_array === null) { return null; } $varCleaned = array(); foreach ((array) $var as $key => $value) { $key = $this->escape($key, $stripe_non_utf8, $html_entity_decode); $value = $this->escape($value, $stripe_non_utf8, $html_entity_decode); /** @noinspection OffsetOperationsInspection */ $varCleaned[$key] = $value; } if ($convert_array === true) { $varCleaned = implode(',', $varCleaned); return $varCleaned; } else { return (array) $varCleaned; } } if (is_string($var) || is_object($var) && method_exists($var, '__toString')) { // "string" $var = (string) $var; if ($stripe_non_utf8 === true) { $var = UTF8::cleanup($var); } if ($html_entity_decode === true) { // use no-html-entity for db $var = UTF8::html_entity_decode($var); } $var = get_magic_quotes_gpc() ? stripslashes($var) : $var; $var = \mysqli_real_escape_string($this->getLink(), $var); return (string) $var; } elseif ($var instanceof \DateTime) { // "DateTime"-object try { return $this->escape($var->format('Y-m-d H:i:s'), false); } catch (\Exception $e) { return null; } } else { return false; } }
/** * Helper function called by preg_replace() on link replacement. * * Maintains an internal list of links to be displayed at the end of the * text, with numeric indices to the original point in the text they * appeared. Also makes an effort at identifying and handling absolute * and relative links. * * @param string $link URL of the link * @param string $display Part of the text to associate number with * @param string|null $linkOverride * * @return string */ protected function buildLinkList($link, $display, $linkOverride = null) { $linkMethod = $linkOverride ? $linkOverride : $this->options['do_links']; if ($linkMethod == 'none') { return $display; } // ignored link types if (preg_match('!^(javascript:|mailto:|#)!i', $link)) { return $display; } if (preg_match('!^([a-z][a-z0-9.+-]+:)!i', $link)) { $url = $link; } else { $url = $this->baseurl; if (UTF8::substr($link, 0, 1) != '/') { $url .= '/'; } $url .= $link; } if ($linkMethod == 'table') { if (($index = array_search($url, $this->linkList, true)) === false) { $index = count($this->linkList); $this->linkList[] = $url; } return $display . ' [' . ($index + 1) . ']'; } elseif ($linkMethod == 'nextline') { return $display . "\n[" . $url . ']'; } elseif ($linkMethod == 'bbcode') { return '[url=' . $url . ']' . $display . '[/url]'; } else { // link_method defaults to inline return $display . ' [' . $url . ']'; } }
})->ifOk(function ($output) { return json_encode(['data' => $output]); }); }); # Generate a CSV file for a TableView # See http://stackoverflow.com/questions/217424/create-a-csv-file-for-a-user-in-php $klein->respond('GET', '/csv', function ($req, $res) use($parser, $stringifier) { $res->header('X-Frame-Options', 'DENY'); $page = $parser->parseJade($_GET['form']); $view = new CSVView($page->getView($_GET['view'])); header("Content-type: text/csv; charset=utf-8"); header("Content-Disposition: attachment; filename=formulaic-" . time() . ".csv"); ob_start(); $view->makeView($view->query(1))->render()->save('php://output'); $result = ob_get_clean(); return $result; }); # Get the details of a particular table entry. $klein->respond('GET', '/details', function ($req, $res) use($parser, $stringifier) { $page = $parser->parseJade($_GET['form']); $view = new DetailsView(); $view->setPage($page); $stringifier->writeResponse(new PageWrapper($view->makeView($view->query($_GET))), $res); }); # See https://github.com/chriso/klein.php/wiki/Sub-Directory-Installation $config = Config::get(); $request = \Klein\Request::createFromGlobals(); $uri = $request->server()->get('REQUEST_URI'); $request->server()->set('REQUEST_URI', UTF8::substr($uri, UTF8::strlen($config['app-path']))); # Route! $klein->dispatch($request);
/** * Chops down a string according to given max length, all characters beyond $maxLength is removed. * * This function is UTF8 compatible * * @param $str * @param $maxLength * @param bool $lengthUnitInByte * * @return string * */ public static function stringChopdown($str, $maxLength, $lengthUnitInByte = false) { if ($lengthUnitInByte) { return substr($str, 0, $maxLength); } $str = UTF8::to_utf8($str); $len = UTF8::strlen($str); if ($len <= $maxLength) { return $str; } return UTF8::substr($str, 0, $maxLength); }
/** * Return first and last position of text * * @param string The parent text of the text to be formatted * @param string The text to be formatted * @return string */ protected function getTextPosition($context, $text) { $pos = UTF8::strpos($context, $text); return [$pos, $pos + UTF8::strlen($text)]; }
function getForm($name) { if (is_string($name) && !preg_match('/[^A-za-z0-9_-]/', $name) && UTF8::strlen($name) > 0) { return 'forms/' . $name . '.jade'; } else { throw new Exception('Invalid form name!'); } }