Stop clean URLs from affecting relative paths in page HTML
I have implemented clean URLs using the following in my .htaccess
RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
And in my index.php the $_SERVER['PATH_INFO']
is parsed to determine the requested page and any parameters.
This all works fine, however any requests for a url with more than one segment, ie
www.example.com/page/foo/bar
cause all linked assets (css, js, images) and hyperlinks on the page to break because they use relative paths. A absolute path with an implied domain (aka prepending all paths with "/") is not viable because the site has to be accessible and working properly as a subdirectory of a parent website in addition to its own root URL. I can not hardcode the fully qualified absolute path for all links either, as I do not have control over some of the content that will be on the page. Using the <base>
tag is also not an possibility.
Do I have any other options here?
Does every request to PHP fall on the same index.php
file? In that case, the file itself knows where it is, and can calculate what directory it's in.
This isn't the neatest way to do it, but it might give you some ideas to work from.
define('DR', $_SERVER['DOCUMENT_ROOT');
define('BD', str_replace(DR, '', dirname($_SERVER['SCRIPT_FILENAME'] . '/'); // base dir
And then prepend all links with BD
.
Do what you normally do when you create a php router... create a link generation facility for assets and URLs.
Since youre using a front controller you can define all your directories up front based on configuration and then generate the paths to things like:
function asset_url($filename, $type = 'img') {
global $config;
if(isset($config['paths'][$type])) {
return $config['paths'][$type] . '/' . $filename;
}
}
Normally id register this configuration with the Registry pattern implemntation instead of using global
but i dunno your set up, so this is just a simple example.
It's a tricky solution. The easiest thing to do is introduce a baseUrl
parameter to your application. It would be empty if the site is running at the root directory, and would be something like /corp/site
is running out of domain.com/corp/site
.
This way, when you display URLs, you would use <?php echo $app_base_url . '/css/file.css' ?>
<?php echo $app_base_url . '/css/file.css' ?>
I use Zend Framework a lot and they have a class called Zend_Controller_Request_Http
which has a method called getBaseUrl
that goes through some complex logic examining the various $_SERVER
variables about the script path and the request filename which ultimately figures out what your base Url actually is.
If you use that specific piece of Zend Framework, you can do something like this:
$request = new Zend_Controller_Request_Http();
$baseUrl = $request->getBaseUrl();
Since Zend Framework is modular, you don't need to include the whole library, I've used just this class before (and its dependencies) so I could easily calculate the base URL in a small application without needing the whole ZF library.
To give you an idea of what logic is involved in determining this, here is the code that does most of the work (note, don't try to use this directly, instead use the Zend Framework classes as shown above).
/**
* Set the base URL of the request; i.e., the segment leading to the script name
*
* E.g.:
* - /admin
* - /myapp
* - /subdir/index.php
*
* Do not use the full URI when providing the base. The following are
* examples of what not to use:
* - http://example.com/admin (should be just /admin)
* - http://example.com/subdir/index.php (should be just /subdir/index.php)
*
* If no $baseUrl is provided, attempts to determine the base URL from the
* environment, using SCRIPT_FILENAME, SCRIPT_NAME, PHP_SELF, and
* ORIG_SCRIPT_NAME in its determination.
*
* @param mixed $baseUrl
* @return Zend_Controller_Request_Http
*/
public function setBaseUrl($baseUrl = null)
{
if ((null !== $baseUrl) && !is_string($baseUrl)) {
return $this;
}
if ($baseUrl === null) {
$filename = (isset($_SERVER['SCRIPT_FILENAME'])) ? basename($_SERVER['SCRIPT_FILENAME']) : '';
if (isset($_SERVER['SCRIPT_NAME']) && basename($_SERVER['SCRIPT_NAME']) === $filename) {
$baseUrl = $_SERVER['SCRIPT_NAME'];
} elseif (isset($_SERVER['PHP_SELF']) && basename($_SERVER['PHP_SELF']) === $filename) {
$baseUrl = $_SERVER['PHP_SELF'];
} elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $filename) {
$baseUrl = $_SERVER['ORIG_SCRIPT_NAME']; // 1and1 shared hosting compatibility
} else {
// Backtrack up the script_filename to find the portion matching
// php_self
$path = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '';
$file = isset($_SERVER['SCRIPT_FILENAME']) ? $_SERVER['SCRIPT_FILENAME'] : '';
$segs = explode('/', trim($file, '/'));
$segs = array_reverse($segs);
$index = 0;
$last = count($segs);
$baseUrl = '';
do {
$seg = $segs[$index];
$baseUrl = '/' . $seg . $baseUrl;
++$index;
} while (($last > $index) && (false !== ($pos = strpos($path, $baseUrl))) && (0 != $pos));
}
// Does the baseUrl have anything in common with the request_uri?
$requestUri = $this->getRequestUri();
if (0 === strpos($requestUri, $baseUrl)) {
// full $baseUrl matches
$this->_baseUrl = $baseUrl;
return $this;
}
if (0 === strpos($requestUri, dirname($baseUrl))) {
// directory portion of $baseUrl matches
$this->_baseUrl = rtrim(dirname($baseUrl), '/');
return $this;
}
$truncatedRequestUri = $requestUri;
if (($pos = strpos($requestUri, '?')) !== false) {
$truncatedRequestUri = substr($requestUri, 0, $pos);
}
$basename = basename($baseUrl);
if (empty($basename) || !strpos($truncatedRequestUri, $basename)) {
// no match whatsoever; set it blank
$this->_baseUrl = '';
return $this;
}
// If using mod_rewrite or ISAPI_Rewrite strip the script filename
// out of baseUrl. $pos !== 0 makes sure it is not matching a value
// from PATH_INFO or QUERY_STRING
if ((strlen($requestUri) >= strlen($baseUrl))
&& ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0)))
{
$baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
}
}
$this->_baseUrl = rtrim($baseUrl, '/');
return $this;
}
链接地址: http://www.djcxy.com/p/34854.html
上一篇: 访问rails资源的相对路径