fixed newsletyter1
This commit is contained in:
+71
-28
@@ -167,9 +167,15 @@ try {
|
|||||||
SET title = ?, subject = ?, preheader = ?, blocks = ?, settings = ?,
|
SET title = ?, subject = ?, preheader = ?, blocks = ?, settings = ?,
|
||||||
revision = revision + 1, updated_by = ?, updated_at = NOW()
|
revision = revision + 1, updated_by = ?, updated_at = NOW()
|
||||||
WHERE iddraft = ? AND deleted_at IS NULL" . ($force ? '' : ' AND revision = ?');
|
WHERE iddraft = ? AND deleted_at IS NULL" . ($force ? '' : ' AND revision = ?');
|
||||||
$params = [$c['title'], $c['subject'], $c['preheader'],
|
$params = [
|
||||||
json_encode($c['blocks'], JSON_UNESCAPED_UNICODE), json_encode($c['settings'], JSON_UNESCAPED_UNICODE),
|
$c['title'],
|
||||||
$userId, $id];
|
$c['subject'],
|
||||||
|
$c['preheader'],
|
||||||
|
json_encode($c['blocks'], JSON_UNESCAPED_UNICODE),
|
||||||
|
json_encode($c['settings'], JSON_UNESCAPED_UNICODE),
|
||||||
|
$userId,
|
||||||
|
$id
|
||||||
|
];
|
||||||
if (!$force) $params[] = $rev;
|
if (!$force) $params[] = $rev;
|
||||||
|
|
||||||
$st = $pdo->prepare($sql);
|
$st = $pdo->prepare($sql);
|
||||||
@@ -178,7 +184,9 @@ try {
|
|||||||
$d = draftRow($pdo, $id);
|
$d = draftRow($pdo, $id);
|
||||||
if ($st->rowCount() === 0) {
|
if ($st->rowCount() === 0) {
|
||||||
fail('Questa newsletter è stata salvata da un\'altra parte (un\'altra scheda o un altro computer).', 409, [
|
fail('Questa newsletter è stata salvata da un\'altra parte (un\'altra scheda o un altro computer).', 409, [
|
||||||
'conflict' => true, 'revision' => (int) $d['revision'], 'updated_at' => $d['updated_at'],
|
'conflict' => true,
|
||||||
|
'revision' => (int) $d['revision'],
|
||||||
|
'updated_at' => $d['updated_at'],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,49 +259,71 @@ try {
|
|||||||
case 'upload_image':
|
case 'upload_image':
|
||||||
if (!$isPost) fail('Metodo non consentito.', 405);
|
if (!$isPost) fail('Metodo non consentito.', 405);
|
||||||
$f = $_FILES['image'] ?? null;
|
$f = $_FILES['image'] ?? null;
|
||||||
if (!$f || $f['error'] !== UPLOAD_ERR_OK) fail('Caricamento non riuscito.');
|
if (!$f || ($f['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
|
||||||
|
$why = [
|
||||||
|
UPLOAD_ERR_INI_SIZE => 'il file supera il limite del server (upload_max_filesize)',
|
||||||
|
UPLOAD_ERR_FORM_SIZE => 'il file è troppo grande',
|
||||||
|
UPLOAD_ERR_PARTIAL => 'caricamento interrotto',
|
||||||
|
UPLOAD_ERR_NO_FILE => 'nessun file ricevuto',
|
||||||
|
UPLOAD_ERR_NO_TMP_DIR => 'manca la cartella temporanea sul server',
|
||||||
|
UPLOAD_ERR_CANT_WRITE => 'il server non riesce a scrivere il file',
|
||||||
|
][$f['error'] ?? UPLOAD_ERR_NO_FILE] ?? 'errore sconosciuto';
|
||||||
|
fail('Caricamento non riuscito: ' . $why . '.');
|
||||||
|
}
|
||||||
if ($f['size'] > 15 * 1024 * 1024) fail('Immagine troppo grande (massimo 15 MB).');
|
if ($f['size'] > 15 * 1024 * 1024) fail('Immagine troppo grande (massimo 15 MB).');
|
||||||
|
|
||||||
$info = @getimagesize($f['tmp_name']);
|
$info = @getimagesize($f['tmp_name']);
|
||||||
$mime = $info['mime'] ?? '';
|
$mime = $info['mime'] ?? '';
|
||||||
if (!in_array($mime, ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], true)) {
|
$ext = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'image/gif' => 'gif', 'image/webp' => 'webp'][$mime] ?? null;
|
||||||
fail('Formato non supportato: usa JPG, PNG, GIF o WebP.');
|
if (!$ext) fail('Formato non supportato: usa JPG, PNG, GIF o WebP.');
|
||||||
}
|
|
||||||
|
|
||||||
$dirRel = 'assets/uploads/newsletter/' . date('Y/m');
|
$dirRel = 'assets/uploads/newsletter/' . date('Y/m');
|
||||||
$dirAbs = __DIR__ . '/' . $dirRel;
|
$dirAbs = __DIR__ . '/' . $dirRel;
|
||||||
if (!is_dir($dirAbs) && !mkdir($dirAbs, 0755, true)) fail('Impossibile creare la cartella delle immagini.', 500);
|
if (!is_dir($dirAbs) && !@mkdir($dirAbs, 0755, true)) {
|
||||||
|
fail('Impossibile creare la cartella ' . $dirRel . ': controlla i permessi di assets/uploads.', 500);
|
||||||
|
}
|
||||||
|
if (!is_writable($dirAbs)) fail('La cartella ' . $dirRel . ' non è scrivibile: controlla i permessi.', 500);
|
||||||
|
|
||||||
$name = date('Ymd_His') . '_' . bin2hex(random_bytes(4));
|
$name = date('Ymd_His') . '_' . bin2hex(random_bytes(4));
|
||||||
[$w, $h] = $info;
|
[$w, $h] = $info;
|
||||||
|
$note = '';
|
||||||
|
|
||||||
if ($mime === 'image/gif') {
|
// Si può ottimizzare? Serve GD con il formato giusto
|
||||||
// Le GIF possono essere animate: le teniamo come sono
|
$reader = ['image/jpeg' => 'imagecreatefromjpeg', 'image/png' => 'imagecreatefrompng', 'image/webp' => 'imagecreatefromwebp'][$mime] ?? null;
|
||||||
$file = $name . '.gif';
|
$canResize = $mime !== 'image/gif' && $reader && function_exists($reader) && function_exists('imagecreatetruecolor');
|
||||||
move_uploaded_file($f['tmp_name'], $dirAbs . '/' . $file);
|
|
||||||
|
if (!$canResize) {
|
||||||
|
// GIF (forse animata) oppure server senza GD: salviamo l'originale
|
||||||
|
if ($mime !== 'image/gif' && $f['size'] > 3 * 1024 * 1024) {
|
||||||
|
fail('Il server non può ridimensionare le immagini (manca la libreria GD) e questa supera 3 MB: riducila prima di caricarla.');
|
||||||
|
}
|
||||||
|
$file = $name . '.' . $ext;
|
||||||
|
if (!move_uploaded_file($f['tmp_name'], $dirAbs . '/' . $file)) fail('Impossibile salvare l\'immagine.', 500);
|
||||||
|
if ($mime !== 'image/gif') $note = 'Caricata senza ottimizzazione (sul server manca la libreria GD).';
|
||||||
} else {
|
} else {
|
||||||
$src = match ($mime) {
|
try {
|
||||||
'image/jpeg' => imagecreatefromjpeg($f['tmp_name']),
|
@ini_set('memory_limit', '512M'); // le foto dal telefono sono grandi
|
||||||
'image/png' => imagecreatefrompng($f['tmp_name']),
|
$src = @$reader($f['tmp_name']);
|
||||||
'image/webp' => imagecreatefromwebp($f['tmp_name']),
|
if (!$src) fail('Immagine non leggibile o danneggiata.');
|
||||||
};
|
|
||||||
if (!$src) fail('Immagine non leggibile.');
|
|
||||||
|
|
||||||
// Foto dal telefono: raddrizza secondo l'orientamento EXIF
|
// Foto dal telefono: raddrizza secondo l'orientamento EXIF
|
||||||
if ($mime === 'image/jpeg' && function_exists('exif_read_data')) {
|
if ($mime === 'image/jpeg' && function_exists('exif_read_data')) {
|
||||||
$o = (int) (@exif_read_data($f['tmp_name'])['Orientation'] ?? 1);
|
$o = (int) (@exif_read_data($f['tmp_name'])['Orientation'] ?? 1);
|
||||||
$rot = [3 => 180, 6 => -90, 8 => 90][$o] ?? 0;
|
$rot = [3 => 180, 6 => -90, 8 => 90][$o] ?? 0;
|
||||||
if ($rot) { $src = imagerotate($src, $rot, 0); $w = imagesx($src); $h = imagesy($src); }
|
if ($rot) {
|
||||||
|
$src = imagerotate($src, $rot, 0);
|
||||||
|
$w = imagesx($src);
|
||||||
|
$h = imagesy($src);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$maxW = 1200; // il doppio della larghezza email: nitida sugli schermi retina
|
$nw = min($w, 1200); // il doppio della larghezza email: nitida sugli schermi retina
|
||||||
$nw = min($w, $maxW);
|
$nh = max(1, (int) round($h * $nw / $w));
|
||||||
$nh = (int) round($h * $nw / $w);
|
|
||||||
|
|
||||||
// PNG con trasparenza resta PNG, tutto il resto diventa JPG (molto più leggero)
|
// PNG con trasparenza resta PNG, il resto diventa JPG (molto più leggero)
|
||||||
$keepPng = false;
|
$keepPng = false;
|
||||||
if ($mime === 'image/png') {
|
if ($mime === 'image/png') {
|
||||||
$ct = ord(file_get_contents($f['tmp_name'], false, null, 25, 1));
|
$ct = ord((string) file_get_contents($f['tmp_name'], false, null, 25, 1));
|
||||||
$keepPng = in_array($ct, [4, 6], true);
|
$keepPng = in_array($ct, [4, 6], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,8 +340,12 @@ try {
|
|||||||
$ok = $keepPng ? imagepng($dst, $dirAbs . '/' . $file, 9) : imagejpeg($dst, $dirAbs . '/' . $file, 82);
|
$ok = $keepPng ? imagepng($dst, $dirAbs . '/' . $file, 9) : imagejpeg($dst, $dirAbs . '/' . $file, 82);
|
||||||
imagedestroy($src);
|
imagedestroy($src);
|
||||||
imagedestroy($dst);
|
imagedestroy($dst);
|
||||||
if (!$ok) fail('Impossibile salvare l\'immagine.', 500);
|
if (!$ok) fail('Impossibile salvare l\'immagine ottimizzata.', 500);
|
||||||
[$w, $h] = [$nw, $nh];
|
[$w, $h] = [$nw, $nh];
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
error_log('newsletter_api [upload_image]: ' . $e->getMessage());
|
||||||
|
fail('Ottimizzazione non riuscita: ' . $e->getMessage(), 500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out([
|
out([
|
||||||
@@ -320,6 +354,7 @@ try {
|
|||||||
'width' => $w,
|
'width' => $w,
|
||||||
'height' => $h,
|
'height' => $h,
|
||||||
'kb' => (int) round(filesize($dirAbs . '/' . $file) / 1024),
|
'kb' => (int) round(filesize($dirAbs . '/' . $file) / 1024),
|
||||||
|
'note' => $note,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
case 'send_test':
|
case 'send_test':
|
||||||
@@ -413,8 +448,16 @@ try {
|
|||||||
$imp = NewsletterWp::import($wpId);
|
$imp = NewsletterWp::import($wpId);
|
||||||
// Se in WordPress non è ancora partita, la colleghiamo: "Pubblica" aggiornerà quella
|
// Se in WordPress non è ancora partita, la colleghiamo: "Pubblica" aggiornerà quella
|
||||||
$status = NewsletterWp::statuses([$wpId])[$wpId] ?? '';
|
$status = NewsletterWp::statuses([$wpId])[$wpId] ?? '';
|
||||||
$id = createDraft($pdo, $userId, $imp['subject'] ?: 'Importata da WordPress', $imp['subject'], $imp['preheader'],
|
$id = createDraft(
|
||||||
$imp['blocks'], $imp['settings'], $status === 'new' ? $wpId : null);
|
$pdo,
|
||||||
|
$userId,
|
||||||
|
$imp['subject'] ?: 'Importata da WordPress',
|
||||||
|
$imp['subject'],
|
||||||
|
$imp['preheader'],
|
||||||
|
$imp['blocks'],
|
||||||
|
$imp['settings'],
|
||||||
|
$status === 'new' ? $wpId : null
|
||||||
|
);
|
||||||
out(['success' => true, 'id' => $id, 'linked' => $status === 'new']);
|
out(['success' => true, 'id' => $id, 'linked' => $status === 'new']);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1219,7 +1219,8 @@ $jsonFlags = JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_
|
|||||||
$('#nlChecks').innerHTML = lastChecks.map(c =>
|
$('#nlChecks').innerHTML = lastChecks.map(c =>
|
||||||
'<div class="' + c[0] + '"><i class="fas ' + (c[0] === 'error' ? 'fa-circle-xmark' : 'fa-triangle-exclamation') + ' me-1"></i>' + esc(c[1]) + '</div>').join('');
|
'<div class="' + c[0] + '"><i class="fas ' + (c[0] === 'error' ? 'fa-circle-xmark' : 'fa-triangle-exclamation') + ' me-1"></i>' + esc(c[1]) + '</div>').join('');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
/* l'anteprima riprova alla prossima modifica */ }
|
/* l'anteprima riprova alla prossima modifica */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$$('.nl-device button').forEach(b => b.addEventListener('click', () => {
|
$$('.nl-device button').forEach(b => b.addEventListener('click', () => {
|
||||||
@@ -1333,7 +1334,7 @@ $jsonFlags = JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_
|
|||||||
const t = $('[data-k="' + fileInput.dataset.upload + '"]', root);
|
const t = $('[data-k="' + fileInput.dataset.upload + '"]', root);
|
||||||
t.value = j.url;
|
t.value = j.url;
|
||||||
t.dispatchEvent(new Event('input'));
|
t.dispatchEvent(new Event('input'));
|
||||||
info.textContent = 'Caricata: ' + j.width + '×' + j.height + ' px, ' + j.kb + ' KB';
|
info.textContent = 'Caricata: ' + j.width + '×' + j.height + ' px, ' + j.kb + ' KB' + (j.note ? ' – ' + j.note : '');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
info.textContent = '';
|
info.textContent = '';
|
||||||
Swal.fire('Immagine non caricata', e.message || 'Errore di rete.', 'error');
|
Swal.fire('Immagine non caricata', e.message || 'Errore di rete.', 'error');
|
||||||
|
|||||||
Reference in New Issue
Block a user