includer vs. return include - php

when you need to include a file, simply use "include file" and when you need to return a configuration file you must use "return include file"...
usually i have a function "loader( $file , $return = false )" where I use $return to return include, or not.
my question is if there is a problem in keeping return include file even for files that are not configuration:
return include "class/view.php"
return include "config/test.php"
thank you

From php.net:
Handling Returns: include returns FALSE on failure and raises a
warning. Successful includes, unless overridden by the included file,
return 1. It is possible to execute a return statement inside an
included file in order to terminate processing in that file and return
to the script which called it. Also, it's possible to return values
from included files. You can take the value of the include call as you
would for a normal function. This is not, however, possible when
including remote files unless the output of the remote file has valid
PHP start and end tags (as with any local file). You can declare the
needed variables within those tags and they will be introduced at
whichever point the file was included.
If your class/view.php or config/test.php uses return, then you may keep it. If there is no return in those files, there is no reason, unless you want to prevent current script from further execution.
Example 1:
<?php
echo 1; // < executes
return include 'somefile.php'; // < script will end here because of "return"
echo 2; // < not executes ever
?>
Example 2:
<?php
echo 1; // < executes
include 'somefile.php'; // < executes
echo 2; // < executes
?>

If included file doesn't have return, it will just return 1, so there will be no problem.

Related

How to 'undeclare' a custom function in a loop

I am collecting a series of php files and testing to see if a single function returns valid output. To facilitate the process, all their functions are named identically. So then I can run:
foreach($fileList as $file) {
require($file);
echo $testFunction();
}
The problem is that php throws an error 'Cannot redeclare function' since the second file's function is named the same as the first. What I want to do is 'undeclare' a function after I test its output but I know this isn't possible and I'm trying to handle this procedurally. unlink($file) does not remove the instance of the function, unfortunately. Is there a simple way to handle this without using an OOP approach?
UPDATE #1
Using exec() instead of shell_exec() allows me to check err status (which is #2). CHMOD was necessary as user/group prevented execution (security settings on this offline server to be updated once the script is functioning). At this point, it does not echo anything since shell_exec() is returning an error (at least I think so since the output from shell_exec is empty and since exec is returning error #2). Here is an updated test:
$fileList = array('test.php');
foreach($fileList as $file) {
// load code from the current file into a $code variable,
// and append a call to the function held in the $testFunction variable
$code = file_get_contents($file) . "\n" . 'testFunction();';
// save this to a temporary file
file_put_contents('test-file.php', $code);
// execute the test file in a separate php process,
// storing the output in the $output variable for examination
//*************** */
$output=null;
$retval=null;
$absPath = realpath('test-file.php');
chmod($absPath,0777);
echo $absPath;
exec($absPath, $output, $retval);
echo "Returned with status $retval and output:\n";
print_r($output);
}
UPDATE #2
While you can't undeclare a function, you can repeatedly assign different functions to the same var. For example:
$listOfFunctionNames = array('function1', 'function2', 'function3);
foreach($listOfFunctionNames as $func) {
$funxion = $func;
$funxion();
}
You can execute the files in another process, for example (assuming $testFunction is defined in the files), you could do something like this (assuming you are running on Linux):
foreach($fileList as $file) {
// load code from the current file into a $code variable,
// and append a call to the function held in the $testFunction variable
$code = file_get_contents($file) . "\n" . '$testFunction();';
// save this to a temporary file
file_put_contents('/tmp/test-file.php', $code);
// execute the test file in a separate php process,
// storing the output in the $output variable for examination
$output = shell_exec('php /tmp/test-file.php');
// examine output as you wish
}
unlink('/tmp/test-file.php');
EDIT:
Since testFunction does not echo, and instead returns the output to be examined, we can simply modify the test file to echo testFunction();.
$code = file_get_contents($file) . "\n" . 'echo testFunction();'; // <- NOTE: the semi-colon after testFunction();
I noticed my original answer was lacking a semi-colon in the test file, which is probably where the error was coming from. What you can do to ensure it's correct is have this script generate the first test file and terminate early. You can then manually inspect the file for correctness and also use PHP to ensure it's parse-able, from the command line:
php -l /tmp/test-file.php
Note also there are more sophisticated ways you could check correctness of each test file, however I am trying to keep the answer concise, as that is starting to stray into a separate question.

PHP: Can You Pass Include Through a Function?

Is it at all possible to include a file through a function? I don't mean returning the contents as a string. I'd like to create my own custom include method, but right now it doesn't seem possible.
For instance, PHP's include method outputs file contents. I'd like to output file contents, but run them through another function first.
For example:
function include_filter($file){
include($file);
}
include_filter($file);
This example does not use additional functionality, because my primary question here is how to include through a function at all. You can see the issue.
If I include through a function such as include_filter, the code will be included locally inside the function only, not at the line the function was called (line 4 in the example).
The include statement does not output the file contents. However, it does evaluate the file you're including, so if that file contains any echo statements then yes, those are executed the moment you include that file.
You can use an output buffer to catch that output and do something with it before re-echo'ing it:
included_file.php:
<?php
echo "This came from an included file.";
main_file.php:
<?php
function include_filter($path) {
ob_start();
include $path;
$output = ob_get_contents();
ob_end_clean();
echo str_replace("an included file", "a filter function", $output);
}
include_filter("included_file.php");
// will output "This came from a filter function."
Demo: https://3v4l.org/2XkL7

PHP require_once persists in a separate process

EDIT: I need to provide more detail, not sure what is going on.
I seem to be having a problem where PHP treats a require_once in a separate process as a repeat of the require in the outer process.
Suppose I have this file which I will run on the CLI:
<?php
require_once 'includeme.php';
$command = "php runme.php";
$handle = popen($command, 'r');
$read = fread($handle, 2096);
$exit = pclose($handle);
print_r($read);
This does the following:
include a file
run a child process, which will also try to include that file.
The file includeme.php is this:
<?php
print "I was included";
Including it should just cause it to return that string.
The runme.php file is this:
<?php
$result = require_once 'includeme.php';
print $result;
Running the main script produces this output:
I was included
1
What seems to be happening is that the runme.php script is getting a 1 for the require_once statement, which is what require_once returns if the script has already been included.
But runme.php is a separate process. How can PHP be thinking it's already included includeme.php?
From the docs:
Successful includes, unless overridden by the included file, return 1
The 1 in your output does not indicate it was already previously included, just that it was included successfully.
Regardless of the return value, you can use require_once everywhere and trust it's working as expected.
Do note that require_once (like, require, include...) is a construct, not PHP function. So, returned 1 probably means, OK, file is included. No idea why echoed I was included was not caught.

how to make sure a PHP script is loaded one time

I have a cronjob system with PHP. I have a file named cron.php and wanna to check if it is not loaded, load it. it is very important to me that this file run only one time and I need the way how define it is already running. I can't use any system functions like exec,system,... do you have any solutions?
NOTE: I run my script trough CURL and include_one and require_once don't work for this case.
You could use flock() to lock the php file itself, like this:
<?php
class Lock{
private $fp;
function __construct(){
$this->fp=fopen(__FILE__,'r');
if (!flock($this->fp,LOCK_EX|LOCK_NB)) {
die('already running !'.PHP_EOL);
}
}
function __destruct(){
flock($this->fp,LOCK_UN);
fclose($this->fp);
}
}
$lock=new Lock();
// simulate some processing
sleep(60);
echo "END";
?>
Can you just use require_once or include_once?
require_once will throw a PHP fatal error (will stop execution) if the file cannot be evaluated.
include_once will throw a PHP warning (execution may continue).
// Require tasks.php to run once
require_once 'path/to/tasks.php';
// Attempt to run tasks.php and only once
include_once 'path/to/tasks.php';
Your problem is essentially equivalent to "Check if a php script is still running"
Please refer this
Check if a php script is still running
if I understand you correctly, you want to prevent your cron.php script from getting started a second time by cron, it is not called from another PHP script? (in that case, require_once would be the right answer)
as I understand it, you need to store a marker that indicates that your script is running and remove that marker at the end of your script.
depending on your environment, you could either create a small file, i.e. .lock or store a status = locked entry in your database.
edit: here is a small code example using the file method:
<?php
// cron.php
$path = '/path/to/your/data/directory/';
if (file_exists($path . '.lock') {
die('cron.php is already running');
}
// if script reaches this point, it is not locked -> create a lock
file_put_contents($path . '.lock', 'lockfile created at ' . now());
//... your code....
//unlocking
unlink($path . '.lock');
?>
If you are using cURL then I believe your are using cURL to request a page such as http://domain.com/cron.php. The machine requesting the script via cURL/wget/browser/etc has no way of knowing if the script is already being executed on the server. However, you can configure your cron.php script to run only once:
<?php
// attempt to obtain a lock
$fp = fopen(basename(__FILE__) . ".lock", "w");
if (flock($fp, LOCK_EX | LOCK_NB) === false) {
echo basename(__FILE__) . ": already running\n";
exit(-1);
}
// code goes here
echo date("Y-m-d H:i:s") . ": cron job started\n";
sleep(30);
echo date("Y-m-d H:i:s") . ": cron job ended\n";
// release the lock
flock($fp, LOCK_UN);
fclose($fp);
The sample code uses PHP flock function. The LOCK_EX flag tells PHP that it needs to obtain an exclusive lock; i.e. no other process is allowed to access the file. The LOCK_NB tells PHP that it should not block (wait for the lock to be released) and return false immediately. Together, the two switches assure that a second process cannot lock the file while the first one has it locked.
you can use require_once or include_once
The general syntax of both the include and require statements are as follows:
include "file_to_load.php";
include_once "file_to_load.php";
When the include_once/require_once statements are used, the file cannot be loaded or executed multiple times. If an attempt is made to load a file twice using one of these two methods, it will be ignored. Because it is unacceptable to define the same function multiple times within a script, these functions allow the developer to include a script as needed without having to check whether it has been previously loaded.
NOTE The capability to return values from external files is limited only to the include_once statements. The require_once statements cannot be used in this fashion.
include_once('class.php');
php.net states
The include_once statement includes and evaluates the specified file
during the execution of the script. This is a behavior similar to the
include statement, with the only difference being that if the code
from a file has already been included, it will not be included again.
As the name suggests, it will be included just once.
You can use either require_once or include_once.
if you are confuse what to use then difference between this two is that
require_once will stop executing preceding code, trwos fatal error, if file mentioned is not found
so if you want preceding code to continue even file is not found then don't use it.
where as the include_once will continue executing preceding code.
You can use Database for this case, make an entry of the page in database and second column for checking whether is it loaded or not (eg. '0' if not loaded yet and '1' it is loaded). Initially keep value of that row as '0' when the page is loaded update that column as '1'.

Is there any tool that will resolve and hardcode every included file of a PHP script?

I would need a tool, if it exists or if you can write in under 5 mins (don't want to waste anyone's time).
The tool in question would resolve the includes, requires, include_once and require_once in a PHP script and actually harcode the contents of then, recursively.
This would be needed to ship PHP scripts in one big file that actually use code and resources from multiple included files.
I know that PHP is not the best tool for CLI scripts, but as I'm the most pro-efficient at it, I use it to write some personal or semi-personal tools. I don't want un-helpful answers or comments that tell me to use something else than PHP or learn something else.
The idea of that approach is to be able to have a single file that would represent everything needed to put it in my personal ~/.bin/ directory and let it live there as a completely functional and self-contained script. I know I could set include paths in the script to something that would honor the XDG data directories standards or anything else, but I wanted to try that approach.
Anyway, I ask there because I don't want to re-invent the wheel and all my searches gave nothing, but if I don't have any insight here, I will continue in the way I was going to and actually write a tool that will resolve the includes and requires.
Thanks for any help!
P.S.: I forgot to include examples and don't want to rephrase the message:
Those two files
mainfile.php
<?php
include('resource.php');
include_once('resource.php');
echo returnBeef();
?>
resource.php
<?php
function returnBeef() {
return "The beef!";
}
?>
Would be "compiled" as (comments added for clarity)
<?php
/* begin of include('resource.php'); */?><?php
function returnBeef() {
return "The beef!";
}
?><?php /* end of include('resource.php); */
/*
NOT INCLUDED BECAUSE resource.php WAS PREVIOUSLY INCLUDED
include_once('resource.php');
*/
echo returnBeef();
?>
The script does not have to output explicit comments, but it could be nice if it did.
Thanks again for any help!
EDIT 1
I made a simple modification to the script. As I have begun writing the tool myself, I have seen a mistake I made in the original script. The included file would have, to do the least amount of work, to be enclosed out of start and end tags (<?php ?>)
The resulting script example has been modified in consequence, but it has not been tested.
EDIT 2
The script does not actually need to do heavy-duty parsing of the PHP script as in run-time accurate parsing. Simple includes only have to be treated (like include('file.php');).
I started working on my script and am reading the file to unintelligently parse them to include only when in <?php ?> tags, not in comments nor in strings. A small goal is to also be able to detect dirname(__FILE__)."" in an include directive and actually honor it.
An interesting problem, but one that's not really solvable without detailed runtime knowledge. Conditional includes would be nearly impossible to determine, but if you make enough simple assumptions, perhaps something like this will suffice:
<?php
# import.php
#
# Usage:
# php import.php basefile.php
if (!isset($argv[1])) die("Invalid usage.\n");
$included_files = array();
echo import_file($argv[1])."\n";
function import_file($filename)
{
global $included_files;
# this could fail because the file doesn't exist, or
# if the include path contains a run time variable
# like include($foo);
$file = #file_get_contents($filename);
if ($file === false) die("Error: Unable to open $filename\n");
# trimming whitespace so that the str_replace() at the end of
# this routine works. however, this could cause minor problems if
# the whitespace is considered significant
$file = trim($file);
# look for require/include statements. Note that this looks
# everywhere, including non-PHP portions and comments!
if (!preg_match_all('!((require|include)(_once)?)\\s*\\(?\\s*(\'|")(.+)\\4\\s*\\)?\\s*;!U', $file, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE ))
{
# nothing found, so return file contents as-is
return $file;
}
$new_file = "";
$i = 0;
foreach ($matches as $match)
{
# append the plain PHP code up to the include statement
$new_file .= substr($file, $i, $match[0][1] - $i);
# make sure to honor "include once" files
if ($match[3][0] != "_once" || !isset($included_files[$match[5][0]]))
{
# include this file
$included_files[$match[5][0]] = true;
$new_file .= ' ?>'.import_file($match[5][0]).'<?php ';
}
# update the index pointer to where the next plain chunk starts
$i = $match[0][1] + strlen($match[0][0]);
}
# append the remainder of the source PHP code
$new_file .= substr($file, $i);
return str_replace('?><?php', '', $new_file);
}
?>
There are many caveats to the above code, some of which can be worked around. (I leave that as an exercise for somebody else.) To name a few:
It doesn't honor <?php ?> blocks, so it will match inside HTML
It doesn't know about any PHP rules, so it will match inside PHP comments
It cannot handle variable includes (e.g., include $foo;)
It may introduce scope errors. (e.g., if (true) include('foo.php'); should be if (true) { include('foo.php'); }
It doesn't check for infinitely recursive includes
It doesn't know about include paths
etc...
But even in such a primitive state, it may still be useful.
You could use the built in function get_included_files which returns an array of, you guessed it, all the included files.
Here's an example, you'd drop this code at the END of mainfile.php and then run mainfile.php.
$includes = get_included_files();
$all = "";
foreach($includes as $filename) {
$all .= file_get_contents($filename);
}
file_put_contents('all.php',$all);
A few things to note:
any include which is actually not processed (ie. an include inside a function) will not be dumped into the final file. Only includes which have actually run.
This will also have a around each file but you can have multiple blocks like that with no issues inside a single text file.
This WILL include anything included within another include.
Yes, get_included_files will list the script actually running as well.
If this HAD to be a stand-alone tool instead of a drop in, you could read the inital file in, add this code in as text, then eval the entire thing (possibly dangerous).

Categories