从PHP调用shell脚本出现问题

4

TLDR;

我有一个 shell 脚本,在命令行中运行良好,但从 PHP 脚本(通过 web 访问)调用时出现问题。

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

导致失败的行是:

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

为什么出现这种情况?我该如何进行调试?

完整的故事

我有以下脚本,它是一个稍微修改过的版本,用于生成自签名 SSL 证书:这里

当我在终端运行它时,作为www-data,它可以正常工作并生成密钥文件、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 $?

1
我敢打赌PHP在特权当前工作目录下运行,因为失败的命令包含相对路径:certs/$PCODE.key。如果将其改为绝对路径会发生什么?或者,你可以在PHP中执行chdir('/tmp/')吗? - bishop
1
@Fred-ii- 请查看 http://php.net/manual/zh/language.operators.execution.php,反引号用于执行 shell 命令,我相信 OP 正试图这样做。 - mega6382
@mega6382 我改口了。 - Funk Forty Niner
http://php.net/manual/zh/function.error-reporting.php << “我怎么调试?” @mega6382 然而,我的错误评论的后半部分依然站得住脚。 - Funk Forty Niner
1
@bishop 尖叫!我刚刚将所有路径转换为绝对路径,并且已经执行了一个命令(在第49行之后执行的命令已成功执行 错误。在第54行之后返回值=1)。我很快会更新我的问题。 - Majid Fouladpour
显示剩余3条评论
1个回答

3
您要执行的命令使用了相对路径,例如:certs/$PCODE.key。当您在执行命令时(通过反引号操作符),这些路径会相对于PHP进程的当前工作目录进行扩展。而这个工作目录通常不是您的命令行使用的相同路径。
为了调试这个问题,您可以使用strace扩展实际命令,例如:strace openssl ...。这将为您提供大量的诊断信息,在最后,您会看到类似于EPERM的内容。
要解决此问题,您可以在PHP中使用chdir设置当前工作目录,或者在脚本中使用cd命令,或者您的脚本可以使用绝对路径。我更喜欢后者。

1
希望我可以给这个点赞超过一次。接受将会跟随 :) - Majid Fouladpour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接