What function or bit of code serves as the main entry point for executing/interpreting a PHP program in the source of PHP itself? Based on things I've googled or read in books, I know that PHP is designed to work with a server of some kind (even the CLI command works by starting up "the command line SAPI", which acts as a mini-server designed to process a single request), and that the server will ask PHP to execute a program.
I know about the minit and rinit lifecycle functions, which serve as entry points for a PHP extension.
What I don't know is where does the PHP source code have this conversation with itself
Hey look, there's a PHP program in this file/string. I ought to run it
I'm not trying to accomplish any specific task here. I'm trying to understand how the internals of PHP does what it does, and find a main entry point where I can start following its execution.
Where is the entry point of the code of some SAPI?
The CLI is a standalone application. As any other application written in C, its entry point is the function main() (file sapi/cli/php_cli.c, line 1200):
int main(int argc, char *argv[])
There are two versions of the CLI for Windows, one of them is a console application and starts with the main() function described above, the other is a Windows GUI application (it doesn't create a console when it starts and uses message boxes for output) that starts with the WinMain() function (file sapi/cli/php_cli.c, line 1198).
main() and WinMain() use the same code here. They have different name and different code fragments here and there by checking if the symbol PHP_CLI_WIN32_NO_CONSOLE is defined. It is defined in file sapi/cli/cli_win32.c that is used to generate the Windows GUI application.
</Windows>
The CGI version is also a standalone console application. Its entry point is also the main() function in file sapi/cgi/cgi_main.c, line 1792.
Similar, the FPM version starts with main() in file sapi/fpm/fpm/fpm_main.c, line 1570.
Apache2 handler is a dynamically loadable module (.dll on Windows, .so on Unix-like systems). It registers some functions as event handlers for the events published by the web server (server start, pre/post configuration loaded, process request etc). These handlers are registered by the php_ap2_register_hook() function in file sapi/apache2handler/sapi_apache2.c, line 738.
(You can find details about how a loadable module integrates with Apache in the Apache documentation.)
The handler that is interesting to us is the function php_handler() that is invoked to handle a HTTP request.
In a similar manner, every SAPI has an entry point (either main() or a function that is invoked by the web server).
All these entry points do similar processing:
initialize themselves;
parse the command line arguments (only if it's CLI, CGI or other kind of standalone application);
read php.ini and/or other configuration they have (the Apache module configuration can be overridden in .htaccess);
create a stream using the input file and pass it to the function php_execute_script() defined in file main/main.c, line 2496;
cleanup and return an exit code to the calling process (the shell or the web server).
Where is the code that actually executes a PHP script?
The function php_execute_script() is a wrapper; it interprets the php.ini configuration entries auto_prepend_file and auto_append_file, prepares the list of files (auto-prepend file, main script, auto-append file) and passes the list to zend_execute_scripts() that processes them.
php_execute_script() is not always invoked, some SAPIs and command line arguments of the CLI produce the direct invocation of zend_execute_scripts().
zend_execute_scripts() is where the interesting things happen.
It compiles the PHP file (and returns a list of OP codes in op_array then, if the compilation succeeds (the returned op_array is not NULL) it executes the OP-codes. There is also exception handling and cleanup; boring work but as important as the parsing and executions nevertheless.
The compilation is a tedious process. It is done by the function zendparse() defined in the file Zend/zend_language_parser.c. The definition of the zendparse() function and the file Zend/zend_language_parser.c are nowhere to be seen in the Git repo; the parser is generated using bison and re2c that read the language syntax rules and the definition of lexical tokens from Zend/zend_language_parser.y and Zend/zend_language_scanner.l and generate the actual compiler in file Zend/zend_language_parser.c.
However, even if the hard work is not visible in the repo, the interesting parts of the compilation process are visible in the files mentioned above.
The execution of the compiled script (the list of OP codes) is done by function zend_execute() that is defined in the file Zend/zend_vm_execute.h. This is also a generated file and the interesting part is that it is generated by a PHP script.
The generator script (Zend/zend_vm_gen.php) uses zend_vm_def.h and zend_vm_execute.skl to generate zend_vm_execute.h and zend_vm_opcodes.h.
zend_vm_def.h contains the actual interpreter code that is executes to handle each OP code.
Where is the code of some function provided by the PHP core or one of its bundled extensions?
The code of the PHP functions and functions provided by extensions is somehow easier to follow. The functions included in the PHP core are located in files in the ext/standard directory, the functions provided by other extensions are located in files in the corresponding ext subdirectories.
In these files, the C functions that implement PHP functions are declared using the PHP_FUNCTION() macro. For example, the implementation of the PHP function strpos()
starts in file ext/standard/string.c, line 1948. The function strchr() being an alias of strstr() is declared using the PHP_FALIAS() macro in file ext/standard/basic_functions.c on line 2833.
And so on, and so forth.
Related
I'm trying to write and run a PHP extension that spins off a pthread (using the POSIX library in C) which detaches and runs forever (it reads messages from a queue, but for the purposes of this question that isn't important, and I'm just trying to get it to spin off a function that just detaches and returns for proof of concept).
To clarify: This is not using the pthreads extension in php, but using the POSIX pthreads library in a custom php extension. I've confirmed that the environment can compile and execute C code that uses the POSIX pthreads library.
The function that spins off the thread is:
static int init_thread()
{
int ret = 0;
pthread_t thread;
ret = pthread_create(&thread, NULL, threadFunc, NULL);
if (ret != 0)
{
fprintf(stderr, "pthread_create failed with error code %d\n", ret);
return -1;
}
return 0;
}
But this seems to stop any of the extension from executing.
Note: I've also tried using a php extension global variable pthread_t instead of instantiating a pthread_t in init_thread but to the same results...
This function is called in RINIT and is only called the very first time a PHP worker process starts, not every request (I've confirmed this separately). For debugging I've tested all this with threadFunc simply detaching and returning with pthread_detach(pthread_self()); and return 0;.
I've confirmed that the extension is set up properly and works without the pthread_create line by printing to log files from MINIT, GINIT, and even in RINIT.
However, whenever the ret = pthread_create(&thread, NULL, threadFunc, NULL); line in init_thread is uncommented, it seems like nothing in the extension runs.
For example, MINIT supposedly runs before any time RINIT runs, and I create and write to a file to confirm that MINIT is running (I use this file as "proof" that the extension is executing code as I expect). However, when the pthread_create line is uncommented, that file that MINIT creates is never even made or written too, even though MINIT should run before that pthread_create is ever reached.
There's no clear error in the nginx or php7.4 log files, and the site works normally even when the extension seems to be broken.
I'm really at my wits end with why this isn't working, as my use of pthread_create is just to spin off a function that detaches and returns. Building with ZTS shouldn't even be required since the thread doesn't interact with PHP at all (Just in case, I've also tried defining ZTS and COMPILE_DL_EXTNAME to run ZEND_TSRMLS_CACHE_DEFINE but to no avail).
I'm running all this with php7.4, and am building the extension as a .so file with phpize, ./configure, and make, then placing the .so file appropriately and adding the extension=EXTENSION_NAME in /etc/php/7.4/fpm/php.ini.
Any and all ideas are greatly appreciated!
If all you're trying to do is spin up a child process that outlives its parent, there are easier ways, eg just call something like this from your main PHP thread:
shell_exec('bash -c "php myotherthread.php" 2>1 >/dev/null &');
Let me start by saying I am totally not a PHP programmer - this was dumped on me to fix.
I have a function that sits in a file by itself, that basically looks like this:
<?php
function UploadFile($source, $destination){
$debugLogPath = '/biglongpath/debug.log';
file_put_contents($debugLogPath,PHP_EOL . "Beginning UploadFile function", FILE_APPEND);
set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');
require_once('Net/SFTP.php');
...Rest of the ftp code here...
}
?>
It's using phpseclib. If I run the main PHP script (that calls this function...) via a web browser, everything works great. When I run that same script via a CRON job, it dies as soon as this function is called. I've verified this by writing out a debug log right before calling the function - the first statement before the function is written to the log, but the "Beginning UploadFile function" is never written.
I'm guessing that maybe it has something to do with the require_once statement - maybe either a path problem or permissions issue when it's executed via CRON?
I've tried wrapping the entire function contents in a try/catch and writing out the Exception, but it still just dies.
I wonder why there are 3 helpful flags, when the question states, that the file is being written? However, this is not the CLI error log and therefore will not automagically log any errors there.The second one suggestion made appears more likely, while there are even more possibilities:
Make sure that these modules are being loaded for the PHP-CLI:
libsodium, openssl, mcrypt, gmp (as the composer.json hints for).
Running php --ini should show which INI files were loaded. Even if the corresponding INI files are there, make sure the instructions inside them are not commented out with a ;.
Manually running the script from CLI, as the user which runs the cronjob suggested, with error reporting enabled. If this shouldn't help, single-step into it with xdebug, to see where exactly it bugs out (NetBeans, Eclipse, VS Code and a few other IDE do support PHP debugging). This requires some effort to set it up, but then it provides a far better debugging methodology.
Is it possible to create Windows exe file from PHP source which include cURLcommands?
I want to create a portable program which works even on machines where PHP or cURL are not installed.
Actually I don't expect that it is possible to create just one executable file which don't need additional libraries. Even full cURL tools can be attached if it is needed.
Maybe I just want some way to join it after.
When I use some php to exe compiler like Phalanger etc, the compilation is successful but when I run the file it throws an error:
Error: Call to undefined function: 'curl_init' in C:\Users\Pavel\Desktop\comm\comments.php on line 6, column 1.
I am a newbie with shell scripting so need a few ideas on parsing a PHP file using a shell script.
Ours is a PHP project and I am improving our shell script which is used to upload code to production server.
There is one PHP config file production.settings.php which needs to be read during upload, for a few constants -
BASE_PATH (path to project root on prod server)
db_host, db_name etc. (database settings of prod database - to be used for taking a backup of the database before upload)
Question
How to read the value of the constants?
They are defined like this:
define("BASE_PATH","/path/to/project/root");
How to read the first uncommented value of the constant?
Note - The constant may be defined more than once in the same file (let's assume the possibilty - this may happen by mistake or there may be commented instances of the line)
So far I am only able to get the number of lines containing the string define("BASE_PATH" using grep in my shell script -
cd ..
PROJECT_ROOT=$PWD
result= grep -ic 'define("BASE_PATH",' $PROJECT_ROOT'/config/main.settings.php'
echo "see"$result
Is this method of parsing good enough or a yml file would be better? Is there any shell command/snippet for doing this so that I can get the result by writing lesser amount of code?
Updates
Check my other questions for more details on this:-
Manipulating an array (printed by php-cli) in shell script,
Assigning values printed by PHP CLI to shell variables,
Initiating dynamic variables (variable variables) in bash shell script
just do it using the php, then call your shell script to invoke the php script.
Assuming you have your bunch of defines defined in defs.php:
define('NAME', 'JOHN');
define('HOBBY', 'FISHING');
then create a php script get_defs.php:
require_once 'defs.php';
$const = get_defined_constants(true);
foreach($const['user'] as $k => $v) {
echo "export $k=$v";
}
then in your shell script, run it like so:
`php get_defs.php`
What happen is, get_defs.php will output bunch of export KEY=VALUE, then shell will run those commands outputted by your php get_defs.php.
Why don't you just code with PHP CLI? That's what you understand? Also maybe you could put constants in a ini file and read them?
If youre comforttable with PHP then use PHP to write the shell script. IF you go this route i would move all config settings to a config file... INI, YAML, XML, whetever floats your boat. Then i would modify the bootstrap of the application that defines your constants to also read from this config file. That way you can use it in botht your script and the app without having to change it.
Can anyone help me with the compilation of C++ code in PHP on the Windows platform? I am using Microsoft Visual C++ 6.0.
I have tried the following options which I knew, but none of them work:
system('test.c')
exec('test.c')
The file 'test.c' has been placed in my php/www/ folder.
I need to first compile the code, which makes test.exe and then using exec( ) I need to run the exe file.
Edit:
In this code "test.c", I am reading from a file "data.txt".
The contents of data.txt is changed every 5 seconds. That's why first I need to compile in PHP and then run the new exe file.
Do a .bat file that:
runs the vcvars32.bat file that comes with Visual Studio
runs "cl.exe yourprogram.c"
Then launch that .bat file from PHP.
(dunno how you would do that btw)
You need to call the compiler (cl.exe) and linker explicitly (See compiler reference) or use makefiles (g++ reference, but shows the point)
http://4answered.com/questions/view/7e1694/Compile-C-file-Using-PHP This helps me to compile and run C program (see video on this link). Use this I wrote this php code and it wokrs
<?php
putenv("PATH=C:\\MinGW\\bin");
exec("gcc C:\\test\\q.c -o C:\\test\\q1.exe");
system("C:\\test\\q1.exe",$output);
echo $output;
my q.c
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("Hello world");
return 0;
}
So you will see "Hello world0" in $output
I am assuming you want to invoke your compiler from a php script?
If that's the case, you'll first have to invoke the compiler itself - not just pass the source code's filename to system. In the case of MSVC++, you will want to look for "cl.exe".
Also, if the corresponding path isn't set in your environment, you will need to use the full path.
Make sure to first understand, how to invoke cl.exe manually, from a command prompt.
Once you understand that, you can try to invoke it from a php script.
However, you need to realize that there are additional factors to consider, such as for example the time required to compile a file vs. the time allowed for a php script to execute before timing out.
I think, you may need to provide us with additional information on what exactly you want to do, and why you want to do it.