PHP и COM-порт: читаем данные с устройства через exec
Когда это нужно
Иногда legacy-система написана на PHP и нужно добавить чтение данных с COM-порта — например, с весов или сканера штрихкодов. Переписывать всё на Python нет времени.
Настройка порта через stty
Перед чтением нужно настроить параметры порта:
stty -F /dev/ttyUSB0 9600 cs8 -cstopb -parenb raw
Это можно сделать прямо из PHP:
exec('stty -F /dev/ttyUSB0 9600 cs8 -cstopb -parenb raw');
Чтение данных
$port = fopen('/dev/ttyUSB0', 'r+b');
if (!$port) {
throw new RuntimeException('Cannot open port');
}
stream_set_timeout($port, 2);
$data = fread($port, 256);
fclose($port);
echo trim($data);
Права доступа
Пользователь www-data должен быть в группе dialout:
sudo usermod -aG dialout www-data
sudo systemctl restart php8.2-fpm
Через Python как посредник
Лучший вариант для сложных протоколов — написать маленький Python-скрипт и вызывать его из PHP:
$output = shell_exec('/usr/bin/python3 /srv/scripts/read_scale.py 2>&1');
$weight = json_decode($output, true)['weight'];
Так PHP остаётся веб-слоем, а Python занимается работой с железом.
Безопасность
Никогда не передавай пользовательский ввод напрямую в exec/shell_exec. Всегда валидируй через escapeshellarg(). Лучше вообще не использовать пользовательские данные в системных командах.