Solved

PHP Path problem

Posted on 2014-09-29
25
196 Views
Last Modified: 2014-10-03
I'm getting perplexed with this. I am using XAMPP, and my application is installed at my C:\xampp\htdocs\photos, where 'photos' is the name of my application. For security purposes, I have decided that documents accessible to the public will be at C:\xampp\htdocs\photos\public, while I put files I do not want the public to access at C:\xampp\htdocs\photos\includes.

So when I run http://localhost/photos/public, it runs the default file index.php. The very first line in this file is:

require_once('..\includes\initialize.php'); // This works just fine and is able to load initialize.php

But inside the file "initialize.php" is where my problem begins. Here is the actual code within initialize.php:

<?php

defined('DS') ? null : define('DS', DIRECTORY_SEPARATOR);
defined('SITE_ROOT') ? null : define('SITE_ROOT', DS.'photos');
defined('LIB_PATH') ? null : define('LIB_PATH', SITE_ROOT.DS.'includes');

// load config file first
echo LIB_PATH.DS.'functions.php'; // prints out \photos\includes\config.php, which is correct
require_once(LIB_PATH.DS.'functions.php'); // This line is getting the error that it's not found! Why??

?>

Open in new window


This thing is frustrating me, and I would really appreciate any help. Thanks.
0
Comment
Question by:elepil
  • 10
  • 9
  • 6
25 Comments
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
This does not look right to me:
echo LIB_PATH.DS.'functions.php'; // prints out \photos\includes\config.php, which is correct

This should print something ending in 'functions.php' instead of 'config.php' - are you sure you're testing the correct script?
0
 

Author Comment

by:elepil
Comment Utility
Oh, sorry, it's supposed to be functions.php, my mistake in my typing.
0
 

Author Comment

by:elepil
Comment Utility
I modified my script a little bit because I wanted to present it as simply as possible, and that meant even shortening my application name. But the file functions.php or config.php both exist in the 'includes' directory, so my typo shouldn't even really matter.
0
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
This is just a guess, but maybe try replacing this:

defined('SITE_ROOT') ? null : define('SITE_ROOT', DS.'photos');

... with this:

defined('SITE_ROOT') ? null : define('SITE_ROOT', 'photos');

Man page references:
http://us3.php.net/manual/en/function.include.php
http://us3.php.net/manual/en/ini.core.php#ini.include-path
0
 

Author Comment

by:elepil
Comment Utility
That did not help. I've actually tried that already before.
0
 

Author Comment

by:elepil
Comment Utility
I've requested that this question be deleted for the following reason:

As much as I tried to simplify the problem, it clearly isn't simple enough because I only got one response, and I doubt the responder even understood it. Reposting, but this time, in an even simpler way.
0
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
Just a thought... Maybe simplifying it obscures the problem?  It might be worth showing the directory structure and the actual code instead of an abstracted version.
0
 

Author Comment

by:elepil
Comment Utility
Ray, did you read my original post? I was very specific about my directory structure, can't do any better than that. Your comments frustrate me.

And I did show the actual code which you tried to tweak by telling me to remove the DS variable. Did you even try it in your own system?

I am reopening a ticket, this time making it extremely simple, one that doesn't even use PHP system constants.
0
 
LVL 34

Expert Comment

by:gr8gonzo
Comment Utility
I think the problem here is that you're starting SITE_ROOT with a directory-separator. So let's say you have this folder structure:

C:\xampp\htdocs\photos\index.php

If you say:
require("\photos\includes\blahblah.php");

...then that first slash takes you back to C:\, so PHP is looking for:
C:\photos\includes\blahblah.php

If you use relative folder structures and say:
require("includes\blahblah.php");

...then that will make PHP look at it's current folder:
C:\xampp\htdocs\photos\index.php => C:\xampp\htdocs\photos\

... and then it will append the rest:
C:\xampp\htdocs\photos\ + includes\blahblah.php => C:\xampp\htdocs\photos\includes\blahblah.php

So you can either define your SITE_ROOT by looking at $_SERVER['DOCUMENT_ROOT"], or even better, just use relative paths when you're including/requiring files. It will make your site more portable (making it easier for development and testing)
0
 
LVL 34

Expert Comment

by:gr8gonzo
Comment Utility
Oops that was supposed to be an objection.
0
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
@elepil: I have read your post.  I have also read your new, "simplified" question.  In that question I have duplicated your directory structure and created a test case that works correctly.  Sorry if you find this frustrating, but sometimes it's not easy for us to guess at what you've tried and not tried.  You'll find the answer over there.
0
 

Author Comment

by:elepil
Comment Utility
gr8gonzo, even if I took out the first backslash so that the path would be:

photos\includes\functions.php

I still would get the same error.

I reopened a new ticket, I think it will be a lot simpler.
0
Easy Project Management (No User Manual Required)

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
Please see: http://www.experts-exchange.com/Programming/Languages/Scripting/PHP/Q_28528399.html#a40353042

Is there any confusion about whether you mean this:

photos\includes\functions.php

... or this:

photos\includes\config.php
0
 
LVL 34

Expert Comment

by:gr8gonzo
Comment Utility
Please re-read my suggestion fully. I was explaining that the backslash was the cause of the problem. If you want to use relative paths, then you wouldn't use SITE_ROOT (the "photos" part) at all.

defined('DS') ? null : define('DS', DIRECTORY_SEPARATOR);
// defined('SITE_ROOT') ? null : define('SITE_ROOT', DS.'photos');
defined('LIB_PATH') ? null : define('LIB_PATH', 'includes'); // <-- removed SITE_ROOT

// load config file first
echo LIB_PATH.DS.'functions.php'; 
require_once(LIB_PATH.DS.'functions.php');

Open in new window

0
 

Author Comment

by:elepil
Comment Utility
gr8gonzo, we're going around an issue that doesn't really address my problem. I reopened a new ticket at http://www.experts-exchange.com/Programming/Languages/Scripting/PHP/Q_28528399.html. I think that is a lot more simplified.

It is common practice for people to use absolute paths in certain scenarios which I really prefer not to have to explain. My problem is not being able to use absolute paths. Telling me not to use absolute paths but to use relative paths instead is not a solution. So I would appreciate an explanation from anyone why my absolute pathing isn't working under Windows. You already suggested taking out the first backslash, and I've already told you I've done that, and it still doesn't work.
0
 
LVL 34

Expert Comment

by:gr8gonzo
Comment Utility
I gave you solutions to using both absolute and relative paths. If you don't want to use relative paths, that's up to you. Remember that we see a LOT of different people of all varying skill levels and all varying projects, so we simply suggest some best practices. If they don't apply to your situation, that's totally fine.

Now, if you re-read my suggestion, I said you can use the value of $_SERVER["DOCUMENT_ROOT"] to help establish the correct starting point if you want to use absolute paths. That environment variable should point to the same starting folder, at which point you can traverse the folder structure up or down:

e.g. Accessing a sub-path from the document root:
require_once($_SERVER["DOCUMENT_ROOT"] . DS . "subfolder\foo.php");

You can even go further up above the document root with "..":
require_once($_SERVER["DOCUMENT_ROOT"] . DS . ".." . DS . "subfolder\foo.php");
0
 

Author Comment

by:elepil
Comment Utility
gr8gonzo, I appreciate your responses. My problem with $_SERVER["DOCUMENT_ROOT"] is that I have read other developers say that it is not always reliable. Some say it's sometimes not set, and some say it becomes problematic on machines with several virtual servers. At this point, I'm leaning more towards using the pathname obtained from the dirname(__FILE__) function as that would be less affected by the environment where my application resides.

As for absolute paths, it isn't always about best practices. Absolute paths remove the ambiguity of locations of critical files, files that are required before anything can function (e.g. database initializations, loading of key functions, etc.) Your suggestion to use relative paths is valid, but in my humble opinion, it is not a panacea, especially when these files to be loaded can be initiated by other files located within different levels in the file hierarchy.

As I said, I do appreciate your response.
0
 
LVL 34

Expert Comment

by:gr8gonzo
Comment Utility
@elepil - DOCUMENT_ROOT is always reliable within your own setup. If you're building something for yourself, then you will always be in control of the factors that populate this value, meaning it is reliable. I know what you've probably read (I've been doing this for quite a while), so here's a summary:

1. It's a $_SERVER environment variable, which means that it gets populated from the web server.
2. Almost every web server populates this value. If it doesn't, then you probably have a bigger problem.
3. In an Apache dynamic virtual hosting environment, you can get different values based on what module populates the value, but 9 times out of 10, it will still work unless someone is heavily screwing with mod_rewrite (htaccess).

So if you're building an app to distribute, then you can certainly use dirname(__FILE__) just as well. I do that in some situations, as well. panacea is a ridiculous concept in programming. Every developer worth their salt will know that one size does not fit all.

That said, you mentioned: "especially when these files ... can be initiated by other files located within different levels in the file hierarchy" - allow me just a word of caution. That sounds a lot like having multiple entry points into the script. Be cautious with that kind of architecture. An application is like a house, and the more doors you add to the house, the more doors you will have to secure. Make sure you do some pen testing along the way. (When possible, I like to create my apps with as few entry points as possible, and keep them all on the same folder level; it usually simplifies initialization and security).
0
 

Author Comment

by:elepil
Comment Utility
gr8gonzo, you said, " An application is like a house, and the more doors you add to the house, the more doors you will have to secure."

I do see the wisdom of your statement, but I'm interested in how you handle your database connections. Assuming every PHP page you make needs to access the database, clearly you have to have database interaction code (e.g. creating a database connection). The way I'm doing it, I have all that in a file called database.php. This file is included in every PHP page right at the top. The location of the file that needs to require_once('database.php') can be anywhere in the directory hierarchy.

So give this scenario, how do you handle it without "opening too many doors"?
0
 
LVL 34

Accepted Solution

by:
gr8gonzo earned 500 total points
Comment Utility
I usually enforce that all requests go through a single PHP file. For example:

http://www.foobar.com/myapp/index.php
http://www.foobar.com/myapp/index.php?page=foo
http://www.foobar.com/myapp/index.php?page=bar

In the above three URLs, all requests go through index.php. The "page" value in the query string indicates which page the user is requesting, and the index.php module can include() that page's code at runtime to deliver the appropriate page.

By this method, I can centralize a lot of critical code for easier maintenance and security. The below is a generic example of how some of those apps are built:

<?php
// index.php

// Load dependencies (database, functions, etc...)
require_once("includes/database.inc.php");
require_once("includes/functions.inc.php");

// Establish security / credentials / session
require_once("includes/security.inc.php");

// Now determine which page to access
$requestedPage = "default_page";
if(isset($_GET["page"]))
{
   // Sanitize the value
   $requestedPage = preg_replace("/^[a-z0-9_]/","",$_GET["page"]);
}

// Load headers and allow URL flags to optionally disable the headers/footers (for things like downloads)
if(!isset($_GET["notemplate"]))
{
  require_once("template/header.inc.php");
}

// Load content by first figuring out which file to load
$pageFile = "pages/" . $requestedPage . ".inc.php";

// Make sure it exists
if(!file_exists($pageFile))
{
  $pageFile = "pages/no_such_page.inc.php";
}

// Now load it
include($pageFile);

// Load footers
if(!isset($_GET["notemplate"]))
{
  require_once("template/footer.inc.php");
}

Open in new window


So you have a directory structure like this:

index.php
includes/database.inc.php
includes/functions.inc.php
includes/security.inc.php
template/header.inc.php
template/footer.inc.php
pages/no_such_page.inc.php
pages/default_page.inc.php
pages/foo.inc.php
pages/bar.inc.php

In the end, your files inside pages/ don't need to worry about page templates, overall security, database connections, etc... All that is already handled by index.php by the time the page is loaded, and every page has the same consistent environment.

An additional benefit is that since every request goes through index.php, you can easily take your app offline with a single change (e.g. maintenance window), update security in one go, and all requests start from the root directory already (allowing relative paths to be used without any concern of where you are in the folder structure).

It's just one design pattern, but it works pretty well for a lot of SaaS apps.
0
 
LVL 34

Expert Comment

by:gr8gonzo
Comment Utility
Oh, and you can always move ALL of those extra PHP files further below the document root so that no file is publicly-accessible except for index.php, significantly reducing your app's attack surface.
0
 

Author Comment

by:elepil
Comment Utility
gr8gonzo, I can see the advantage of the way you're doing things. I like the fact that all page redirects will converge in index.php. Not only will it be easier to figure out the "flow" of your application just by looking at one single page, you'd also be able to use relative pathnames to selectively load required files without the issues I'm going through. Perhaps the only thing that bothers me with this approach is the reliance on GET query parameters, something that might tempt hackers to "play around".

Although I'm new to PHP, I have been a software developer for quite some time using a non-stateless platform (specifically, Adobe Flex which runs on Flash Player and Java). Unfortunately, it is part of being "new" to a platform to be uncertain of possible unintended consequences down the road. I'd imagine your approach won't really make debugging harder, but that leads me to wonder ... may I ask what IDE you use? I'm having problems finding an IDE that allows debugging of BOTH PHP and JavaScript. Thanks.
0
 
LVL 34

Expert Comment

by:gr8gonzo
Comment Utility
Ultimately, the reliance on GET is kind of a moot point. More often than not, you're going to need to rely on GET and/or POST data at some point, and you're probably going to get at least some people playing around with those parameters. Using them is not a security risk by itself. It's -how- you handle the data that counts. For example, if I were a malicious user and I saw a URL like:

http://www.foobar.com/myapp/index.php?page=foo

... then I'd likely try out different values, including values that contain ".." and "/" to see if I can squeeze any private information about the target system by the resulting errors. That is why I included an example snippet of code that sanitizes the $_GET["page"] variable and removes every character that isn't alphanumeric or an underscore. I also included handling of situations (the "page_not_found" page) when the resulting sanitized value doesn't match up to an existing file. In a stateless development environment, you need to sanitize and check your data, but as long as you're doing it correctly, you should be safe.

You can use free tools like Burp to do some automated, basic pen testing in a sandbox environment:
http://portswigger.net/burp/

If you haven't done penetration testing before, the basic idea behind it (using Burp as an example) is that you start up the program and it acts as a proxy in your browser. It listens to the data you send out, and what comes back. You walk through the steps of using your application, hitting all the pages and buttons, and Burp "learns" all that info. Then you can let it loose and it'll go and try to hit everything with common attacks, SQL injection, etc... and give you a report of what it was able to successfully attack.

Stateless is definitely a different way of thinking about development. I, too, have a stronger background in client-side languages (from VB 3 through C#.NET and Java) and unfortunately, I have yet to find a good PHP debugger. Honestly, after you're in the PHP language for a little while, you only run into so many varieties of errors and it's usually pretty easy to find and fix them, so I stopped looking a long time ago. I do miss having breakpoints, locals, and a watch window in a full debugger, though.

That said, I've heard JetBrains has an IDE called something like "PHPStorm" (?) that apparently mimics some of the behavior of a full IDE. I haven't tried it personally, but I've heard good things. I just write PHP code in UltraEdit nowadays. It's just a pumped-up text editor with syntax highlighting and the works, and it's worked just fine for me for a long time now (don't fix what ain't broke).

For Javascript, I'm hard-pressed to recommend anything except for Firebug. Sure, it's Firefox-only, but any IE-specific Javascript bugs are usually easy to catch after Firefox gives you a clean bill of health (check for trailing commas, cut out any console.log commands, etc...).

Back to the first issue, you can't avoid hackers or people messing with your URLs. You just have to prepare your script to handle those attempts. Centralizing the entry point makes it a lot easier to do just that.
0
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
Firebug is a great tool.  Javascript debugging with Chrome Dev Tools makes a good bit of sense, too.
http://discover-devtools.codeschool.com/
Perhaps the only thing that bothers me with this approach is the reliance on GET query parameters, something that might tempt hackers to "play around".
What can I say but, "Accept Only Known Good Values."  The QA Engineer walks into a bar. Orders a beer. Orders 0 beers. Orders 999999999 beers. Orders a lizard. Orders -1 beers. Orders a sfdeljknesv.
0
 
LVL 34

Expert Comment

by:gr8gonzo
Comment Utility
Yep, both Chrome and IE have debugging consoles nowadays. Javascript debugging is similar between Chrome and Firebug, and they both have similar tool sets, but Firebug's versions of those tools are slightly better, in my opinion. IE's debugging console barely ranks higher than a piece of -.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Things That Drive Us Nuts Have you noticed the use of the reCaptcha feature at EE and other web sites?  It wants you to read and retype something that looks like this.Insanity!  It's not EE's fault - that's just the way reCaptcha works.  But it is …
This article discusses how to create an extensible mechanism for linked drop downs.
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now