树莓派PHP配置WiFi时RECONFIGURE命令超时问题求助
树莓派无头系统WiFi配置问题排查与修复方案
问题背景
在64位无头树莓派上搭建开机WiFi检测系统:有WiFi连接时全屏打开指定网页;无连接时启用AP模式,通过Apache+PHP搭建的本地站点扫描WiFi,提交密码后修改wpa_supplicant-wlan0.conf配置。终端执行sudo wpa_cli -i wlan0 reconfigure正常,但PHP端执行时出现**'RECONFIGURE命令超时'**错误。要求保留Pi与设备的AP连接,已排除重启WiFi方案,寻求代码修复或替代的连接检测方案。
现有脚本代码
扫描WiFi的PHP脚本
<?php $result = shell_exec('sudo iwlist wlan0 scan'); $networks = explode('Cell', $result); unset($networks[0]); $data = []; $cachedNetworks = []; foreach ($networks as $item) { $pattern = '/Address:(.*?)Channel:(.*?)Frequency:(.*?)GHz.*?Quality=(.*?)\/(.*?) Signal level=(.*?) dBm.*?ESSID:"(.*?)"/s'; preg_match($pattern, $item, $matches); if ((!in_array($matches[7], $cachedNetworks)) && ($matches[7] != '')) { $cachedNetworks[] = $matches[7]; $data[] = array( 'Address' => trim($matches[1]), 'Channel' => trim($matches[2]), 'Frequency' => trim($matches[3]), 'Quality' => trim($matches[4]), 'MaxQuality' => trim($matches[5]), 'SignalLevel' => trim($matches[6]), 'ESSID' => trim($matches[7]) ); } } echo json_encode($data, true);
配置WiFi的PHP脚本
<?php $psk = $_GET["password"]; $response['success'] = false; $fileContent = "country=DE ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid=\"" . $_GET['ssid'] . "\" psk=\"" . $_GET['password'] . "\" key_mgmt=WPA-PSK }"; // 检查路径并确保文件可写 $filePath = '/etc/wpa_supplicant/wpa_supplicant-wlan0.conf'; if (is_writable($filePath)) { // 覆盖文件 file_put_contents($filePath, $fileContent); $response['response'] = "文件已成功覆盖。"; } else { $response['response'] = "无法覆盖文件,请检查文件权限。"; return; } // 检查连接状态 $t = exec("sudo wpa_cli -i wlan0 reconfigure"); $output = shell_exec("/sbin/iwconfig wlan0"); if (strpos($output, 'Frequency:') !== false) { $response['success'] = true; $response['response'] = "已连接。T:" . $t . " 结果:" . $output; } else { $fileContent = "country=DE ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1"; file_put_contents($filePath, $fileContent); $response['response'] = "未连接。T:" . $t . " 结果:" . $output; } echo json_encode($response);
问题原因分析
- PHP执行超时限制:Apache的PHP进程默认执行超时较短,
wpa_cli reconfigure涉及WiFi协商,耗时可能超过限制导致被终止。 - 权限与环境差异:PHP以
www-data用户执行sudo,可能缺少终端环境中的权限或环境变量,导致命令执行异常。 - 连接检测逻辑不可靠:用
iwconfig的Frequency:字段判断连接状态不准确,部分连接场景下该字段可能不出现。
代码修复方案
1. 延长PHP脚本执行时间
在配置WiFi的脚本开头添加超时设置,给WiFi协商足够时间:
// 延长脚本执行时间至60秒,可根据实际情况调整 set_time_limit(60);
2. 优化wpa_cli执行方式,捕获完整输出
替换原exec调用为proc_open,捕获命令的输出和错误信息,便于排查问题:
$descriptorspec = [ 0 => ['pipe', 'r'], // 标准输入 1 => ['pipe', 'w'], // 标准输出 2 => ['pipe', 'w'], // 标准错误 ]; $process = proc_open('sudo wpa_cli -i wlan0 reconfigure', $descriptorspec, $pipes); $t = ''; if (is_resource($process)) { $output = stream_get_contents($pipes[1]); $errors = stream_get_contents($pipes[2]); fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); $returnCode = proc_close($process); $t = "退出码: $returnCode | 输出: $output | 错误: $errors"; } else { $t = "无法启动wpa_cli进程"; }
3. 替换连接检测逻辑,使用可靠方式
推荐两种更准确的检测方式:
方式一:用iwgetid检查关联SSID
$connectedSSID = trim(shell_exec('iwgetid wlan0 -r')); if (!empty($connectedSSID)) { $response['success'] = true; $response['response'] = "已成功连接到SSID: $connectedSSID | wpa_cli输出: $t"; } else { // 恢复默认配置 $fileContent = "country=DE ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1"; file_put_contents($filePath, $fileContent); $response['response'] = "连接失败,已恢复默认配置 | wpa_cli输出: $t"; }
方式二:用wpa_cli status获取连接状态
$wpaStatus = shell_exec('sudo wpa_cli -i wlan0 status'); if (strpos($wpaStatus, 'wpa_state=COMPLETED') !== false) { $response['success'] = true; $response['response'] = "连接成功 | wpa_cli状态: $wpaStatus"; } else { // 恢复默认配置 $fileContent = "country=DE ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1"; file_put_contents($filePath, $fileContent); $response['response'] = "连接失败,已恢复默认配置 | wpa_cli输出: $t"; }
4. 配置www-data用户免sudo密码
编辑sudoers文件(执行sudo visudo),添加以下内容,避免PHP执行sudo时需要输入密码:
www-data ALL=(ALL) NOPASSWD: /sbin/wpa_cli, /sbin/iwlist, /sbin/iwgetid
替代连接检测方案(异步执行)
如果wpa_cli reconfigure始终超时,可将配置验证逻辑放到Shell脚本中异步执行,避免PHP等待超时:
1. 创建Shell脚本(/usr/local/bin/wifi-config-test.sh)
#!/bin/bash SSID="$1" PSK="$2" CONF_FILE="/etc/wpa_supplicant/wpa_supplicant-wlan0.conf" LOG_FILE="/var/log/wifi-config.log" # 写入WiFi配置 cat > $CONF_FILE << EOF country=DE ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid="$SSID" psk="$PSK" key_mgmt=WPA-PSK } EOF # 执行配置重载 sudo wpa_cli -i wlan0 reconfigure # 等待10秒让WiFi完成协商 sleep 10 # 检查连接状态 if iwgetid wlan0 -r > /dev/null; then echo "$(date '+%Y-%m-%d %H:%M:%S') 成功连接到SSID: $SSID" >> $LOG_FILE else # 恢复默认配置 cat > $CONF_FILE << EOF country=DE ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 EOF echo "$(date '+%Y-%m-%d %H:%M:%S') 连接SSID:$SSID失败,已恢复默认配置" >> $LOG_FILE fi
2. 赋予脚本执行权限
sudo chmod +x /usr/local/bin/wifi-config-test.sh
3. 修改PHP脚本调用异步执行
<?php $ssid = $_GET['ssid']; $password = $_GET['password']; $response['success'] = true; $response['response'] = "配置已提交,正在后台验证连接,请稍候查看WiFi状态。"; // 异步执行Shell脚本,不等待返回 shell_exec("sudo /usr/local/bin/wifi-config-test.sh '$ssid' '$password' > /dev/null 2>&1 &"); echo json_encode($response);
内容的提问来源于stack exchange,提问作者ysLuk
相关产品推荐
相关产品推荐

