How to define $_SERVER['DOCUMENT_ROOT'] - php

I am trying to install a PHP application on a Linux running Apache2 and PHP5.
I noticed that, whenever I try to access the application (for example, hitting the index.php file), the browser returns a blank page. Running a phpinfo() works fine though.
Through testing, I have realized that the problem lies in the code of the applicatio, which has lost of lines like this one:
require_once($_SERVER['DOCUMENT_ROOT'] . '/202-config/functions.php');
If I change this to require_once('./202-config/functions.php');, then the application runs ok (at least that part of the application.
If I run a print_r($_SERVER), DOCUMENT_ROOT appears empty.
My question for you guys is: as I dont want to go through all the code in this application and replace these require_once statements, is there a way to define the value of DOCUMENT_ROOT?
Thanks.

From the docs:
The entries in this array are created by the web server. There is no guarantee that every web server will provide any of these;
Also if you run script from command line it might not be set.
Workaround is to set explicitly:
if (!isset($_SERVER['DOCUMENT_ROOT']) || empty($_SERVER['DOCUMENT_ROOT']))
$_SERVER['DOCUMENT_ROOT'] = __DIR__; //or dirname(__FILE__) for older php verstions
Note: You use $_SERVER['DOCUMENT_ROOT'] to include scripts. So it's better idea to rely on constants __DIR__ and __FILE__ rather than $_SERVER.

Do you have set the DocumentRoot "/var/www" in your Apache-Virtualhost-Config? In CLI this field is empty. In that case you can set this value manually:
if ($_SERVER['DOCUMENT_ROOT'] == '') {
$_SERVER['DOCUMENT_ROOT'] = __DIR__;
}
or for PHP < 5.2
if ($_SERVER['DOCUMENT_ROOT'] == '') {
$_SERVER['DOCUMENT_ROOT'] = dirname(__FILE__);
}

You also could do something like this:
if (empty($_SERVER['DOCUMENT_ROOT'])) {
$_SERVER['DOCUMENT_ROOT'] = './';
}
But this is not a nice way

Related

How can I keep a script running in the background-not working

I am trying to fire up the Ratchet's chat-server.php file which is needed to fire up the socket server from a php file so that whenever a client visits the page the server is started but its not happening. This chat-server.php file needs to be run from the terminal but I am trying to run it from the main page on user visit.
FILE STRUCTURE
./index.php
./config.php
./vendor/(all vendor files)
./src/MyApp/Chat.php
./js/app.js
./inc/connect.php <--Database connection file
./inc/send-message.php
./inc/startServer.php
./inc/bg.php
./inc/serverStatus.txt
./css/index.css
./css/reset.css
./bin/chat-server.php
config.php
<?php
include_once ("./inc/startServer.php");
?>
chat-server.php
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;
if(isset($startNow)){
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8080
);
$server->run();
}
?>
bg.php
<?php
$startNow = 1;
include_once ("../bin/chat-server.php");
?>
startServer.php
<?php
$statusFile = dirname(__FILE__).'/serverStatus.txt';
$status = file_get_contents($statusFile);
if($status == "0"){
function execInBackground($cmd) {
if(substr(php_uname(), 0, 7) == "WINDOWS") {
pclose(popen('start /B ' . $cmd, 'r'));
file_put_contents($statusFile, 1);
}
else {
exec($cmd . ' > /dev/null &');
file_put_contents($statusFile, 1);
}
}
execInBackground("php " . dirname(__FILE__) . "/bg.php");
}
?>
serverStatus.txt
Its default value has been set to 0
NOTE: Updated the code accordingly but doesn't work still now.
Plus I don't have any idea about restarting the server incase of any failure or how to shutdown the server when all clients leave.
When you including files using relative paths you must remember that they are relative to the current running file, not just to current file.
In your case. When you accessing index.php and including in it config.php and from then startServer.php it's all ok, because you are including ./inc/startServer.php which is right, relative to index.php.
But than you are including ../inc/serverStatus.txt, which is not right, because you are still running index.php and that relative path resolves to /../inc/serverStatus.txt in other words you are trying to access a file that is one level higher than your DOCUMENT_ROOT. So you will never get into your if statement.
You can use a __FILE__ constant which is always resolves to the absolute path of the current file. So you can change your $statusFile to
$statusFile = dirname(__FILE__) . '/serverStatus.txt';
Next thing is regards your exec() and popen(pclose()) commands. If you want to execute some command that is not in your PATH environment variable, than you must specify an absolute path to your file. Because you don't know from which folder it will be started. It may be started from Apache home dir or maybe started from your user's home dir. It depends on the setup of your PHP is it sapi module or is it fcgi. Anyway, you need to change your execInBackground() to
execInBackground("php " . dirname(__FILE__) . "/bg.php");
And add some spaces in your commands, like this:
pclose(popen('start /B ' . $cmd, 'r'));
exec($cmd . ' > /dev/null &');
this way you will not have some strange errors that might occur.
In your bg.php you need to change current working directory, like this:
<?php
$startNow = 1;
chdir(dirname(__FILE__));
include_once ("../bin/chat-server.php");
?>
This way, PHP will find chat-server.php no matter from what folder you will run it.
BTW, how did you planning to stop your server? =)
UPDATE: Also you have a variable scope issue in your function execInBackground(). Your function relies on the variable $statusFile, but this variable defined in the global scope and is not visible inside the function. To make it visible, you must include statement global $statusFile; in your function before accessing $statusFile. Like this:
function execInBackground($cmd) {
global $statusFile;
if (false !== stripos(PHP_OS, 'win')) {
pclose(popen('start /B ' . $cmd, 'r'));
file_put_contents($statusFile, 1);
} else {
exec($cmd . ' > /dev/null &');
file_put_contents($statusFile, 1);
}
}
and I've changed the way you are checking the OS, because your approach contained an error.
UPDATE2:
After a bunch of tests, I figured out that when php-script running in the background (under Windows) it can't use "echo()" to write to STDOUT. When it happens, php-script will silently die, with no errors. So change all echo()'s to some log-function.
Change listening port to some other, that is free for sure, like 50000. Because, 8080 is often may be already taken by some web server or other service.
And remember! You can start your chat server only if you have your own server (like VPS/VDS or dedicated server), on the public hosting no one will allow you to open some port for incoming connections for security reasons. On the public servers there are often disabled functions like exec(), popen() and similar for the same reasons.
I think you should read http://php.net/manual/es/function.shell-exec.php
Note that this function is disabled when PHP is running in safe mode.

Cron Script Doesn't Work in Server Side

i have some cron files. And it was in under httpdocs. But i decided to move under cron folder. And i change the script.
config.php to ../config.php
When i call script from browser every thing works fine. But when i call from ssh i got en error undefined index : SERVER_NAME
I couldn't run cronjob. What can i do that ?
stock.php file
include_once '../config.php';
require_once CLASS_PATH.'class.product.php';
include_once INC_PATH.'functions.php';
....
config.php file
if ( !defined('ABSPATH') ) {
define('ABSPATH', dirname(__FILE__).'/');
}
define('PROTOCOL',(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') ? 'https' : 'http');
define('HOST', PROTOCOL.'://'.$_SERVER['SERVER_NAME']);
define('CLASS_PATH',ABSPATH.'includes/class/');
define('INC_PATH',ABSPATH.'includes/');
//if (isset($_SERVER['SERVER_NAME'])){
define('PRODUCT_IMG_PATH', 'images/product/');
//}
define('HEAD_META',ABSPATH.'view/head-meta.php');
define('NAVBAR', ABSPATH.'view/navbar.php');
define('HEADER', ABSPATH.'view/header.php');
define('FOOTER', ABSPATH.'view/footer.php');
The reason is that when you are running through ssh or command line you are in CLI mode, therefore none of those CGI variables can be used. It's recommended to use getenv() command instead which supports some of defined variables in CLI mode. However you need to configure and define them in you php.ini
You may need to look at Command line usage documentation for more details
How are you running it from cron? It seems that the server variables aren't being found when you run from terminal - which would make sense if you were php-running the file on the server. The SERVER-variables in php are set by the webserver - i.e. what answers a request over port 80 to the files in a specific location.
Here's php's documentation on server variables.
http://www.php.net/manual/en/reserved.variables.server.php
You web server is the one who fills the php $_SERVER array. I quote from the manual (http://www.php.net/manual/en/reserved.variables.server.php):
The entries in this array are created by the web server. There is no
guarantee that every web server will provide any of these; servers may
omit some, or provide others not listed here.
Obviously, if you call your script from the command line, there's no web servers to fill the $_SERVER array, and that's the reason of your problem.
To solve it, you can modify your config.php to load predefined values to the variables you need in case they don't exist. It would be something like this for every undef var:
if (!isset($_SERVER['SERVER_NAME'])) $_SERVER['SERVER_NAME']="localhost";

$_SERVER['HTTP_HOST'] different on localhost versus deployment staging server

We discovered bugs in our site after deploying from our localhost development environment to our staging server.
We narrowed the bugs down to the following PHP code snippet:
$_SERVER['HTTP_HOST']
We use that to construct paths to various files used by our website.
For example:
// EXAMPLE #1 -- THIS WORKS ON OUR LOCAL MACHINE
$theSelectedImage = "http://" . $_SERVER['HTTP_HOST'] . "/ourWebSite/egyptVase.png";
// EXAMPLE #2 --BUT IT MUST BE THIS TO WORK ON THE STAGING SERVER
$theSelectedImage = "http://" . $_SERVER['HTTP_HOST'] . "/egyptVase.png";
Here is the crux of the problem:
on our localhost machine, $_SERVER['HTTP_HOST'] resolves to 'localhost' -- notice we then need to append our website folder name like I show in EXAMPLE #1 above. I.E. on our localhost machine, $_SERVER['HTTP_HOST'] is unaware of which website folder involved -- we have to append it.
but on our staging server, $_SERVER['HTTP_HOST'] resolves to 'www.ourWebSite.com'.
In that case we don't need to append anything -- the staging web server returns our website folder.
Have we thought of a couple kludgy inelegant 'snide-remarks-in-code-reviews' workarounds. Yes.
But I'm thinking there's a better way -- any ideas?
One option is to have a configuration file that would pull properly depending on what host it's on (normally based on APPLICATION_ENV). Zend Framework does this by loading the correct section of a .ini file corresponding to the APPLICATION_ENV in the apache config. You could use a PHP file with an array or anything else, really. All you would need to do is set the APPLICATION_ENV to be one thing on staging/production but something different on dev servers.
A simple example:
switch (APPLICATION_ENV) {
case 'dev':
define('APPLICATION_URL', $_SERVER['HTTP_HOST'] . '/ourWebSite');
break;
case 'production':
case 'staging':
define('APPLICATION_URL', $_SERVER['HTTP_HOST']);
break;
}
The config file is the correct answer.. I use an default and override set up.
In config.php
$config = array('url' => 'http://production.url'); // 'conf1'=> 'var1', etc
$dev_config = array();
#include_once('dev-config.php');
$config = array_merge($config, $dev_config);
In dev-config.php you add any overrides to the $dev_config
$dev_config['url'] = 'http://localhost/ourWebSite';
Then in production, I just delete the dev-config file. Super easy, works flawlessly.
If you want to keep it the way you have it, this can also be solved with an http.conf tweak on your dev box. You need to set your documentRoot to what ever it is now plus the /ourWebSite that way http://localhost/ will point to the same folder with in your code as http://production.url/
how about
function get_homepath(){
$host = $_SERVER['HTTP_HOST'];
if ( $host == 'localhost' ){ return $host . '/ourWebSite/'; }
return $host . '/';
}
Usually people set up different environment settings depending on if its a development environment or production environment. The reason for this, as you found out, is to easily move code around from development to production.
Instead of inserting a $_SERVER variable into the url directly, set up a condition that will check $_SERVER['HTTP_HOST'], find out what environment we are, and inject a different variable holding the real path for your scripts.

can't include("absolute_path")

I can't figure out why this won't work.
$docRoot = getenv("DOCUMENT_ROOT");
include_once($docRoot."/conn/connection.php");
include_once($docRoot."/auth/user.php");
It works locally through wamp, but it won't work on my live server. I tried this:
if(!include_once($docRoot."/auth/user.php")){
session_start();
$debug = array();
$debug["docRoot"] = $docRoot;
$debug["inc_path"] = $docRoot."/auth/user.php";
$debug["file_exists"] = file_exists($debug["inc_path"]);
$_SESSION['DEBUG'] = $debug;
// exit
header("Location:debug.php");
exit();
}
The debug page just echoes that array and it shows the correct absolute paths and indicates that the file does in fact exist. So why didn't the include_once() work? The server (a DV account on a MediaTemple server) has not been configured at all, so I wonder if there is an apache or php setting that is messing with me.
Ultimately, what I want here is a way to refer to a file in such a way that if I move the file, or include it in another file, nothing will break. Any ideas?
In your debugging you might try is_readable($docRoot."/conn/connection.php"). The file_exists function will return true even if the file does not have readable permissions.
If you get an error code we might be able to provide more info as to what is going wrong.
Turn on error reporting dummy. It turns out one of the includes on another file was breaking this page and I wasn't able to trace that out until I turned on error reporting.
Incidentally, the problematic include was missing a leading slash in the filepath ( include("dir/file.ext"); ) which works on my local wamp setup and breaks on the linux server.

How can I get the path of the PHP binary from PHP?

How can I get the binary path of php from PHP?
I saw it in phpinfo(), but I need another method that gets it in Linux and Windows systems.
You can use:
$_SERVER['_']
Also, the predefined constant PHP_BINDIR gives the directory where the PHP executable is found.
Sample on CodePad and Ideone.
It looks like, for security reasons, $_SERVER values are not exposed.
Linux Only
Use the "which" command to find php.
$phpPath = exec("which php");
Note this does not guarantee the same php executable that your web server may be using, but rather the first instance that was found while looking through the paths.
A method using environment variables, assuming the php executable is in the system path.
function getPHPExecutableFromPath() {
$paths = explode(PATH_SEPARATOR, getenv('PATH'));
foreach ($paths as $path) {
// We need this for XAMPP (Windows)
if (strstr($path, 'php.exe') && isset($_SERVER["WINDIR"]) && file_exists($path) && is_file($path)) {
return $path;
}
else {
$php_executable = $path . DIRECTORY_SEPARATOR . "php" . (isset($_SERVER["WINDIR"]) ? ".exe" : "");
if (file_exists($php_executable) && is_file($php_executable)) {
return $php_executable;
}
}
}
return FALSE; // Not found
}
Maybe the best solution is in the Symfony process component:
PhpExecutableFinder.php and ExecutableFinder.php. In use:
<?php
use Symfony\Component\Process\PhpExecutableFinder;
$phpFinder = new PhpExecutableFinder;
if (!$phpPath = $phpFinder->find()) {
throw new \Exception('The php executable could not be found, add it to your PATH environment variable and try again');
}
return $phpPath;
In Windows, using WAMP, you can use the ini variable - extension_dir - as it is placed in the PHP folder.
Like this:
echo str_replace('ext/', 'php.exe', ini_get('extension_dir'));
Normally, in a simple default PHP installation under Windows, the php.ini file is located and loaded from the same directory of the PHP binary.
To simplify, Windows users:
echo dirname(php_ini_loaded_file()).DIRECTORY_SEPARATOR.'php.exe';
VoilĂ !
Of course, if you are using multiple .ini files, it may not work if the files are not into the same PHP binary directory. BTW, this may solve to most of cases. Windows developers running PHP from local development environment.
As of PHP 5.4 you can simply use the PHP_BINARY reserved constant.
It's very easy!
var_dump(getenv('PHPBIN'));
But it works only on Windows, so we should use this answer.
How did I get this? I just typed echo echo phpinfo(); and searched the php path there. Just see here:
Then I just getting it here: php getenv and ... you see the result.
For Windows and XAMPP:
$php = getenv('PHPRC') . '/php.exe';
if(is_file($expected)){
return $php;
}

Categories