I'm trying out a lot of PHP example projects. For most examples I need to setup a VirtualHost in the Apache config (httpd-vhosts.conf) to get them working.
But sometimes I just want to copy or test a project, without going through the hassle of making another VirtualHost.
It would be nice if everything still works too when I try http://localhost/ProjectDir/ instead of http://ProjectDir/
In Phalcon I know how to fix the root directory, by changing the config or with setBaseUri(), but this is a bit inconvenient to change every time. It would be nice if this could be done automatically somehow. (I do realize that in this way I can not use absolute URLs or links inside the HTML (starting with /) since that would mean the root folder of the Apache server then but this could be solved with an automatically configured prefix-variable).
How do other developers handle this situation, or do you really choose between a virtual host or http://localhost/ProjectDir/ ?
Is there a way for a PHP script to detect if it's running in a
virtual host or in a subdir of localhost?
UPDATE
Found out I could use $_SERVER['SERVER_NAME'] to determine if it's 'localhost' or something else. Not very elegant, but it's a sufficient solution, I guess.
Within html views:
I like to use absolute paths from the document root for ease. (Relative paths are flexible but can get complicated.)
<img src="/images/foo.jpg">
Of course if I want to move the project into a sub directory, the path above will need to be adjusted. (We could use the html base tag, but that can have side effects.):
<img src="/subdir/images/foo.jpg">
We could use a variable in our views that we prefix to links and asset paths:
<?php
$base = '/subdir'; // Set somewhere.
?>
<img src="<?php echo $base ?>/images/foo.jpg">
To set the $base variable automatically, I sometimes assign it to Symfony/Component/HttpFoundation/Request::getBasePath(). (There are some other useful utility methods in that component.) Or use something similar from another framework/library/component.
Assigning a value in one place in a central configuration isn't that much of a hardship. I find prefixing paths within the views more of a pain.
In one of my development environments, I use a symlink from the directory root to the project directories directory root:
/var/www -> /sites/example.com/pub
And swap it as and when needed. You can avoid writing multiple virtual host configs that way and skip the other steps mentioned above.
However, configurable prefixes can be useful in other ways:
$base_cdn = 'http://cdn.example.com';
$base_nav = '/subdir';
$base_static = '//static.example.com/foo';
assuming the entry is index.php
function getVirtualHostPath(): string
{
$temp = str_replace("index.php", "", $_SERVER["SCRIPT_NAME"]);
return substr($temp, 1);
}
// "https://domain.example/subdir/api/v2/store/inventory" => "subdir/"
// "https://domain.example/api/v2/store/inventory" => ""
// "https://domain.example/subdir/api/v2/store/inventory" => "subdir/"
// "https://127.0.0.1/api/v2/store/inventory" => ""
Explanation:
dump $_SERVER super global in production (that uses virtual hosts) and filter out all keys that does not contain "subdir".
filter out all keys that are not present in CGI 1.1 specification
copy the same keys from development environment without virtual host.
$_SERVER["SCRIPT_NAME"] contains "/subdir/index.php" in prod and "/index.php" in dev. Removing "index.php" will return the virtual host path.
Related
HTML references the site's "doc root" (like say localhost/) with the slash (/) in an attribute like href="/" (which by default would go to localhost/index.html or index.php), but I'm not seeing an easy way to specify in PHP the "docroot" like what $_SERVER['DOCUMENT_ROOT'] does...
I've read that if I start a path with / (like '/some.log') that slash will refer to the docroot, but I'm finding that's not the case as I've gotten file write permission errors and realpath() says it's trying to write literally to the Linux root folder of /.
Is there some easy way to refer to this? I could define my own constant but the base file (or a universally-included file) is not necessarily a constant in our archaic code base...
Many $_SERVER values are populated with external variables and DOCUMENT_ROOT is one of them. It isn't even a standard CGI variable either. If you run PHP on top of Apache you'll have such variable with whatever value was set in Apache's DocumentRoot directive.
Now, you're probably assuming that there's always a one-to-one mapping between file system paths and URL paths. That's not always the case; in fact URL rewriting and router-based applications are kind of nowadays norm.
If you add up the fact that there're also may ways to configure virtual hosts and PHP within Apache... The thing is that $_SERVER['DOCUMENT_ROOT']:
Does not necessarily exist
Is not necessarily correct
May not be helpful at all
So you have a number of alternatives depending on your use case:
Define your own value (I'd suggest a PHP constant) as part of your apps boostrapping
Hard-code a leading path /
… or even use $_SERVER['DOCUMENT_ROOT'] as-is ;-)
HTML is working via the web server. The web server has a configuration of... the DocumentRoot (apache, not sure what nginx calls it), so the HTML / reference will be taken to the correct place BY APACHE.
PHP isn't limited to web programming - I cheerfully admit to using it for database work and processing text files and combinations thereof for utility programming to make my job easier. Even when used for web programming, it isn't limited to only staying within the webserver-config-defined DocumentRoot. So when you reference / you really are referencing the top of the actual file system.
So... nothing is broken, nothing needs changing, but I think the issue is how you are interpreting / vs $_SERVER['DOCUMENT_ROOT'] and the fact that very similar terminology is used.
The best solution I could find is assigning $_SERVER['DOCUMENT_ROOT'] to a constant:
define('DOCROOT', $_SERVER['DOCUMENT_ROOT']);
It's easier to type and just as global, even in class definitions and instantiated objects, simply called like:
$path = DOCROOT . '/logfolder';
This will work as long as the calling script or an included file has the definition.
It is also possible to set server environment variables that are passed down to PHP in a $_ENV array (would is still easier to type), though that is dependent on your server and configuration.
I am sure that this is a repost but I cannot find a question the same as what I want to find out. Essentially, whenever I am working offline, all URIs that I use across the site refer to offline locations eg 127.0.0.1/home.html however, when I go to upload the site, these URIs need to be changed to their equivalents eg example.com/home.html and I either need to go through all of the pages and update these references or use some php to insert the correct address at every point where an address is used. At the minute I am using something like this:
Top of every page:
<?php $offline = false; ?>
Link:
Home
But this seems like a poor way to achieve something which should be relatively simple. What is the standard way of keeping these references up to date. I considered using relative links everywhere but that proved to have problems (for example view includes don't work correctly) and I tried setting the base href to the homepage but that threw up other problems.
Any suggestions would be very much appreciated. Thanks.
$server=$_SERVER['SERVER_ADDR'];
// Local
if(strstr($server,'127.0.0'))
{
define('ROOT_PATH','http://127.0.0.1/');
}
// Server
else
{
define('ROOT_PATH','http://www.yoursite.com/');
}
Put this code in php file and include in every page.
And then:
Home
In this case you can put your files in folder too, for example:
define('ROOT_PATH','http://www.yoursite.com/mysite/');
Another way you could do it is using relative paths.
For files in the same directory you'd use ./ and for files above that directory use ../ This works for anchors in HTML and requires and includes in PHP.
As Waygood suggested, it sounds like you need to change your paths from absolute to either site root relative or relative paths. Example: 127.0.0.1/home.html would become just /home.html if using site root relative. Alternatively, if there's a reason why you must include absolute paths, you can set an environment variable on the server or a PHP constant that indicates the environment type and toggle links based on this value. Using environment variables has the added benefit of being able to keep the exact same code base on your dev and production machines and not having to resort to host or IP detection. Here's an example from zend framework's docs guide that I use:
defined('APPLICATION_ENV') || define('APPLICATION_ENV',
(getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));
From: http://framework.zend.com/manual/1.12/en/zend.application.quick-start.html
A neat way that I have found to resolve this issue is to amend your HOSTS file so that it points example.com to 127.0.0.1 so that you can refer to example.com everywhere but be redirected to 127.0.0.1 until your development has finished.
Currently our PHP app requires to be set up in the web server's document root (usually by configuring Apache's virtual hosts).
The main reason for that dependency is that our URL-generation logic assumes that all URLs can be accessed through the absolute path /. That makes for easy linking to resources such as images, and pages.
The user may be visiting the app from different sub-folders, so we cannot assume a simple relative path to work.
How would we decouple the app from needing to run in the document root of the web server? Would you suggest parsing $_SERVER['DOCUMENT_ROOT'] in that URL controller to try to decide how far down in the filesystem the file is being accessed? Right now, I don't see a sure-fire way of doing that parsing. Also a complication here is that we use Apache's ReRewrite so URLs don't necessarily match the file system.
I generally use a Simple and Stupid method for this purpose like:
If users can access indeterministically from different entry points of the application, the entry points should know "where they are" relatively to the application root.
First I should know the relative position of my current script w.r. application root so I statically write into the script i.e;
For a script that should be at
...approotdirname/appsubdir1name/appsubdir2name/here.php
.
$relPath = 'approotdirname/appsubdir1name/appsubdir2name';
Note that if your script is at the application root, the $curPath calculated below will be directly your application position on the server.
Second I should learn the current script file path from Php with a uniform format:
$curPath = str_replace('\\','/',dirname(__FILE__));
(str_replace is for replacing \ with / in case they exist.)
In fact a copy of the $relPath (if figured correctly) should exist at the end of the $curPath.
Then I will find the position of $relPath in the $curPath:
$p = stripos($curPath, $relPath, 0);
if(($p === false)||($p < 0)){echo "Relative path: $relPath is invalid."; exit(0);}
Now when we subtract $relPath from $curPath we get where on earth is our application root positioned on the server with a little checking.
$rootPath = ($p > 0)? substr($curPath, 0, $p-1): '/';
I hope this helps.
Please note that restricting user access through a single point like an index.php at application root is generally accepted as a better practice. There at the entry point you can get
$rootPath = str_replace('\\','/',dirname(__FILE__)).'/';
and use it all through your application for file access and includes. As a bonus, you can move your entire application without breaking its file relations.
I see two options:
Refactor the existing program to route all requests through a single script (suggested above, but it's not practical for our project)
Use smudge and clean attribute filters, requiring some relativley advanced git.
I have wamp setup on my windows box. Generally, when I bring a site down from the web, I create a folder inside my www folder for the site name. ex: c:\wamp\www\mysite. Once I have the folder, I copy down all the live files. The issue is that all the paths are then broken because my local folder isn't rooted.
What is the best way to setup paths so that if the site moves to a folder that isn't rooted, it will work easily?
I use a file (usually called something like config.php) to keep track of the root folder. My definitions (constants) look like this:
define('BASE_DIR','/wherever/whenever/');
define('LIB_DIR', BASE_DIR . 'lib/');
And then when you need to include a file
include LIB_DIR . 'aFile.php';
This would be something you do on a new site or if you have time to refactor your current site.
Create an include file, that has constants setup based upon whatever the root directory is... then in your code, use the constants you created to include files.
Also note, that when you are using directory "slashes", always use the build in constant DIRECTORY_SEPARATOR instead of hard coding it, this will allow you to go from WIndows to Linux seamlessly.
We use $_SERVER['DOCUMENT_ROOT'] to determine where we are in the filesystem and then simply append the folder name of our project to that. This works perfectly for us. You should always use a configuration.php where you define basic paths and URL's that may change when moving the project from one server/folder to another.
Option 1. Use <base href=""/> tag
Option 2. Use a config file, like #MattCan suggests
Option 3. Use a server environment variable, like #Bjorn suggests
Option 4. Create a virtual host on your apache, than you can create a domain who appoint exactly where are your app folder. Apache Doc here
Hi guys I'm in a bit of a pickle here now. Well to start with I built a simple CMS in PHP with an admin panel the directory structure is like this:
root/
->admin/
->images/
It worked fine as is however the client requirements changed and they wanted that instead of having to access the admin folder as a folder within the root it be accessed as a web subdomain. so www.site.com/admin becomes admin.site.com
However this has terrible messed up and destroyed practically all the referencing I had done. Like I upload images on the CMS - however now uploading on ../images doesn't work as its now under a subdomain and I'm all messed up in trying to relatively reference images from there too. I've been trying to hack away at my config file for weeks and can't get to fix this :( - help please - on the front end the site is o.k. but my admin section is all messed up :(
I'm using PHP and MySQL.
Sounds like you've learned how toxic relative paths can be.
Possible quick fix: what happens if you copy/symlink/alias admin.domain.com/images to point at the same images folder that lives on your front-end site? I think that extra "../"es will basically be ignored.
More permanently, and in general, don't use relative paths. They will cause you nothing but pain. A couple of strategies:
1) Define some constant that points at the right location for images, css, etc:
define('IMG_DIR','/images');
define('CSS_DIR','/images');
// ... some time later
echo '<img src="' . IMG_DIR . '/myimage.jpg'"/>';
2) Much better: just maintain one constant that tells you where your application lives.
define('APP_ROOT','/myapp'); //could be chanted to just '/' if it doesn't live in some folder on the server
// ... later that day ...
echo '<img src=\"' . APP_ROOT . '/images/myimage.jpg"/>';
// ... or maybe you need to link to a logout script?
echo 'Log Out';
It's important to assume you application might need to run from the root ("/") or some directory on the server, etc.
The same goes for any filesystem operations you might do purely on the server side. Use absolute filesystem paths. If your main application has a script like "config/config.php", you could stick this at the top:
define('APP_FS_ROOT',realpath(dirname(__FILE__) . '/..'));
Assuming both the frontend and the admin are on the same file system, you will need to use absolute paths for everything in the admin. In the admin's config create a define that maps to the frontend's physical upload/image folder. For example, from the fontend you can access uploads folder with the relative path ./upload but from the admin.example.com site you will be required to use the absolute path /user/example.com/upload.
The fontend's config would look like (www.site.com/config.php):
define("UPLOAD_FOLDER", "./uploads");
define("WEB_UPLOAD_FOLDER", "/uploads");
The admin's config would look like (admin.site.com/config.php):
define("UPLOAD_FOLDER", "/user/site.com/upload");
define("WEB_UPLOAD_FOLDER", "http://www.site.com/uploads");
Then both the frontend and admin would reference the physical folder with:
$filename = UPLOAD_FOLDER . "/myupload.mp3";
And to create hyperlinks to the upload you would use this:
My Upload
Another possible solution would be to define a directory alias in apache for the directories you've moved.
Lets say your sub domain root is
/subdomains/images
<VirtualHost>
...
Alias /images "/subdomains/images"
...
</VirtualHost>
Both www.yourDomain.com/images and images.yourDomain.com would load the same files.
Or, if your using linux, a symlink could accomplish the same thing.