1{ stdenv
2, config
3, callPackages
4, lib
5, pkgs
6, phpPackage
7, autoconf
8, pkg-config
9, aspell
10, bzip2
11, curl
12, cyrus_sasl
13, enchant2
14, freetds
15, gd
16, gettext
17, gmp
18, html-tidy
19, icu64
20, libffi
21, libiconv
22, libkrb5
23, libsodium
24, libxml2
25, libxslt
26, libzip
27, net-snmp
28, nix-update-script
29, oniguruma
30, openldap
31, openssl_1_1
32, openssl
33, overrideSDK
34, pam
35, pcre2
36, postgresql
37, bison
38, re2c
39, readline
40, rsync
41, sqlite
42, unixODBC
43, uwimap
44, valgrind
45, zlib
46, fetchpatch
47}:
48
49lib.makeScope pkgs.newScope (self: with self; {
50 buildPecl = callPackage ../build-support/php/build-pecl.nix {
51 php = php.unwrapped;
52 };
53
54 composerHooks = callPackages ../build-support/php/hooks { };
55
56 mkComposerRepository = callPackage ../build-support/php/build-composer-repository.nix { };
57 buildComposerProject = callPackage ../build-support/php/build-composer-project.nix { };
58
59 # Wrap mkDerivation to prepend pname with "php-" to make names consistent
60 # with how buildPecl does it and make the file easier to overview.
61 mkDerivation = origArgs:
62 let
63 args = lib.fix (lib.extends
64 (_: previousAttrs: {
65 pname = "php-${previousAttrs.pname}";
66 passthru = (previousAttrs.passthru or { }) // {
67 updateScript = nix-update-script { };
68 };
69 meta = (previousAttrs.meta or { }) // {
70 mainProgram = previousAttrs.meta.mainProgram or previousAttrs.pname;
71 };
72 })
73 (if lib.isFunction origArgs then origArgs else (_: origArgs))
74 );
75 in
76 pkgs.stdenv.mkDerivation args;
77
78 # Function to build an extension which is shipped as part of the php
79 # source, based on the php version.
80 #
81 # Name passed is the name of the extension and is automatically used
82 # to add the configureFlag "--enable-${name}", which can be overridden.
83 #
84 # Build inputs is used for extra deps that may be needed. And zendExtension
85 # will mark the extension as a zend extension or not.
86 mkExtension = lib.makeOverridable
87 ({ name
88 , configureFlags ? [ "--enable-${extName}" ]
89 , internalDeps ? [ ]
90 , postPhpize ? ""
91 , buildInputs ? [ ]
92 , zendExtension ? false
93 , doCheck ? true
94 , extName ? name
95 , ...
96 }@args: stdenv.mkDerivation ((builtins.removeAttrs args [ "name" ]) // {
97 pname = "php-${name}";
98 extensionName = extName;
99
100 outputs = [ "out" "dev" ];
101
102 inherit (php.unwrapped) version src;
103
104 enableParallelBuilding = true;
105
106 nativeBuildInputs = [
107 php.unwrapped
108 autoconf
109 pkg-config
110 re2c
111 bison
112 ];
113
114 inherit configureFlags internalDeps buildInputs zendExtension doCheck;
115
116 preConfigurePhases = [
117 "genfiles"
118 "cdToExtensionRootPhase"
119 ];
120
121 genfiles = ''
122 if [ -f "scripts/dev/genfiles" ]; then
123 ./scripts/dev/genfiles
124 fi
125 '';
126
127 cdToExtensionRootPhase = ''
128 # Go to extension source root.
129 cd "ext/${extName}"
130 '';
131
132 preConfigure = ''
133 nullglobRestore=$(shopt -p nullglob)
134 shopt -u nullglob # To make ?-globbing work
135
136 # Some extensions have a config0.m4 or config9.m4
137 if [ -f config?.m4 ]; then
138 mv config?.m4 config.m4
139 fi
140
141 $nullglobRestore
142
143 phpize
144 ${postPhpize}
145
146 ${lib.concatMapStringsSep
147 "\n"
148 (dep: "mkdir -p ext; ln -s ${dep.dev}/include ext/${dep.extensionName}")
149 internalDeps
150 }
151 '';
152
153 checkPhase = ''
154 runHook preCheck
155
156 NO_INTERACTION=yes SKIP_PERF_SENSITIVE=yes make test
157 runHook postCheck
158 '';
159
160 installPhase = ''
161 runHook preInstall
162
163 mkdir -p $out/lib/php/extensions
164 cp modules/${extName}.so $out/lib/php/extensions/${extName}.so
165 mkdir -p $dev/include
166 ${rsync}/bin/rsync -r --filter="+ */" \
167 --filter="+ *.h" \
168 --filter="- *" \
169 --prune-empty-dirs \
170 . $dev/include/
171
172 runHook postInstall
173 '';
174
175 meta = {
176 description = "PHP upstream extension: ${name}";
177 inherit (php.meta) maintainers homepage license;
178 };
179 }));
180
181 php = phpPackage;
182
183 # This is a set of interactive tools based on PHP.
184 tools = {
185 box = callPackage ../development/php-packages/box { };
186
187 castor = callPackage ../development/php-packages/castor { };
188
189 composer = callPackage ../development/php-packages/composer { };
190
191 deployer = callPackage ../development/php-packages/deployer { };
192
193 grumphp = callPackage ../development/php-packages/grumphp { };
194
195 phan = callPackage ../development/php-packages/phan { };
196
197 phing = callPackage ../development/php-packages/phing { };
198
199 phive = callPackage ../development/php-packages/phive { };
200
201 php-cs-fixer = callPackage ../development/php-packages/php-cs-fixer { };
202
203 php-parallel-lint = callPackage ../development/php-packages/php-parallel-lint { };
204
205 phpcbf = callPackage ../development/php-packages/phpcbf { };
206
207 phpcs = callPackage ../development/php-packages/phpcs { };
208
209 phpmd = callPackage ../development/php-packages/phpmd { };
210
211 phpstan = callPackage ../development/php-packages/phpstan { };
212
213 psalm = callPackage ../development/php-packages/psalm { };
214
215 psysh = callPackage ../development/php-packages/psysh { };
216 };
217
218
219
220 # This is a set of PHP extensions meant to be used in php.buildEnv
221 # or php.withExtensions to extend the functionality of the PHP
222 # interpreter.
223 # The extensions attributes is composed of three sections:
224 # 1. The contrib conditional extensions, which are only available on specific PHP versions
225 # 2. The contrib extensions available
226 # 3. The core extensions
227 extensions =
228 # Contrib conditional extensions
229 lib.optionalAttrs (!(lib.versionAtLeast php.version "8.3")) {
230 blackfire = callPackage ../development/tools/misc/blackfire/php-probe.nix { inherit php; };
231 } //
232 # Contrib extensions
233 {
234 amqp = callPackage ../development/php-packages/amqp { };
235
236 apcu = callPackage ../development/php-packages/apcu { };
237
238 ast = callPackage ../development/php-packages/ast { };
239
240 couchbase = callPackage ../development/php-packages/couchbase { };
241
242 datadog_trace = callPackage ../development/php-packages/datadog_trace {
243 buildPecl = buildPecl.override {
244 stdenv = if stdenv.isDarwin then overrideSDK stdenv "11.0" else stdenv;
245 };
246 inherit (pkgs) darwin;
247 };
248
249 ds = callPackage ../development/php-packages/ds { };
250
251 event = callPackage ../development/php-packages/event { };
252
253 gnupg = callPackage ../development/php-packages/gnupg { };
254
255 grpc = callPackage ../development/php-packages/grpc { };
256
257 igbinary = callPackage ../development/php-packages/igbinary { };
258
259 imagick = callPackage ../development/php-packages/imagick { };
260
261 inotify = callPackage ../development/php-packages/inotify { };
262
263 mailparse = callPackage ../development/php-packages/mailparse { };
264
265 maxminddb = callPackage ../development/php-packages/maxminddb { };
266
267 memcache = callPackage ../development/php-packages/memcache { };
268
269 memcached = callPackage ../development/php-packages/memcached { };
270
271 meminfo = callPackage ../development/php-packages/meminfo { };
272
273 memprof = callPackage ../development/php-packages/memprof { };
274
275 mongodb = callPackage ../development/php-packages/mongodb {
276 inherit (pkgs) darwin;
277 };
278
279 msgpack = callPackage ../development/php-packages/msgpack { };
280
281 oci8 = callPackage ../development/php-packages/oci8 { };
282
283 opentelemetry = callPackage ../development/php-packages/opentelemetry { };
284
285 openswoole = callPackage ../development/php-packages/openswoole { };
286
287 pdlib = callPackage ../development/php-packages/pdlib { };
288
289 pcov = callPackage ../development/php-packages/pcov { };
290
291 pdo_oci = buildPecl rec {
292 inherit (php.unwrapped) src version;
293
294 pname = "pdo_oci";
295 sourceRoot = "php-${version}/ext/pdo_oci";
296
297 buildInputs = [ pkgs.oracle-instantclient ];
298 configureFlags = [ "--with-pdo-oci=instantclient,${pkgs.oracle-instantclient.lib}/lib" ];
299
300 internalDeps = [ php.extensions.pdo ];
301
302 postPatch = ''
303 sed -i -e 's|OCISDKMANINC=`.*$|OCISDKMANINC="${pkgs.oracle-instantclient.dev}/include"|' config.m4
304 '';
305
306 meta.maintainers = lib.teams.php.members;
307 };
308
309 pdo_sqlsrv = callPackage ../development/php-packages/pdo_sqlsrv { };
310
311 phalcon = callPackage ../development/php-packages/phalcon { };
312
313 php-spx = callPackage ../development/php-packages/php-spx { };
314
315 pinba = callPackage ../development/php-packages/pinba { };
316
317 protobuf = callPackage ../development/php-packages/protobuf { };
318
319 rdkafka = callPackage ../development/php-packages/rdkafka { };
320
321 redis = callPackage ../development/php-packages/redis { };
322
323 relay = callPackage ../development/php-packages/relay { inherit php; };
324
325 rrd = callPackage ../development/php-packages/rrd { };
326
327 smbclient = callPackage ../development/php-packages/smbclient { };
328
329 snuffleupagus = callPackage ../development/php-packages/snuffleupagus {
330 inherit (pkgs) darwin;
331 };
332
333 sqlsrv = callPackage ../development/php-packages/sqlsrv { };
334
335 ssh2 = callPackage ../development/php-packages/ssh2 { };
336
337 swoole = callPackage ../development/php-packages/swoole { };
338
339 uv = callPackage ../development/php-packages/uv { };
340
341 vld = callPackage ../development/php-packages/vld { };
342
343 xdebug = callPackage ../development/php-packages/xdebug { };
344
345 yaml = callPackage ../development/php-packages/yaml { };
346 } // (
347 # Core extensions
348 let
349 # This list contains build instructions for different modules that one may
350 # want to build.
351 #
352 # These will be passed as arguments to mkExtension above.
353 extensionData = [
354 { name = "bcmath"; }
355 { name = "bz2"; buildInputs = [ bzip2 ]; configureFlags = [ "--with-bz2=${bzip2.dev}" ]; }
356 { name = "calendar"; }
357 { name = "ctype"; }
358 {
359 name = "curl";
360 buildInputs = [ curl ];
361 configureFlags = [ "--with-curl=${curl.dev}" ];
362 doCheck = false;
363 }
364 { name = "dba"; }
365 {
366 name = "dom";
367 buildInputs = [ libxml2 ];
368 configureFlags = [
369 "--enable-dom"
370 ];
371 }
372 {
373 name = "enchant";
374 buildInputs = [ enchant2 ];
375 configureFlags = [ "--with-enchant" ];
376 doCheck = false;
377 }
378 { name = "exif"; doCheck = false; }
379 { name = "ffi"; buildInputs = [ libffi ]; }
380 {
381 name = "fileinfo";
382 buildInputs = [ pcre2 ];
383 }
384 { name = "filter"; buildInputs = [ pcre2 ]; }
385 { name = "ftp"; buildInputs = [ openssl ]; }
386 {
387 name = "gd";
388 buildInputs = [ zlib gd ];
389 configureFlags = [
390 "--enable-gd"
391 "--with-external-gd=${gd.dev}"
392 "--enable-gd-jis-conv"
393 ];
394 doCheck = false;
395 }
396 {
397 name = "gettext";
398 buildInputs = [ gettext ];
399 postPhpize = ''substituteInPlace configure --replace 'as_fn_error $? "Cannot locate header file libintl.h" "$LINENO" 5' ':' '';
400 configureFlags = [ "--with-gettext=${gettext}" ];
401 }
402 {
403 name = "gmp";
404 buildInputs = [ gmp ];
405 configureFlags = [ "--with-gmp=${gmp.dev}" ];
406 }
407 {
408 name = "iconv";
409 configureFlags = [
410 "--with-iconv${lib.optionalString stdenv.isDarwin "=${libiconv}"}"
411 ];
412 doCheck = false;
413 }
414 {
415 name = "imap";
416 buildInputs = [ uwimap openssl pam pcre2 libkrb5 ];
417 configureFlags = [ "--with-imap=${uwimap}" "--with-imap-ssl" "--with-kerberos" ];
418 }
419 {
420 name = "intl";
421 buildInputs = [ icu64 ];
422 }
423 {
424 name = "ldap";
425 buildInputs = [ openldap cyrus_sasl ];
426 configureFlags = [
427 "--with-ldap"
428 "LDAP_DIR=${openldap.dev}"
429 "LDAP_INCDIR=${openldap.dev}/include"
430 "LDAP_LIBDIR=${openldap.out}/lib"
431 ] ++ lib.optionals stdenv.isLinux [
432 "--with-ldap-sasl=${cyrus_sasl.dev}"
433 ];
434 doCheck = false;
435 }
436 {
437 name = "mbstring";
438 buildInputs = [ oniguruma pcre2 ];
439 doCheck = false;
440 }
441 {
442 name = "mysqli";
443 internalDeps = [ php.extensions.mysqlnd ];
444 configureFlags = [ "--with-mysqli=mysqlnd" "--with-mysql-sock=/run/mysqld/mysqld.sock" ];
445 doCheck = false;
446 }
447 {
448 name = "mysqlnd";
449 buildInputs = [ zlib openssl ];
450 # The configure script doesn't correctly add library link
451 # flags, so we add them to the variable used by the Makefile
452 # when linking.
453 MYSQLND_SHARED_LIBADD = "-lssl -lcrypto";
454 # The configure script builds a config.h which is never
455 # included. Let's include it in the main header file
456 # included by all .c-files.
457 patches = [
458 (pkgs.writeText "mysqlnd_config.patch" ''
459 --- a/ext/mysqlnd/mysqlnd.h
460 +++ b/ext/mysqlnd/mysqlnd.h
461 @@ -1,3 +1,6 @@
462 +#ifdef HAVE_CONFIG_H
463 +#include "config.h"
464 +#endif
465 /*
466 +----------------------------------------------------------------------+
467 | Copyright (c) The PHP Group |
468 '')
469 ];
470 }
471 {
472 name = "opcache";
473 buildInputs = [ pcre2 ] ++
474 lib.optional
475 (!stdenv.isDarwin && lib.meta.availableOn stdenv.hostPlatform valgrind)
476 valgrind.dev;
477 zendExtension = true;
478 postPatch = lib.optionalString stdenv.isDarwin ''
479 # Tests are flaky on darwin
480 rm ext/opcache/tests/blacklist.phpt
481 rm ext/opcache/tests/bug66338.phpt
482 rm ext/opcache/tests/bug78106.phpt
483 rm ext/opcache/tests/issue0115.phpt
484 rm ext/opcache/tests/issue0149.phpt
485 rm ext/opcache/tests/revalidate_path_01.phpt
486 '';
487 # Tests launch the builtin webserver.
488 __darwinAllowLocalNetworking = true;
489 }
490 {
491 name = "openssl";
492 buildInputs = [ openssl ];
493 configureFlags = [ "--with-openssl" ];
494 doCheck = false;
495 }
496 # This provides a legacy OpenSSL PHP extension
497 # For situations where OpenSSL 3 do not support a set of features
498 # without a specific openssl.cnf file
499 {
500 name = "openssl-legacy";
501 extName = "openssl";
502 buildInputs = [ openssl_1_1 ];
503 configureFlags = [ "--with-openssl" ];
504 doCheck = false;
505 }
506 { name = "pcntl"; }
507 { name = "pdo"; doCheck = false; }
508 {
509 name = "pdo_dblib";
510 internalDeps = [ php.extensions.pdo ];
511 configureFlags = [ "--with-pdo-dblib=${freetds}" ];
512 # Doesn't seem to work on darwin.
513 enable = (!stdenv.isDarwin);
514 doCheck = false;
515 }
516 {
517 name = "pdo_mysql";
518 internalDeps = with php.extensions; [ pdo mysqlnd ];
519 configureFlags = [ "--with-pdo-mysql=mysqlnd" "PHP_MYSQL_SOCK=/run/mysqld/mysqld.sock" ];
520 doCheck = false;
521 }
522 {
523 name = "pdo_odbc";
524 internalDeps = [ php.extensions.pdo ];
525 configureFlags = [ "--with-pdo-odbc=unixODBC,${unixODBC}" ];
526 doCheck = false;
527 }
528 {
529 name = "pdo_pgsql";
530 internalDeps = [ php.extensions.pdo ];
531 configureFlags = [ "--with-pdo-pgsql=${postgresql}" ];
532 doCheck = false;
533 }
534 {
535 name = "pdo_sqlite";
536 internalDeps = [ php.extensions.pdo ];
537 buildInputs = [ sqlite ];
538 configureFlags = [ "--with-pdo-sqlite=${sqlite.dev}" ];
539 doCheck = false;
540 }
541 {
542 name = "pgsql";
543 buildInputs = [ pcre2 ];
544 configureFlags = [ "--with-pgsql=${postgresql}" ];
545 doCheck = false;
546 }
547 { name = "posix"; doCheck = false; }
548 { name = "pspell"; configureFlags = [ "--with-pspell=${aspell}" ]; }
549 {
550 name = "readline";
551 buildInputs = [
552 readline
553 ];
554 configureFlags = [
555 "--with-readline=${readline.dev}"
556 ];
557 postPatch = ''
558 # Fix `--with-readline` option not being available.
559 # `PHP_ALWAYS_SHARED` generated by phpize enables all options
560 # without the possibility to override them. But when `--with-libedit`
561 # is enabled, `--with-readline` is not registered.
562 echo '
563 AC_DEFUN([PHP_ALWAYS_SHARED],[
564 test "[$]$1" != "no" && ext_shared=yes
565 ])dnl
566 ' | cat - ext/readline/config.m4 > ext/readline/config.m4.tmp
567 mv ext/readline/config.m4{.tmp,}
568 '';
569 doCheck = false;
570 }
571 { name = "session";
572 doCheck = false;
573 }
574 { name = "shmop"; }
575 {
576 name = "simplexml";
577 buildInputs = [ libxml2 pcre2 ];
578 configureFlags = [
579 "--enable-simplexml"
580 ];
581 }
582 {
583 name = "snmp";
584 buildInputs = [ net-snmp openssl ];
585 configureFlags = [ "--with-snmp" ];
586 # net-snmp doesn't build on darwin.
587 enable = (!stdenv.isDarwin);
588 doCheck = false;
589 }
590 {
591 name = "soap";
592 buildInputs = [ libxml2 ];
593 configureFlags = [
594 "--enable-soap"
595 ];
596 doCheck = false;
597 }
598 {
599 name = "sockets";
600 doCheck = false;
601 }
602 { name = "sodium"; buildInputs = [ libsodium ]; }
603 { name = "sqlite3"; buildInputs = [ sqlite ]; }
604 { name = "sysvmsg"; }
605 { name = "sysvsem"; }
606 { name = "sysvshm"; }
607 { name = "tidy"; configureFlags = [ "--with-tidy=${html-tidy}" ]; doCheck = false; }
608 {
609 name = "tokenizer";
610 patches = [ ../development/interpreters/php/fix-tokenizer-php81.patch ];
611 }
612 {
613 name = "xml";
614 buildInputs = [ libxml2 ];
615 configureFlags = [
616 "--enable-xml"
617 ];
618 doCheck = false;
619 }
620 {
621 name = "xmlreader";
622 buildInputs = [ libxml2 ];
623 internalDeps = [ php.extensions.dom ];
624 env.NIX_CFLAGS_COMPILE = toString [ "-I../.." "-DHAVE_DOM" ];
625 doCheck = false;
626 configureFlags = [
627 "--enable-xmlreader"
628 ];
629 }
630 {
631 name = "xmlwriter";
632 buildInputs = [ libxml2 ];
633 configureFlags = [
634 "--enable-xmlwriter"
635 ];
636 }
637 {
638 name = "xsl";
639 buildInputs = [ libxslt libxml2 ];
640 doCheck = false;
641 configureFlags = [ "--with-xsl=${libxslt.dev}" ];
642 }
643 { name = "zend_test"; }
644 {
645 name = "zip";
646 buildInputs = [ libzip pcre2 ];
647 configureFlags = [
648 "--with-zip"
649 ];
650 doCheck = false;
651 }
652 {
653 name = "zlib";
654 buildInputs = [ zlib ];
655 configureFlags = [
656 "--with-zlib"
657 ];
658 }
659 ];
660
661 # Convert the list of attrs:
662 # [ { name = <name>; ... } ... ]
663 # to a list of
664 # [ { name = <name>; value = <extension drv>; } ... ]
665 #
666 # which we later use listToAttrs to make all attrs available by name.
667 #
668 # Also filter out extensions based on the enable property.
669 namedExtensions = builtins.map
670 (drv: {
671 name = drv.name;
672 value = mkExtension drv;
673 })
674 (builtins.filter (i: i.enable or true) extensionData);
675
676 # Produce the final attribute set of all extensions defined.
677 in
678 builtins.listToAttrs namedExtensions
679 );
680})