Hypothetical scenario, I have these files:
file1.php:
#!/bin/php
<?php
echo "starting\n";
$pid = pcntl_fork();
define('ME', 'Parent');
if($pid == 0) {
include 'file2.php';
exit;
}
echo "I am: ".ME;
file2.php:
#!/bin/php
<?php
define('ME', 'File2');
echo "Defined: ".ME;
When I run file1.php, I get an error, because ME is already defined and you can't re-define a constant. How can I tell php to reset ALL defined constants and variables, so that it can include a new file without carrying anything over? As far as I can see, my only options is to use shell_exec or similar to run a shell command to start a new php process, but that seems really roundabout - is there any way to clear out existing defined constants?
My specific use case is a large framework with many files included at various stages, much of which I can't touch, so you can assume that the only thing I'm able to modify in the above example is the contents of the if($pid == 0) { ... } brackets.
Related
I want a PHP CLI* script to run, do a task, sleep for two seconds, and then run again. Currently, this looks like this:
#!/usr/bin/env php
<?php
require __DIR__ . '/config/app.php';
$w = new Worker;
if ($w->running) {
exit;
} elseif ($job = $w->next()) {
$w->run($job);
sleep(2);
exec(__FILE__);
exit;
} else {
exit;
}
However, it occurs to me that the new run starts before the old run completes. I am mostly a web developer, so am unfamiliar with this level (I’m at home at a somewhat higher level of abstraction), but I think this becomes what’s known as a fork bomb. How can I do this safely?
I’ve read the PHP manual for pnctl_exec(), but I’m not confident that I’m understanding it correctly.
* It’s done as PHP so most of the actual functionality can be in a library which can also be called from a web interface.
You could simply put a loop around your worker and execute it, while it has some jobs to do.
#!/usr/bin/env php
<?php
require __DIR__ . '/config/app.php';
$w = new Worker;
if ($w->running) {
exit;
}
while ($job = $w->next()) {
$w->run($job);
sleep(2); // Not sure, if you really need this?
}
I have been looking for a way to run one piece of code only once in php. I want to create and set a variable at the beginning of the webpage and whenever I call that file, the code will ignore that line.
I found this in which there are basically two suggestions: setting a session variable and creating a lock file which I don't want to since there might be many users at the same time and I need to have a lock file for each one of them.
I tried the first option but it doesn't work.
Here are my two files:
config.php
<?php
if (at the beginning){
$variable = something
echo 'hello';
}
else
do something
?>
second.php
<?php
require_once 'config.php'
//do some other stuff
?>
Whenever second.php is called, it prints 'hello' in the webpage, so if (at the beginning) returns true even though it is not at the beginning. Note that, I check whether at the beginning by if(!isset($_SESSION['done'])){ $_SESSION['done'] = 'done'; }
I wonder what is my mistake and how can I solve the problem. Any help is appreciated.
The program flow for config.php should be:
<?php
session_start();
if (!isset($_SESSION['done'])) {
$_SESSION['done'] = 1;
echo 'hello';
}
else {
// do something
}
?>
I'm trying to set up a cron job to update all of our clients. They each have their own db and directory in our web root. An individual call uses this script:
<?php
include_once 'BASEPATH'.$_REQUEST['client'].'PATHTOPHPLIB';
//Call some functions here
//backup db
$filename='db_backup_'.date('G_a_m_d_y').'.sql';
$result=exec('mysqldump '.Config::read('db.basename').' --password='.Config::read('db.password').' --user='.Config::read('db.user').' --single-transaction >BACKUPDIRECTORYHERE'.$filename,$output);
if($output=='') {
/* no output is good */
}else {
logit('Could not backup db');
logit($output);
}
?>
I need to call this same script multiple times, each with a unique include based on a client variable being passed in. We originally had a unique cron job for each client, but this is no longer a possibility. What is the best way to call this script? I'm looking at creating a new php script that will have an array of our clients and loop through it running this script, but I can't just include it because the libraries will have overlapping functions. I'm not considering cUrl because these scripts are not in the web root.
First off, a quick advert for the Symfony console component. There are others, but I've been using Symfony for a while and gravitate towards that. Hopefully you are PSR-0 /Composer -able in your project. Even if you aren't this could give you and excuse to do something self contained.
You absolutely don't want these sorts of scripts under the webroot. There is no value in having them run through apache, and there are limitations imposed on them in terms of memory and runtime that are different in a command line php context.
Base script:
<?php
if (PHP_SAPI != "cli") {
echo "Error: This should only be run from the command line environment!";
exit;
}
// Script name is always passed, so $argc with 1 arg == 2
if ($argc !== 2) {
echo "Usage: $argv[0] {client}\n";
exit;
}
// Setup your constants?
DEFINE('BASEPATH', '....');
DEFINE('PATHTOPHPLIB', '...');
require_once 'BASEPATH' . $argv[1] . 'PATHTOPHPLIB';
//Call some functions here
//backup db
$filename='db_backup_'.date('G_a_m_d_y').'.sql';
$result=exec('mysqldump '.Config::read('db.basename').' -- password='.Config::read('db.password').' --user='.Config::read('db.user').' --single-transaction >BACKUPDIRECTORYHERE'.$filename,$output);
if($output=='') {
/* no output is good */
} else {
logit('Could not backup db');
logit($output);
}
Calling Script Runs in cron:
<?php
// Bootstrap your master DB
// Query the list of clients
DEFINE('BASE_SCRIPT', 'fullpath_to_base_script_here');
foreach ($clients as $client) {
exec('/path/to/php ' . BASE_SCRIPT . " $client");
}
If you want to keep things decoupled inside the caller script you could pass the path to the backup processing script rather than hardwiring it, and if so, use the same techniques to get the param from $argc and $argv.
I am using PHP Include:
<?php include 'file1.php'; ?>
i want to only include the first few lines of file1.php - is this possible?
If you really want to include (run as PHP), then just pull those lines out into a new file:
new.php:
<?php
// line 1
// line 2
And include it in both files:
existing.php and other.php:
<?php
include('new.php');
...
<?php
$return_from_inc = include('file1.php');
?>
file1.php
<?php
if ($x === 1) { return 'A'; }
else { return 'B'; }
//... return ("break") running script wherever you want to
?>
Depending on the content of those first lines, why don't you use PHP Functions?
file1.php
<?php
function what_i_want_to_include(){
//"First lines" content
}
}
existing.php
<?php
include('file1.php');
what_i_want_to_include();
?>
Using functions it's the simplest way to do it.
You can simply use return on the line of your choice and control will be sent back to the calling file.
If called from within a function, the return statement immediately ends execution of the current function, and returns its argument as the value of the function call. return will also end the execution of an eval() statement or script file.
If called from the global scope, then execution of the current script file is ended. If the current script file was included or required, then control is passed back to the calling file. Furthermore, if the current script file was included, then the value given to return will be returned as the value of the include call. If return is called from within the main script file, then script execution ends. If the current script file was named by the auto_prepend_file or auto_append_file configuration options in php.ini, then that script file's execution is ended.
Source: PHP Manual
There are a few options to achieve this, but let me stress out that if this is necessary for your application to work you should really consider reviewing the app design.
If you want it programatically you can either grab the first x lines and use eval() to parse them. Example:
$file_location = '/path/to/file.php';
$number_of_lines = 5; //
$file_array = file($file_location);
if(!$file) {
return false; // file could not be read for some reason
}
$first_lines = array_slice($file_array, 0, $number_of_lines);
$to_be_evaluated = implode('', $first_lines);
eval($to_be_evaluated);
But you should take not that eval expects a string without the php opening tag (<?php), at least, not at the start. So you should search for it and delete it in the first line (if present):
if(strpos($first_lines[0], '<?php') !== false) {
$first_lines[0] = substr(strpos($first_lines[0], '<?php') + 5);
}
Another, and better option, and as suggested above, just pull out the required lines, save them to another file, and include them in both. You could also do this programatically, you could even extract the needed lines and save them to a temporary file on the fly.
Edit it is a 'weird' question, in the sense that it should not be necessary. Could you explain what exactly you are trying to do? Most probably we can come up with a nice alternative.
Edit
As I understand it correctly you have in the file-to-be-included a lot of stuff, but only the database settings are needed. In that case, put them elsewhere! Example:
settings.php
$connection = new mysqli($host, $user, $pass, $db);
if($connection->connect_error) {
die('This failed...');
}
header.php
<?php require_once('settings.php'); ?>
<html>
<head>
<title>My awesome website</title>
... other stuff
</head>
other_file.php
<?php
require_once('settings.php');
$r = $connection->query('SELECT * FROM `my_table` WHERE `random_field`=`random_value`');
etc. etc.
In settings.php you could also put everything in functions to ensure pieces are only executed when needed. You could in example create a get_connection() function, which checks if a database connection exists, otherwise creates it and returns it for usage.
No need for fancy eval() functions at all!
Please bear in mind that it isn't a crime to divide your application in a thousand files. It really isn't!
Does anyone here know when PHP executes include and include_once calls?
I'm wondering because I come from a Flash and Desktop development background where you have to import your classes at the beginning of each class.
But now that I am starting to build more complex PHP code, it seems like it would be better to just include classes when I actually need them to save on loading time. For example, look at the following psuedo code:
if (I_need_to_check_login)
{
include_once "Class.class.php";
$C = new Class();
}
If I do this, is the file Class.class.php going to be included everytime the code is run or only when I execute the include_once.
I'm a bit of a Class freak and usually build a class for just about any functionality used by my apps, so I often have lots of class files.
include, include_once are standard PHP instructions. This means the interpreter executes each include, include_once when he finds one in the flow of the program. If a control structure avoids to execute a piece of code which has an include instruction, this one won't be executed.
In your example, the include_once, will be executed if, and only if, I_need_to_check_login is true.
Includes are only performed if interpreter ever gets there. eg:
$variable = false;
if ($variable) {
include 'a.php';
} else {
include 'b.php';
}
In this case only b.php would be included.
For more on its behavior: PHP Manual - include
Yes, every time you have to call: $C = new Class(); you will have to require or include the file. Now what you can do instead of include_once is:
if (!class_exists('MyClass')) {
include("Class.class.php");
}
which mean you might not have you include it again, if you already included it before. This will also improve performance since include is faster to execute than include_once.
Files are actually included only if you perform include_once command.
So if that I_need_to_check_login evaluates to false - file will not be included at all
It can be easily checked by yourself with adding echo "I've been included"; exit; to the first line of that file.