1

I am trying to read some variables from a php config file using bash & it is working for the most part, but I am having issues trying to use the values passed back.
The variuable is found in config, but when it is passed back it still has the single or double quotes from PHP around it.

Here is what I am using.

DBPASS="$(grep -oE '\$database_password = .*;' $CONFIG | tail -1 | sed 's/$database_password = //g;s/;//g')"

now, the variables may be wrapped in either single or double quotes AND a single quote may be present in a password field. So I can't just strip all of them out.

any idea how to do this?

UPDATE

So going another way with this, I have added a bit to the bash script (which basically backs up a CMS) that will look for and write a little PHP "helper". That helper will just read the config, build an array & pass it back to the bash script.

HELPER="backup-helper.php";

CONFIG="../core/config/config.inc.php"

if [ ! -f "$HELPER" ]; then
    echo '<?php' >> $HELPER;
    echo '$config = "$argv[1]";' >> $HELPER;
    echo 'include_once($config);' >> $HELPER;
    echo 'echo $dbase;' >> $HELPER; 
    echo 'echo $modx_core_path;' >> $HELPER;

    echo 'return "this";' >> $HELPER;
    chmod 755 $HELPER;

    php $HELPER  $CONFIG;
fi

So this is basically just looking for the helper files & creating it if it does not exist, then runs it to test - this all works.

I can easily add the logic to create an array of what I need from the config file, but:

how do I format it (the array to be passed back) so that bash will understand it? how do I pass it (the array) back to bash? (basically how do I tell bash to expect a return value?)

4
  • None of the things you're doing in that pipeline would be problematic in pure PHP. What about just pulling $CONFIG into an array with file() and processing it natively? Commented May 2, 2018 at 20:06
  • I'm trying to read the PHP variables into a bash shell script not doing anything with PHP, just reading a CMS config file so bash can run an automatic update. Commented May 2, 2018 at 20:17
  • If you needed these values in a PHP script, I'd suggest using a PHP function to include() the file, then cherry-pick the variable(s) you want (in an array if there's more than one) that gets passed back as the return value of the function. But if you really are trying to extract PHP variable values for use in a shell script, I'll put some options into an answer. Commented May 3, 2018 at 3:52
  • Related: stackoverflow.com/questions/2464760/… Commented Jul 23, 2022 at 18:19

1 Answer 1

6

If you're feeling lucky, something like this:

eval $(sed -Ene '/^\$database_(username|password)/{s/ = /=/;s/^\$//;s/;$//;p;}' config.php)

I'll just say here that you absolutely shouldn't do this, it's a bad idea, and I only included as a counterexample. You WILL eventually shoot yourself in the foot if you write shell scripts like this.

Something like this would be safer:

db_username="$(php -r 'include("config.php"); print $database_username;')"
db_password="$(php -r 'include("config.php"); print $database_password;')"

Of course, it depends on having a PHP interpreter around to handle the reading and parsing of the PHP script. If that just isn't possible, then you run the risk of writing your shell-based PHP interpreter in a way that isn't fully compliant with how PHP interprets PHP scripts. Buyer beware, may contain nuts, etc.

You could do something really ugly like this:

#!/usr/bin/env bash

shopt -s extglob

while read -r line; do
  #echo "line = $line"
  case "$line" in
    '$database_username = '*|'$database_password = '*)
      output="${line#\$database_+([[:alpha:]]) = }"
      output="${output#\"}"     # strip leading double quote
      output="${output%\";}"    # strip trailing double quote and semicolon
      ;;
  esac
  case "$line" in
    '$database_username = '*)
      db_username="$output"
      ;;
    '$database_password = '*)
      db_password="$output"
      ;;
  esac
done < config.php

printf 'u = %s\np = %s\n' "$db_username" "$db_password"

This has the advantage of NO PIPELINES, all its functionality is self-contained within a bash script. But it will break if your config.php contains spaces trailing the semicolon, or spaces before the semicolon, or lines broken and continued with escaped newlines, or variables that are built over multiple lines with things like $database_password .= "MOAR"; or any number of other things that might be perfectly valid PHP.

My strong preference is Door Number Two, using a PHP interpreter to interpret your PHP.


UPDATE

If your PHP configuration is in an array (as with Drupal, for example), you might be able to export that array to bash with something like the following:

declare -A conf
while IFS== read -r -d '' key value; do
  conf["$key"]="$value"
done < <( php -r 'include("config.php"); foreach ($conf as $key => $value) printf("%s=%s\0",$key,$value);')'

This uses bash process to provide a dump of the PHP array in a format that can safely be read by bash's read command. This might be advantageous if you have A LOT of things you want to read from your PHP config, and you only want to launch PHP once rather than for every value you're fetching.

Note that you might have to adjust this if any of your keys contain an equals sign. Also, associative arrays are a feature of bash 4.

Sign up to request clarification or add additional context in comments.

6 Comments

plus one for the php -r approach. That's imo the right way to do it, at least for a production solution.
Sort of going another way on this one - see my updated question
@SeanKimball, no edit is showing. Did you create a new question?
Your solution looks good, if I had control over the format of the config file, unfortunately, I do not. can't guarantee spaces or even single/double quotes around values. Hence the 'helper file'
So .. you've asked a NEW question in the form of an update to your existing question. My answer to your new question is the "door number two" in my existing answer. Let PHP parse the PHP. But you don't need a helper app. Just do what I suggested using php -r.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.