PHP shared hosting interpretation of $_SERVER['DOCUMENT_ROOT'] - php

I've been using a PHP script to have automated versioning on files, and in it, it uses $_SERVER['DOCUMENT_ROOT'] to get the path to locate the file.
It works most of the time, but every so often, the server(shared hosting) seems to misinterpret the path.
It SHOULD ALWAYS be: /home/username/public_html
But sometimes it comes out as: /usr/local/apache/htdocs, and then errors occur.
This is the line of the script where it's used:
$ver = '.'.filemtime($_SERVER['DOCUMENT_ROOT'].$url).'.';
Is there another way to get the website root rather than server in the line above? Like just / at the top of the domain or subdomain, like where the RewriteBase would be defined?
Input is appreciated.

Referring to it explicitly in your script(s) would solve the problem as long as the doc_root doesn't change by default:
$ver = '.'.filemtime('/home/username/public_html/'.$url).'.';
You should always have access to this directory as shared hosting structures don't usually change (unless they want to loose customers!). Let them know it's happening and ask why too.

Related

Have script path with unresolved symlinks in PHP?

Let's say we have a web directory with the following paths:
framework/
index.php
...
instance/
index.php -> ../framework/index.php (symlink)
...
If we now make a request for (...)/instance/index.php PHP will resolve the symlinks and set __FILE__ as (...)/framework/index.php
Is there a way around this so e.g. dirname(__FILE__) would be (...)/instance?
EDIT: Since it has been pointed out, I'm actually not sure if PHP itself is resolving the links or something else. In my case I'm using nginx as a webserver with php-fpm as FastCGI.
(The background is that I want to have multiple instances of a CMS or Framework referencing a common code base.)
The best approximation for your case is dirname($_SERVER['SCRIPT_FILENAME']) to get the "instance" dir, if you can live with the general warning in the doc about the $_SERVER vars:
There is no guarantee that every web server will provide any of these;
servers may omit some, or provide others not listed here.
Also, the PHP manual does not explicitly promise that symlinks will be preserved, but that seems to be the case (unless of course your server thinks otherwise). See also this answer.
(Note: this also works in CLI mode. If the script was launched via a relative path (to the CWD), PHP will keep it that way, so you may end up with "." then.)
However, for the general problem (of getting any script's dir with symlinks preserved), this doesn't work. It only works for the script that has been reached via HTTP. Since any other scripts you include later on will all have the same $_SERVER['SCRIPT_FILENAME'] (of course), regardless of their location, dirname($_SERVER['SCRIPT_FILENAME']) will yield the wrong dir if they are located elsewhere...
I don't think PHP has a solution for that today (as of v7.2).
(And you were correct initially: PHP is doing the symlink-resolving for __FILE__, irrespective of your server. And it's unlikely that this would ever change, because it has stayed this way for too long (and too much code depends on it), even though there's realpath() if we wanted the resolved path, while there's no bullet-proof solution for the symlinked case.)

Is there a setting that allows php variables to be set in an included php script and then reused in the main file?

I have just checked out a project from an SVN and have tried to run the project on my local machine using WAMP and virtual hosts. I'm getting a lot of errors saying variables have not been declared and after further investigation have found that they are set in separate PHP files and then have been included into the page throwing the errors.
This works absolutely fine on live but not on my local which makes me think it must be a PHP setting. I've looked in the PHP.ini file but don't really know what I'm looking for.
There are two things I would like to know...
Firstly is there something I can adjust in my PHP.ini file to solve this and secondly, is it a good idea to have this setting(should there be one), as I have always worked with PHP variables, private to the page unless setting a $_SESSION variable.
Hope this makes sense to someone.
I should also mention I'm using windows and the server that runs the file is using Linux.
Thanks in advance
my guess is: your local and remote server have two different include paths set. you can check that by looking at the output of get_include_path()
then, check if paths are correct, you might want to check paths of these files
are they in the same directory? if no, are the paths in include relative or absolute? and how are the paths defined? these info will help you to get your answer. no php.ini setting can probably help you here.

include statement using a variable in the filename

(Please be patient, this does have something to do with include.) I am waiting for a domain to transfer over and am trying to set it up on the new hosting service ahead of time. I realized that on the old site all the path names were absolute, so all my links on the new host point to pages on the old host. I decided to make them all relative (for future possible moves also). I first did it like this:
index.php
include ('./header.php');
header.php
include "./panel.php";
panel.php
Contents of panel.
This works, and my page displays:
Contents of panel.
Then I decided to set a variable for the domain because I want to include this header file from files in subdirectories and I can use the domain variable to make an absolute path. Right now I have a temporary domain name, which I can change later to the real domain name when the transfer comes through. So I changed header.php to:
$domain="http://tempdomain.com"; //I can change this after the transfer
$panel=$domain."/panel.php";
echo $panel;
if ((include $panel) !== 1)
{
echo "<br>include failed";
}
What I get is:
http://tempdomain.com/panel.php
include failed
I've looked at various sites for include syntax, but I can't find any error in my code. All these files are in the / directory. Any ideas?
When you include, you have to give the directory structured, not the url.
Your hosting server path may be home/public/www/htdocs/your_directory_name/panel.php something like this. Then it will work.
remort include is also posiible
if
1. server's php.ini should allow it.
2. the file which will be included should not be preprossed before include. That means it must return unprocessed code :)
First, the allow_url_fopen flag must be set in php.ini. Otherwise remote include() cannot be done. Run var_dump(ini_get("allow_url_fopen")); to see if it is the case.
Second, "Windows versions of PHP prior to PHP 4.3.0 do not support access of remote files via this function, even if allow_url_fopen is enabled." - see PHP docs
Third, your remote PHP script must produce valid PHP code as output. If you include() via http, then not the script itself, but its output will be included.

How can we check if we are running the PHP script on localhost?

Is there a way to check if we are running a PHP script on localhost - development server or on live server - production server? Is there any PHP constant, variable, function,etc that can give me this information.
I need this to put different settings for production and development server. Now I parse the URL to see which one it is but I was wondering s there any better way to do that. My concern is that we may change the URL of the script and that may ruin my check.
I am looking few a solution with one config file and IF condition in it depending on which I will define different settings. The only problem is that I do not want to change the IF statement when there are changes on the server settings like hostname, document_root or something else that I am using to identify local/remote host.
And want to SVN update from one source without changing anything to my production server.
And I would like ideally to be able to run and CRON jobs with these settings.
I use the SetEnv in my host definition to locate on which environment i am running (Dev, Stage, Production) :
<VirtualHost *:80>
(all the host info)
SetEnv SERVER_CONTEXT "dev"
</VirtualHost>
And each config file as an extra word in it : config.dev.ini, config.stage.ini, config.prod.ini, etc, ...
It works like a charm.
if($_SERVER["REMOTE_ADDR"]=="127.0.0.1"){
$local = True;
}else{
$local = False;
}
EDIT
You could also check the first part of the address and see if the server is in the local network, the again assuming your server won't be in the local network when in production
I set an environment variable in the Apache configuration and check that. This has the advantage over using a PHP configuration file that all your application code remains exactly the same on PROD, TEST, DEV etc; no need to go and make changes after a check out, as the code just pulls the config from Apache.
To demonstrate, the following can be set in your VirtualHost configuration
SetEnv ENVIRONMENT PROD
In your PHP code, you can then check the environment with
$env = getenv('ENVIRONMENT');
If you feel the need to make this available everywhere, you can then use define, but I don't find it necessary (I use the specified environment to load the appropriate configuration files and create a read-only Singleton configuration, which is then used to check any configuration options; better than if ($env == 'PROD') {} type code, as all that logic is in the config, not in your code).
Use a config file you include with a define in it
define("DEBUG",true); //set to false for live
and use that in your code, e.g.:
if(DEBUG){}
You can try and use the global $_SERVER['SERVER_NAME'] This should tell you the host name of the system that's running the script. You could use this to determine what settings to use (depending on the system).
I don't know that this will output 'localhost' however and you may need to know your actual host name of your development machine.
The server has no idea what environment it is unless you tell it to. What I do is use DEFINE to set the environment. My application code is the same on every instance but the my configuration files change. That way you can use .htaccess file include the configuration files on every script and check to see what they settings are.
I know this word may sound strange to PHP developer, but have you considered build of your project?
In PHP there's nothing to compile, however changing copied files is one of features of any build process. You could specify 2 targets: production and dev. There would be no need for any conditionals, that should work, or may work, but under some circumstances won't.
i always make "config.php" wich i include to other php files...
it contains something like (home file):
$CONFIG['server']="dev";
$CONFIG['db_user']="root";
and thing like that...
so at home i have this one up there and at server where site is running i have another one wich i dont update if not changes to it...
so on server i have something like:
$CONFIG['server']="prod";
$CONFIG['db_user']="lwu9918_admin";
and then in other php files:
include("config.php");
if($CONFIG['server']=="dev"){echo "Development";}
thing like that!
On dev server
* * * * * php -r cronjob.php this_is_dev
On production server
* * * * * php -r cronjob.php this_is_live
In your script
switch ($argv[1])
case 'this_is_dev':
// load your dev configuration
break;
case 'this_is_live':
// load your live configuration
break;
default:
die('invalid server');
break;
}
since is meant for cronjob, the $argv is exist
good luck with Windows :(
you better put the cli running program outside www directory ,for example
c:\iis\www is the public html directory
the cli file should be put under c:\iis instead

What is the best way to determine which server the script is on and therefore the configuration in PHP?

I'm trying to determine the best way of having a PHP script determine which server the script/site is currently running on.
At the moment I have a switch() that uses $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] to determine which server it's on. It then sets a few paths, db connection parameters, SMTP paramters and debug settings based on which server it's on. (There maybe additional parameters depending on the site needs.)
This means that I can simply drop the site onto any of the configured servers without having to change any code (specifically the configuration). If it's a new server, then I simply add a new case and it's ready from then on.
We have done loading config files based on the same SERVER_NAME:SERVER_PORT combination, but found that it's another file you have to maintain, plus we weren't sure on the speed of parsing ini files, (although having extra cases for each server may be just as slow).
Another problem we have is when a site is often moved between 2 servers, but we use the same SERVER_NAME and SERVER_PORT on each. This means we need to temporarily comment one case and ensure it doesn't get into the repo.
Another other ideas? It needs to be available on all servers (sometimes SERVER_NAME and SERVER_PORT are not). It would also be nice if it worked with the CLI PHP.
How about using $_SERVER['SERVER_ADDR'] and base your identity off the IP address of the server.
UPDATE: In a virtual host situation, you might also like to concatenate the IP with the document root path like so:
$id = $_SERVER['SERVER_ADDR'] . $_SERVER['DOCUMENT_ROOT'];
We use the $_SERVER['HTTP_HOST'] variable to create the filename of a PHP include file which contains all the vhost-specific information (we deploy the same software to a lot of vhosts)
I like this technique, as you can get clever with it to build hierarchies of configurations, e.g. for www.foo.com,
try to load com.config.php
try to load foo.com.config.php
try to load www.foo.com.config.php
Doing it this way lets you set options for all your live sites globally, and tweak individual sites on as as-needed basis. We have our own internal root domain name for developer sandboxes too, so we can enable all the developer level options in internal.config.php
You can also do this in reverse, i.e. try to load www.foo.com.config.php, and only if not found would you try to load foo.com.config.php, and so on. More efficient, but a little less flexible.
Here are some variables you can check:
$_SERVER['HTTP_HOST'];
I use this one for checking which server I'm on when php is running through apache.
$_SERVER['USER'];
$_SERVER['LOGNAME'];
I use these two for when I know I'm running from the console. One of those invariably resolves to a usable username. There seem to be no other host-defining variables in console mode.
This might not help you enough; If you find you still have a hard time being able to uniquely identify what server you are on you can give it a little bit of a "push." In my situation I have a small config file which is unique to each server, basically setting a php variable defining which environment I'm running in (e.g. development or production.) This way you only need to maintain one small, easy to recreate file outside of your source control.
Ive always kept a config.php on my sites, storeing such infomation which may be percificic to that server.
Being php parseing it is nearly (eg the file needs to be opened, closed, etc) as fast as having the code at the top of each script, and much faster than ini and xml config solutions
Centralised location for the sites configuration on each server, so easy to keep upto date (server doesn't change that oftern, updateing the config is simple with an update script).
Can be generated by the script, all my sites have a function that rebuilds the config file useing the $config[] assoc array.
Updates that effect the config file are as simple as "$config['key'] = 'new value';config_update()"
I have been using the following mechanism:
if(__FILE__ === '/Sites/mywebsite.com/includes/config.php')
define('SERVER', 'DEV');
else
define('SERVER', 'PRODUCTION');
My development environment has a rather distinct path structure so this works well, and I don't need to worry if additional domains are added to $_SERVER[HTTP_HOST], or a client that provides an incorrect HTTP_HOST value (although that would be rare ...).
Why don't you have configuration files for each host stored outside of the project directory and read it from the php code?
Having host specific code is not really a good practice.
$posix_uname = function_exists('posix_uname') ? posix_uname() : null;
$this_hostname = !empty($_SERVER["HOSTNAME"]) ? $_SERVER["HOSTNAME"] : $_ENV["HOSTNAME"];
$this_hostname = !empty($this_hostname) ? $this_hostname : $posix_uname['nodename'];
We use environment variables for this (ENVPHP environment variable which will contain the specific server environment - ie. development/test/production). This approach works very well for CLI scripts as well (for CLI you set the OS environment variables, for Apache you can use SetEnv switches in the host configuration). In PHP you access this environment variable using getenv('ENVPHP')...

Categories