解決php中通過exec呼叫python指令碼報ModuleNotFoundError錯誤

2023-07-17 12:01:33

背景

出於某些原因,我們有時會在PHP中通過exec來呼叫Python程式碼,有可能是某些功能只能用Python實現(或用Python實現比較方便),有可能是出於效能考慮(Python可以執行耗時任務)。

但我們有時會發現,在控制檯用命令列的方式執行python指令碼一切正常,在 php 中用 exec 呼叫就報 ModuleNotFoundError: No module named 'xxx' 錯誤。

本文是在 Ubuntu 20.04 上以 ubuntu 使用者身份進行的測試。

錯誤原因

使用者不同

這種錯誤一般都是因為執行指令碼的使用者不同導致的,php用exec呼叫python指令碼時,使用的使用者一般是 www-data,而我們在控制檯一般都是 rootubuntu 使用者。

這個可以通過 whoami 命令來驗證。

php程式碼如下:

$pythonScript = "whoami";
Log::info("exec script:" . $pythonScript);
exec($pythonScript, $output, $returnValue);
Log::info("exec output:" . json_encode($output));
Log::info("exec returnValue:" . $returnValue);

輸出如下:

[2023-07-13 10:34:27] local.INFO: exec script:whoami  
[2023-07-13 10:34:27] local.INFO: exec output:["www-data"]  
[2023-07-13 10:34:27] local.INFO: exec returnValue:0  

為什麼使用者不同就會導致 ModuleNotFoundError: No module named 'xxx' 這個錯誤呢,根本原因還是許可權問題。

許可權問題

我們在控制檯寫python指令碼時,一般會通過 pip[3] install [xxx]的形式安裝依賴的包,這時包一般會安裝在使用者目錄。

下面做個測試,我們安裝 python-dotenv這個包,然後檢視包的安裝位置:

可以看到這個包安裝在了 /home/ubuntu/.local/lib/python3.8/site-packages 這個目錄。

下面我們試一下用 www-data 使用者的身份是否有許可權呼叫。

Python測試程式碼:

from dotenv import load_dotenv

load_dotenv()

分別用當前使用者和www-data呼叫:

可以看到用www-data呼叫時果然報ModuleNotFoundError: No module named 'dotenv'錯誤。

我們檢視一下我們安裝的python-dotenvwww-data使用者是否可用:

sudo -u www-data pip3 show python-dotenv

可以看到確實是沒有的。

即然原因確定了,接下來就好辦了。

解決方案

方案一:修改web伺服器使用者

即然是控制檯使用者可以執行指令碼,我們把Web伺服器使用者改為控制檯使用者就可以了,以 apache 為例具體步驟如下:

1.開啟apache組態檔:sudo vim /etc/apache2/apache2.conf

2.更改以下兩行,將執行的使用者和組設定為自己所需的:

User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
#更改為
User ubuntu
Group ubuntu

3.重啟apache:sudo service apache2 restart

注:這種方案能解決問題,但並不好,因為許可權給的太大了,有很大的安全風險,不建議用。

方案二:給 www-data 使用者安裝python依賴庫

在安裝之前我們確認一下www-data使用者是否沒有安裝python-dotenv包:

sudo -u www-data pip3 show python-dotenv

下面我們給 www-data 使用者安裝python-dotenv包:

#安裝
sudo -u www-data pip3 install python-dotenv

#顯示安裝路徑
sudo -u www-data pip3 show python-dotenv

我們可以看到,安裝到了 /var/www/.local/lib/python3.8/site-packages目錄下。

我們來驗證一下:

sudo -u www-data python3 pyscripts/test.py

可以看到不報錯了。

大家還有別的方案嗎?歡迎留言討論。