Is is possible for a php script to know if another script calls it via require or require_once?
eg:
if scripta.php calls me do xyz;
if scriptb.php calls me do abc;
Edit: Thanks for your suggestions guys. It was more of a what if question, rather than an actual problem. I realise I could set a variable, $caller and update it when I made the require statement. I just wondered if there was another way to do this in the file that's being called :)
If you just want to check if the your file was included or not:
$_SERVER['SCRIPT_FILENAME'] will always return the filename of the script that has been originally called. (e.g. "start.php")
The constant __FILE__ will always return the true file name of the script that it is used in. (e.g. "library.inc.php")
So you can do something like this:
if ($_SERVER['SCRIPT_FILENAME'] !== __FILE__) {
echo "script was included!";
}
else {
echo "script was called directly!";
}
If you want to distinguish from where the file has been included:
$include_from = get_included_files();
if (count($include_from) > 1) {
$include_from = $include_from[count($include_from)-2];
}
else {
$include_from = $include_from[0];
}
switch ($include_from) {
case __FILE__:
// not included, called directly
break;
case "/path/to/scripta.php":
// do abc
break;
case "/path/to/scriptb.php":
// do xyz
break;
default:
// do other stuff
break;
}
You can retrieve the files in the order in which they have been included via get_included_files() (returns an array of the filenames).
The main file that was executed is always the 0th element.
If you're looking for the file that included the current file, the last but one element is your candidate.
I suggest using get_included_files (or get_required_files):
if(in_array($my_file, get_included_files())
{
// do something
}
Replace $my_file with the file you need to check.
One possibility is defining constants.
Calling script:
define("SCRIPT_NAME", "script_a.php");
And in the called script:
if(defined("SCRIPT_NAME") && SCRIPT_NAME == "script_a.php") {
// Do stuff
}
You can use debug_backtrace()
Example:
If you use debug_backtrace() on an included file :
array(1) {
[0]=> array(3) {
["file"]=> string(71) "/home/index.php"
["line"]=> int(3)
["function"]=> string(7) "require"
}
}
a require is nothing else then a code snipped loaded into the exact place the require or require_once call is called.
if you really want to know what exact file is calling it, you could do it relative dirty and assign a variable before the call and check inside your script what kind of value it has
e.g.
$require_reference = "main.php";
require_once ("some_script.php");
now inside the some_script.php you do something like this:
if (isset($require_reference) && $require_reference == "main.php")
{
// dome something
}
this will work but it is really messy. Maybe you should try to refactor your design
Related
I have some kind of problem, but i don't get it.. I have an function for including/requiring files, which check is file already included and does exists:
function __include($fileclass, $is_required=false) {
static $already_included = array();
// checking is set extension of php file, if not append it.
if (substr($fileclass,-4)!=".php") $fileclass = $fileclass.".php";
// if already included return;
if (isset($already_included[$fileclass])) return true;
// check if file exists:
if (file_exists($fileclass)) {
if (!$is_required) include $fileclass;
else require $fileclass;
$already_included[$fileclass] = 1;
return true;
}
else {
if ($is_required) die("can't find required file");
return false;
}
}
And it works good, but when i started to work on the project, i've used it to include a file, which uses variable from parent file (the one that included it), but it drops notice Notice: Undefined variable: VARIABLE_NAME.
So to be clear at coding:
I have two files file_parent.php and file_child.php, what I've tried:
file_parent.php:
function __include($fileclass, $is_required=false) { /** i've mentioned it above **/ }
class __CONNECTION {
private $test;
public function __construct() {
$this->test = "SOMETHING";
}
};
$Connect = new __CONNECTION();
// here i used it to include the children file:
__include('file_child.php');
file_child.php:
print_r($Connect);
And i get Notice: Undefined variable: Connect.
When i change at file_parent.php my function include:
__include('file_child.php');
to standard include:
include 'file_child.php';
Everything will work fine, variable is defined and will be printed.
I guess there's some problem with function, but could someone explain what's the real reason for happening this, and is there a possible repair to fix it to including/requiring works through function and to not lose variables from previous files.
Thanks!
Well, how do i see, when i printed all defined variables (get_defined_vars()), i got this:
Array
(
[fileclass] => test_file2.php
[is_required] =>
[already_included] => Array
(
)
)
So that means the variables are passed, but only one that exists within function (because the function is temporary), so i could make it work to pass variables to function, but as it's not the only variable I need so I am gonna use one of two way:
global as #Tom Doodler said in comment, and later catch it with $GLOBALS
or use function to do checks and return just a path if exists/or empty string if file doesn't exists and then just include/require it.
Thanks everyone.
I will not accept this answer, so if someone could better explain the way function behaves in this solution, i will accept that.
I have a PHP file as seen below that is a config file.
When I use return in my code and var_dump(include 'config.php');
I see an array, but when I delete return the result is
int 1
Does include work like a function in this case? And why I have to use return here?
<?php
return array(
'database'=>array(
'host'=>'localhost',
'prefix'=>'cshop_',
'database'=>'finalcshop',
'username'=>'root',
'password'=>'',
),
'site'=>array(
'path'=>'/CshopWorking',
)
);
The return value of includeis either "true"(1) or "false". If you put a return statement in the included file, the return value will be whatever you return. You can then do
$config = include config.php';
and $configwill then contain the values of the array you returned in config.php.
An include fetches PHP-code from another page and pastes it into the current page. It does not run the code, until your current page is run.
Use it like this:
config.php
$config = array(
'database'=>array(
'host'=>'localhost',
'prefix'=>'cshop_',
'database'=>'finalcshop',
'username'=>'root',
'password'=>'',
),
'site'=>array(
'path'=>'/CshopWorking',
)
);
And in your file, say index.php
include( 'config.php' );
$db = new mysqli(
$config['database']['host'],
$config['database']['username'],
$config['database']['password'],
$config['database']['database'] );
This way, you do not need to write all that stuff into every file and it is easy to change!
Here are some statements with similarities:
include - insert the file contents at that point and run it as if it were a part of the code. If the file does not exist, it will throw a warning.
require - same as include, but if the file is not found an error is thrown and the script stops
include_once - same as include, but if the file has been included before, it will not do so again. This prevents a function declared in the included file to be declared again, throwing an error.
require_once - same as include_once, but throws an eeror if the file was not found.
First off, include is not a function; it is a language construct. What that means is something you should Google for yourself.
Back to your question: what include 'foo.php does is literally insert the content of 'foo.php' into your script at that exact point.
An example to demonstrate: say you have two files, foo.php and bar.php. They look as follows:
foo.php:
<?php
echo "<br>my foo code";
include 'bar.php';
$temp = MyFunction();
bar.php:
<?php
echo "<br>my bar code";
function MyFunction()
{
echo "<br>yes I did this!";
}
This would work, because after evaluating the include statement, your foo.php looks like this (for your PHP server):
<?php
echo "<br>my foo code";
echo "<br>my bar code";
function MyFunction()
{
echo "<br>yes I did this!";
}
$temp = MyFunction();
So your output would be:
my foo code
my bar code
yes I did this!
EDIT: to clarify further, if you create variables, functions, GLOBAL defines, etc. in a file, these will ALL be available in any file in which you include that file, as if you wrote them there (because as I just explained, that is basically what PHP does).
I'm building a dynamic website, but the pages are not showing up because of the error
Fatal error: Function name must be a string php
on the line
$p= $_GET('p');
The whole code for including the files is
$folder = 'de/';
$folder = 'en/';
if(!empty($_GET['p'])){
$pages = scandir($folder,0);
unset($pages[0],$pages[1]);
$p= $_GET('p');
if(in_array($p.'.inc.php', $pages)){
include($folder.'/'.$p.'.inc.php');
}else{
echo 'error message';
}
}else{
include($folder.'home.inc.php');
}
What's wrong with my code?
UPDATE
I've updated the code, but now i get the error
*failed to open stream: No such file or directory*
I'm working on a local server.
$p= $_GET('p');
should be
$p= $_GET['p'];
Your code is quite inefficient. Why slurp up the directory's contents into an array and then search the array when you could simply have:
if (isset($_GET['p']) {
$file = $folder . $_GET['p'] .'.inc.php';
if (is_readable($file)) {
include($file);
} else {
die('error');
}
} else {
include($folder.'home.inc.php');
}
This is BY FAR simpler than your convoluted logic. It is however, also vulnerable to the exact same vulnerability: you're allow the user to specify a full path to ANY *.inc.php file on your server for which they know the path name. Depending on your setup, this could allow the user to include files which you ever intended to be executed in this manner and leak internal details of your system/configuration.
$p= $_GET('p');
You really didn't notice that you were using parenthesis?
Use:
$p = $_GET['p'];
$p= $_GET('p'); it should be $p= $_GET['p'];
The error seems $_GET('p') should be $_GET['p'] instead.
A few considerations:
The if(!empty($_GET['p'])), could be changed to if (array_key_exists('p', $_GET) && !empty($_GET['p']) instead. PHP always complain about array indexes and it's a good way to prevent it.
on unset($pages[0],$pages[1]);, if the array doesn't return 2 elements, it will return null and PHP unset function will complain. A better way could you check if there are elements on $pages variable;
In case of scandir doesn't return any element, not sure if it'll return null or array, so in this case if(in_array($p.'.inc.php', $pages)) will throw a error.
Cheers
if (isset($_GET['ssl'])) {
switch ($_GET['ssl']) {
case 1:
{
header("Location: https://site.com");
exit;
}
default:
{
header("Location: http://site.com");
exit;
}
}
}
Should I be using exit; because I'm using header? Or should I use break like the switch requires?
As I still feel bad about that whole exchange yesterday, I figured I'd offer an answer and explain some things to do with break and exit().
As amosrivera points out, using a break is not required within a switch statement; it is also valid within other loop structures.
From the manual:
break ends execution of the current
for, foreach, while, do-while or
switch structure.
What this means is that for each one of these loop types, it will stop execution of the current loop, but not the execution of the calling script itself. Note also:
break accepts an optional numeric
argument which tells it how many
nested enclosing structures are to be
broken out of.
The purpose is to stop executing the loop; in a switch, it prevents fall-through. For example:
function mySwitch($var) {
$return = '';
switch ($var) {
case 1:
$return .= 'a';
case 2:
$return .= 'b';
break;
case 3:
$return .= 'c';
}
return $return;
}
echo mySwitch(1); // outputs 'ab'
echo mySwitch(2); // outputs 'b'
echo mySwitch(3); // outputs 'c'
See live example: http://codepad.org/8EMvYt7V
switch will match the first case then run each case following until it reaches a break or return.
Concerning return, if called in a function within a loop, it will end the function execution and, possibly confusingly, return() will also end the current script execution if called in the global scope, but in a different way from exit() (for instance, for include'd or require'd files, it will not affect the main script).
How exit() (or die()) differ from break and return is that is ends execution of the entire script, not just the current loop (break), function (return), or script (return()).
Now, I happen to agree with coreyward that it's probable you don't need a switch for this; I use a different method under a potentially different scenario:
if (strtolower($_SERVER['HTTPS']) != 'on') {
exit(header("location: https://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}"));
}
Which could be rewritten to be:
if (strtolower($_SERVER['HTTPS']) != 'on' && $_GET['ssl']) {
exit(header("location: https://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}"));
}
Or you could create a lookup list of actions/pages that require ssl and call that in the redirect:
function requireSSL($page) {
$req = array('login.php','myaccount.php','updateaccount.php');
return in_array($page, $req);
}
function doSSLRedirect($page) {
if (strtolower($_SERVER['HTTPS']) != 'on' && requireSSL($page)) {
exit(header("location: https://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}"));
}
}
Then you can call this when you need to enforce a redirect (and you don't need $_GET['ssl'] in the URL):
doSSLRedirect($_SERVER['SCRIPT_NAME']);
This would be more handy if you're using some kind of MVC pattern and were checking for actions in the URL; otherwise, you could just use an include checkssl.php at the head of your script.
Since I don't know how you're actually implementing your SSL check, these are just suggestions. Looking at the code you have above, if that were simply plugged in at the top of a page, you might end up with an infinite loop if you inadvertently add the ssl variable back to the redirected URL.
As far as calling exit() (or die()), you don't have to pair the two, but they typically do occur at the same time or near each other, since any output that follows should not be seen by the user's browser.
For instance, if you separated them, you might create a check for the redirect in case you have other things you want to happen before exit (maybe some logging or something).
For example:
$sslredirected = false;
if (isset($_GET['ssl'])) {
switch ($_GET['ssl']) {
case 1:
header("Location: https://site.com");
$sslredirected = true;
default:
header("Location: http://site.com");
$sslredirected = false;
}
}
if ($sslredirected === true) {
$otherstuff = youNeedToDoBeforeRedirection();
exit;
}
However, in this case you could probably just as easily put that in an include'd file and just call that in your switch and let it do the exit() call. There's a number of different ways this could go.
One other note about using header(), you need to call it before anything is outputted (including whitespace). See http://codepad.org/nJ4aght4 for an example of what I mean. Note in this case, the header is not sent, so the redirect will not occur.
Hopefully this helps. :)
I think you mean switch requires break, and the point is, it doesn't requires it, break should be used when needed to after a condition, in this case you are already doing that with exit the way you have it is fine.
the whole code block is pointless in my opinion, you can achieve the exact same results like so:
$protocol = empty($_GET['ssl']) ? 'http' : 'https';
header("Location: " . $protocol . "://site.com");
exit;
the function empty will be true if the value the index is not defined as well as being empty or 0.
Use exit at the end if u need :
if (isset($_GET['ssl'])) {
switch ($_GET['ssl']) {
case 1:
{
header("Location: https://site.com");
break;
}
default:
{
header("Location: http://site.com");
}
}
}
exit;
switch isn't really appropriate here — it's making things more complicated, not less.
if (isset($_GET['ssl']) {
header('Location: ' . ($_GET['ssl'] ? 'https' : 'http') . '://example.com/');
exit();
}
When you want to omit the remaining of a loop you write a break statement.
Is there something that you can write to omit the remaining of an included file (but not terminate the rest of the app like when using die or exit)?
You can use a return statement to exit an included file, and optionally return a value.
Example:
<?php
// file1.php:
$value = include('file2.php');
echo $value;
Which includes:
<?php
// file2.php:
if($_REQUEST['something'] == 'something else')
return 'Something else';
//do some stuff if _REQUEST['something'] != 'something else'
return 'something';
Obviously a useless example, but, it demonstrates the use of return to eit an include()ed file.
you could split your include into two separate files, then require the two as necessary instead of just one, or possibly just require the one and have that one require the second as necessary.