PHP: Difference between revisions

From NixOS Wiki
imported>JasonWoof
explain configuring extensions without apache too
Klinger (talk | contribs)
 
(9 intermediate revisions by 5 users not shown)
Line 1: Line 1:
__TOC__
__TOC__
See also:
* [https://nixos.org/manual/nixpkgs/stable/#ssec-php-user-guide PHP User Guide in the nixpkgs manual].
* [[phpfpm]] on this wiki


== Install ==
== Install ==
Line 10: Line 15:




== Setting custom php.ini configurations ==
== Configuration ==
 
=== Setting custom php.ini configurations ===


The `buildEnv` attribute on php can add extra configuration options. For instance, to set a memory_limit in the NixOS configuration.nix:
The `buildEnv` attribute on php can add extra configuration options. For instance, to set a memory_limit in the NixOS configuration.nix:
Line 23: Line 30:
</syntaxhighlight>
</syntaxhighlight>


== Setting custom plugins and php.ini configurations ==
In case of using php-fpm, the following example enables error reporting. Use this only in development environments
 
<syntaxhighlight lang="nix>
services.phpfpm.phpOptions = ''
  display_errors = on;
'';
</syntaxhighlight>
 
=== Setting custom plugins and php.ini configurations ===


In this example we install the [[xdebug]] extension, and add a php.ini directive to enable it.
In this example we install the [[xdebug]] extension, and add a php.ini directive to enable it.
Line 37: Line 52:
     '';
     '';
   })
   })
];
</syntaxhighlight>
</syntaxhighlight>


You can see the full list of extensions e.g. with:
$ nix repl
nix-repl> pkgs = import <nixpkgs> {}           
nix-repl> builtins.attrNames pkgs.phpExtensions


== Apache, plugins, settings ==
== Apache, plugins, settings ==
Line 55: Line 78:
};
};
</syntaxhighlight>
</syntaxhighlight>
== OCI image ==
Here's an example on how to build an OCI image running a PHP application:
Using nginx:
<syntaxhighlight lang="nix>
packages = let
  src = ./.;
  php = pkgs.php81;
in {
  app = php.buildComposerProject {
    inherit src;
    pname = "app-demo";
    version = "1.0.0";
    vendorHash = "sha256-SrE51k3nC5idaDHNxiNM7NIbIERIf8abrCzFEdxOQWA=";
  };
  oci-image = let
    nginxPort = "8000";
    nginxWebRoot = "${self'.packages.app}/share/php/app-demo/public";
    nginxConf = pkgs.writeText "nginx.conf" ''
      user nobody nobody;
      daemon off;
      error_log /dev/stdout info;
      pid /dev/null;
      events {}
      http {
        access_log /dev/stdout;
        server {
          listen ${nginxPort};
          index index.php index.html;
          charset utf-8;
          add_header X-Frame-Options "SAMEORIGIN";
          add_header X-Content-Type-Options "nosniff";
          location / {
            root ${nginxWebRoot};
            try_files $uri $uri/ /index.php?$query_string;
          }
          location ~ \.php$ {
            root ${nginxWebRoot};
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            include ${pkgs.nginx}/conf/fastcgi_params;
            include ${pkgs.nginx}/conf/fastcgi.conf;
          }
        }
      }
    '';
  in
  pkgs.dockerTools.buildLayeredImage {
    name = self'.packages.app.pname;
    tag = "latest";
    contents = [
      php
      pkgs.nginx
      pkgs.fakeNss
      (pkgs.writeScriptBin "start-server" ''
        #!${pkgs.runtimeShell}
        php-fpm -y /etc/php-fpm.d/www.conf.default & nginx -c ${nginxConf};
      '')
    ];
    extraCommands = ''
      mkdir -p var/log/nginx
      mkdir -p var/cache/nginx
      mkdir -p tmp
      chmod 1777 tmp
    '';
    config = {
      Cmd = [ "start-server" ];
      ExposedPorts = {
        "${nginxPort}/tcp" = {};
      };
    };
  };
};
</syntaxhighlight>
Using Caddy:
<syntaxhighlight lang="nix>
packages = let
          src = ./.;
          php = pkgs.php1;
in {
  app = php.buildComposerProject {
    inherit src;
    pname = "app-demo";
    version = "1.0.0";
    vendorHash = "sha256-SrE51k3nC5idaDHNxiNM7NIbIERIf8abrCzFEdxOQWA=";
  };
  oci-image = let
    webport = "8000";
    webroot = "${self'.packages.app}/share/php/app-demo/public";
    caddyFile = pkgs.writeText "Caddyfile" ''
    :${webport}
    root * ${webroot}
    log
    encode gzip
    php_fastcgi 127.0.0.1:9000
    file_server
    '';
  in
  pkgs.dockerTools.buildLayeredImage {
    name = self'.packages.app.pname;
    tag = "latest";
    contents = [
      php
      pkgs.caddy
      pkgs.fakeNss
      (pkgs.writeScriptBin "start-server" ''
        #!${pkgs.runtimeShell}
        php-fpm -D -y /etc/php-fpm.d/www.conf.default
        caddy run --adapter caddyfile --config ${caddyFile}
      '')
    ];
    extraCommands = ''
      mkdir -p tmp
      chmod 1777 tmp
    '';
    config = {
      Cmd = [ "start-server" ];
      ExposedPorts = {
        "${webport}/tcp" = {};
      };
    };
  };
};
</syntaxhighlight>
== Use php Packages with Extensions in a nix-shell ==
To use php packages with some extensions enabled, create a <code>shell.nix</code> similar to the following:
<syntaxhighlight lang="nix>
{ pkgs ? import <nixpkgs> { } }:
let
  phpEnv = pkgs.php.buildEnv {
    extensions = { enabled, all }: enabled ++ (with all; [ xsl ]);
    extraConfig = "memory_limit=-1";
  };
in
pkgs.mkShell {
  buildInputs = with pkgs; [
    phpEnv
    phpEnv.packages.composer
    symfony-cli
  ];
}
</syntaxhighlight>
== Troubleshooting ==
=== Memcached Extension Isn't Enabled ===
Using <code>phpExtensions.memcached</code> inside of <code>environment.systemPackages</code> will lead to the memcached php extension not being enabled in the <code>php.ini</code> file. Here's how to fix it:
<syntaxhighlight lang="nix>
let
  # Replace pkgs.php with the php version you want; ex pkgs.php83
  php = pkgs.php.buildEnv {
    extensions = { enabled, all }: enabled ++ (with all; [ memcached ]);
  };
in {
  environment.systemPackages = with pkgs; [ php ];
}
</syntaxhighlight>
[[Category:Languages]]

Latest revision as of 16:24, 29 October 2024

See also:

Install

  environment.systemPackages = with pkgs; [ php ];

See nix search php (nix search nixpkgs php with Flakes) for additional versions like php74, etc.


Configuration

Setting custom php.ini configurations

The `buildEnv` attribute on php can add extra configuration options. For instance, to set a memory_limit in the NixOS configuration.nix:

environment.systemPackages =
  let
    php = pkgs.php.buildEnv { extraConfig = "memory_limit = 2G"; };
  in [
    php
  ];

In case of using php-fpm, the following example enables error reporting. Use this only in development environments

services.phpfpm.phpOptions = ''
  display_errors = on;
'';

Setting custom plugins and php.ini configurations

In this example we install the xdebug extension, and add a php.ini directive to enable it.

environment.systemPackages = [
  (pkgs.php.buildEnv {
    extensions = ({ enabled, all }: enabled ++ (with all; [
      xdebug
    ]));
    extraConfig = ''
      xdebug.mode=debug
    '';
  })
];

You can see the full list of extensions e.g. with:

$ nix repl

nix-repl> pkgs = import <nixpkgs> {}            

nix-repl> builtins.attrNames pkgs.phpExtensions

Apache, plugins, settings

Here's how to configure Apache to use a particular PHP configuration/version/etc

# in /etc/nixos/configuration.nix (not inside systemPackages)
services.httpd.phpPackage = pkgs.php.buildEnv {
    extensions = ({ enabled, all }: enabled ++ (with all; [
        xdebug
    ]));
    extraConfig = ''
        xdebug.mode=debug
    '';
};

OCI image

Here's an example on how to build an OCI image running a PHP application:

Using nginx:

packages = let
  src = ./.;
  php = pkgs.php81;
in {
  app = php.buildComposerProject {
    inherit src;

    pname = "app-demo";
    version = "1.0.0";

    vendorHash = "sha256-SrE51k3nC5idaDHNxiNM7NIbIERIf8abrCzFEdxOQWA=";
  };

  oci-image = let
    nginxPort = "8000";
    nginxWebRoot = "${self'.packages.app}/share/php/app-demo/public";

    nginxConf = pkgs.writeText "nginx.conf" ''
      user nobody nobody;
      daemon off;
      error_log /dev/stdout info;
      pid /dev/null;
      events {}
      http {
        access_log /dev/stdout;
        server {
          listen ${nginxPort};
          index index.php index.html;
          charset utf-8;

          add_header X-Frame-Options "SAMEORIGIN";
          add_header X-Content-Type-Options "nosniff";
          location / {
            root ${nginxWebRoot};
            try_files $uri $uri/ /index.php?$query_string;
          }
          location ~ \.php$ {
            root ${nginxWebRoot};
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            include ${pkgs.nginx}/conf/fastcgi_params;
            include ${pkgs.nginx}/conf/fastcgi.conf;
          }
        }
      }
    '';
  in
  pkgs.dockerTools.buildLayeredImage {
    name = self'.packages.app.pname;
    tag = "latest";

    contents = [
      php
      pkgs.nginx
      pkgs.fakeNss
      (pkgs.writeScriptBin "start-server" ''
        #!${pkgs.runtimeShell}
        php-fpm -y /etc/php-fpm.d/www.conf.default & nginx -c ${nginxConf};
      '')
    ];

    extraCommands = ''
      mkdir -p var/log/nginx
      mkdir -p var/cache/nginx
      mkdir -p tmp
      chmod 1777 tmp
    '';

    config = {
      Cmd = [ "start-server" ];
      ExposedPorts = {
        "${nginxPort}/tcp" = {};
      };
    };
  };
};

Using Caddy:

packages = let
          src = ./.;
          php = pkgs.php1;
in {
  app = php.buildComposerProject {
    inherit src;

    pname = "app-demo";
    version = "1.0.0";

    vendorHash = "sha256-SrE51k3nC5idaDHNxiNM7NIbIERIf8abrCzFEdxOQWA=";
  };

  oci-image = let
    webport = "8000";
    webroot = "${self'.packages.app}/share/php/app-demo/public";

    caddyFile = pkgs.writeText "Caddyfile" ''
    :${webport}
    root * ${webroot}
    log
    encode gzip
    php_fastcgi 127.0.0.1:9000
    file_server
    '';
  in
  pkgs.dockerTools.buildLayeredImage {
    name = self'.packages.app.pname;
    tag = "latest";

    contents = [
      php
      pkgs.caddy
      pkgs.fakeNss
      (pkgs.writeScriptBin "start-server" ''
        #!${pkgs.runtimeShell}
        php-fpm -D -y /etc/php-fpm.d/www.conf.default
        caddy run --adapter caddyfile --config ${caddyFile}
      '')
    ];

    extraCommands = ''
      mkdir -p tmp
      chmod 1777 tmp
    '';

    config = {
      Cmd = [ "start-server" ];
      ExposedPorts = {
        "${webport}/tcp" = {};
      };
    };
  };
};

Use php Packages with Extensions in a nix-shell

To use php packages with some extensions enabled, create a shell.nix similar to the following:

{ pkgs ? import <nixpkgs> { } }:
let
  phpEnv = pkgs.php.buildEnv {
    extensions = { enabled, all }: enabled ++ (with all; [ xsl ]);
    extraConfig = "memory_limit=-1";
  };
in
pkgs.mkShell {
  buildInputs = with pkgs; [
    phpEnv
    phpEnv.packages.composer
    symfony-cli
  ];
}

Troubleshooting

Memcached Extension Isn't Enabled

Using phpExtensions.memcached inside of environment.systemPackages will lead to the memcached php extension not being enabled in the php.ini file. Here's how to fix it:

let
  # Replace pkgs.php with the php version you want; ex pkgs.php83
  php = pkgs.php.buildEnv {
    extensions = { enabled, all }: enabled ++ (with all; [ memcached ]); 
  };
in {
  environment.systemPackages = with pkgs; [ php ];
}