0

I'm using MacOS 13.4 on a 2021 MBP.

I need to be able to toggle between versions of PHP to test PHP applications for compatibility across both PHP 7 and 8.

I used brew to install PHP 8.2. Then discovered that core no longer allows versioning formulae, so I used brew tap shivammathur/php to install PHP 7.4.

After that, I used brew link --overwrite --force php@7.4 and brew link --overwrite --force php@8.2 to switch. While checking the cli confirmed that the switch was successful, apache httpd still only saw 8.2.

So I decided to write a bash script to try to automate a full switch of both PHP cli and PHP on apache, without directly editing the httpd.conf file (using an include to set the correct .so library).

Here's the script:

#!/bin/bash

    # Specify the paths for each version of PHP
    php_7_4_path="/opt/homebrew/opt/php@7.4/lib/httpd/modules/libphp7.so"
    php_8_1_path="/opt/homebrew/opt/php@8.1/lib/httpd/modules/libphp.so"
    php_8_2_path="/opt/homebrew/opt/php@8.2/lib/httpd/modules/libphp.so"

    php_conf_file="/opt/homebrew/etc/httpd/php.conf"
    php_conf_backup="php_conf_file.backup"

    # Function to update the php.conf file with the correct PHP version
    update_php_conf() {
        php_version="$1"
        php_module_path=""

        case "$php_version" in
            7.4)
                php_module_path="$php_7_4_path"
                ;;
            8.1)
                php_module_path="$php_8_1_path"
                ;;
            8.2)
                php_module_path="$php_8_2_path"
                ;;
            *)
                echo "Invalid PHP version specified."
                exit 1
                ;;
       
    esac

        cp "$php_conf_backup" "$php_conf_file"  # Restore the original php.conf file
        sed -i '' "s|#{php_module_path}|$php_module_path|" "$php_conf_file"
    }

    # Usage: switch_php_version <version>
    switch_php_version() {
        desired_version="$1"

        # Use Brew to switch the PHP version
        brew unlink php
        brew link --overwrite --force "php@$desired_version"

        # Backup the original php.conf file (if not already done)
        if [ ! -f "$php_conf_backup" ]; then
            cp "$php_conf_file" "$php_conf_backup"
        fi

        # Update the php.conf file with the correct PHP version
        update_php_conf "$desired_version"

        # Restart Apache
        apachectl restart
    }

    # Usage example: ./switch-php.sh 8.2
    switch_php_version "$1"

Here's the Include I have in /opt/homebrew/etc/httpd/httpd.conf:

Include /opt/homebrew/etc/httpd/php.conf

Here's what the placeholder php.conf file contains:

LoadModule php_module #{php_module_path}

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

Here's how it looks when 8.2 is enabled:

LoadModule php_module /opt/homebrew/opt/php@8.2/lib/httpd/modules/libphp.so

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

and with 7.4 enabled:

LoadModule php_module /opt/homebrew/opt/php@7.4/lib/httpd/modules/libphp7.so

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

The script appears to work as intended,but when 7.4 is enabled, apache won't start: Syntax error on line 1 of /opt/homebrew/etc/httpd/php.conf: Can't locate API module structure `php_module' in file /opt/homebrew/opt/php@7.4/lib/httpd/modules/libphp7.so: dlsym(0x968e8d00, php_module): symbol not found

I've tried to be as comprehensive as possible to make finding a resolution easier.

Thanks!

DevAdmin
  • 13
  • 3

1 Answers1

0

I found the issue. The line to load the module for php 7 uses a different naming construct:

LoadModule php7_module /opt/homebrew/opt/php@7.4/lib/httpd/modules/libphp7.so

I was just using the generic php_module, which worked fine for 8.2.

This required that I change the substitution variables to include not only the path to the module, but also the name that is expected. This also required a minor change to the file php_conf_file.backup.

Here's the updated script:

#!/bin/bash

    # Specify the paths for each version of PHP
    php_7_4_path="php7_module /opt/homebrew/opt/php@7.4/lib/httpd/modules/libphp7.so"
    php_8_1_path="php_module /opt/homebrew/opt/php@8.1/lib/httpd/modules/libphp.so"
    php_8_2_path="php_module /opt/homebrew/opt/php@8.2/lib/httpd/modules/libphp.so"

    php_conf_file="/opt/homebrew/etc/httpd/php.conf"
    php_conf_backup="/opt/homebrew/etc/httpd/php_conf_file.backup"

    # Function to update the php.conf file with the correct PHP version
    update_php_conf() {
        php_version="$1"
        php_module_path=""

        case "$php_version" in
            7.4)
                php_module_path="$php_7_4_path"
                ;;
            8.1)
                php_module_path="$php_8_1_path"
                ;;
            8.2)
                php_module_path="$php_8_2_path"
                ;;
            *)
                echo "Invalid PHP version specified."
                exit 1
                ;;
       
    esac

        cp "$php_conf_backup" "$php_conf_file"  # Restore the original php.conf file
        sed -i '' "s|#{php_module_path}|$php_module_path|" "$php_conf_file"
    }

    # Usage: switch_php_version <version>
    switch_php_version() {
        desired_version="$1"

        # Use Brew to switch the PHP version
        brew unlink php
        brew link --overwrite --force "php@$desired_version"

        # Backup the original php.conf file (if not already done)
        if [ ! -f "$php_conf_backup" ]; then
            cp "$php_conf_file" "$php_conf_backup"
        fi

        # Update the php.conf file with the correct PHP version
        update_php_conf "$desired_version"

        # Restart Apache
        apachectl restart
    }

    # Usage example: ./switch-php.sh 8.2
    switch_php_version "$1"

And here's the other change that needs to be made to the file php_conf_file.backup:

LoadModule #{php_module_path}
<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

I hope you find this useful!

Cheers.

DevAdmin
  • 13
  • 3