Paketbaurichtlinien für PHP

Paketbaurichtlinien für PHP-Addon-Module in Fedora

Verschiedene Typen von PHP-Paketen

Es gibt im Wesentlichen 4 verschiedene Arten von PHP-Modulen, die für Fedora paketiert sind:

  • Die Module der PHP Extension Community Library (PECL) sind PHP-Module, die üblicherweise in C geschrieben sind und beim Start dynamisch vom PHP-Interpreter geladen werden. Diese werden zugunsten von PIE (Pipe Injection) eingestellt.

  • PEAR-Module (PHP Extension and Application Repository) bietet wiederverwendbare PHP-Komponenten (meist Klassen), die in eigenen PHP-Anwendungen und -Skripten beispielsweise mit der include()-Direktive eingebunden werden können. Dies gilt jedoch als veraltet und wird nicht mehr empfohlen. Verwenden Sie stattdessen „Composer“.

  • Composer-registrierte Bibliotheken, bei denen es sich um wiederverwendbare, in PHP geschriebene Komponenten handelt, in der Regel PSR-0-konforme Klassen, die in einer Paketregistrierung, meist auf Packagist, registriert sind.

  • CHANNEL: Pakete, die einen Kanal registrieren. Ein Kanal ist ein Repository, das PHP-Erweiterungen bereitstellt. Dies ist veraltet und wird nicht mehr empfohlen.

  • PIE registrierte Erweiterungen, die üblicherweise in C geschriebene PHP-Module sind und vom PHP-Interpreter beim Start dynamisch geladen werden. Sie sind in einer Paketregistrierung, meist auf Packagist, registriert.

  • Andere Pakete, die eine PHP-Erweiterung bereitstellen, die nicht von den PEAR/PECL-Mechanismen verarbeitet wird.

Während Upstream für PECL und PEAR das gleiche Paket- und Vertriebsformat verwendet, müssen bei der Erstellung von RPMs einige Unterschiede berücksichtigt werden.

Bei der Installation von php-pear werden 3 Kanäle definiert:

  • pear.php.net (alias pear): der Standardkanal für das PHP-Erweiterungs- und Anwendungs-Repository

  • pecl.php.net (alias pecl): der Standardkanal für die PHP Extension Community Library

  • __uri : Pseudo-Kanal für statische Pakete

Andere Kanäle müssen sowohl während des RPM-Bauprozesses als auch während der RPM-Installation konfiguriert werden.

Benennungsschema

  • PECL-Pakete aus dem Standard-PECL-Kanal sollten nach dem Schema php-pecl-PECLPaketname-%{version}-%{release}.%{arch}.rpm benannt werden.

  • PEAR-Pakete aus dem Standard-PEAR-Kanal sollten nach dem Schema php-pear-PEARPaketname-%{version}-%{release}.noarch.rpm benannt werden.

  • CHANNEL-Pakete sollten nach dem Schema php-channel-ChannelAlias-%{version}-%{release}.noarch.rpm benannt werden.

  • Pakete aus anderen Kanälen sollten nach dem Schema php-ChannelAlias-Paketname-%{version}-%{release}.noarch.rpm benannt werden.

  • Composer-fähige Pakete (die auf packagist.org oder einer anderen Registry referenziert werden) sollten den Namen php-vendor-library-%{version}-%{release}.noarch.rpm tragen (wobei vendor/library der bekannte Packagist-Name ist, das name-Attribut in composer.json). Wenn vendor gleich library ist, kann eines davon weggelassen werden (z.B. kann symfony/symfony in php-symfony umbenannt werden).

  • PIE-fähige Pakete (die in packagist.org oder einer anderen Registry referenziert werden) sollten den Namen php-vendor-extension-%{version}-%{release}.%{arch}.rpm tragen (wobei vendor/extension der bekannte Packagist-Name ist, das name-Attribut in composer.json). Wenn vendor gleich extension ist, kann eines der beiden weggelassen werden (z.B. kann xdebug/xdebug in php-xdebug umbenannt werden).

  • Andere Pakete sollten den Namen php-PackageName-%{version}-%{release}.%{arch}.rpm tragen; %{arch} kann gegebenenfalls durch noarch ersetzt werden.

Bitte stellen Sie sicher, dass ein reines PHP-Paket (PEAR, packagist…​) korrekt für noarch erstellt wird.

Wie bei anderen Paketen sollte der Name nur Kleinbuchstaben enthalten, Unterstriche und Schrägstriche werden durch Bindestriche ersetzt.

Die Namen PECLPackageName und PEARPackageName sollten mit dem Namensschema des Upstream-Projekts übereinstimmen. Die Crack-PHP-Erweiterung würde demnach php-pecl-crack heißen, und die resultierenden Pakete wären php-pecl-crack-0.4-1.i386.rpm und php-pecl-crack-0.4-1.src.rpm.

Beachten Sie, dass Anwendungen, die in PHP geschrieben sind, nicht in den php-*-Namensraum gehören.

Dateiplatzierung

Nicht-PEAR-PHP-Software, die gemeinsam genutzte Bibliotheken bereitstellt, sollte ihre PHP-Quelldateien für diese Bibliotheken in einem Unterordner von %{_datadir}/php ablegen, dessen Name dem Namen der Software entspricht. Beispielsweise würde eine Bibliothek namens Whizz_Bang (mit einem RPM-Paket namens php-something-Whizz-Bang) die PHP-Quelldateien für ihre gemeinsam genutzten Bibliotheken in %{_datadir}/php/Whizz_Bang ablegen.

Eine PSR-0-konforme Bibliothek [1] würde ihre PHP-Dateien in %{_datadir}/php/ ablegen.

Eine PSR-4-konforme Bibliothek [2]) würde ihre PHP-Dateien in einem PSR-0-konformen Verzeichnisbaum unter %{_datadir}/php/ ablegen.

Die upstreamseitig bereitgestellte PEAR-Dokumentation wird in %{pear_docdir} installiert, sollte dort bleiben und muss als %doc gekennzeichnet werden.

Die upstreamseitig bereitgestellte PECL-Dokumentation wird in %{pecl_docdir} installiert, sollte dort bleiben und muss als %doc gekennzeichnet werden.

Die Datei composer.json wird nicht verwendet und sollte als %doc installiert werden, da sie nützliche Informationen über das Paket und seine Abhängigkeiten enthält.

Requires und Provides

PEAR-Pakete aus dem Standard-Channel/Repository

Ein PEAR-Paket MUSS Folgendes haben:

BuildRequires:    php-pear(PEAR)
Requires:         php-pear(PEAR)
Requires(post):   %{__pear}
Requires(postun): %{__pear}
Provides:         php-pear(foo) = %{version}

Das virtuelle „Provides“ sollte exakt mit dem Upstream-Namen übereinstimmen, einschließlich Groß-/Kleinschreibung und Unterstrich, z.B.: php-pear(Text_Wiki)

Für ein PEAR-Paket müssen alle seine Abhängigkeiten als PEAR-Pakete vorliegen. Es sollte daher nur diejenigen Pakete einbinden, die die virtuelle Bereitstellungsmethode php-pear(foo) verwenden. Eine bekannte Ausnahme bilden nicht gebündelte Bibliotheken (die häufig gebündelt werden, da sie in keinem PEAR-Kanal verfügbar sind).

Pakete für CHANNEL- (Repository-)Konfiguration

Ein CHANNEL-Paket MUSS Folgendes haben:

Requires:         php-pear(PEAR)
Requires(post):   %{__pear}
Requires(postun): %{__pear}
Provides:         php-channel(channelname)

PEAR-Pakete aus einem Nicht-Standard-Channel/Repository

Ein PEAR-Paket MUSS Folgendes haben:

BuildRequires:    php-channel(channelname)
BuildRequires:    php-pear(PEAR)
Requires:         php-pear(PEAR)
Requires(post):   %{__pear}
Requires(postun): %{__pear}
Requires:         php-channel(channelname)
Provides:         php-pear(channelname/foo) = %{version}

Composer-registrierte Pakete

Jedes auf Packagist registrierte Paket (das am weitesten verbreitete und daher implizite Paketregister) MUSS Folgendes enthalten:

Provides:     php-composer(vendor/library) = %{version}

Pakete aus anderen Registrierungen MÜSSEN Folgendes haben:

Provides:     php-composer(registry_url/vendor/library) = %{version}

Das virtuelle „Provides“ sollte exakt mit dem Upstream-Namen übereinstimmen, einschließlich Unterstrich, z. B.: php-composer(pear/console_table)

Pakete, die von PEAR nach Composer/Packagist migriert wurden, sollten bei Bedarf auch php-pear(foo) per „Provides“ bereitstellen (wird von anderen PEAR-Paketen verwendet).

Pakete dürfen keine Abhängigkeiten von php-pear(foo) aufweisen, sollten aber php-composer(pear/foo) verwenden.

composer.json nützliche Attribute (siehe Composer-Schema-Dokumentation)

  • name

  • description : eine Zeile, kann als „Summary“ für RPM verwendet werden

  • homepage : kann als „URL“ für RPM verwendet werden

  • license

  • require: Beschreibt obligatorische Abhängigkeiten wie die PHP-Version, PHP-Erweiterungen oder andere Composer-Bibliotheken, die vom RPM-Paket als php-composer(foo) eingebunden werden müssen.

  • require-dev: beschreibt Entwicklungsabhängigkeiten, die üblicherweise zur Bauzeit nützlich sind (z.B. zum Ausführen von Unit-Tests), und könnte daher als BuildRequires erscheinen.

  • suggest : beschreibt optionale Abhängigkeiten und kann daher als Requires erscheinen (Entscheidung des Paketierers).

  • conflict : wie „Conflicts“ in RPM

  • replace : wie „Obsoletes“ in RPM

  • provide : Für zusätzliche virtuelle „Provides“; muss auch in den RPM-„Provides“ als php-composer(foo) enthalten sein.

C-Erweiterungen (PECL und andere)

Um sicherzustellen, dass eine Binärerweiterung mit einer bestimmten PHP-Version korrekt ausgeführt wird, muss geprüft werden, ob das jeweilige Paket sowohl eine API als auch eine ABI besitzt, die mit der installierten PHP-Version übereinstimmen. Der Mechanismus hierfür ist wie folgt:

BuildRequires: php-devel
Requires:      php(zend-abi) = %{php_zend_api}
Requires:      php(api) = %{php_core_api}

Jede Erweiterung MUSS außerdem (um das Heraus-/Einrücken von php-src zu verfolgen) den module-Namen verwenden, wie er von „php --modules“ ausgegeben wird, oder den .so-Dateinamen in Kleinbuchstaben.

Provides:     php-module = %{version}
Provides:     php-module%{_isa} = %{version}

PECL-Pakete

Die PECL-Erweiterung MUSS eine ABI-Prüfung haben (siehe C-Erweiterungen oben).

Ein PECL-Paket MUSS außerdem Folgendes haben:

Provides:     php-pecl(foo) = %{version}
Provides:     php-pecl(foo)%{?_isa}  = %{version}

PECL-Pakete aus einem nicht standardmäßigen Kanal/Repository

Ein PECL-Paket aus einem nicht standardmäßigen Kanal MUSS (anstelle der bisherigen „Provides“) Folgendes haben:

Requires: php-channel(channelname)
Provides: php-pecl(channelname/foo) = %{version}
Provides: php-pecl(channelname/foo)%{?_isa} = %{version}

PIE-Pakete

Die PIE-Erweiterung MUSS eine ABI-Prüfung haben (siehe C-Erweiterungen oben).

Jedes auf Packagist (dem am weitesten verbreiteten und daher impliziten Paketregister) registrierte Paket MUSS Folgendes enthalten:

Provides:     php-pie(vendor/extension) = %{version}

Andere Pakete

PHP-Add-ons, die weder PEAR noch PECL sind, sollten das fordern, was Sinn ergibt (entweder eine Basis-PHP-Version oder ein php-api, php(zend-abi), je nach Bedarf).

Apache-Abhängigkeit

Eine PHP-Bibliothek darf keine expliziten „Requires“ für php oder httpd haben, da diese Bibliotheken mit jedem Webserver oder jeder SAPI (php-cli, php-cgi, php-fpm, …​) verwendbar sein sollen.

Nur eine PHP-Webanwendung, die eine spezifische httpd-Konfiguration für Apache bereitstellt, sollte ein „Requires“ für httpd und mod_php haben.

„Requires“ für Erweiterungen

PHP-Erweiterungen müssen ein „Requires“ für alle abhängigen Erweiterungen (php-json, php-gd, php-mbstring, …​) enthalten. Diese Erweiterungen sind virtuelle „Provides“ der PHP-Teilpakete.

Folgendes kann ignoriert werden, da immer vorhanden: core, date, filter, hash, pcre, random, reflection, session, spl, standard.

Abhängigkeit von einer minimalen PHP-Version

Falls Sie eine minimale PHP-Version angeben müssen, empfiehlt sich die Verwendung von php(language) >= $VERSION als „Requires“ (wobei $VERSION die minimale PHP-Version ist).

C-Erweiterung und Konfigurationsdateien für PECL-Pakete

Jede Erweiterung sollte eine Konfigurationsdatei in %{php_inidir} und/oder %{php_ztsinidir} ablegen, um die Erweiterung zu aktivieren. Diese Datei muss den Namen der geladenen Erweiterung enthalten. Die Datei muss ein numerisches Präfix verwenden, um die korrekte Ladefolge sicherzustellen:

  • Der Bereich 00-19 ist für zend_extensions reserviert (z.B.: 10-opcache.ini, 15-xdebug.ini, …​)

  • Der Bereich 20-39 ist für Erweiterungen aus PHP-Quellen reserviert (z.B.: 20-pdo.ini, 30-pdo_pgsql.ini, …​)

  • Der Bereich 40-99 ist für andere Erweiterungen verfügbar (z.B.: 40-zip.ini, …​)

Makros und Scriptlets

PHP-ZTS-Erweiterung

Wenn der Apache HTTPD im Worker-Modus (anstatt im Prefork-Modus) ausgeführt wird, wird die ZTS-Version („Zend Thread Safe“) von PHP verwendet.

Wenn ein Erweiterungsentwickler eine ZTS-Version dieser Erweiterung bereitstellen möchte, muss er Folgendes sicherstellen:

  • die Erweiterung ist thread-sicher

  • die von der Erweiterung verwendeten Bibliotheken sind thread-sicher

Das Paket php-devel stellt die notwendigen Dateien zum Erstellen von ZTS-Modulen bereit und bietet mehrere Hilfsmakros:

Für Standard-(NTS-)Erweiterungen

%{__php}          %{_bindir}/php
%{php_extdir}     %{_libdir}/php/modules
%{php_inidir}     %{_sysconfdir}/php.d
%{php_incldir     %{_includedir}/php

Für ZTS-Erweiterungen

%{__ztsphp}       %{_bindir}/zts-php
%{php_ztsextdir}  %{_libdir}/php-zts/modules
%{php_ztsinidir}  %{_sysconfdir}/php-zts.d
%{php_ztsincldir  %{_includedir}/php-zts/php

php-devel stellt die während des Baus einer ZTS-Erweiterung benötigten ausführbaren Dateien bereit, und zwar:

  • zts-phpize

  • zts-php-config

  • zts-php (was nur zum Ausführen der Testsuite während des Bauprozesses nützlich ist)

Pakete für CHANNEL- (Repository-)Konfiguration

Hier sind einige empfohlene Scriptlets zum ordnungsgemäßen Registrieren und Abmelden des Kanals:

%post
if [ $1 -eq  1 ] ; then
   %{__pear} channel-add %{pear_xmldir}/%{name}.xml > /dev/null || :
else
   %{__pear} channel-update %{pear_xmldir}/%{name}.xml > /dev/null ||:
fi

%postun
if [ $1 -eq 0 ] ; then
   %{__pear} channel-delete %{channelname} > /dev/null || :
fi

PEAR-Module

Das Paket php-pear bietet einige nützliche Makros:

  • %{pear_phpdir}

  • %{pear_docdir} (expandiert zu %{_docdir}/pear.)

  • %{pear_testdir}

  • %{pear_datadir}

  • %{pear_xmldir}

  • %{pear_metadir} (expandiert zu /var/lib/pear.)

Diese Definitionen für die .spec-Datei dürften von Interesse sein:

BuildRequires:    php-pear >= 1:1.4.9-1.2
Provides:         php-pear(PackageName) = %{version}
Requires:         php-common >= 4.3, php-pear(PEAR)
Requires(post):   %{_bindir}/pear
Requires(postun): %{_bindir}/pear

Stellen Sie sicher, dass Sie am Ende von %install alle PEAR-Metadatendateien löschen:

rm -rf %{buildroot}/%{pear_metadir}/.??*

Hier sind einige empfohlene Scriptlets zur ordnungsgemäßen Registrierung des Moduls:

%post
%{_bindir}/pear install --nodeps --soft --force --register-only %{pear_xmldir}/%{name}.xml >/dev/null ||:

Und hier sind einige empfohlene Scriptlets zum ordnungsgemäßen Abmelden des Moduls aus dem Standardkanal:

%postun
if [ "$1" -eq "0" ] ; then
%{_bindir}/pear uninstall --nodeps --ignore-errors --register-only Foo_Bar >/dev/null ||:
fi

Von einem nicht standardmäßigen Kanal (der Befehl pear erfordert die Angabe des Kanals):

%postun
if [ "$1" -eq "0" ] ; then
%{_bindir}/pear uninstall --nodeps --ignore-errors --register-only Foo_channel/Foo_Bar >/dev/null ||:
fi

PECL-Module

Das Paket php-pear bietet einige nützliche Makros:

  • %{pecl_phpdir}

  • %{pecl_docdir}

  • %{pecl_testdir}

  • %{pecl_datadir}

  • %{pecl_xmldir}

Um bestimmte Informationen aus PHP zu extrahieren, müssen Sie möglicherweise einige zusätzliche Makros definieren. Es wird empfohlen, Folgendes zu verwenden:

%global php_apiver  %((echo 0; php -i 2>/dev/null | sed -n 's/^PHP API => //p') | tail -1)
%{!?__pecl:     %{expand: %%global __pecl     %{_bindir}/pecl}}
%{!?php_extdir: %{expand: %%global php_extdir %(php-config --extension-dir)}}

Die (De-)Registrierung von Modulen wird automatisch durch Dateitrigger im Paket php-pear gehandhabt.

Für ältere Releases finden Sie hier einige empfohlene Scriptlets zum ordnungsgemäßen Registrieren und Deregistrieren eines Moduls:

BuildRequires: php-pear
Requires(post): %{__pecl}
Requires(postun): %{__pecl}

%post
%{pecl_install} %{pecl_xmldir}/%{name}.xml >/dev/null || :


%postun
if [ $1 -eq 0 ]  ; then
%{pecl_uninstall} %{pecl_name} >/dev/null || :
fi

Weitere Module

Wenn Ihr Modul kompilierten Code enthält, müssen Sie möglicherweise einige Makros definieren, um Informationen aus PHP zu extrahieren. Es wird empfohlen, Folgendes zu verwenden:

%global php_apiver  %((echo 0; php -i 2>/dev/null | sed -n 's/^PHP API => //p') | tail -1)
%global php_extdir  %(php-config --extension-dir 2>/dev/null || echo "undefined")
%global php_version %(php-config --version 2>/dev/null || echo 0)

Zusätzliche Hinweise für Paketierer

PEAR-und PECL-Pakete

Das Quellarchiv enthält eine package.xml-Datei außerhalb eines Verzeichnisses, daher müssen Sie

%setup -q -c

in Ihrem `%prep-Abschnitt verwenden, um zu verhindern, dass Dateien ins BuildRoot geschrieben werden.

PEAR-Pakete

Um Ihre erste Spec-Datei zu erstellen, können Sie die Standardvorlage des Pakets rpmdevtools verwenden:

rpmdev-newspec -t php-pear php-pear-Foo

Oder Sie können eine selbst erzeugen; stellen Sie sicher, dass Sie das Paket +php-pear-PEAR-Command-Packaging installiert haben:

pear make-rpm-spec Foo.tgz