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; }
/** * 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 . '] '; } }
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; }
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; }
/** * 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 . ']'; } }
/** * Get random bytes * * @ref https://github.com/paragonie/random_compat/ * * @param int $length Output length * * @return string|false false on error */ public static function get_random_bytes($length) { if (!$length || !ctype_digit((string) $length)) { return false; } else { $length = (int) $length; } if (function_exists('random_bytes') && self::is_php('7.0')) { /** * PHP 7 -> http://php.net/manual/de/function.random-bytes.php */ try { $return = random_bytes($length); } catch (\Exception $e) { $return = false; } return $return; } else { /** * PHP 5.2.0 - 5.6.x way to implement random_bytes() * * // WARNING: Unfortunately, none of the following PRNGs is guaranteed to exist ... * * In order of preference: * 1. PHP-Module: "mcrypt" via mcrypt_create_iv() * 2. Linux / BSD: "/dev/urandom" via fread() * 3. Windows: \COM('CAPICOM.Utilities.1')->GetRandom() * 4. PHP+OpenSSL: openssl_random_pseudo_bytes() */ /** * 1. PHP-Module */ if (extension_loaded('mcrypt') && defined(MCRYPT_DEV_URANDOM) === true) { $output = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); if ($output !== false && UTF8::strlen($output, '8bit') === $length) { return $output; } } /** * 2. Linux / BSD */ if (!ini_get('open_basedir') && is_readable('/dev/urandom')) { $fp = fopen('/dev/urandom', 'rb'); if (!empty($fp)) { $st = fstat($fp); // In C, this would be: (stat_mode & S_IFMT) !== S_IFCHR if (($st['mode'] & 0170000) !== 020000) { fclose($fp); $fp = false; } unset($st); } } if (isset($fp) && $fp !== false) { /** * stream_set_read_buffer() / stream_set_chunk_size does not exist in HHVM * * If we don't set the stream's read buffer to 0, PHP will * internally buffer 8192 bytes, which can waste entropy * * stream_set_read_buffer returns 0 on success */ if (function_exists('stream_set_chunk_size')) { stream_set_chunk_size($fp, $length); } if (function_exists('stream_set_read_buffer')) { stream_set_read_buffer($fp, $length); } $remaining = $length; $buf = ''; do { $read = fread($fp, $remaining); // We cannot safely read from the file, so exit the do-while loop. if ($read === false) { $buf = false; break; } // Decrease the number of bytes returned from remaining. $remaining -= UTF8::strlen($read, '8bit'); $buf .= $read; } while ($remaining > 0); fclose($fp); if ($buf !== false) { if (UTF8::strlen($buf, '8bit') === $length) { return $buf; } } } /* * 3. Windows * * PHP can be used to access COM objects on Windows platforms * * --- * * PROBLEM: you see this error-message: * com_exception thrown with message * "Failed to create COM object `CAPICOM.Utilities.1': Ungültige Syntax * * SOLUTION: register the dll: * regsvr32 c:\windows\capicom.dll * * --- * * @ref http://php.net/manual/en/ref.com.php */ if (extension_loaded('com_dotnet') && class_exists('COM') === true) { // init $buf = ''; /** @noinspection PhpUndefinedClassInspection */ $util = new \COM('CAPICOM.Utilities.1'); /** * Let's not let it loop forever. If we run N times and fail to * get N bytes of random data, then CAPICOM has failed us. */ $execCount = 0; do { /** @noinspection PhpUndefinedMethodInspection */ $buf .= base64_decode($util->GetRandom($length, 0)); if (UTF8::strlen($buf, '8bit') >= $length) { return UTF8::substr($buf, 0, $length); } ++$execCount; } while ($execCount < $length); } /** * 4. PHP + OpenSSL * * fallback to "openssl_random_pseudo_bytes()" */ if (function_exists('openssl_random_pseudo_bytes')) { $output = openssl_random_pseudo_bytes($length, $strong); if ($output !== false && $strong === true) { if (UTF8::strlen($output, '8bit') === $length) { return $output; } } } return false; } }
/** * @param string $word * * @return string */ private function capitalizeWord($word) { $encoding = $this->encoding; $firstCharacter = UTF8::substr($word, 0, 1, $encoding); $restOfWord = UTF8::substr($word, 1, null, $encoding); $firstCharacterUppercased = UTF8::strtoupper($firstCharacter, $encoding); return new static($firstCharacterUppercased . $restOfWord, $encoding); }
/** * Scan attributes from input & return them if found. * * @return Object|null */ protected function scanAttributes() { if ('(' === $this->input[0]) { $index = $this->getDelimitersIndex('(', ')'); $input = UTF8::substr($this->input, 1, $index - 1); $token = $this->takeToken('attributes', $input); $attributes = preg_split('/ *, *(?=[\'"\\w-]+ *[:=]|[\\w-]+ *$)/', $token->value); $this->consumeInput($index + 1); $token->attributes = array(); foreach ($attributes as $i => $pair) { $pair = preg_replace('/^ *| *$/', '', $pair); $colon = UTF8::strpos($pair, ':'); $equal = UTF8::strpos($pair, '='); $sbrac = UTF8::strpos($pair, '\''); $dbrac = UTF8::strpos($pair, '"'); if ($sbrac < 1) { $sbrac = false; } if ($dbrac < 1) { $dbrac = false; } if (false !== $sbrac && $colon > $sbrac || false !== $dbrac && $colon > $dbrac) { $colon = false; } if (false !== $sbrac && $equal > $sbrac || false !== $dbrac && $equal > $dbrac) { $equal = false; } if (false === $colon && false === $equal) { $key = $pair; $value = true; } else { $splitter = false !== $colon ? $colon : $equal; if (false !== $colon && $colon < $equal) { $splitter = $colon; } $key = UTF8::substr($pair, 0, $splitter); $value = preg_replace('/^ *[\'"]?|[\'"]? *$/', '', UTF8::substr($pair, ++$splitter, UTF8::strlen($pair))); if ('true' === $value) { $value = true; } elseif (empty($value) || 'null' === $value || 'false' === $value) { $value = false; } } $token->attributes[preg_replace(array('/^ +| +$/', '/^[\'"]|[\'"]$/'), '', $key)] = $value; } return $token; } }
})->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); }