how to read SetEnv in PHP when calling from the command line? - php

What I like about Apache .conf files, and what is commonly used obviously is the SetEnv command. However, when I run php artisan do:something from the command line, this same access to the .conf file appears to not be available (after all there is no "domain" or "website" understood from the command line).
In short, what is an alternate way to either read the same .conf file for the envvar's (ideal) or read from some file outside my codebase to differentiate environment (not ideal but certainly OK)?

You can use .htaccess parser when running Your app.
<?php
require_once 'vendor/autoload.php';
if(php_sapi_name() === 'cli') {
$file = new \SplFileObject(__DIR__.'/.htaccess');
$parser = new \Tivie\HtaccessParser\Parser();
$htaccess = $parser->parse(null, IGNORE_WHITELINES|IGNORE_COMMENTS);
foreach($htaccess AS $line) {
if($line->getName() == 'SetEnv') {
putenv($line->getArguments()[0], $line->getArguments()[1]);
}
}
}
Just FYI In modern containerized world it's better to use environment variables that passed on script invocation or in container image directives.
Let's say this is Your script (test.php):
<?php
if(getenv('PASSWORD') === 'blablabla') {
// do something secret
echo 'Psst... I have got a secret to share with You';
}
And execute it like:
PASSWORD=blablabla php test.php
how it looks in Dockerfile (part of it):
ENV MODE dev
CMD ['php', 'test.php']
and in php code:
if(getenv('MODE') == 'dev') {
// enable logger, debugger and etc...
}

Related

PHP file permissions, chmod & mkdir not working

I created a php function that allows me to add images to a folder within my web application project. Right now it only works when I manually set the permissions of the folder to write enabled. Unfortunately that is not exactly what I need, because when I push my code to my group members with git, they would still have to manually set the permissions of the folder to enable writing as well, in order for my pushed code to work. all my group members and I are each running this project locally via an apache server, and I believe the problem is that apache does not have access to write within any of the folders within the project unless the folders are somehow set to write enable for everyone. I feel like it's not feasible to tell all my group members to change their folder permissions just so my one function can write to a folder.
I am looking for a way to set file permissions within my php code, I have already tried php functions such as chmod and mkdir to set permissions, however it gives me errors saying that I don't have permission to use those functions, which I guess makes sense, but is there a possible work around?
$structure = 'path';
mkdir($structure, 0777, true)
or
$structure = 'path';
mkdir($structure)
chmod($structure, 0777);
<?php $result = mkdir ("/path/to/directory", "0777");
?>
Try this it will working
Try using this (if shell_exec() is allowed):
(list of issues: only works on linux, has a security issue with potential solutions at bottom of post)
<?php
function readFile($file) { return shell_exec("cat $file"); }
function writeFile($file,$cont) { return shell_exec("echo $cont > $file"); }
function makeFile($filename) { return shell_exec("touch $filename"); }
function makeFolder($filename) { return shell_exec("mkdir -pv $filename"); }
// the -pv was used so you could do makeFolder("1/2/3/4")
function appendFile($file,$cont) { fileWrite($file,readFile($file).$cont); }
function appendToTopOfFile($file,$cont) { fileWrite($file,$cont.readFile($file);); }
?>
Use escapeshellcmd or escapeshellargs to escape user input.
ex.
$file=escapeshellcmd($_GET['file']);
echo readFile($file);

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";

How to define $_SERVER['DOCUMENT_ROOT']

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

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