1

I have a project that is not in the root of the XAMPP folder:

htdocs/my-folder/projects/my-project
htdocs/my-folder/projects/my-project/index.php
htdocs/my-folder/projects/my-project/js/
htdocs/my-folder/projects/my-project/css/

that folder contains an index.php file from where I try to call stylesheets and scripts. Initially, I'd just do it like this:

<script src="js/myscript.js"></script>

which worked. However, the project has expanded and now a user can "save" the current page (similar to how JSFiddle does it), and the URL will look different. Upon a first save a random string will be appended as a conf parameter, which results in something like this (locally) and should have a public equivalent:

localhost/my-folder/projects/my-project?conf=abcd # locally
http://mywebsite.com/projects/my-project?conf=abcd # publicly

Upon second save, the URL gets an additional parameters, a version number:

localhost/my-folder/projects/my-project?conf=abcd&v=2 # locally
http://mywebsite.com/projects/my-project?conf=abcd&v=2 # publicly

But, to get a nice URL I use this .htaccess:

Options +FollowSymLinks -MultiViews

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (\w+)[/](\d+)$ ?conf=$1&v=$2 [L,NC]

which will result in something like this:

localhost/my-folder/projects/my-project/abcd/2 # locally
http://mywebsite.com/projects/my-project/abcd/2 # publicly

The thing is, when the URL is changed to some structure as above (without the parameters, but with the rewritten URLs, e.g. localhost/my-folder/projects/my-project/abcd/2) then the initial call to the resources (scripts, styles) in my index file won't be correct any longer.

In other words, if this is the url: localhost/my-folder/projects/my-project/abcd/2 then the server will look for a a script file in localhost/my-folder/projects/my-project/abcd/2/js/myscript.js, which is obviously wrong.

The question, thus, is: how can I get the absolute path to the current file, but that also works in XAMPP (so not __FILE__ or __DIR__ which will dig in the file strucure and return file://) and also on production environments.

hjpotter92
  • 78,589
  • 36
  • 144
  • 183
Bram Vanroy
  • 27,032
  • 24
  • 137
  • 239

2 Answers2

1

You'll have to use the base element in your pages. The usage will be something like:

<base href="/projects/my-project/" />

for the public server and

<base href="/my-folder/projects/my-project/" />

locally.

hjpotter92
  • 78,589
  • 36
  • 144
  • 183
  • That's kind of part of the problem I suppose, I need this to be as dynamic as possible. In other words, I don't want to have to create a tag for each case, I need a snippet of code that works regardless of the environment. – Bram Vanroy Nov 08 '15 at 16:14
  • @BramVanroy In that case you'll have to use absolute paths in the `` and ` – hjpotter92 Nov 08 '15 at 16:32
  • Again, that's not possible. An absolute path would differ locally and on the server. `http://localhost/my-project/styles.css` vs. `http://my-project.com/styles.css`. – Bram Vanroy Nov 08 '15 at 16:35
  • @BramVanroy In that case, look around at the [server variables at php docs](http://php.net/manual/en/reserved.variables.server.php) and see if any of them suit your requirements. – hjpotter92 Nov 08 '15 at 17:00
0

I hackingly figured it out. By checking the end of the url, we determine if we are in root or if we are in a specific instance (ending with a digit e.g. /1.

<?php
// Is connection secure? Do we need https or http?
// See http://stackoverflow.com/a/16076965/1150683
$isSecure = false;
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
    $isSecure = true;
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) 
    && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'
    || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) 
    && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
        $isSecure = true;
}

$REQUEST_PROTOCOL = $isSecure ? 'https' : 'http';
$REQUEST_PROTOCOL .= '://';

// Create path variable to the root of this project
$path_var = $REQUEST_PROTOCOL.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];

// If URL ends in a slash followed by one or more digits (e.g. http://domain.com/abcde/1), 
// returns a cleaned version of the URL, e.g. http://domain.com/
if (preg_match("/\/\d+\/?$/", $path_var)) {
    $path_var = preg_replace("/\w+\/\d+\/?$/", '', $path_var);
}
?>

Now we can use it in our PHP file!

<link href="<?php echo $path_var; ?>css/styles.css" rel="stylesheet">
Bram Vanroy
  • 27,032
  • 24
  • 137
  • 239
  • If it is Apache 2.4 or later release, you can simply refer to `$_SERVER['REQUEST_SCHEME']` for `http/https` – hjpotter92 Nov 08 '15 at 17:50
  • @hjpotter92 Thanks for the feedback. Can't use that unfortunately, my host's still on 2.22. But it's good to know anyway! – Bram Vanroy Nov 08 '15 at 20:06
  • Also, replace the last `if preg_match` block entirely with `$path_var = preg_replace("~\w+/\d+/?$~", '', $path_var);` – hjpotter92 Nov 08 '15 at 20:08