123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575 |
- <?php
- namespace Grav\Common;
- use Grav\Common\Page\Page;
- use Grav\Common\Page\Pages;
- /**
- * The URI object provides information about the current URL
- *
- * @author RocketTheme
- * @license MIT
- */
- class Uri
- {
- const HOSTNAME_REGEX = '/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/';
- public $url;
- protected $basename;
- protected $base;
- protected $root;
- protected $bits;
- protected $extension;
- protected $host;
- protected $content_path;
- protected $path;
- protected $paths;
- protected $query;
- protected $params;
- /**
- * Constructor.
- */
- public function __construct()
- {
- $name = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost');
- // Remove port from HTTP_HOST generated $name
- $name = Utils::substrToString($name, ':');
- // Validate the hostname
- $name = preg_match(Uri::HOSTNAME_REGEX, $name) ? $name : 'unknown';
- $port = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80;
- $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
- $root_path = str_replace(' ', '%20', rtrim(substr($_SERVER['PHP_SELF'], 0, strpos($_SERVER['PHP_SELF'], 'index.php')), '/'));
- // set the base
- if (isset($_SERVER['HTTPS'])) {
- $base = (@$_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
- } else {
- $base = 'http://';
- }
- // add the sever name
- $base .= $name;
- // add the port of needed
- if ($port != '80' && $port != '443') {
- $base .= ":".$port;
- }
- // check if userdir in the path and workaround PHP bug with PHP_SELF
- if (strpos($uri, '/~') !== false && strpos($_SERVER['PHP_SELF'], '/~') === false) {
- $root_path = substr($uri, 0, strpos($uri, '/', 1)) . $root_path;
- }
- // set hostname
- $address = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '::1';
- // check for localhost variations
- if ($name == 'localhost' || $address == '::1' || $address == '127.0.0.1') {
- $this->host = 'localhost';
- } else {
- $this->host = $name;
- }
- $this->base = $base;
- $this->root = $base . $root_path;
- $this->url = $base . $uri;
- }
- /**
- * Initializes the URI object based on the url set on the object
- */
- public function init()
- {
- $grav = Grav::instance();
- $config = $grav['config'];
- $language = $grav['language'];
- // resets
- $this->paths = [];
- $this->params = [];
- $this->query = [];
- // get any params and remove them
- $uri = str_replace($this->root, '', $this->url);
- // remove double slashes
- $uri = preg_replace('#/{2,}#', '/', $uri);
- // remove the setup.php based base if set:
- $setup_base = $grav['pages']->base();
- if ($setup_base) {
- $uri = str_replace($setup_base, '', $uri);
- }
- // If configured to, redirect trailing slash URI's with a 301 redirect
- if ($config->get('system.pages.redirect_trailing_slash', false) && $uri != '/' && Utils::endsWith($uri, '/')) {
- $grav->redirect(rtrim($uri, '/'), 301);
- }
- // process params
- $uri = $this->processParams($uri, $config->get('system.param_sep'));
- // set active language
- $uri = $language->setActiveFromUri($uri);
- // split the URL and params
- $bits = parse_url($uri);
- // process query string
- if (isset($bits['query']) && isset($bits['path'])) {
- $this->query = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
- $uri = $bits['path'];
- }
- // remove the extension if there is one set
- $parts = pathinfo($uri);
- // set the original basename
- $this->basename = $parts['basename'];
- // set the extension
- if (isset($parts['extension'])) {
- $this->extension = $parts['extension'];
- }
- $valid_page_types = implode('|', $config->get('system.pages.types'));
- if (preg_match("/\.(".$valid_page_types.")$/", $parts['basename'])) {
- $uri = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS). '/' .$parts['filename'];
- }
- // set the new url
- $this->url = $this->root . $uri;
- $this->path = $uri;
- $this->content_path = trim(str_replace($this->base, '', $this->path), '/');
- if ($this->content_path != '') {
- $this->paths = explode('/', $this->content_path);
- }
- }
- /**
- * Process any params based in this URL, supports any valid delimiter
- *
- * @param $uri
- * @param string $delimiter
- *
- * @return string
- */
- private function processParams($uri, $delimiter = ':')
- {
- if (strpos($uri, $delimiter) !== false) {
- $bits = explode('/', $uri);
- $path = array();
- foreach ($bits as $bit) {
- if (strpos($bit, $delimiter) !== false) {
- $param = explode($delimiter, $bit);
- if (count($param) == 2) {
- $plain_var = filter_var(urldecode($param[1]), FILTER_SANITIZE_STRING);
- $this->params[$param[0]] = $plain_var;
- }
- } else {
- $path[] = $bit;
- }
- }
- $uri = '/' . ltrim(implode('/', $path), '/');
- }
- return $uri;
- }
- /**
- * Return URI path.
- *
- * @param string $id
- * @return string
- */
- public function paths($id = null)
- {
- if (isset($id)) {
- return $this->paths[$id];
- } else {
- return $this->paths;
- }
- }
- /**
- * Return route to the current URI. By default route doesn't include base path.
- *
- * @param bool $absolute True to include full path.
- * @param bool $domain True to include domain. Works only if first parameter is also true.
- * @return string
- */
- public function route($absolute = false, $domain = false)
- {
- return urldecode(($absolute ? $this->rootUrl($domain) : '') . '/' . implode('/', $this->paths));
- }
- /**
- * Return full query string or a single query attribute.
- *
- * @param string $id Optional attribute.
- * @return string
- */
- public function query($id = null, $raw = false)
- {
- if (isset($id)) {
- return isset($this->query[$id]) ? $this->query[$id] : null;
- } else {
- if ($raw) {
- return $this->query;
- } else {
- return http_build_query($this->query);
- }
- }
- }
- /**
- * Return all or a single query parameter as a URI compatible string.
- *
- * @param string $id Optional parameter name.
- * @param boolean $array return the array format or not
- * @return null|string
- */
- public function params($id = null, $array = false)
- {
- $config = Grav::instance()['config'];
- $params = null;
- if ($id === null) {
- if ($array) {
- return $this->params;
- }
- $output = array();
- foreach ($this->params as $key => $value) {
- $output[] = $key . $config->get('system.param_sep') . $value;
- $params = '/'.implode('/', $output);
- }
- } elseif (isset($this->params[$id])) {
- if ($array) {
- return $this->params[$id];
- }
- $params = "/{$id}". $config->get('system.param_sep') . $this->params[$id];
- }
- return $params;
- }
- /**
- * Get URI parameter.
- *
- * @param string $id
- * @return bool|string
- */
- public function param($id)
- {
- if (isset($this->params[$id])) {
- return urldecode($this->params[$id]);
- } else {
- return false;
- }
- }
- /**
- * Return URL.
- *
- * @param bool $include_host Include hostname.
- * @return string
- */
- public function url($include_host = false)
- {
- if ($include_host) {
- return $this->url;
- } else {
- $url = (str_replace($this->base, '', rtrim($this->url, '/')));
- return $url ? $url : '/';
- }
- }
- /**
- * Return the Path
- *
- * @return String The path of the URI
- */
- public function path()
- {
- $path = $this->path;
- if ($path === '') {
- $path = '/';
- }
- return $path;
- }
- /**
- * Return the Extension of the URI
- *
- * @param null $default
- *
- * @return String The extension of the URI
- */
- public function extension($default = null)
- {
- if (!$this->extension) {
- $this->extension = $default;
- }
- return $this->extension;
- }
- /**
- * Return the host of the URI
- *
- * @return String The host of the URI
- */
- public function host()
- {
- return $this->host;
- }
- /**
- * Gets the environment name
- *
- * @return String
- */
- public function environment()
- {
- return $this->host();
- }
- /**
- * Return the basename of the URI
- *
- * @return String The basename of the URI
- */
- public function basename()
- {
- return $this->basename;
- }
- /**
- * Return the base of the URI
- *
- * @return String The base of the URI
- */
- public function base()
- {
- return $this->base;
- }
- /**
- * Return root URL to the site.
- *
- * @param bool $include_host Include hostname.
- * @return mixed
- */
- public function rootUrl($include_host = false)
- {
- if ($include_host) {
- return $this->root;
- } else {
- $root = str_replace($this->base, '', $this->root);
- return $root;
- }
- }
- /**
- * Return current page number.
- *
- * @return int
- */
- public function currentPage()
- {
- if (isset($this->params['page'])) {
- return $this->params['page'];
- } else {
- return 1;
- }
- }
- /**
- * Return relative path to the referrer defaulting to current or given page.
- *
- * @param string $default
- * @param string $attributes
- * @return string
- */
- public function referrer($default = null, $attributes = null)
- {
- $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
- // Check that referrer came from our site.
- $root = $this->rootUrl(true);
- if ($referrer) {
- // Referrer should always have host set and it should come from the same base address.
- if (stripos($referrer, $root) !== 0) {
- $referrer = null;
- }
- }
- if (!$referrer) {
- $referrer = $default ? $default : $this->route(true, true);
- }
- if ($attributes) {
- $referrer .= $attributes;
- }
- // Return relative path.
- return substr($referrer, strlen($root));
- }
- /**
- * Return the IP address of the current user
- *
- * @return string ip address
- */
- public function ip()
- {
- if (getenv('HTTP_CLIENT_IP'))
- $ipaddress = getenv('HTTP_CLIENT_IP');
- else if(getenv('HTTP_X_FORWARDED_FOR'))
- $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
- else if(getenv('HTTP_X_FORWARDED'))
- $ipaddress = getenv('HTTP_X_FORWARDED');
- else if(getenv('HTTP_FORWARDED_FOR'))
- $ipaddress = getenv('HTTP_FORWARDED_FOR');
- else if(getenv('HTTP_FORWARDED'))
- $ipaddress = getenv('HTTP_FORWARDED');
- else if(getenv('REMOTE_ADDR'))
- $ipaddress = getenv('REMOTE_ADDR');
- else
- $ipaddress = 'UNKNOWN';
- return $ipaddress;
- }
- /**
- * Is this an external URL? if it starts with `http` then yes, else false
- *
- * @param string $url the URL in question
- * @return boolean is eternal state
- */
- public function isExternal($url)
- {
- if (Utils::startsWith($url, 'http')) {
- return true;
- } else {
- return false;
- }
- }
- /**
- * The opposite of built-in PHP method parse_url()
- *
- * @param $parsed_url
- * @return string
- */
- public static function buildUrl($parsed_url)
- {
- $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
- $host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
- $port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
- $user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
- $pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
- $pass = ($user || $pass) ? "$pass@" : '';
- $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
- $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
- $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
- return "$scheme$user$pass$host$port$path$query$fragment";
- }
- /**
- * Converts links from absolute '/' or relative (../..) to a grav friendly format
- *
- * @param $page the current page to use as reference
- * @param string $markdown_url the URL as it was written in the markdown
- *
- * @return string the more friendly formatted url
- */
- public static function convertUrl(Page $page, $markdown_url, $type = 'link')
- {
- $grav = Grav::instance();
- /** @var Grav\Common\Language\Language $language */
- $language = $grav['language'];
- // Link processing should prepend language
- $language_append = '';
- if ($type == 'link' && $language->enabled()) {
- $language_append = $language->getLanguageURLPrefix();
- }
- $pages_dir = $grav['locator']->findResource('page://');
- $base_url = rtrim($grav['base_url'] . $grav['pages']->base(), '/') . $language_append;
- // if absolute and starts with a base_url move on
- if (pathinfo($markdown_url, PATHINFO_DIRNAME) == '.' && $page->url() == '/') {
- return '/' . $markdown_url;
- // no path to convert
- } elseif ($base_url != '' && Utils::startsWith($markdown_url, $base_url)) {
- return $markdown_url;
- // if contains only a fragment
- } elseif (Utils::startsWith($markdown_url, '#')) {
- return $markdown_url;
- } else {
- $target = null;
- // see if page is relative to this or absolute
- if (Utils::startsWith($markdown_url, '/')) {
- $normalized_url = Utils::normalizePath($base_url . $markdown_url);
- $normalized_path = Utils::normalizePath($pages_dir . $markdown_url);
- } else {
- $normalized_url = $base_url . Utils::normalizePath($page->route() . '/' . $markdown_url);
- $normalized_path = Utils::normalizePath($page->path() . '/' . $markdown_url);
- }
- // special check to see if path checking is required.
- $just_path = str_replace($normalized_url, '', $normalized_path);
- if ($just_path == $page->path()) {
- return $normalized_url;
- }
- $url_bits = parse_url($normalized_path);
- $full_path = ($url_bits['path']);
- if (file_exists($full_path)) {
- // do nothing
- } elseif (file_exists(urldecode($full_path))) {
- $full_path = urldecode($full_path);
- } else {
- return $normalized_url;
- }
- $path_info = pathinfo($full_path);
- $page_path = $path_info['dirname'];
- $filename = '';
- if ($markdown_url == '..') {
- $page_path = $full_path;
- } else {
- // save the filename if a file is part of the path
- if (is_file($full_path)) {
- if ($path_info['extension'] != 'md') {
- $filename = '/' . $path_info['basename'];
- }
- } else {
- $page_path = $full_path;
- }
- }
- // get page instances and try to find one that fits
- $instances = $grav['pages']->instances();
- if (isset($instances[$page_path])) {
- $target = $instances[$page_path];
- $url_bits['path'] = $base_url . rtrim($target->route(), '/') . $filename;
- return Uri::buildUrl($url_bits);
- }
- return $normalized_url;
- }
- }
- }
|