#!/bin/bash
### Copyright 1999-2017. Parallels IP Holdings GmbH. All Rights Reserved.
#

#
# Plesk script
#


### Copyright 1999-2017. Parallels IP Holdings GmbH. All Rights Reserved.

### Copyright 1999-2017. Parallels IP Holdings GmbH. All Rights Reserved.

php_module_extract_name()
{
	local config="$1"
	local state="${2:-}"  # "", enabled, disabled

	local prefix=""
	[ ! "$state" = "enabled" ] || prefix='^\s*'
	[ ! "$state" = "disabled" ] || prefix='^\s*;\s*'

	perl -nle 'print $2 if /'"${prefix}"'(?:zend_|)extension\s*=\s*([\"'"\'"']?)(.*)\.so\1/' "$config"
}

php_module_is_enabled()
{
	local config="$1"
	local ext_s="$2"
	php_module_extract_name "$config" 'enabled' | grep -q "^$ext_s\$"
}

php_module_is_disabled()
{
	local config="$1"
	local ext_s="$2"
	php_module_extract_name "$config" 'disabled' | grep -q "^$ext_s\$"
}

php_module_enable()
{
	local config="$1"
	local ext_s="$2"
	perl -pi -e 's#^\s*;\s*((?:zend_|)extension\s*=\s*([\"'"\'"']?)'"${ext_s}"'.so\2)#\1#g' "$config"
}

php_module_disable()
{
	local config="$1"
	local ext_s="$2"

	perl -pi -e 's#^\s*((?:zend_|)extension\s*=\s*([\"'"\'"']?)'"${ext_s}"'.so\2)#; \1#g' "$config"
}

# vim:ft=sh:
#!/bin/bash
### Copyright 1999-2017. Parallels IP Holdings GmbH. All Rights Reserved.
# vim:ft=sh:

option_error()
{
	err "$@"
	err ""
	usage
}

err()
{
	echo "$@" >&2
}

debug()
{
	if [ $_V -ge 1 ]; then
		echo "debug: $*" >&2
	fi
}

usage()
{
cat << EOT >&2
Usage: $prog [OPTIONS]
	-p,--php-cli				Appropriate PHP cli for operations. Mandatory.
	-c,--php-ini				php.ini config for operations. Mandatory.
	-l,--list					Display extensions availiable for load
	-e,--enable=ext				Enable specified extension. Can be specified several times.
	-d,--disable=ext			Disable specified extension. Can be specified several times.
	-v,--verbose				Be more verbose.
	-h,--help					Display this message.
EOT
exit 1
}

get_extension_type()
{
# Check got from ext/standard/dl.c. But may be we should attempt to load via dl or -d
# However, dl can be disabled, and failure of load in -d doesn't cause php to return 1

	local ext_file="$extension_dir/$1.so"

	if readelf -s --wide "$ext_file" | awk '{print $8}' | grep -q -E '^(_|)zend_extension_entry$'; then
		debug "$ext_file: zend_extension detected"
		echo "zend_extension"
		return
	elif readelf -s --wide "$ext_file" | awk '{print $8}' | grep -q -E '^(_|)get_module$'; then
		debug "$ext_file: common_extension detected"
		echo "extension"
		return
	else
		debug "$ext_file: not a php extension"
		echo ""
	fi
}

find_config()
{
	local ext="$1"
	for c in `get_configs`; do
		php_module_extract_name "$c" | xargs -n1 basename | grep -q "^$ext\$" || continue
		echo $c
		return
	done
}

enmod()
{
	local ext="$1"
	if [ -z "$ext" ]; then
		err "empty extension specified"
		return 1
	fi

	local config=$(find_config "$ext")
	local ext_s="$ext"
	local ext_type=$(get_extension_type "$ext")

	if [ -z "$config" ]; then
		err "cannot find config for extension '$ext'"
		return 1
	fi

	if [ "$ext_type" != "extension" -a "$ext_type" != "zend_extension" ]; then
		err "$ext: invalid extension format - not a PHP library"
		return 1
	fi

	if [ "$ext_type" = "zend_extension" ]; then
		ext_s="$extension_dir/${ext}"
	fi

# if extension enabled in config?
	if php_module_is_enabled "$config" "$ext"; then
		debug "$ext (${ext}.so) already enabled in $config, do nothing"
		return 0
	fi

	if [ "$ext_type" = "zend_extension" ] && php_module_is_enabled "$config" "$ext_s"; then
		debug "$ext (${ext_s}.so) already enabled in $config, do nothing"
		return 0
	fi

	if php_module_is_disabled "$config" "$ext"; then
		debug "$ext (${ext}.so) disabled in $config, switch it on"
		php_module_enable "$config" "$ext"
		return 0
	fi

	if [ "$ext_type" = "zend_extension" ] && php_module_is_disabled "$config" "$ext_s"; then
		debug "$ext (${ext_s}.so) disabled in $config, switch it on"
		php_module_enable "$config" "$ext_s"
		return 0
	fi

	debug "$ext is not found in $config, add new line"
	echo "${ext_type}=${ext_s}.so" >> "$config"
	return 0
}

dismod()
{
	local ext="$1"
	if [ -z "$ext" ]; then
		err "empty extension specified"
		return 1
	fi

	local config=$(find_config "$ext")
	local ext_s="$ext"
	local ext_type=$(get_extension_type "$ext")

	if [ -z "$config" ]; then
		err "cannot find config for extension '$ext'"
		return 1
	fi

	if [ "$ext_type" != "extension" -a "$ext_type" != "zend_extension" ]; then
		err "$ext: invalid extension format - not a PHP library"
		return 1
	fi

	if [ "$ext_type" = "zend_extension" ]; then
		ext_s="$extension_dir/${ext}"
	fi

# if extension enabled in config?

	if php_module_is_disabled "$config" "$ext"; then
		debug "$ext ($ext) already disabled in $config, do nothing"
		return 0
	fi

	if [ "$ext_type" = "zend_extension" ] && php_module_is_disabled "$config" "$ext_s"; then
		debug "$ext (${ext_s}.so) already disabled in $config, do nothing"
		return 0
	fi

	if php_module_is_enabled "$config" "$ext"; then
		debug "$ext (${ext}.so) enabled in $config, switch it off"
		php_module_disable "$config" "$ext"
	fi

	if [ "$ext_type" = "zend_extension" ] && php_module_is_enabled "$config" "$ext_s"; then
		debug "$ext (${ext_s}.so) enabled in $config, do switch it off"
		php_module_disable "$config" "$ext_s"
		return 0
	fi

	return 0
}

enable_extensions()
{

	[ -n "$1" ] || return 0

	if check_native_debian_php; then
		$debian_mods_enmod_bin "$@"
		return $?
	fi

	for i in "$@"; do
		if ! enmod $i; then
			err "Cannot enable extension '$i'"
			return 1
		fi
	done
}

disable_extensions()
{
	[ -n "$1" ] || return 0

	if check_native_debian_php; then
		$debian_mods_dismod_bin "$@"
		return $?
	fi

	for i in "$@"; do
		if ! dismod $i; then
			err "Cannot disable extension '$i'"
			return 1
		fi
	done
}

check_native_debian_php()
{

	if [ -n "${debian}" ]; then
		return $debian
	fi

	debian=1

	php_bin="`readlink -e $php_cli`"

	if [ -x "/usr/sbin/php5enmod" -a "$php_bin" = "/usr/bin/php5" ]; then
		debian=0
		debian_mods_availiable_dir="/etc/php5/mods-available"
		debian_mods_enmod_bin="/usr/sbin/php5enmod"
		debian_mods_dismod_bin="/usr/sbin/php5dismod"
		return $debian
	fi

	if [ -x "/usr/sbin/phpenmod" -a "$php_bin" = "/usr/bin/php7.0" ]; then
		debian=0
		debian_mods_availiable_dir="/etc/php/7.0/mods-available"
		debian_mods_enmod_bin="/usr/sbin/phpenmod"
		debian_mods_dismod_bin="/usr/sbin/phpdismod"
		return $debian
	fi

	return "$debian"
}

get_configs()
{
	if ! check_native_debian_php; then
		_get_configs
		return
	fi

# On debian, we have separate configs for enabled and disabled extensions.
	if [ "$1" = "enabled" ]; then
		_get_configs
		return
	fi

	{
		_get_configs
		ls $debian_mods_availiable_dir/*.ini
	} | xargs -n1 readlink -f | sort -u
}

_get_configs()
{
	$php_cli -c $php_ini -r 'print(php_ini_scanned_files());' | tr ',' '\n' | sort -u | grep -v '^$'
	echo $php_ini
}

have()
{
	if [ -z "$1" ]; then
		err "Error: not enough argument for have function"
		return 1
	fi

	local item=$1
	shift
	for i in "$@"; do
		if [ "$item" = "$i" ]; then
			return 0
		fi
	done
	return 1
}

list_extensions()
{
# First get enabled extensions/zend_extensions
	declare -a got_extensions=()
	local ext configs_enabled
	configs_enabled=$( for c in `get_configs "enabled"`; do
		php_module_extract_name "$c" enabled;
	done )
	for line in $configs_enabled; do
		[ -n "$line" ] || continue
		[ -f "$extension_dir/${line}.so" -o -f "${line}.so" ] || continue
		ext=`basename $line`
		got_extensions+=( $ext )
		echo "$ext on"
	done

# Now get disabled extensions/zend_extensions, need to check existance of file
	for c in `get_configs`; do
		php_module_extract_name "$c";
	done | while read line; do
		[ -n "$line" ] || continue
		[ -f $extension_dir/${line}.so -o -f ${line}.so ] || continue
		have "$(basename $line)" ${got_extensions[*]} && continue || :
		echo "`basename $line` off"
	done
}

prog="`basename $0`"

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
umask 022

TEMP=`getopt -o vhlp:c:e:d: --long help,verbose,php-cli:,php-ini:,list,enable:,disable: \
     -n "$prog" -- "$@"`

if [ $? != 0 ]; then
	echo "Internal Error: getopt cannot parse this command line: $@" >&2
	exit 1
fi

declare -a ext_enable=()
declare -a ext_disable=()
list_cmd=""

_V=0
eval set -- "$TEMP"
while true ; do
	case "$1" in
		-p|--php-cli) php_cli="$2";shift 2;;
		-c|--php-ini) php_ini="$2";shift 2;;
		-e|--enable) ext_enable+=( $2 ); shift 2;;
		-d|--disable) ext_disable+=( $2 ); shift 2;;
		-l|--list) list_cmd="1"; shift;;
		-v|--verbose) let _V++; shift;;
		-h|--help) usage ;;
		--) shift ; break ;;
		*) echo "Unknown option '$1'" ; exit 1 ;;
	esac
done

if [ -z "$php_cli" ]; then
	option_error "No php cli (--php-cli) specified"
fi

if [ ! -x "$php_cli" ]; then
	option_error "PHP cli ($php_cli) should be executeable"
fi

if [ -z "$php_ini" ]; then
	option_error "No php ini (--php-ini) specified"
fi

if [ ! -f "$php_ini" ]; then
	option_error "PHP ini ($php_ini) doesn't exist, or not a file"
fi

extension_dir=$("$php_cli" -c "$php_ini" -r 'print(ini_get("extension_dir"));')

if [ -z "$extension_dir" -o ! -d "$extension_dir" ]; then
	option_error "Extension dir \"$extension_dir\" is empty or not directory"
fi

if [ -z "$list_cmd" -a "${#ext_enable[@]}" -eq 0 -a "${#ext_disable[@]}" -eq 0 ]; then
	option_error "No action specified"
fi

if [ -n "$list_cmd" ] && ! [ "${#ext_enable[@]}" -eq 0 -a "${#ext_disable[@]}" -eq 0 ]; then
	option_error "You cannot use --list and --enable/--disable simultaneously"
fi

if [ -n "$list_cmd" ]; then
	list_extensions
	exit $?
fi

enable_extensions ${ext_enable[*]} && disable_extensions ${ext_disable[*]}
