php - 从 PHP 调用的 shell 脚本问题

标签 php shell command-line sh

长篇小说;

我有一个 shell 脚本,它在从命令行运行时工作正常,但如果从 PHP 脚本(通过 Web 访问)中调用则不行。

在这两种情况下,调用用户都是 www-data

失败的行是这样的:

openssl genrsa -des3 -out certs/$PCODE.key -passout env:PASSPHRASE 2048

为什么会这样?我该如何调试它?

全文

我有以下脚本,它是 this gist 的略微修改版本用于生成自签名 SSL 证书。

当我从终端以 www-data 运行它时,它工作正常并生成 key 文件、CSR 和 SSL 证书文件。但是当我从 PHP 脚本中调用脚本时,它会输出错误并且不会生成任何文件。是什么导致失败?我该如何调试?

来自终端:

 me@machine$ sudo su www-data  
 www-data@machine$ ./gencert.sh acme  
 www-data will generate an SSL cert for acme.dev  
 Command after line 32 executed oK  
 Passphrase expoted as I7gOnWxWd0hOk38Zu ... FbxL3K3Rzlv  
 Generating RSA private key, 2048 bit long modulus  
 ..............................................+++  
 .................+++  
 e is 65537 (0x10001)  
 Command after line 49 executed oK  
 Command after line 54 executed oK  
 Command after line 65 executed oK  
 writing RSA key  
 Command after line 69 executed oK  
 Signature ok  
 subject=/C=IR/ST=Alborz/.../emailAddress=noreply@acme.dev  
 Getting Private key  
 Command after line 74 executed oK

结果文件:

  • certs/acme.key.org
  • certs/acme.key
  • certs/acme.csr
  • certs/acme.crt

来自 PHP:

$r = `/var/www/testbench/pm/shell/gencert.sh acme`;
echo $r;

没有生成文件,输出是这样的:

www-data will generate an SSL cert for acme.dev
Command after line 32 executed oK
Passphrase expoted as 1Fd1seZoe2XF ... oSmQFJdVpdwOeTo2CK5VjLxp
Error. Return value = 1 after line 49 

返回 1 的行是这样的:
openssl genrsa -des3 -out certs/$PCODE.key -passout env:PASSPHRASE 2048

修改后的 shell 脚本如下:

#!/bin/bash

# Bash shell script for generating self-signed certs. Run this in a folder, as it
# generates a few files. Large portions of this script were taken from the
# following artcile:
# 
# http://usrportage.de/archives/919-Batch-generating-SSL-certificates.html
# https://deliciousbrains.com/ssl-certificate-authority-for-local-https-development/
# Additional alterations by: Brad Landers
# Date: 2012-01-27

# Script accepts a single argument, the fqdn for the cert
PCODE="$1"
if [ -z "$PCODE" ]; then
  echo "Usage: $(basename $0) <PCODE>"
  exit 11
fi

THE_USER="$(whoami)"
echo "$THE_USER will generate an SSL cert for $PCODE.dev"

fail_if_error() {
  [ $1 != 0 ] && {
    echo -n "Error. Return value = $1 after line $LASTLINE"
    unset PASSPHRASE
    exit 10
  }
  echo "Command after line $LASTLINE executed oK"
}

# Generate a passphrase
LASTLINE="${LINENO}"
export PASSPHRASE=$(head -c 500 /dev/urandom | tr -dc a-z0-9A-Z | head -c 128; echo)
fail_if_error $?
echo -n "Passphrase expoted as "
printenv PASSPHRASE

# Certificate details; replace items in angle brackets with your own info
subj="
C=IR
ST=Alborz
O=ACME
localityName=Karaj
commonName=*.$PCODE.dev
organizationalUnitName=WebAdmin
emailAddress=noreply@$PCODE.dev
"

LASTLINE="${LINENO}"
# Generate the server private key
openssl genrsa -des3 -out certs/$PCODE.key -passout env:PASSPHRASE 2048
fail_if_error $?

LASTLINE="${LINENO}"
# Generate the CSR
openssl req \
    -new \
    -batch \
    -subj "$(echo -n "$subj" | tr "\n" "/")" \
    -key certs/$PCODE.key \
    -out certs/$PCODE.csr \
    -passin env:PASSPHRASE
fail_if_error $?

LASTLINE="${LINENO}"
cp certs/$PCODE.key certs/$PCODE.key.org
fail_if_error $?

LASTLINE="${LINENO}"
# Strip the password so we don't have to type it every time we restart Apache
openssl rsa -in certs/$PCODE.key.org -out certs/$PCODE.key -passin env:PASSPHRASE
fail_if_error $?

LASTLINE="${LINENO}"
# Generate the cert (good for 10 years)
openssl x509 -req -days 3650 -in certs/$PCODE.csr -signkey certs/$PCODE.key -out certs/$PCODE.crt
fail_if_error $?

最佳答案

您要执行的命令具有相对路径,例如:certs/$PCODE.key。当您执行命令时(在本例中通过反引号运算符),路径会相对于 PHP 进程的当前工作目录展开。这很少(如果有的话)与您的命令 shell 使用的路径相同。

要调试它,您可以使用 strace 扩展您的实际命令,例如:strace openssl ...。这将为您提供大量诊断信息,并且在接近尾声时,您会看到类似 EPERM 的内容。

要解决这个问题,您可以在 PHP 中使用 chdir 来设置当前工作目录,或者您可以在脚本中使用 cd,或者您的脚本可以使用绝对目录路径。我更喜欢后者。

关于php - 从 PHP 调用的 shell 脚本问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46731913/

相关文章:

javascript - Laravel 5.8 从空值创建默认对象

shell - 如何在脚本中的特定字符后插入新行

php - 我应该使用哪种排序规则在 MySQL 中存储这些国家/地区名称?

php - 两个 wordpress 站点在同一个数据库上使用不同的主题

linux - 使用 grep 查找两个大词表之间的差异

git - 如何解压打包引用?

Python 不能在 git bash 的命令行中工作

java - 如何在 Windows 上创建一个 jar 文件?

php - PHP 中通过引用传递调用时间的解决方法?

java - 如何从java捕获错误并打印c程序触发器的流