PHP is a server-side scripting language.
Refer to the Dockerfiles at https://git.steamr.com/docker/php-fpm if you wish to install PHP-FPM manually.
The PHP interpreter consists of two parts: The PHP Core and the Zend Engine.
The PHP core handles communication with bindings, SAPIs, file and network IO, and handling of the many PHP extensions.
The Zend Engine is responsible for interpreting the PHP code into bytecode. The interpretation process involves splitting the code into tokens using a tokenizer (initiated by PHP's core function
zend_compile_file()) and converting these tokens into bytecode.
zend_compile_string() can also be used to compiles a string and is used for functions such as
The PHP bytecode is executed by the PHP's virtual machine. The VM has a virtual CPU with its own set of instructions. Execution is initiated by passing an array of opcodes to
The register-based bytecode of PHP consists of opcodes, constants, variables, and meta information. PHP has around 200 different opcodes that cover all existing language constructs. (see https://www.php.net/manual/en/internals2.opcodes.php).
Each opcode conforms to the
zend_op data structure and has:
- an opcode number (
znode_uchar) used to find the corresponding opcode handler in a lookup table.
- two operand parameters (value as
znode_op, type as
- a result operand to store return values (
znode_op, type as
- IS_UNUSED: Operand not used
- IS_CONST: Constants are literals in code
- IS_TMPVAR: Temporary variable, as result of
~0, where 0 would be the first, 1 the second, an so on.
- IS_VAR: Non-simple variables or variables requiring a lookup.
- IS_CV: Compiled variable to save PHP from looking up variables in hash table.
!n, where n is the offset to the compiled-variable array.
Index to retrieve the handler address in the lookup table is: Failed to parse (Missing <code>texvc</code> executable. Please see math/README to configure.): i = opcode_number * 25 + op1_type * 5 + op2_type
- Zend Guard
ionCube header looks like:
<?php //0xxxx *load extension / print message code* binary encoded data using custom Base64
The file is checked using Adler32 and binary contents are encoded using a custom Base64 format.
The ionCube loader hooks
zend_compile_file() and tests for
<?php // at the beginning of an executed PHP file. The hexadecimal value immediately following this specifies the size of the fallback code which the loader skips. The binary encoded data is then loaded and parsed by the ionCube extension.
To always show all errors and warnings:
error_reporting(E_ALL); ini_set('display_errors', 1);
In more detail:
// Turn off all error reporting error_reporting(0); // Report simple running errors error_reporting(E_ERROR | E_WARNING | E_PARSE); // Reporting E_NOTICE can be good too (to report uninitialized // variables or catch variable name misspellings ...) error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE); // Report all errors except E_NOTICE // This is the default value set in php.ini error_reporting(E_ALL ^ E_NOTICE); // Report all PHP errors (see changelog) error_reporting(E_ALL); // Report all PHP errors error_reporting(-1); // Same as error_reporting(E_ALL); ini_set('error_reporting', E_ALL);
UTF-8 to hex
There is basically NO good way.
HTTP POST Array Empty
I had an issue where a PHP POST array was empty when a POST request was made. It turns out that PHP now needs the
Content-Type header set for it to be populated regardless of the HTTP method being used.
In detail, when the following request was made,
$_POST was empty:
POST /print HTTP/1.1 Connection: Keep-Alive User-Agent: WebSlipPrinting Content-Length: 56 Host: 172.20.1.151 template_data=Hello There!&Username=test&Password=123456
The data though was still sent since
$_SERVER['CONTENT_LENGTH'] was 56 as in the original request. The data was also present in the
php://input stream. ie:
var_dump(file_get_contents("php://input")); # Returned: # string(56) "template_data=Hello There!&Username=test&Password=123456"
Content-Type value to the header fixes the issue, with the final request as:
POST /print HTTP/1.1 Connection: Keep-Alive Content-Type: application/x-www-form-urlencoded User-Agent: WebSlipPrinting Content-Length: 56 Host: 172.20.1.151 template_data=Hello There!&Username=test&Password=123456
This may have something to do with the
enable_post_data_reading option in PHP. From the config file:
647 ; Whether PHP will read the POST data. 648 ; This option is enabled by default. 649 ; Most likely, you won't want to disable this option globally. It causes $_POST 650 ; and $_FILES to always be empty; the only way you will be able to read the 651 ; POST data will be through the php://input stream wrapper. This can be useful 652 ; to proxy requests or to process the POST data in a memory efficient fashion. 653 ; http://php.net/enable-post-data-reading 654 ;enable_post_data_reading = Off
PDOException : could not find driver
You need to have the pdo driver installed. In my case, I was trying to use the pdo-mysql connector which wasn't compiled with PHP. To fix this, install the PDO driver or compile it manually with:
In my case, I needed mysql:
sh: -t: command not found when attempting to run the
mail() function, you probably did not set the
sendmail_path variable in your
; sendmail_path =
sendmail_path = /usr/sbin/sendmail -t -i
If you get
Recipient names must be specified when calling
mail(), you need to set the
-t flag in