A work in progress design documentation for the "new pecl" iteration.
Basis:
The current favourite name is pie
, the PHP Installer for E
xtensions.
pie
is the assumed name in this document, although this is to be discussed
and confirmed.pie
is a CLI tool, probably bundled as a PHAR like Composer is
pie install <thing>
assumes the PHAR exist
in $PATH
, for example in
/usr/bin/pie
. If not, you would do something
like php pie.phar install <thing>
.Whilst we are not going to rule out EVER implementing the following features, we just don't plan to include them in the initial version of this new tool. We will consider these items for future inclusion and improvements:
pie self-update
- we can likely replicate the way Composer does a
self-update, but this is out of initial scope
since we will be distributing as a PHAR, it is relatively straightforward to
do a simple replacement to begin with.composer.json
and install missing
extensions globallycomposer.json
filesymfony/console
to simplify writing the CLI tool itselfcomposer/composer
to resolve dependencies; it knows how to do all this
stuff already, lets not re-invent the
wheel - once we have a better idea of what calls we need to make, it may make
sense to split some of
composer/composer
out into separate libraries we can consume; although that
might be a huge undertaking in itself,
so is really just a "strech goal".pie
would be assumed, and its
corresponding phpize
tool would be used. To use a different installed PHP
version, you could use (for example)
/usr/bin/php8.2 /usr/bin/pie ...
pie
will need to be run with sudo
access (so it
can make install
to root-owned paths). Care should
be taken to ensure only the minimal amount is run with elevated privileges, so
we don't accidentally give root to a
malicious PECL package. Ideally, pie
would run without sudo
, and just
prompt for access, when needed (for
example, by invoking a sub-process with sudo
.install {package}{?:version-constraint}{?@stability}
Installs the requested package. The {package}
is a Composer package name, and
not the extension name. For example, pie install xdebug/xdebug
is a valid
request. At the time of writing, PIE-compatible packages are listed on
https://packagist.org/extensions. Note that
previous iterations of this design draft suggested using the extension name as
the pie install
parameter, but after some discussion
it was agreed to use the Composer package name instead.
If version-constraint
is given, try to install that version if it matches the
allowed versions. Version constraints are resolved using the same format as
Composer, along with the minimum stability.
^1.0
will install the latest stable and backwards-compatible version with
1.0.0
and above, according to semantic versioning. See Composer docs for details.^2.3@beta
will install the latest beta and backwards-compatible version
with 2.3.0
and above (for example, 2.3.0-beta.3
).dev-main
will install the latest commit on the main
branch at the time
of command execution. This would not work with Windows, as there is no
release with Windows binaries.dev-main#07f454ad797c30651be8356466685b15331f72ff
will install the specific
commit denoted by the commit sha after #
, in this case the commit
07f454ad797c30651be8356466685b15331f72ff
would be installed. This would
not work with Windows, as there is no release with Windows binaries.If no version-constraint
is given, try to install any compatible latest and
stable version.
On Windows this downloads the correct DLL (attached as file to the release tag), if available. Otherwise, it will download the source and compile the extension.
It will then attempt to create a 20-{extension_name}.ini
file
with extension={extension_name}
in the directory
returned by php-config --ini-dir
, the name that is used is the one from the
"name" element in the metadata file.
If the extension is a Zend extension (such as Xdebug), then it will write the
line zend_extension={extension_name}
instead.
If the extension has a composer.json defined priority, the 20
in the ini file
filename will be replaced by that
priority.
Each step should run with as few privileges as possible.
build {package}{?:version-constraint}{?@stability}
Same behaviour as install, but only compiles (or downloads if it's Windows).
changelog {?version}
Shows the release notes of the version it was going to install, or from the specific version, if given.
download {package}{?:version-constraint}{?@stability}
Same behaviour as build, but puts the files in a local directory for manual building and installation.
info
Shows the description from the metadata file
list
Shows all available commands
show
Shows all installed extensions available with the PHP version in the path, including their versions. This includes all loaded PHP extensions, and not just PIE-sourced ones.
upgrade {?{package}{?:version-constraint}{?@stability}}
Attempts to upgrade all installed versions to the latest available ones on GitHub (unless their major version has changed). If a specific package is specified, only attempt to upgrade that specific one.
--dry-run
Shows what it is about to do, but doesn't actually install
--force
To attempt to install a version that doesn't match the version constraints from the meta-data, for instance to install an older version than recommended, or when the signature is not available.
--with-php-config=/path/to/php-config
Allows installation of extensions with PHP versions that are not in the path
--{option}{?=value}
All options specified in the configure-options
section of the composer.json
file can be given, including a value if they take them. For example, for Xdebug
you could run pie install xdebug/xdebug --without-xdebug-compression
.
Create a composer.json
in your repository, and commit it. The following is
ONLY AN EXAMPLE, and is not necessarily the real composer.json
in Xdebug.
{
"name": "xdebug/xdebug",
"type": "php-ext-zend",
"license": "Xdebug-1.03",
"description": "Xdebug is an amazing tool...",
"require": {
"ext-something": "*",
"php": ">=7.4.21,<8.4"
},
"conflict": {
"ext-a-conflicting-extension": "*"
},
"replace": {
"ext-xdebug": "*"
},
"php-ext": {
"extension-name": "ext-xdebug",
"priority": 80,
"support-zts": false,
"configure-options": [
{
"name": "enable-xdebug-dev",
"description": "Enable developer flags"
},
{
"name": "without-xdebug-compression",
"description": "Disable compression through zlib"
},
{
"name": "some-path-to-something",
"needs-value": true,
"description": "This should be the path to the thing that is needed."
}
]
}
}
Submit your repo URL
into https://packagist.org/packages/submit.
Packagist
will read the composer.json
as usual.
When releases are made, Packagist will do the usual thing of producing metadata for the release
composer.json
name
MUST be in a typical vendor/package
format seen in regular
Composer PHP packages, for example asgrim/my-ext
.type
dictates if it is a PHP Module (php-ext
) or a Zend
Extension (php-ext-zend
).require
definitions, except php
version
itself.php-ext
is a new top-level element to provide additional metadata for
building the extension, if required.
extension-name
field. If the extension-name
is omitted,
invalid, or an empty string, the extension-name
will be derived from
the top level name
. The vendor/
prefix will be removed, and that will
be used as the extension name, for example asgrim/my-ext
will become
ext-my-ext
. The extension-name
field, if defined, may or may not have
the ext-
prefix, and tooling such as PIE will be expected to normalise
this appropriately."support-zts": false
should be set in php-ext
section, but you
may explicitly advertise ZTS support by
specifying "support-zts": true
.xdebug/xdebug
would reasonably be expected to name the extension as
ext-xdebug
). To help semantic understanding, a PIE package MAY optionally
specify a replace
for the extension, in the format ext-my-ext
. Whilst this
will not be used by PIE (at least for now), it may provide some benefit in
understanding the correlation between the package name (e.g. asgrim/my-ext
)
and the extension name (e.g. ext-my-ext
).Windows needs pre-built binary DLLs. The expected workflow is that the release
is made, then some kind of build takes
place (for example, in a GitHub Action, or manually on a compatible build
environment), and the .zip
file is added to
the GitHub release.
The name for the ZIP must follow the following pattern:
php_{extension-name}-{tag}-{php-maj/min}-{ts|nts}-{compiler}-{arch}.zip
php_xdebug-3.3.2-8.3-ts-vs16-x86_64.zip
The descriptions of these items:
extension-name
the name of the extension, e.g. xdebug
tag
for example 3.3.0alpha3
- defined by the tag/release you have madephp-maj/min
- for example 8.3
for PHP 8.3.*compiler
- usually something like vc6
, vs16
- fetch from
'PHP Extension Build' flags in php -i
ts|nts
- Thread-safe or non-thread safe.arch
- for example x86_64
.
Architecture
from php -i
PHP_INT_SIZE
- 4 for 32-bit, 8 for 64-bit.The pre-built ZIP should contain at minimum a DLL named in the same way as the
ZIP itself, for example
php_{extension-name}-{tag}-{php-maj/min}-{ts|nts}-{compiler}-{arch}.dll
.
The .dll
will be moved into the PHP
extensions path, and renamed, e.g.
to C:\path\to\php\ext\php_{extension-name}.dll
. The ZIP file may include
additional resources, such as:
php_{extension-name}.pdb
- this will be moved alongside
the C:\path\to\php\ext\php_{extension-name}.dll
*.dll
- any other .dll
would be moved alongside C:\path\to\php\php.exe
C:\path\to\php\extras\{extension-name}\.
Run:
$ pie install xdebug/xdebug
PIE uses composer/composer
library to help resolve dependencies
sequenceDiagram
participant pie
participant composer as composer library
participant packagist as packagist.org
pie ->> composer : request to install "xdebug/xdebug"
composer ->> packagist : read metadata to resolve dependencies
packagist ->> composer : metadata
composer ->> pie : release information
ext-something
in the ext-xdebug
example above)
is not installed, Composer can detect
this missing depenedency, and warn accordingly.composer.json
dependencies, due to the complexity of different package managers on different
platforms.--with-php-config
with ZTS
enabled, but the extension specifies "support-zts": false
in
its composer.json
manifest, the installation will
be halted with an error explanation. Converseley, if using a PHP without ZTS,
but the extension specifies "supports-nts": false
, the installation will
similarly fail.Once we have the release information, for Linux:
phpize
./configure <options>
make
make install
(note: this part may need sudo
)The <options>
for ./configure
come from the $.php-ext.configure-options
section in composer.json
. These would
be specified as part of the build
or install
commands. Here are some
examples:
$ pie install xdebug/xdebug
$ pie install xdebug/xdebug --enable-xdebug-dev
$ pie install xdebug/xdebug --enable-xdebug-dev --without-xdebug-compression
$ pie install xdebug/xdebug --some-path-to-something=/usr/local/lib/something
$ pie install xdebug/xdebug --not-a-defined-configuration-option # this would fail
When installing the extension on Windows, the PHP version invoking PIE would be
used for determining the PHP version,
library install path and so on, unless --with-php-path=<php-path>
is provided.
Example:
# Assuming C:\usr\php8.3.4\php.exe is in the $PATH
$ pie install xdebug/xdebug # uses C:\usr\php8.3.4\php.exe (i.e. the version that invoked PIE)
$ pie install xdebug/xdebug --with-php-path="C:\usr\php7.4.33" # uses C:\usr\php7.4.33\php.exe
In the follow examples, the $PHP_PATH
is whichever the path is given above,
e.g. C:\usr\php8.3.4
or C:\usr\php7.4.33
Determine the expected name for the Windows ZIP:
extension-name
- We know this already minus ext-
from the package nametag
- Composer gave us the release versionphp-maj/min
- We know this from the version of PHP that invoked pie
compiler
- processed from PHP_COMPILER_ID
(if possible in userland)
or parsing phpinfo, like xdebug.-nts
or omitted - We know this from the version of PHP that invoked pie
-arch
- for example x86_64
, fetch using php -r "echo php_uname('m');"
.Because arch is optional, we have to try therefore, the following file formats, in order:
php_{extension-name}-{tag}-{php-maj/min}-{ts|nts}-{compiler}-{arch}.zip
3.3.0alpha3
on PHP 8.3 on
an x86_64
machine: php_xdebug-3.3.0alpha3-8.3-nts-vs16-x86_64.zip
If the release is found:
php_{extension-name}-{tag}-{php-maj/min}-{ts|nts}-{compiler}-{arch}.dll
to $PHP_PATH\ext\php_{extension-name}.dll
php_{extension-name}.pdb
to $PHP_PATH\ext\php_{extension-name}.pdb
(if it exists)*.dll
to $PHP_PATH\*.dll
(if they exist, but
exclude php_{extension-name}.dll
)$PHP_PATH\extras\{extension-name}\.
php-config --ini-dir
exists, and there is
no {priority}-{extension-name}.ini
(or {extension-name}.ini
?)
file, create one with contents:
extension/zend_extension={extension-name}
in the "conf.d" directory (if configured).
{priority}-{extension-name}.ini
or {extension-name}.ini
exists in the downloaded release tarball,
append its contents to the created file. If the INI path does not exist,
create a "temp" ini file that developers
can copy into a directory, or append to their php.ini file(s).git
to read)CHANGELOG
/ CHANGELOG.md
/ CHANGES
etc. (or other
variations)This graph is a high level overview of the key processes of downloading, building and installing both Windows and Linux based PHP extensions:
flowchart LR
subgraph composer
dependency-resolver
release-notes-processing
composer-json-php-ext-config
end
subgraph packagist
metadata
end
subgraph LinuxDownloader
direction LR
DownloadZipFromGitHub-->ExtractZip
end
subgraph WindowsDownloader
direction LR
DetermineCompiler-->DetermineExpectedDllNames
DetermineZendThreadSafe-->DetermineExpectedDllNames
DeterminePlatformArch-->DetermineExpectedDllNames
DetermineExpectedDllNames-->DownloadDllFromGitHub
end
subgraph LinuxBuilder
direction LR
Phpize-->Configure
Configure-->Make
end
subgraph WindowsBuilder
direction LR
no-op
end
style InstallWithSuperuser fill:#ffa15e
subgraph InstallWithSuperuser
direction LR
InstallLibrary--windows-->CopyDllToPhp
InstallLibrary--"linux"-->MakeInstall
CopyDllToPhp-->ConfigurePhpIni
MakeInstall-->ConfigurePhpIni
end
entrypoint(bin/pie)
entrypoint--pie changelog-->ChangelogCommand
ChangelogCommand-->DependencyResolver
entrypoint--pie info-->InfoCommand
InfoCommand-->DependencyResolver
entrypoint--pie download-->DownloadCommand
DownloadCommand-->Downloader
Downloader--resolve ext-name-->DependencyResolver
DependencyResolver-->composer
composer--request metadata-->packagist
Downloader--"linux"-->LinuxDownloader
Downloader--windows-->WindowsDownloader
entrypoint--pie build-->BuildCommand
BuildCommand--1-->Downloader
BuildCommand--2-->Builder
Builder--"linux"-->LinuxBuilder
Builder--windows-->WindowsBuilder
entrypoint--pie upgrade-->InstallCommand
entrypoint--pie install-->InstallCommand
InstallCommand--1-->Downloader
InstallCommand--2-->Builder
InstallCommand--3-->Installer
Installer-->InstallWithSuperuser
InstallWithSuperuser-->ShowReleaseNotes
ShowReleaseNotes-->Cleanup
entrypoint--pie show-->ShowCommand
ShowCommand-->ListInstalledModulesAndVersions
composer-->ShowReleaseNotes