v1.4.0 — Mise à jour firmware hors-ligne par upload ZIP
Nouvelle fonctionnalité permettant de mettre à jour le firmware sans connexion internet, via upload d'un fichier .zip depuis l'interface admin. Fichiers ajoutés: - update_firmware_from_file.sh (rsync + exclusions + chown + restart services) - .update-exclude (liste d'exclusions évolutive, versionnée) - html/.htaccess (limite upload PHP 50MB) Fichiers modifiés: - html/launcher.php (handler upload_firmware) - html/admin.html (UI upload + barre de progression) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -410,6 +410,107 @@ if ($type == "update_firmware") {
|
||||
]);
|
||||
}
|
||||
|
||||
if ($type == "upload_firmware") {
|
||||
// Firmware update via ZIP file upload (offline mode)
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
echo json_encode(['success' => false, 'message' => 'POST method required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Check file upload
|
||||
if (!isset($_FILES['firmware_file']) || $_FILES['firmware_file']['error'] !== UPLOAD_ERR_OK) {
|
||||
$upload_errors = [
|
||||
UPLOAD_ERR_INI_SIZE => 'File exceeds server upload limit',
|
||||
UPLOAD_ERR_FORM_SIZE => 'File exceeds form upload limit',
|
||||
UPLOAD_ERR_PARTIAL => 'File was only partially uploaded',
|
||||
UPLOAD_ERR_NO_FILE => 'No file was uploaded',
|
||||
UPLOAD_ERR_NO_TMP_DIR => 'Missing temporary folder',
|
||||
UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk',
|
||||
];
|
||||
$error_code = $_FILES['firmware_file']['error'] ?? UPLOAD_ERR_NO_FILE;
|
||||
$error_msg = $upload_errors[$error_code] ?? 'Unknown upload error';
|
||||
echo json_encode(['success' => false, 'message' => $error_msg]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$file = $_FILES['firmware_file'];
|
||||
|
||||
// Validate extension
|
||||
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
||||
if ($ext !== 'zip') {
|
||||
echo json_encode(['success' => false, 'message' => 'Only .zip files are allowed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Validate size (50MB max)
|
||||
if ($file['size'] > 50 * 1024 * 1024) {
|
||||
echo json_encode(['success' => false, 'message' => 'File too large (max 50MB)']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Get current version before update
|
||||
$old_version = 'unknown';
|
||||
if (file_exists('/var/www/nebuleair_pro_4g/VERSION')) {
|
||||
$old_version = trim(file_get_contents('/var/www/nebuleair_pro_4g/VERSION'));
|
||||
}
|
||||
|
||||
// Prepare extraction directory
|
||||
$tmp_dir = '/tmp/nebuleair_update';
|
||||
$extract_dir = "$tmp_dir/extracted";
|
||||
shell_exec("rm -rf $tmp_dir");
|
||||
mkdir($extract_dir, 0755, true);
|
||||
|
||||
// Move uploaded file
|
||||
$zip_path = "$tmp_dir/firmware.zip";
|
||||
if (!move_uploaded_file($file['tmp_name'], $zip_path)) {
|
||||
echo json_encode(['success' => false, 'message' => 'Failed to move uploaded file']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Extract ZIP
|
||||
$unzip_output = shell_exec("unzip -o '$zip_path' -d '$extract_dir' 2>&1");
|
||||
|
||||
// Detect project root folder (Gitea creates nebuleair_pro_4g-main/ inside the zip)
|
||||
$source_dir = $extract_dir;
|
||||
$entries = scandir($extract_dir);
|
||||
$subdirs = array_filter($entries, function($e) use ($extract_dir) {
|
||||
return $e !== '.' && $e !== '..' && is_dir("$extract_dir/$e");
|
||||
});
|
||||
|
||||
if (count($subdirs) === 1) {
|
||||
$subdir = reset($subdirs);
|
||||
$candidate = "$extract_dir/$subdir";
|
||||
if (file_exists("$candidate/VERSION")) {
|
||||
$source_dir = $candidate;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate VERSION exists in the archive
|
||||
if (!file_exists("$source_dir/VERSION")) {
|
||||
shell_exec("rm -rf $tmp_dir");
|
||||
echo json_encode(['success' => false, 'message' => 'Invalid archive: VERSION file not found']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$new_version = trim(file_get_contents("$source_dir/VERSION"));
|
||||
|
||||
// Execute update script
|
||||
$command = "sudo /var/www/nebuleair_pro_4g/update_firmware_from_file.sh '$source_dir' 2>&1";
|
||||
$output = shell_exec($command);
|
||||
|
||||
// Cleanup (also done in script, but just in case)
|
||||
shell_exec("rm -rf $tmp_dir");
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'output' => $output,
|
||||
'old_version' => $old_version,
|
||||
'new_version' => $new_version,
|
||||
'timestamp' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($type == "set_RTC_withNTP") {
|
||||
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/set_with_NTP.py';
|
||||
$output = shell_exec($command);
|
||||
|
||||
Reference in New Issue
Block a user