public function getPresenterClass(&$name) { if (isset($this->cache[$name])) { list($className, $name) = $this->cache[$name]; return $className; } if (!is_string($name) || !String::match($name, "#^[a-zA-Z-ÿ][a-zA-Z0-9-ÿ:]*\$#")) { throw new InvalidPresenterException("Presenter name must be alphanumeric string, '{$name}' is invalid."); } $classNameBase = str_replace(':', 'Module\\', $name) . 'Presenter'; $classNames = array_map(function ($namespace) use($classNameBase) { return ($namespace ? $namespace . "\\" : "") . $classNameBase; }, $this->namespaces); foreach ($classNames as $className) { if (!class_exists($className)) { continue; } $reflection = new ClassReflection($className); if (!$reflection->implementsInterface('Nette\\Application\\IPresenter')) { throw new InvalidPresenterException("Cannot load presenter '{$name}', class '{$className}' is not Nette\\Application\\IPresenter implementor."); } if ($reflection->isAbstract()) { throw new InvalidPresenterException("Cannot load presenter '{$name}', class '{$className}' is abstract."); } return $className; } throw new InvalidPresenterException("Cannot load presenter {$name}, class " . implode(" nor ", $classNames) . " does not exist"); }
/** * Filter: removes unnecessary whitespace and shortens value to control's max length. * @return string */ public function sanitize($value) { if ($this->control->maxlength && Nette\String::length($value) > $this->control->maxlength) { $value = iconv_substr($value, 0, $this->control->maxlength, 'UTF-8'); } return Nette\String::trim(strtr($value, "\r\n", ' ')); }
/** * Invoke filter * @param string code * @param WebLoader loader * @param string file * @return string */ public function __invoke($code, WebLoader $loader, $file) { if (String::endsWith($file, ".less")) { return $this->getLessC()->parse($code); } return $code; }
/** * Filter: shortens value to control's max length. * @return string */ public function checkMaxLength($value) { if ($this->control->maxlength && Nette\String::length($value) > $this->control->maxlength) { $value = iconv_substr($value, 0, $this->control->maxlength, 'UTF-8'); } return $value; }
/** * This method will be called when the component (or component's parent) * becomes attached to a monitored object. Do not call this method yourself. * @param IComponent * @return void */ protected function attached($dataGrid) { if ($dataGrid instanceof DataGrid) { $this->setParent($dataGrid->getComponent('columns', TRUE)); if ($this->caption === NULL) { $this->caption = \Nette\String::capitalize($this->getName()); } } }
/** * Processes given request. * * @author Jan Tvrdík * @param PresenterRequest * @return void * @throws Nette\Applicationy\AbortException|BadRequestException */ public function processRequest(PresenterRequest $request) { $params = $request->getParams(); if (!isset($params['page'])) { throw new BadRequestException('Invalid request. Parameter \'page\' is required.'); } $this->page = $params['page']; if (!Nette\String::match($this->page, self::PAGE_REGEXP)) { throw new BadRequestException('Parameter \'page\' contains illegal characters.'); } $this->sendTemplate(); }
/** * @param string presenter name * @return string class name * @throws InvalidPresenterException */ public function getPresenterClass(& $name) { if (isset($this->cache[$name])) { list($class, $name) = $this->cache[$name]; return $class; } if (!is_string($name) || !Nette\String::match($name, "#^[a-zA-Z\x7f-\xff][a-zA-Z0-9\x7f-\xff:]*$#")) { throw new InvalidPresenterException("Presenter name must be alphanumeric string, '$name' is invalid."); } $class = $this->formatPresenterClass($name); if (!class_exists($class)) { // internal autoloading $file = $this->formatPresenterFile($name); if (is_file($file) && is_readable($file)) { Nette\Loaders\LimitedScope::load($file); } if (!class_exists($class)) { throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' was not found in '$file'."); } } $reflection = new Nette\Reflection\ClassReflection($class); $class = $reflection->getName(); if (!$reflection->implementsInterface('Nette\Application\IPresenter')) { throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is not Nette\\Application\\IPresenter implementor."); } if ($reflection->isAbstract()) { throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is abstract."); } // canonicalize presenter name $realName = $this->unformatPresenterClass($class); if ($name !== $realName) { if ($this->caseSensitive) { throw new InvalidPresenterException("Cannot load presenter '$name', case mismatch. Real name is '$realName'."); } else { $this->cache[$name] = array($class, $realName); $name = $realName; } } else { $this->cache[$name] = array($class, $realName); } return $class; }
public function processArguments($args, IContext $context) { return array_map(function ($arg) use($context) { if (!is_string($arg)) { return $arg; } elseif (String::startsWith($arg, "%")) { return $context->getService(substr($arg, 1)); } elseif (String::startsWith($arg, "\$\$")) { return Environment::getConfig(substr($arg, 2)); } elseif (String::startsWith($arg, "\$")) { return Environment::getVariable(substr($arg, 1)); } else { return $arg; } }, $args); }
/** * Processes <texy>...</texy> elements. * * @author David Grudl, Jan Tvrdík * @param string * @return string */ public static function texyElements($s) { $texy = self::$texy; if ($texy === NULL) throw new \InvalidStateException(get_class($this) . '::$texy must be set.'); return Nette\String::replace($s, '#<texy>(.*?)</texy>#s', function ($m) use ($texy) { $s = $m[1]; $singleLine = (strpos($s, "\n") === FALSE); $s = trim($s, "\n"); $tabs = strspn($s, "\t"); if ($tabs) $s = Nette\String::replace($s, "#^\t{1,$tabs}#m", ''); $s = $texy->process($s, $singleLine); return "{syntax double}$s{{/syntax}}"; } ); }
private function canonicalizeDestination($destination) { // searching for any string that wikipedia knows $c = curl_init(); curl_setopt($c, CURLOPT_RETURNTRANSFER, 1); curl_setopt($c, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json')); curl_setopt($c, CURLOPT_USERAGENT, 'Travelbot 1.0 beta'); curl_setopt($c, CURLOPT_FOLLOWLOCATION, TRUE); curl_setopt($c, CURLOPT_MAXREDIRS, 100); $uri = new Uri('http://en.wikipedia.org/w/api.php'); $uri->setQuery(array('format' => 'json', 'action' => 'opensearch', 'search' => $destination, 'limit' => 5)); curl_setopt($c, CURLOPT_URL, (string) $uri); $result = curl_exec($c); curl_close($c); $json = json_decode($result); if ($json === FALSE) { throw new InvalidStateException('Malformed JSON response.'); } if (!isset($json[1][0])) { throw new ArticleException('Article not found.'); } $destination = $json[1][0]; // canonization (redirection to the final article) $c = curl_init(); curl_setopt($c, CURLOPT_RETURNTRANSFER, 1); curl_setopt($c, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json')); curl_setopt($c, CURLOPT_USERAGENT, 'Travelbot 1.0 beta'); curl_setopt($c, CURLOPT_FOLLOWLOCATION, TRUE); curl_setopt($c, CURLOPT_MAXREDIRS, 100); $uri = new Uri('http://en.wikipedia.org/w/api.php'); $uri->setQuery(array('format' => 'json', 'action' => 'query', 'titles' => $destination, 'redirects' => TRUE)); curl_setopt($c, CURLOPT_URL, (string) $uri); $result = curl_exec($c); curl_close($c); $json = json_decode($result); if ($json === FALSE) { return $destination; } if (isset($json->query->redirects[0])) { return $json->query->redirects[0]->to; } else { if (isset($json->query->normalized[0])) { return String::capitalize($json->query->normalized[0]->to); } } return $destination; }
/** * Static factory. * @param string element name (or NULL) * @param array|string element's attributes (or textual content) * @return Html */ public static function el($name = NULL, $attrs = NULL) { $el = new static(); $parts = explode(' ', $name, 2); $el->setName($parts[0]); if (is_array($attrs)) { $el->attrs = $attrs; } elseif ($attrs !== NULL) { $el->setText($attrs); } if (isset($parts[1])) { foreach (Nette\String::matchAll($parts[1] . ' ', '#([a-z0-9:-]+)(?:=(["\'])?(.*?)(?(2)\\2|\\s))?#i') as $m) { $el->attrs[$m[1]] = isset($m[3]) ? $m[3] : TRUE; } } return $el; }
/** * Processes <texy>...</texy> elements. * * @author David Grudl, Jan Tvrdík * @param string * @return string */ public function __invoke($s) { $texy = $this->texy; $autoChangeSyntax = $this->autoChangeSyntax; if ($texy === NULL) throw new \InvalidStateException(get_class($this) . '::$texy must be set.'); return Nette\String::replace($s, '#<texy>(.*?)</texy>#s', function ($m) use ($texy, $autoChangeSyntax) { $s = $m[1]; $singleLine = (strpos($s, "\n") === FALSE); $s = trim($s, "\r\n"); $tabs = strspn($s, "\t"); if ($tabs) $s = Nette\String::replace($s, "#^\t{1,$tabs}#m", ''); $s = $texy->process($s, $singleLine); return ($autoChangeSyntax ? "{syntax double}$s{{/syntax}}" : $s); } ); }
public function getPanel() { $s = ''; foreach ($this->queries as $query) { list($sql, $params, $time, $rows) = $query; $s .= '<tr><td>' . sprintf('%0.3f', $time * 1000) . '</td><td class="database-sql">' . Connection::highlightSql(Nette\String::truncate($sql, self::$maxLength)) . '</td><td>' . htmlSpecialChars(implode(', ', $params)) . '</td><td>' . $rows . '</td></tr>'; } return empty($this->queries) ? '' : '<style> #nette-debug-database td.database-sql { background: white !important } </style> <h1>Queries: ' . count($this->queries) . ($this->totalTime ? ', time: ' . sprintf('%0.3f', $this->totalTime * 1000) . ' ms' : '') . '</h1> <div class="nette-inner"> <table> <tr><th>Time ms</th><th>SQL Statement</th><th>Params</th><th>Rows</th></tr>' . $s . ' </table> </div>'; }
/** * @param string * @param array * @return array of [sql, params] */ public function process($sql, $params) { $this->params = $params; $this->counter = 0; $this->remaining = array(); $cmd = strtoupper(substr(ltrim($sql), 0, 6)); // detect array mode $this->arrayMode = $cmd === 'INSERT' || $cmd === 'REPLAC' ? 'values' : 'assoc'; /*~ \'.*?\'|".*?"| ## string :[a-zA-Z0-9_]+:| ## :substitution: \? ## placeholder ~xs*/ $sql = Nette\String::replace($sql, '~\'.*?\'|".*?"|:[a-zA-Z0-9_]+:|\\?~s', array($this, 'callback')); while ($this->counter < count($params)) { $sql .= ' ' . $this->formatValue($params[$this->counter++]); } return array($sql, $this->remaining); }
/** * Make relative url absolute * @param string image url * @param string single or double quote * @param string absolute css file path * @param string source path * @return string */ public static function absolutizeUrl($url, $quote, $cssFile, $sourcePath) { // is already absolute if (preg_match("/^([a-z]+:\\/)?\\//", $url)) { return $url; } $docroot = realpath(WWW_DIR); $basePath = rtrim(Environment::getVariable("baseUri"), '/'); // inside document root if (String::startsWith($cssFile, $docroot)) { $path = $basePath . substr(dirname($cssFile), strlen($docroot)) . DIRECTORY_SEPARATOR . $url; // outside document root } else { $path = $basePath . substr($sourcePath, strlen($docroot)) . DIRECTORY_SEPARATOR . $url; } //$path = self::cannonicalizePath($path); $path = strtr($path, "\\", "/"); return $quote === '"' ? addslashes($path) : $path; }
protected function createComponentAddTagForm() { $form = new AppForm(); $form->addText("name", "Name", 40, 50); $form->addSubmit("s", "Add"); $presenter = $this; $form->onSubmit[] = function ($form) use($presenter) { $name = $form->values["name"]; $tag = new Tag(); $tag->name = $name; $tag->url = String::webalize($name); try { $tag->save(); $presenter->flashMessage("Tag was added!"); $presenter->redirect("default"); } catch (\ModelException $e) { $tag->addErrorsToForm($form); } }; return $form; }
public function setUrl($url) { $uriScript = new UriScript($url); $uriScript->setScriptPath(Environment::getHttpRequest()->getUri()->getScriptPath()); $httpRequest = new HttpRequest($uriScript); $presenterRequest = Environment::getApplication()->getRouter()->match($httpRequest); if ($presenterRequest === null || !String::startsWith($url, Environment::getVariable("baseUri"))) { $this->url = $url ?: null; $this->destination = null; $this->params = array(); } else { $presenter = $presenterRequest->getPresenterName(); $params = $presenterRequest->getParams(); $action = isset($params["action"]) ? $params["action"] : "default"; $module = isset($params["module"]) ? $params["module"] . ":" : ""; unset($params["action"]); $this->destination = "{$module}{$presenter}:{$action}"; $this->params = $params; $this->url = null; } }
/** * Process <texy>...</texy> elements. * @param string * @return string */ public static function texyElements($s) { return String::replace($s, '#<texy([^>]*)>(.*?)</texy>#s', function ($m) { list(, $mAttrs, $mContent) = $m; // parse attributes $attrs = array(); if ($mAttrs) { foreach (String::matchAll($mAttrs, '#([a-z0-9:-]+)\\s*(?:=\\s*(\'[^\']*\'|"[^"]*"|[^\'"\\s]+))?()#isu') as $m) { $key = strtolower($m[1]); $val = $m[2]; if ($val == NULL) { $attrs[$key] = TRUE; } elseif ($val[0] === '\'' || $val[0] === '"') { $attrs[$key] = html_entity_decode(substr($val, 1, -1), ENT_QUOTES, 'UTF-8'); } else { $attrs[$key] = html_entity_decode($val, ENT_QUOTES, 'UTF-8'); } } } return TemplateFilters::$texy->process($m[2]); }); }
/** * Sets a header. * @param string * @param string|array value or pair email => name * @param bool * @return MailMimePart provides a fluent interface */ public function setHeader($name, $value, $append = FALSE) { if (!$name || preg_match('#[^a-z0-9-]#i', $name)) { throw new \InvalidArgumentException("Header name must be non-empty alphanumeric string, '{$name}' given."); } if ($value == NULL) { // intentionally == if (!$append) { unset($this->headers[$name]); } } elseif (is_array($value)) { // email $tmp =& $this->headers[$name]; if (!$append || !is_array($tmp)) { $tmp = array(); } foreach ($value as $email => $name) { if ($name !== NULL && !Nette\String::checkEncoding($name)) { throw new \InvalidArgumentException("Name is not valid UTF-8 string."); } if (!preg_match('#^[^@",\\s]+@[^@",\\s]+\\.[a-z]{2,10}$#i', $email)) { throw new \InvalidArgumentException("Email address '{$email}' is not valid."); } if (preg_match('#[\\r\\n]#', $name)) { throw new \InvalidArgumentException("Name cannot contain the line separator."); } $tmp[$email] = $name; } } else { $value = (string) $value; if (!Nette\String::checkEncoding($value)) { throw new \InvalidArgumentException("Header is not valid UTF-8 string."); } $this->headers[$name] = preg_replace('#[\\r\\n]+#', ' ', $value); } return $this; }
/** * Analyse PHP file. * @param string * @return void */ private function scanScript($file) { $T_NAMESPACE = PHP_VERSION_ID < 50300 ? -1 : T_NAMESPACE; $T_NS_SEPARATOR = PHP_VERSION_ID < 50300 ? -1 : T_NS_SEPARATOR; $expected = FALSE; $namespace = ''; $level = 0; $time = filemtime($file); $s = file_get_contents($file); if ($matches = String::match($s, '#//nette' . 'loader=(\\S*)#')) { foreach (explode(',', $matches[1]) as $name) { $this->addClass($name, $file, $time); } return; } foreach (token_get_all($s) as $token) { if (is_array($token)) { switch ($token[0]) { case T_COMMENT: case T_DOC_COMMENT: case T_WHITESPACE: continue 2; case $T_NS_SEPARATOR: case T_STRING: if ($expected) { $name .= $token[1]; } continue 2; case $T_NAMESPACE: case T_CLASS: case T_INTERFACE: $expected = $token[0]; $name = ''; continue 2; case T_CURLY_OPEN: case T_DOLLAR_OPEN_CURLY_BRACES: $level++; } } if ($expected) { switch ($expected) { case T_CLASS: case T_INTERFACE: if ($level === 0) { $this->addClass($namespace . $name, $file, $time); } break; case $T_NAMESPACE: $namespace = $name . '\\'; } $expected = NULL; } if ($token === '{') { $level++; } elseif ($token === '}') { $level--; } } }
/** * Cross-Site Request Forgery (CSRF) form protection. * @param string * @param int * @return void */ public function addProtection($message = NULL, $timeout = NULL) { $session = $this->getSession()->getNamespace('Nette.Forms.Form/CSRF'); $key = "key{$timeout}"; if (isset($session->{$key})) { $token = $session->{$key}; } else { $session->{$key} = $token = Nette\String::random(); } $session->setExpiration($timeout, $key); $this[self::PROTECTOR_ID] = new HiddenField($token); $this[self::PROTECTOR_ID]->addRule(self::PROTECTION, $message, $token); }
/** * Reads single token (optionally delimited by comma) from string. * @param string * @return string */ public function fetchToken(& $s) { if ($matches = String::match($s, '#^((?>'.LatteFilter::RE_STRING.'|[^\'"\s,]+)+)\s*,?\s*(.*)$#s')) { // token [,] tail $s = $matches[2]; return $matches[1]; } return NULL; }
/** * Matches next token. * @param string * @return array */ private function match($re) { if ($matches = String::match($this->input, $re, PREG_OFFSET_CAPTURE, $this->offset)) { $this->output .= substr($this->input, $this->offset, $matches[0][1] - $this->offset); $this->offset = $matches[0][1] + strlen($matches[0][0]); foreach ($matches as $k => $v) $matches[$k] = $v[0]; } return $matches; }
/** * Convert date to RFC822 * @param string|date $date * @return string */ public static function prepareDate($date) { if ($date instanceof \DateTime) { $date = $date->getTimestamp(); } if (is_string($date) && $date === (string) (int) $date) { $date = (int) $date; } if (is_string($date) && !String::endsWith($date, "GMT")) { $date = strtotime($date); } if (is_int($date)) { $date = gmdate('D, d M Y H:i:s', $date) . " GMT"; } return $date; }
/** * Parses PHP file. * @param string * @return void */ private static function parseScript($file) { $T_NAMESPACE = PHP_VERSION_ID < 50300 ? -1 : T_NAMESPACE; $T_NS_SEPARATOR = PHP_VERSION_ID < 50300 ? -1 : T_NS_SEPARATOR; $s = file_get_contents($file); if (String::match($s, '#//nette' . 'loader=(\\S*)#')) { return; // TODO: allways ignore? } $expected = $namespace = $class = $docComment = NULL; $level = $classLevel = 0; foreach (token_get_all($s) as $token) { if (is_array($token)) { switch ($token[0]) { case T_DOC_COMMENT: $docComment = $token[1]; case T_WHITESPACE: case T_COMMENT: continue 2; case T_STRING: case $T_NS_SEPARATOR: case T_VARIABLE: if ($expected) { $name .= $token[1]; } continue 2; case T_FUNCTION: case T_VAR: case T_PUBLIC: case T_PROTECTED: case $T_NAMESPACE: case T_CLASS: case T_INTERFACE: $expected = $token[0]; $name = NULL; continue 2; case T_STATIC: case T_ABSTRACT: case T_FINAL: continue 2; // ignore in expectation // ignore in expectation case T_CURLY_OPEN: case T_DOLLAR_OPEN_CURLY_BRACES: $level++; } } if ($expected) { switch ($expected) { case T_CLASS: case T_INTERFACE: $class = $namespace . $name; $classLevel = $level; $name = ''; // break intentionally omitted // break intentionally omitted case T_FUNCTION: if ($token === '&') { continue 2; } // ignore // ignore case T_VAR: case T_PUBLIC: case T_PROTECTED: if ($class && $name !== NULL && $docComment) { self::$cache[$class][$name] = self::parseComment($docComment); } break; case $T_NAMESPACE: $namespace = $name . '\\'; } $expected = $docComment = NULL; } if ($token === ';') { $docComment = NULL; } elseif ($token === '{') { $docComment = NULL; $level++; } elseif ($token === '}') { $level--; if ($level === $classLevel) { $class = NULL; } } } }
/** * @param string $header * @return string */ public static function getContentType($header, $default = NULL) { $match = String::match($header, self::CONTENT_TYPE); return isset($match['type']) ? $match['type'] : $default; }
public function getOffset($i) { $tokens = String::split($this->input, $this->re, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); list(, $offset) = $tokens[$i]; return array( $offset, ($offset ? substr_count($this->input, "\n", 0, $offset) + 1 : 1), $offset - strrpos(substr($this->input, 0, $offset), "\n"), ); }
/** * Float validator: is a control's value float number? * @param TextBase * @return bool */ public static function validateFloat(TextBase $control) { return (bool) String::match($control->getValue(), '/^-?[0-9]*[.,]?[0-9]+$/'); }
public function setUrl($url) { $this->url = String::webalize($url); }
/** * Return array entries that match the pattern. * @param array * @param string * @param int * @return array */ public static function grep(array $arr, $pattern, $flags = 0) { Debug::tryError(); $res = preg_grep($pattern, $arr, $flags); String::catchPregError($pattern); return $res; }