質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.61%

web(php)でgpioの操作を教えてほしい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,884

score 13

前提・実現したいこと

ラズパイにnginx,phpを導入し、web上からgpioを操作したいです。
web→php→python→gpio→Lチカ

助けていただけるととても助かります。どうぞよろしくおねがいします。

発生している問題・エラーメッセージ

下記を確認したところ、webからgpioを制御しようとしてもLチカができない
(おそらくlinuxのgpioの権限の問題)

試したこと

php→pythonのtestファイルを作成し、web上からの動作確認済(ここの連携は問題なし)
web→php→pythonによる表示は問題なし。

プロンプト上でphpを起動し、pyファイルを呼び出し、Lチカすることを確認。
php→python→gpio→Lチカも問題なし

nginxのユーザ www-dataであることを確認し、gpioのグループに追加。
追加されたことを確認済。

コード

php

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>LedTest</title>
</head>
<body>
<?php
if(isset($_POST["start"])) {
        echo "LED Light ON";
        $path ='sudo python /var/www/html/ledStart.py';
        exec($path);

}
else if(isset($_POST["stop"])) {
        echo "LED Light OFF";
        $path ='sudo python /var/www/html/ledStop.py';
        exec($path);

}

?>
<form method="POST" action="">
<input type="submit" value="start" name="start"> 
<input type="submit" value="stop" name="stop"> 
</form>
</body>
</html>

python(ledStart.py)

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)

GPIO.output(25, True)

python(ledStop.py)

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)

GPIO.output(25, False)
GPIO.cleanup()

LEDはgpio25番に接続しています。

補足情報(FW/ツールのバージョンなど)

はじめて投稿させていただきます。
心優しい方、どうぞよろしくおねがいします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+3

WEBサーバーであるnginxを経由し、PHPスクリプト内でsudoコマンドを実行するときにはwww-dataユーザーで実行されるため、sudoコマンドの実行で失敗していると思います。その場合、/var/log/auth.logに恐らく以下のようなエラーログが出力されているはずです。

Mar 25 11:31:33 raspberrypi sudo: pam_unix(sudo:auth): conversation failed
Mar 25 11:31:33 raspberrypi sudo: pam_unix(sudo:auth): auth could not identify password for [www-data]

もし上記があたっているとしたら、www-dataユーザーがsuコマンドを正しく実行でき、pythonスクリプトを実行できるようにする必要があります。具体的には、visudoコマンドで/etc/sudoersファイルを編集し、www-data ユーザーが sudo を使用して /usr/bin/python3を実行できるようにします。

以下は、質問者さんのような状況でwww-dataユーザーがsudoコマンドを実行できるようsudoersファイルを修正した例です。/etc/sudoers ファイルをcatコマンドで表示しています。

root@raspberrypi:/etc# cat /etc/sudoers
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults        env_reset
Defaults        mail_badpass
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification
root    ALL=(ALL:ALL) ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

# See sudoers(5) for more information on "#include" directives:

Cmnd_Alias LEDSTART_CMD = /usr/bin/python3 /var/www/html/ledStart.py
Cmnd_Alias LEDSTOP_CMD = /usr/bin/python3 /var/www/html/ledStop.py

#includedir /etc/sudoers.d
pi ALL=(ALL) NOPASSWD: ALL
www-data ALL=(ALL) NOPASSWD: LEDSTART_CMD, LEDSTOP_CMD
root@raspberrypi:/etc#

下の方で www-data ALL=(ALL) NOPASSWD: LEDSTART_CMD, LEDSTOP_CMD と記述して、www-dataユーザーがパスワード無しで、/usr/bin/python3 /var/www/html/ledStart.py (と ledStop.py)を実行できるように指定しています。コマンドはフルPATHで指定する必要があるので pythonではなく、/usr/bin/python3とします。またLEDのON/OFFでpythonスクリプトファイルも違うので、Cmnd_Aliasでそれぞれ指定します。

WEBで検索するとwww-data ALL=(ALL) NOPASSWD: ALL のように簡単に修正する例が見つかりますが、上記のようにpythonコマンドだけでなく、なんでも実行できるようになってしまうので、セキュリティの観点からはお勧めできない指定だと思います。実験やテストではなく、実運用で使用する場合は危険ですので注意した方が良いかと思われます。(ラズパイであれば実験用だと思いますが)

visudo の使い方は検索すればいくらでも参考記事が見つかりますので割愛しますが、修正を間違えるとsuコマンドが使えなくなって致命的な状況になるのでご注意の上、使用してみてください。

この内容で当方のラズパイ1 modelBにてご提示のスクリプトとほぼ同等のものを使用し、GPIOでのLED 点灯/消灯ができました。質問者さんがご使用のラズパイ本体やraspbianは恐らくもっと新しいと思うので、異なるところもあるかもしれません。


追記しました:2019-03-25 15:04 

質問者さんのケースでは(恐らく)sudoerの問題だと思い、visudoコマンドでwww-dataユーザーをsudoさせるようにする回答をしましたが、別案のひとつとしてsudoコマンドを使用せず、/etc/sudoersの修正もせずにroot権限で実行する方法をご紹介します。

linuxにはSUID(Set User ID)と言う特殊なアクセス権があって、実行ファイルにこのアクセス権をセットすることでその実行ファイルのオーナー(所有者)の権限で実行することができます。

UNIX処方箋:- SUIDとは

これを利用して、/usr/bin/python3 /var/www/html/ledStart,pyを実行するC言語で作成したプログラムをPHPスクリプトから実行するようにすれば、sudoを使用しなくてもrootで/usr/bin/python3を実行し、GPIOを操作してLEDのON/OFFをすることができるようになります。

具体的には以下のようなsystem でプログラム内からpython3スクリプトを実行するC言語のプログラムを用意します。

#include <stdlib.h>

int main(int argc, char *argv[])
{
    system("/usr/bin/python3 /var/www/html/ledStart.py");

    return 0;
}


これをコンパイル(ビルド)して実行ファイルを作り、その実行ファイルのオーナーをrootにしてchmod u+s 実行ファイル名としてSUIDをセットします。

pi@raspberrypi ~ $ gcc -Wall led_start.c -o led_start
pi@raspberrypi ~ $ ls -l led_start
-rwxr-xr-x 1 pi pi 5478 Mar 25 14:34 led_start

pi@raspberrypi ~ $ sudo chown root:root led_start
pi@raspberrypi ~ $ ls -l led_start
-rwxr-xr-x 1 root root 5478 Mar 25 14:34 led_start

pi@raspberrypi ~ $ sudo chmod u+s led_start; ls -l led_start
-rwsr-xr-x 1 root root 5478 Mar 25 14:34 led_start
pi@raspberrypi ~ $

この実行ファイルが/home/pi/led_startだとして、PHPスクリプトの中から以下のように実行するとLEDが点灯します。www-dataユーザーでPHPスクリプトが実行されますが、sudoを使用しなくてもGPIOを制御できます。

# ...抜粋
if(isset($_POST["start"])) {
    echo "LED Light ON";
    #$path ='sudo python /var/www/html/ledStart.py';
    #$path ='sudo /usr/bin/python3 /var/www/html/ledStart.py';

    # SUID な/home/pi/led_startを実行する
    $path ='/home/pi/led_start';
    exec($path);
}

実験レベルではこんな使い方も有りかと思い、技術的な観点からご紹介させていただきました。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/25 22:11

    とても丁寧なご回答、ありがとうございます!

    はじめてでありましたが、質問させていただけてよかったです。

    ご指摘の通り、エラーログを発見いたしました。

    セキュリティの観点からのご指摘もくださり、大変助かりました!

    熟読、理解後、実装してみたいと思います!

    本当にありがとうございます。

    キャンセル

  • 2019/04/07 11:08

    先日www-dataに権限を付与したところ、機能しました!

    また、linuxの知識が不足していることにも気づかされました。

    dodox86さんの丁寧な解説のおかげで、また1つの勉強できたこと、大変感謝しています。

    ありがとうございます。

    キャンセル

  • 2019/04/07 11:46 編集

    経過のご報告ありがとうございます。お役に立てて良かったです。ラズパイだとlinuxでハードもつなげて色々試し易いので、色々いじってみると良いと思います。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る