I'm using Windows 10 Home Single Language Edition which is a 64-bit Operating System on my machine.
I've installed the most latest version of XAMPP which has installed PHP 7.2.6 on my machine.
I come across the following sentence from the paragraph in PHP Manual
Make a call to the phpinfo() function and you will see a lot of useful
information about your system and setup such as available predefined
variables, loaded PHP modules, and configuration settings.
I tried executing the below script and saw the output in my web browser :
<?php phpinfo(); ?>
I checked the entire output carefully. In the output of phpinfo() I could only see the $_SERVER predefined variable along with it's possible indexes specific to set-up on my machine.
But what about other predefined variables in PHP viz. $GLOBALS, $_GET, $_POST, $_FILES, $_COOKIE, $_SESSION, $_REQUEST, $_ENV, $http_response_header, $argc, $argv?
According to what the text from PHP Manual is saying all the above mentioned predefined variables along with their respective values should be displayed in the output of the script <?php phpinfo(); ?> but it's not happening. Why so?
Is the text from PHP manual misguiding the users of PHP?
Or am I getting the wrong understanding of the text from PHP Manual?
Please explain me in detail.
As you can see in the PHP source code for phpinfo(), it will display the variables in question:
if (flag & PHP_INFO_VARIABLES) {
zval *data;
SECTION("PHP Variables");
php_info_print_table_start();
php_info_print_table_header(2, "Variable", "Value");
if ((data = zend_hash_str_find(&EG(symbol_table), "PHP_SELF", sizeof("PHP_SELF")-1)) != NULL && Z_TYPE_P(data) == IS_STRING) {
php_info_print_table_row(2, "PHP_SELF", Z_STRVAL_P(data));
}
if ((data = zend_hash_str_find(&EG(symbol_table), "PHP_AUTH_TYPE", sizeof("PHP_AUTH_TYPE")-1)) != NULL && Z_TYPE_P(data) == IS_STRING) {
php_info_print_table_row(2, "PHP_AUTH_TYPE", Z_STRVAL_P(data));
}
if ((data = zend_hash_str_find(&EG(symbol_table), "PHP_AUTH_USER", sizeof("PHP_AUTH_USER")-1)) != NULL && Z_TYPE_P(data) == IS_STRING) {
php_info_print_table_row(2, "PHP_AUTH_USER", Z_STRVAL_P(data));
}
if ((data = zend_hash_str_find(&EG(symbol_table), "PHP_AUTH_PW", sizeof("PHP_AUTH_PW")-1)) != NULL && Z_TYPE_P(data) == IS_STRING) {
php_info_print_table_row(2, "PHP_AUTH_PW", Z_STRVAL_P(data));
}
php_print_gpcse_array(ZEND_STRL("_REQUEST"));
php_print_gpcse_array(ZEND_STRL("_GET"));
php_print_gpcse_array(ZEND_STRL("_POST"));
php_print_gpcse_array(ZEND_STRL("_FILES"));
php_print_gpcse_array(ZEND_STRL("_COOKIE"));
php_print_gpcse_array(ZEND_STRL("_SERVER"));
php_print_gpcse_array(ZEND_STRL("_ENV"));
php_info_print_table_end();
}
However, as you can see, it uses php_print_gpcse_array to print each key/value pair in it when a) the superglobal exists (SAPI dependent) and b) it actually contains values.
TL;DR: no, the PHP manual is not misleading in that regard.
Related
Why does this line return null in my live server?
filter_input(INPUT_SERVER, 'REQUEST_METHOD');
The live server is php5.5.9
Have I missed something?
I thought it is used to replace the global method below?
$_SERVER['REQUEST_METHOD'];
some of the code,
public function __construct()
{
// Construct other generic data.
$this->clientRequestMethod = filter_input(INPUT_GET, 'method'); // such as list, add, update, etc
$this->clientPostMethod = filter_input(INPUT_POST, 'method'); // such as update
$this->serverRequestMethod = filter_input(INPUT_SERVER, 'REQUEST_METHOD'); //such as get or post
}
public function processEntry()
{
// Determine the $_SERVER['REQUEST_METHOD'] whether it is post or get.
if ($this->serverRequestMethod === 'POST' && $this->clientPostMethod != null)
{
$this->processPost();
}
else if($this->serverRequestMethod === 'GET' && $this->clientRequestMethod != null)
{
$this->processRequest();
}
}
So the problem/bug is this:
filter_input() doesn't work with INPUT_SERVER or INPUT_ENV when you use FASTCGI
The bug has been known for years and I found nothing saying it was addressed. I found several work-arounds but no complete solution so I plopped the best work-around into this helper function for a project-wide solution. To provide some level of security and avoid train wrecks, the function falls back to filter_var() where filter_input() fails. It uses the same format as the native filter_input() function for easy integration into projects and easy future removal should the bug ever be fixed.
function filter_input_fix ($type, $variable_name, $filter = FILTER_DEFAULT, $options = NULL )
{
$checkTypes =[
INPUT_GET,
INPUT_POST,
INPUT_COOKIE
];
if ($options === NULL) {
// No idea if this should be here or not
// Maybe someone could let me know if this should be removed?
$options = FILTER_NULL_ON_FAILURE;
}
if (in_array($type, $checkTypes) || filter_has_var($type, $variable_name)) {
return filter_input($type, $variable_name, $filter, $options);
} else if ($type == INPUT_SERVER && isset($_SERVER[$variable_name])) {
return filter_var($_SERVER[$variable_name], $filter, $options);
} else if ($type == INPUT_ENV && isset($_ENV[$variable_name])) {
return filter_var($_ENV[$variable_name], $filter, $options);
} else {
return NULL;
}
}
This seems the best solution. Please let me know if it contains errors that might cause issues.
I had the same problem where it was working on my local machine (OSX Mavericks, PHP version 5.4.24) and not on my live server (Cent OS 5). I upgraded the server from 5.3.9 to 5.5.15 (and added the mb and mcrypt functions although that's probably irrelevant) and now it works.
This probably isn't helpful if you're on a shared host but you could ask them if they can rebuild PHP/Apache.
I was having the same issue in my XAMPP localhost as well and was looking for solutions madly. What I ended up with, it is a known PHP bug for this function if you are running the PHP in FCGI mode (FCGI/PHP 5.4 in my case). I was confirmed going through this link.
The workaround I used is to filter_var($_SERVER['PHP_AUTH_USER'], FILTER_SANITIZE_STRING) but this is not an alternative of filter_input. filter_input is more secure.
FastCGI seems to cause strange side-effects with unexpected null values when using INPUT_SERVER and INPUT_ENV with this function. You can use this code to see if it affects your server.
If you want to be on the safe side, using the superglobal $_SERVER and $ENV variables will always work. You can still use the filter* functions for Get/Post/Cookie without a problem, which is the important part!
Source: http://php.net/manual/es/function.filter-input.php#77307
I solve it changing my php.ini from:
variables_order = "GPCS"
To:
variables_order = "GPCSE"
By default PHP wasn't registering the environment variables, so this change enabled them. The interesting is that the INPUT_SERVER variables came back to work too!
Just two addiotional informations, i am using PHP 7.0.13 and as said in other answers, this issue is related to a PHP bug.
Another option is use the following:
filter_var(getenv('REQUEST_METHOD'));
My personal solution was to change filter_input to filter_var :
With filter_input (not working on a Siteground shared hosting):
filter_input(INPUT_SERVER, 'REQUEST_URI')
With filter_var (now it works on Siteground)
filter_var($_SERVER['REQUEST_URI'],FILTER_UNSAFE_RAW, FILTER_NULL_ON_FAILURE)
The problem affects Apache + fcgid + php-cgi 8.1.9 too.
It't caused by auto_globals_jit enabled (default) . When disabled (in php.ini on php startup), filter_input(INPUT_SERVER) works correctly.
I'm writing a small extenstion for PHP. Is there way to know at runtime, the name of the script file (e.g.: test.php) that is running? Maybe some global or environment variables?
You can fetch $_SERVER['PHP_SELF'] (or any other $_SERVER variable if you need to), like this:
// This code makes sure $_SERVER has been initialized
if (!zend_hash_exists(&EG(symbol_table), "_SERVER", 8)) {
zend_auto_global* auto_global;
if (zend_hash_find(CG(auto_globals), "_SERVER", 8, (void **)&auto_global) != FAILURE) {
auto_global->armed = auto_global->auto_global_callback(auto_global->name, auto_global->name_len TSRMLS_CC);
}
}
// This fetches $_SERVER['PHP_SELF']
zval** arr;
char* script_name;
if (zend_hash_find(&EG(symbol_table), "_SERVER", 8, (void**)&arr) != FAILURE) {
HashTable* ht = Z_ARRVAL_P(*arr);
zval** val;
if (zend_hash_find(ht, "PHP_SELF", 9, (void**)&val) != FAILURE) {
script_name = Z_STRVAL_PP(val);
}
}
The script_name variable will contain the name of the script.
In case you're wondering, the first block, that initializes $_SERVER, is necessary because some SAPIs (e.g.: the Apache handler) will initialize $_SERVER only when the user script accesses it (just-in-time). Without that block of code, if you try to read $_SERVER['PHP_SELF'] before the script tried accessing $_SERVER, you'd end up with an empty value.
Obviously, you should add error handling in the above code in case anything fails, so that you don't invoke undefined behavior when trying to access script_name.
Try the variable $argv. The first item in that array contains the name of the script.
EDIT
For C the function
int main takes two paramters argc and argv (see here). The same still holds as above. i.e. argv[0] is the command name.
I tried this script, but it didn't work for me. The first statement:
if (!zend_hash_exists(&EG(symbol_table), "_SERVER", 8)
fails. I'm running PHP from the CLI. However, I did set variables through my PHP script and when I use print_r($_SERVER) through the same script I get a full array of values.
I think the negation in before the zend_hash_exists() is not necessary in this context.
I'm currently working on a project that requires session variables to store search information, which is pretty common place. Typically, I've used isset() to check if a session variable exists. However, there seems to be a problem that is bewildering...not sure what is going on. Any help is appreciated. The code...
<?php
# Check to make sure the session is started
if (session_id() != '') echo 'Session has started<br/>';
# Check every possible way I know to make sure variable is set
if (array_key_exists('adminsearchrange', $_SESSION) && isset($_SESSION['adminsearchrange'])
&& !empty($_SESSION['adminsearchrange']) && $_SESSION['adminsearchrange'] != NULL) {
echo 'Search range is set and is not empty<br/>';
echo $_SESSION['adminsearchrange'];
}
?>
The output...
Session has started
Search range is set and is not empty
Notice: Undefined index: adminsearchrange in /Users/.../events_items.php on line 1182
Based on the comments, I took the simplest approach...created a new file whose entire contents is listed below. Still get the same error (above), and oddly enough, it still references the the exact line and file (even though that file is not being included in any way)...and no, there isn't any .htaccess rewriting of any sort. The code (all in one file)...
<?php
session_start();
if (session_id() != '') echo 'Session has started<br/>';
if (array_key_exists('adminsearchrange', $_SESSION) && isset($_SESSION['adminsearchrange'])
&& !empty($_SESSION['adminsearchrange']) && $_SESSION['adminsearchrange'] != NULL) {
echo 'Search range is set and is not empty<br/>';
echo $_SESSION['adminsearchrange'];
}
?>
It appears the session was hosed (somehow). A simple session_destroy() solved the problem.
I need to determine whether the current invocation of PHP is from the command line (CLI) or from the web server (in my case, Apache with mod_php).
Any recommended methods?
php_sapi_name is the function you will want to use as it returns a lowercase string of the interface type. In addition, there is the PHP constant PHP_SAPI.
Documentation can be found here: http://php.net/php_sapi_name
For example, to determine if PHP is being run from the CLI, you could use this function:
function isCommandLineInterface()
{
return (php_sapi_name() === 'cli');
}
I have been using this function for a few years
function is_cli()
{
if ( defined('STDIN') )
{
return true;
}
if ( php_sapi_name() === 'cli' )
{
return true;
}
if ( array_key_exists('SHELL', $_ENV) ) {
return true;
}
if ( empty($_SERVER['REMOTE_ADDR']) and !isset($_SERVER['HTTP_USER_AGENT']) and count($_SERVER['argv']) > 0)
{
return true;
}
if ( !array_key_exists('REQUEST_METHOD', $_SERVER) )
{
return true;
}
return false;
}
php_sapi_name() is really not the best way to perform this check because it depends on checking against many possible values. The php-cgi binary can be called from the command line, from a shell script or as a cron job and (in most cases) these should also be treated as 'cli' but php_sapi_name() will return different values for these (note that this isn't the case with the plain version of PHP but you want your code to work anywhere, right?). Not to mention that next year there may be new ways to use PHP that we can't possibly know now. I'd rather not think about it when all I care about is weather I should wrap my output in HTML or not.
Fortunately, PHP has a way to check for this specifically. Just use http_response_code() without any parameters and it'll return TRUE if ran from a web server type environment and FALSE if ran from a CLI type environment. Here is the code:
$is_web=http_response_code()!==FALSE;
This will even work if you accidentally(?) set a response code from a script running from the CLI (or something like the CLI) before you call this.
I think he means if PHP CLI is being invoked or if it is a response from a web request. The best way would be to use php_sapi_name() which if it was running a web request would echo Apache if that is what it was running.
To list of a few taken from the php docs on php_sapi_name():
aolserver
apache
apache2filter
apache2handler
caudium
cgi (until PHP 5.3)
cgi-fcgi
cli
cli-server (Built-in web server as of PHP 5.4)
continuity
embed
fpm-fcgi
isapi
litespeed
milter
nsapi
phttpd
pi3web
roxen
thttpd
tux
webjames
This should handle all the cases (including php-cgi)
return (php_sapi_name() === 'cli' OR defined('STDIN'));
function is_cli() {
return !http_response_code();
}
example:
if (is_cli()) {
echo 'command line';
} else {
echo 'browser';
}
Try
isset($_SERVER['REQUEST_METHOD'])
if it's set, you're in a browser.
Alternatlely, you could check if
isset($_SERVER['argv'])
but that might not be true on windows CLI, IDK.
I used this:
php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)
This is from Drush codebase, environment.inc where they have similar check to make.
I would suggest to check if some of the entries of the $_SERVER array are set.
E.g.:
if (isset($_SERVER['REQUEST_METHOD'])) {
print "HTTP request\n";
} else {
print "CLI invocation\n";
}
According to http://jp2.php.net/manual/en/features.commandline.php There are a number of constants set only when running from the CLI. These constants are STDIN, STDOUT and STDERR. Testing for one of those will tell you if it is in cli mode
joomla way
if (array_key_exists('REQUEST_METHOD', $_SERVER)) die();
An easy way is to interrogate the $argv variable, (Which you will probably do for command line parameters anyway). Even if there are no parameters $argv returns an empty array.
If it is set, then cli was used. You may then assume all other invocations are via some web server or other.
eg:
if (isset($argv)) {
// Do the cli thing.
}
The correct answer to this question depends on the real intent behind it:
Is the SAPI the deciding factor (web-context or not)?
Or is the information interpreted as 'running in a tty'?
If the former the answers given and comments written are enough to find a solution that works.
If the latter, the recipes given here will fail if the tool is run as cronjob, or as background-job from another daemon -- in that case I suggest to further test if STDIN is a TTY:
function at_tty() {
return defined("\STDIN") && posix_isatty(\STDIN);
}
How, so many complicated solutions. How about ...
if($_SERVER['REQUEST_SCHEME']=="http" or $_SERVER['REQUEST_SCHEME']=="https"){
// must be browser :)
}
// Detect CLI calls
define("IS_CLI_CALL",( strcmp(php_sapi_name(),'cli') == 0 ));
if(IS_CLI_CALL){
//do you stuff here
}
Based off Silver Moon's answer above, I'm using this function for returning correct linebreaks:
/**
* Linebreak function
* #return "/n" if cli, else return <br>
*/
protected static function lb(){
return (defined('STDIN') || php_sapi_name() === 'cli' || isset($_ENV['SHELL']) ||
(empty($_SERVER['REMOTE_ADDR']) && !isset($_SERVER['HTTP_USER_AGENT']) && count($_SERVER['argv']) > 0) ||
!isset($_SERVER['REQUEST_METHOD'])) ? "\n" : "<br>";
}
A practical hint
The official way (as told by many) is PHP_SAPI as a constant, or php_sapi_name() as a function, they both return cli when you're in a command line situation. They're right.
But!...
Consider using $_SERVER["argv"] (also $argv in most cases) which is null when you run in a browser, and an array when you've been called from command line. The advantage of this approach (or using both) is that you can simulate a terminal run in a browser, by just giving a (fake) value to the $argv / $_SERVER["argv"] variable. This comes in handy when you test on an outside server (prod, staging, etc) where you typically won't get SSH access.
The best way to do this is keeping in mind whether you may or may not need a CLI simulation, and use both $argv and PHP_SAPI to coordinate this - e.g. you may need to output an extra <pre> tag beforehand if PHP_SAPI is not "cli" but $argv has a value.
My preferred method:
if (array_key_exists('SHELL', $_ENV)) {
echo "Console invocation";
}
else {
echo "HTTP invocation";
}
I'd try:
echo exec('whoami');
Usually webservers are run under a different username, so that should be telling.
I tried things like $_ENV['CLIENTNAME'] == 'Console' but that seems to work on only certain OS's (worked in windows, not linux).
I tried !empty($_ENV['SHELL']) but that doesn't work always either...
Is there a way to check this that will work in all OS's/environments?
Use php_sapi_name()
Returns a lowercase string that
describes the type of interface (the
Server API, SAPI) that PHP is using.
For example, in CLI PHP this string
will be "cli" whereas with Apache it
may have several different values
depending on the exact SAPI used.
For example:
$isCLI = (php_sapi_name() == 'cli');
You can also use the constant PHP_SAPI
Check on http://php.net/manual/en/features.commandline.php#105568
"PHP_SAPI" Constant
<?php
if (PHP_SAPI === 'cli')
{
// ...
}
?>
I know this is an old question, but for the record, I see HTTP requests coming in without a User-Agent header and PHP does not automatically define HTTP_USER_AGENT in this case.
if ($argc > 0) {
// Command line was used
} else {
// Browser was used
}
$argc coounts the amount of arguments passed to the command line.
Simply using php page.php, $argc will return 1
Calling page.php with a browser, $argc will return NULL
One solution is to check whether STDIN is defined:
if (!defined("STDIN")) {
die("Please run me from the console - not from a web-browser!");
}
Check the HTTP_USER_AGENT , it should exist in http request