Menggunakan Borang Kenalan pada Hugo dengan PHPMailer melalui SSH

Laman statik tidak menjalankan kod sebelah pelayan, tetapi borang kenalan masih memerlukannya. Berikut adalah cara saya menghubungkan borang kenalan PHP/PHPMailer pada laman Hugo yang digunakan pada hosting dikongsi melalui SSH — dan apa yang tidak kena sepanjang perjalanan.

Persediaan

Laman ini dibina dengan Hugo dan outputnya di-rsync ke hos cPanel yang dikongsi. PHP tersedia di sebelah pelayan, jadi borang kenalan menghantar ke fail contact.php yang berada bersama output Hugo dalam public_html/.

PHPMailer mengendalikan penghantaran SMTP. Saya menyertakan perpustakaan secara terus (tanpa Composer) — fail-fail berada dalam static/vendor/phpmailer/ dan Hugo menyalinnya ke dalam public/ semasa pembinaan.

Memastikan Kelayakan Tidak Masuk Git

Kelayakan SMTP tidak seharusnya disimpan dalam git. Pendekatannya:

  • contact.php memanggil require __DIR__ . '/mail-config.php';
  • mail-config.php mentakrifkan pemalar (SMTP_HOST, SMTP_USER, SMTP_PASS, dll.)
  • static/mail-config.php ditambah ke .gitignore
  • static/mail-config.example.php disimpan dalam git sebagai templat rujukan

Di pelayan, mail-config.php mendapat chmod 600 — boleh dibaca oleh pemilik proses sahaja.

Deployment melalui SSH

Arahan deployment:

hugo && rsync -avz --exclude='mail-config.php' \
  -e "ssh -p 7822" \
  public/ user@ftp.example.com:~/public_html/ \
  && ssh -p 7822 user@ftp.example.com \
     "chmod 600 ~/public_html/mail-config.php"

Perkara penting:

  • --exclude='mail-config.php' menghalang rsync daripada menimpa fail kelayakan yang hidup
  • chmod 600 digunakan semula selepas setiap deployment sebagai langkah keselamatan

Nyahpepijat SMTP

Kelayakan dalam mail-config.php pada mulanya salah. Untuk mendiagnosis, saya memuat naik skrip ujian yang menjalankan PHPMailer dengan SMTPDebug = 2 terus di pelayan:

scp -P 7822 smtp_test.php user@ftp.example.com:/tmp/
ssh -p 7822 user@ftp.example.com "php /tmp/smtp_test.php; rm /tmp/smtp_test.php"

Output debug menunjukkan 535 Incorrect authentication data dengan serta-merta — mengesahkan ia adalah masalah kelayakan, bukan tembok api atau isu TLS. Setelah diperbetulkan, output menunjukkan 235 Authentication succeeded dan mel berjaya dihantar.

Kebenaran Fail

Hosting dikongsi sangat ketat tentang kebenaran fail. Peraturannya:

Jenis Kebenaran
Direktori 755
Fail 644
Konfigurasi sensitif 600

Hugo menyalin fail dari static/ dengan mengekalkan kebenaran sumbernya. Jika fail sumber mempunyai mod yang salah, ia akan menjadi salah di pelayan. Betulkan sekali di sumber:

find static -type f -exec chmod 644 {} \;
find static -type d -exec chmod 755 {} \;

Selepas itu, setiap pembinaan hugo menghasilkan output dengan kebenaran yang betul dan rsync menyebarkannya dengan bersih — tiada pembetulan kebenaran di sebelah pelayan diperlukan pada deployment masa hadapan.

Dua fail yang memerlukan perhatian manual:

  • .htaccess berada terus dalam public_html/, tidak diuruskan oleh Hugo. Tetapkan sekali: chmod 644 .htaccess. Apache tidak dapat menyajikan sebarang halaman jika tidak dapat membaca fail ini.
  • mail-config.php dikecualikan dari rsync dan mesti chmod 600 — arahan deployment menguruskan ini.

Borang Kenalan: Fetch dan Bukannya POST Biasa

Borang asal menggunakan HTML biasa <form action="..."> POST. Ini berfungsi tetapi pelayar memaparkan JSON mentah di halaman apabila pengesahan gagal — pengguna melihat {"ok":false,"errors":[...]} dan perlu menekan Kembali.

Versi yang ditambah baik memintas penghantaran dengan fetch:

  • Pengesahan sebelah klien berjalan dahulu — ralat jelas tidak pernah mencapai pelayan
  • Ralat pelayan dipetakan kembali ke sorotan medan sebaris
  • Apabila berjaya, JS mengubah hala ke /{lang}/contact/?sent=1 — halaman terima kasih yang betul

Satu perangkap dengan templat Hugo: penapis | jsonify membungkus nilai rentetan dalam tanda petikan JSON. Pada param seperti /contact.php ia menghasilkan "/contact.php" — betul. Tetapi digunakan dua kali ia menghasilkan "\"/contact.php\"", iaitu URL yang mengandungi aksara tanda petikan literal. Fetch gagal senyap-senyap. Gunakan interpolasi biasa sebaliknya:

var action = "{{ .Site.Params.contactFormAction }}";

Juga tambah ini_set('display_errors', '0'); di bahagian atas contact.php. Jika amaran PHP dihidupkan, ia akan ditambah ke hadapan badan respons JSON, merosakkan JSON.parse di pelayar.

Ringkasan

Masalah Penyelesaian
Kelayakan dalam git mail-config.php berasingan, dalam gitignore, chmod 600
Kegagalan pengesahan SMTP Skrip ujian di pelayan dengan SMTPDebug = 2
403 pada semua halaman .htaccess adalah 700 — tetapkan ke 644
403 pada imej Fail sumber static/ ada kebenaran salah — betulkan di sumber
Ralat penghuraian JSON di pelayar display_errors=1 membocorkan amaran PHP ke dalam badan respons
“Something went wrong” semasa hantar `