Skip to content

Instantly share code, notes, and snippets.

@michaelbutler
Last active July 19, 2024 07:28
Show Gist options
  • Save michaelbutler/4a89bb23e2d30f1b0585b98d2b67cf55 to your computer and use it in GitHub Desktop.
Save michaelbutler/4a89bb23e2d30f1b0585b98d2b67cf55 to your computer and use it in GitHub Desktop.
Install multiple PHP versions on Arch / Manjaro Linux

Install Any PHP on Arch / Manjaro

Through the AUR it is possible to install older and newer PHP versions, simultaneously on the same system. I often had trouble installing using pacman and pamac so here's what I did:

mkdir -p $HOME/bin
mkdir ~/src
cd ~/src
git clone https://aur.archlinux.org/php81.git
cd php81
makepkg -si
# Wait a very long time (it literally compiles and installs php AND ALL MODULES
# enter sudo password after the compile step is done

In that example, php 8.1 is now available at /usr/bin/php81 along with /usr/bin/phpize81 . These steps can be repeated by just changing php81 to another version, such as php74 or php80 to get more versions installed.

Then, to help with activating a specific PHP version at any given time (mainly for CLI commands) I use this simple script, placed in my $PATH:

Update: Better version of this script is in a comment below.

#!/usr/bin/env bash

[[ -n $DEBUG ]] && set -x

red='\033[0;31m'
green='\033[0;32m'
reset='\033[0m'

# $1 is version: 7 for latest 7, 8 for latest 8

if [ "$1" == "7" ]; then
  echo -e "${green}Activating php 7 at location /usr/bin/php7 ...${reset}"
  rm -f $HOME/bin/php $HOME/bin/phpize
  ln -s /usr/bin/php7 $HOME/bin/php
  ln -s /usr/bin/phpize7 $HOME/bin/phpize
  sleep 0.5
  php -v
fi

if [ "$1" == "8" ]; then
  echo -e "${green}Activating php 8.1 at location /usr/bin/php81 ...${reset}"
  rm -f $HOME/bin/php $HOME/bin/phpize
  ln -s /usr/bin/php81 $HOME/bin/php
  ln -s /usr/bin/phpize81 $HOME/bin/phpize
  sleep 0.5
  php -v
fi

Then I can run it any time with phpenv 7 to activate 7.4, and phpenv 8 to activate 8.1. You can customize and add more versions as needed, just update the paths.

As a reminder, php --ini will print out the location of the .ini files that are loaded.

@michaelbutler
Copy link
Author

michaelbutler commented Feb 22, 2022

How to UPDATE PHP when a patch is released

  • cd to the directory originally used in the above instructions (e.g. cd ~/src/php81)
  • git pull to pull in the latest updates
  • makepkg -si and wait a while

Note 1: If you deleted the directory before, you can just repeat the original steps (clone the repository and run the makepkg -si command to install the latest).

Note 2: The system package manager (e.g. Discover on KDE) might try to update PHP, but that will fail. You have to do it via these steps instead.

Handy Links:

@michaelbutler
Copy link
Author

michaelbutler commented Feb 22, 2022

Apologies for no instructions involving apache and php-fpm, as I don't use them anymore. For development I just use the built-in PHP server (with php -S) or Docker. And in production I use Docker as well. Specifically with nginx-unit.

EDIT: See below for an enhanced version with support for php-fpm, pecl, etc. And all versions without needed to update the script.

@superbiche
Copy link

superbiche commented Mar 7, 2022

@michaelbutler thanks a lot, installing with Trizen was such a pain.

I made some enhancements on the ~/bin/phpenv script so we can easily switch to any version without having to add every one of them to the script. EDIT: also this now links php-fpm, php-cgi, phpdbg, pear and pecl aliases linking to the right version.

#!/usr/bin/env bash

[[ -n $DEBUG ]] && set -x

red='\033[0;31m'
green='\033[0;32m'
reset='\033[0m'

VERSION=$1

if [[ -z $1 ]]; then
  echo -e "${red}Error: no version specified!${reset}"
  echo -e "Usage: \`phpenv [VERSION]\`"
  echo -e "Example: \`phpenv 81\`"
fi

PHP_BIN="/usr/bin/php$VERSION"
PHPIZE_BIN="/usr/bin/phpize$VERSION"
PHP_FPM_BIN="/usr/bin/php-fpm$VERSION"
PHP_DBG_BIN="/usr/bin/phpdbg$VERSION"
PHP_CGI_BIN="/usr/bin/php-cgi$VERSION"
PHP_PEAR_BIN="/usr/bin/pear$VERSION"
PHP_PECL_BIN="/usr/bin/pecl$VERSION"

if [[ -f "$PHP_BIN" ]]; then
  echo -e "${green}Activating PHP $VERSION..."
  rm -f $HOME/bin/php $HOME/bin/phpize $HOME/bin/php-fpm $HOME/bin/phpdbg $HOME/bin/php-cgi $HOME/bin/pear $HOME/bin/pecl
  ln -s $PHP_BIN $HOME/bin/php
  ln -s $PHPIZE_BIN $HOME/bin/phpize
  ln -s $PHP_FPM_BIN $HOME/bin/php-fpm
  ln -s $PHP_DBG_BIN $HOME/bin/phpdbg
  ln -s $PHP_CGI_BIN $HOME/bin/php-cgi
  ln -s $PHP_PEAR_BIN $HOME/bin/pear
  ln -s $PHP_PECL_BIN $HOME/bin/pecl
  php -v
else
  echo -e "${red}Error: $PHP_BIN could not be found!${reset}"
fi

This way if you have php74 and php80 and php81, you can switch to the exact version using, for instance, phpenv 80.

@michaelbutler
Copy link
Author

@superbiche great improvement on that, thanks!

@michaelbutler
Copy link
Author

@superbiche I just added a note about upgrading patch versions, it seemed to work for me to simply git pull in the cloned dir and then run makepkg -si again. I went from PHP 8.1.2 to 8.1.4 for php81

@superbiche
Copy link

@michaelbutler amazing, just tried upgrading 8.1 - which was broken due to missing intl, no idea why - and it worked smoothly while reinstalling intl. Thanks !

@MaitreCake
Copy link

Hello,

Thanks for this work.
I am a totally newbie on arch-linux. I did pacman php-legacy but was not able to enable it. Finding this post was such a relief for me .
However, if the make php81 did work, the phpenv 81 sent me the following errors :

Activating PHP 81...
ln: failed to create symbolic link '/home/alarm/bin/php': No such file or directory
ln: failed to create symbolic link '/home/alarm/bin/phpize': No such file or directory
ln: failed to create symbolic link '/home/alarm/bin/php-fpm': No such file or directory
ln: failed to create symbolic link '/home/alarm/bin/phpdbg': No such file or directory
ln: failed to create symbolic link '/home/alarm/bin/php-cgi': No such file or directory
ln: failed to create symbolic link '/home/alarm/bin/pear': No such file or directory
ln: failed to create symbolic link '/home/alarm/bin/pecl': No such file or directory

You can replace home/alarm by root when logged as root user.

I just left Ubuntu and I understand there is an issue with symlink.
Something telle me that it should not be in a personnal folder...
However I do not know how to solve it. Any help would be welcome.

Regards

@michaelbutler
Copy link
Author

@MaitreCake I realized I never put the command mkdir -p $HOME/bin -- doing that should solve your issue. Essentially, it requires a bin folder inside your home directory. I typically put custom scripts and things there (doesn't require sudo).

@NikunjGupta01
Copy link

Hello I know this not where to ask but when i am building and installing using make si .It completes successfully but it does not create an the php73 or php74 file in /bin

@timosz
Copy link

timosz commented Dec 27, 2023

Great work! Thanks for sharing!

@iv7dev
Copy link

iv7dev commented May 9, 2024

Thank you! Excellent work

@JakubTkac
Copy link

c-client is having problems to be compiled on gcc 13. Not sure if it is connected but now I am also getting this error while trying to makepkg -si php81 or php74

/home/jakub/src/php81/src/php-8.1.28/ext/libxml/libxml.c: In function ‘zif_libxml_use_internal_errors’:
/home/jakub/src/php81/src/php-8.1.28/ext/libxml/libxml.c:981:48: warning: comparison of distinct pointer types lacks a cast [-Wcompare-distinct-pointer-types]
  981 |         if (current_handler && current_handler == php_libxml_structured_error_handler) {
      |                                                ^~
/home/jakub/src/php81/src/php-8.1.28/ext/libxml/libxml.c:999:49: error: passing argument 2 of ‘xmlSetStructuredErrorFunc’ from incompatible pointer type [-Wincompatible-pointer-types]
  999 |                 xmlSetStructuredErrorFunc(NULL, php_libxml_structured_error_handler);
      |                                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                 |
      |                                                 void (*)(void *, xmlError *) {aka void (*)(void *, struct _xmlError *)}
In file included from /usr/include/libxml2/libxml/valid.h:15,
                 from /usr/include/libxml2/libxml/parser.h:19,
                 from /home/jakub/src/php81/src/php-8.1.28/ext/libxml/libxml.c:32:
/usr/include/libxml2/libxml/xmlerror.h:898:57: note: expected ‘xmlStructuredErrorFunc’ {aka ‘void (*)(void *, const struct _xmlError *)’} but argument is of type ‘void (*)(void *, xmlError *)’ {aka ‘void (*)(void *, struct _xmlError *)’}
  898 |                                  xmlStructuredErrorFunc handler);
      |                                  ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
/home/jakub/src/php81/src/php-8.1.28/ext/libxml/libxml.c: In function ‘zif_libxml_get_last_error’:
/home/jakub/src/php81/src/php-8.1.28/ext/libxml/libxml.c:1016:15: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
 1016 |         error = xmlGetLastError();
      |               ^
make: *** [Makefile:968: ext/libxml/libxml.lo] Error 1
==> ERROR: A failure occurred in build().
    Aborting...

@ahmada3mar
Copy link

@Its-Satyajit
Copy link

Its-Satyajit commented Jul 14, 2024

I've made some enhancement on top this. take a look https://github.com/Its-Satyajit/phpv

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment