1

I have a directory structure like this:

www/
  index.php
  my-library/
    my-library.php
    assets/
      my-library.css
      images/
        loading.gif

I need my-library.php to inject stylesheets into index.php. To do so, I need to get the relative path from index.php to my-library/ -- which in this particular case, would simply be "my-library".

From within my-library.php, is it possible for me to acquire this relative path?

Or must index.php supply it, with something like the following?

<?php
require "my-library/my-library.php";
$mlib->linkroot='my-library';
?>

To clarify, below I have included a more detailed representation of what I'm trying to do:

index.php:

<?php require "my-library/my-library.php"; ?>
<!doctype html>
<head>
  <title>Testing My Library</title>
  <?php $mlib->injectAssets(); ?>
</head>
<body>..</body>

my-library.php:

<?php
class MyLibrary(){
  public $rootpath;
  public $linkroot;
  function __construct(){
    $this->rootpath= __DIR__; // absolute path to my library's root directory (for serverside use)
    $this->linkroot = "???"; // relative path to my library's root from index.php (for clientside use, like linking in stylesheets)
  }
  function injectAssets(){
    $csslink = $this->linkroot.'/assets/my-library.css';
    echo '<link href="'.$csslink.'" rel="stylesheet" />';
  }
}
$mlib = new MyLibrary();
?>

The line I'm interested in figuring out, would be $this->linkroot = "???";.

I'm practically trying to acquire the string that was used to include/require the current script.

7
  • Uh, how about '/index.php'? the '/' will put everything at site root and you can go from there. Commented Dec 28, 2013 at 1:23
  • @chas688: I can't rely on the user of the library (in this case, index.php) to be located at the webspace's root. The idea is, no matter where index.php is, or where my-library/ is in relation to it, the linkroot must be a valid relative path between the two, allowing library assets to automatically be loaded clientside. A truly dynamic library like this focuses on complete flexibility. Commented Dec 28, 2013 at 1:26
  • As mentioned in the question, I know that I can have the user (index.php) explicitly supply this linkroot to the library, with something tacky like $mlib->linkroot('my-library');. I'm really just looking for something less aesthetically ghastly; something with elegance, and a hint of class. Commented Dec 28, 2013 at 1:30
  • check out this answer (may be along the right track) stackoverflow.com/questions/4737609/… Commented Dec 28, 2013 at 1:35
  • @chas688: Not quite. I already use __DIR__ as the realroot for the same purpose as the answer you linked -- the serverside inclusion of assets, where absolute paths are acceptable. Commented Dec 28, 2013 at 1:44

3 Answers 3

2

I got it! I only had to build a Rube Goldberg Machine to do it!

Thanks PHP.

$linkroot = ascertainLinkroot();

function ascertainLinkroot(){
  return makeRelativePath(
    getTopScriptPath(),
    __DIR__
  );
}

function getTopScriptPath(){
  $backtrace = debug_backtrace(
    defined( "DEBUG_BACKTRACE_IGNORE_ARGS")
      ?DEBUG_BACKTRACE_IGNORE_ARGS
      :FALSE );
  $top_frame = array_pop($backtrace);
  $top_script_path = $top_frame['file'];
  return $top_script_path;
}

function makeRelativePath($from,$to){
  // Compatibility
  $from = is_dir($from) ?rtrim($from,'\/').'/' :$from;
  $to   = is_dir($to)   ?rtrim($to,'\/').'/'   :$to;
  $from = str_replace('\\','/',$from);
  $to   = str_replace('\\','/',$to);
  //----------------------------
  $from = explode('/',$from);
  $to   = explode('/',$to);
  $path = $to;
  foreach($from as $depth => $dir) {
    if ($dir === $to[$depth]) { // find first non-matching dir
      array_shift($path); // ignore it
    } else {
      $remaining = count($from)-$depth; // get number of remaining dirs to $from
      if ($remaining>1){
        // add traversals up to first matching dir
        $padLength = -(count($path)+$remaining-1);
        $path = array_pad($path, $padLength, '..');
        break;
      } else {
        $path[0] = './'.$path[0];
      }
    }
  }
  return rtrim(implode('/', $path),'\/');
}

So, basically, I use the makeRelativePath function to calculate a relative path from the top script's absolute path to the current script's absolute directory path (__DIR__).

I realized that I'm actually looking for the relative path to the library from the top script, not just the parent script -- because the top script is the one where clientside assets will need to be referenced in relation to.

Naturally, PHP doesn't just give you the top script's absolute path. On some environments, the top script's path can be available as a $_SERVER variable, however environment independence is important for me, so I had to find a way.

getTopScriptPath was my solution, as it uses debug_backtrace to find it (creepy, I know), but it is the only environment-independent way to fetch it (to my knowledge).

Still hoping for a more elegant solution, but am satisfied that this one works.

Sign up to request clarification or add additional context in comments.

Comments

0

I believe this is what you're looking for:

$this->linkroot = basename(pathinfo($_SERVER['REQUEST_URI'], PATHINFO_DIRNAME));

You can remove basename() to get the full path. Basically, you can run the following code:

echo '<pre>';
var_dump($_SERVER);
echo '</pre>';

If the path you're looking for isn't there in some shape or form, then it simply isn't available and you will have no other choice but to hard code it, or at least hard code part of it.

2 Comments

For some reason, this evaluated to an empty string, in my experimentation.
You're right, in that the path I'm looking for is not present in $_SERVER. This does not mean however, that I'll have to hardcode anything. You see, I can create a relative path between any two absolute paths, and considering I already have __DIR__ within my-library.php, I only then need the absolute path to the top running (parent) script. The top script path is available under some environments as $_SERVER['SCRIPT_FILENAME'], however I require environment independence: which can be achieved an alternate way, with debug_backtrace. See my answer, for more details.
0

Have you tried doing a relative link from the root? If not, you might try something like this, if I understand your folder structure.

<link href="/my-library/assets/my-library.css" rel="stylesheet" type="text/css" />

Links like this in any page within your site will pull the same stylesheet, up or down the site structure.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.