Saat melakukan migrasi data bibliografi ke SLiMS, saya menemukan error berikut ketika membuka menu Bibliography → Bibliographic List:
Exception
unserialize(): Error at offset 0 of 4 bytes
in /admin/modules/bibliography/biblio_utils.inc.php
Trace error kurang lebih menunjukkan:
#1 unserialize
#2 showTitleAuthors
#3 createDataGrid
Pada kasus ini saya menggunakan:
PHP 8.3.6
SLiMS v9.8.0
MySQL 8
Error tersebut ternyata bukan disebabkan oleh judul, pengarang, atau data bibliografi utama, melainkan nilai labels pada tabel indeks pencarian search_biblio.
1. Memahami penyebab error
SLiMS memiliki fungsi showTitleAuthors() di:
admin/modules/bibliography/biblio_utils.inc.php
Di dalam proses tersebut, data label bibliografi dibaca menggunakan fungsi PHP:
unserialize($_labels);
Masalah muncul ketika nilai yang diberikan kepada unserialize() bukan data serialized PHP yang valid.
Sebagai contoh, fungsi ini mengharapkan data seperti:
a:1:{i:0;s:7:"Contoh";}
atau tidak memprosesnya apabila nilainya memang kosong.
Namun dalam kasus saya, database ternyata menyimpan:
NULL
sebagai string, bukan sebagai nilai SQL NULL.
PHP kemudian mencoba menjalankan kira-kira seperti ini:
unserialize('NULL');
Hasilnya adalah:
unserialize(): Error at offset 0 of 4 bytes
Kenapa disebut 4 bytes?
Karena string:
NULL
terdiri dari empat karakter:
N U L L
2. Jangan langsung menyalahkan biblio.labels
Awalnya saya memeriksa tabel utama biblio:
SELECT
biblio_id,
labels
FROM biblio
WHERE labels IS NOT NULL
AND labels != '';
Hasilnya:
0 rows
Artinya biblio.labels ternyata tidak bermasalah.
Ini penting karena SLiMS juga memiliki tabel indeks pencarian:
search_biblio
Pada konfigurasi search engine tertentu, daftar bibliografi dapat mengambil data dari tabel indeks tersebut.
Karena itu pemeriksaan perlu dilanjutkan ke search_biblio.
3. Periksa search_biblio.labels
Jalankan query berikut melalui Adminer, phpMyAdmin, MySQL CLI, atau aplikasi pengelola database lainnya:
SELECT
biblio_id,
title,
labels,
LENGTH(labels) AS panjang,
HEX(labels) AS hex_labels
FROM search_biblio
WHERE labels IS NOT NULL
AND labels <> ''
ORDER BY biblio_id
LIMIT 100;
Pada kasus saya hasilnya seperti ini:
| biblio_id | title | labels | panjang | hex_labels |
|---|---|---|---|---|
| 1 | Radiative transfer in the atmosphere and ocean | NULL | 4 | 4E554C4C |
| 2 | The Scalar-tensor theory of gravitation | NULL | 4 | 4E554C4C |
| 3 | Introduction to spectropolarimetry | NULL | 4 | 4E554C4C |
Di sinilah penyebab masalah mulai terlihat.
Nilai:
panjang = 4
dan:
HEX(labels) = 4E554C4C
membuktikan bahwa nilai tersebut benar-benar string ASCII:
NULL
bukan SQL NULL.
4. Perbedaan SQL NULL dan string 'NULL'
Ini bagian yang sangat penting.
SQL:
NULL
berarti tidak memiliki nilai.
Sedangkan:
'NULL'
adalah teks biasa yang terdiri dari empat karakter.
Contohnya:
UPDATE search_biblio
SET labels = NULL;
berarti mengisi kolom dengan SQL NULL.
Sementara:
UPDATE search_biblio
SET labels = 'NULL';
justru menyimpan teks:
NULL
ke database.
Bagi MySQL keduanya berbeda, dan bagi PHP perbedaannya menjadi sangat penting ketika data tersebut diproses menggunakan unserialize().
5. Pastikan jumlah data yang bermasalah
Sebelum memperbaiki database, kita bisa menghitung jumlah record yang memiliki string 'NULL':
SELECT COUNT(*) AS total
FROM search_biblio
WHERE labels = 'NULL';
Kita juga dapat melihat contoh recordnya:
SELECT
biblio_id,
title,
labels
FROM search_biblio
WHERE labels = 'NULL'
LIMIT 20;
Jika record ditemukan, kemungkinan besar inilah sumber error unserialize().
6. Backup database terlebih dahulu
Sebelum menjalankan query UPDATE, sebaiknya lakukan backup database SLiMS.
Misalnya melalui Adminer:
Database
→ Export
→ SQL
Atau menggunakan mysqldump.
Hal ini penting terutama jika database sudah digunakan untuk layanan perpustakaan aktif.
7. Memperbaiki search_biblio.labels
Setelah yakin bahwa masalahnya adalah string 'NULL', jalankan:
UPDATE search_biblio
SET labels = NULL
WHERE labels = 'NULL';
Perhatikan perbedaannya:
SET labels = NULL
bukan:
SET labels = 'NULL'
Query tersebut mengubah string "NULL" menjadi SQL NULL yang sebenarnya.
8. Sinkronkan dengan tabel biblio
Dalam kasus saya, kolom labels pada tabel utama biblio sudah benar.
Karena itu saya juga dapat menyinkronkan nilai labels pada search_biblio dengan tabel biblio:
UPDATE search_biblio sb
JOIN biblio b
ON b.biblio_id = sb.biblio_id
SET sb.labels = b.labels;
Dengan demikian:
biblio.labels
↓
search_biblio.labels
menjadi konsisten.
Query ini sebaiknya dilakukan setelah Anda memastikan bahwa nilai biblio.labels memang benar.
9. Verifikasi setelah perbaikan
Setelah melakukan update, jalankan:
SELECT COUNT(*) AS sisa
FROM search_biblio
WHERE labels = 'NULL';
Hasil yang diharapkan:
0
Kemudian periksa apakah masih ada label tidak kosong:
SELECT
biblio_id,
title,
labels
FROM search_biblio
WHERE labels IS NOT NULL
AND labels <> ''
LIMIT 100;
Jika memang koleksi Anda tidak menggunakan label, hasilnya dapat berupa:
0 rows
10. Uji kembali SLiMS
Sekarang kembali ke administrator SLiMS dan buka:
Bibliography
→ Bibliographic List
Pada kasus saya, setelah nilai string "NULL" di search_biblio.labels diubah menjadi SQL NULL, error:
unserialize(): Error at offset 0 of 4 bytes
berhasil diatasi.
Query lengkap perbaikan
Jika sudah memastikan penyebabnya sama, query intinya adalah:
-- Cek terlebih dahulu
SELECT
biblio_id,
title,
labels,
LENGTH(labels) AS panjang,
HEX(labels) AS hex_labels
FROM search_biblio
WHERE labels = 'NULL'
LIMIT 100;
-- Ubah string 'NULL' menjadi SQL NULL
UPDATE search_biblio
SET labels = NULL
WHERE labels = 'NULL';
-- Sinkronkan labels search_biblio dengan tabel utama
UPDATE search_biblio sb
JOIN biblio b
ON b.biblio_id = sb.biblio_id
SET sb.labels = b.labels;
-- Verifikasi
SELECT COUNT(*) AS sisa_string_null
FROM search_biblio
WHERE labels = 'NULL';
Jika query terakhir menghasilkan:
0
maka string 'NULL' pada kolom tersebut sudah berhasil dibersihkan.
Mengapa masalah ini bisa terjadi setelah migrasi?
Kasus seperti ini cukup mudah muncul ketika data SLiMS dibuat melalui script migrasi sendiri.
Ada tiga kondisi yang sebenarnya berbeda:
NULL
''
'NULL'
Keterangan:
| Nilai | Arti |
|---|---|
NULL | SQL NULL / tidak ada nilai |
'' | string kosong |
'NULL' | teks “NULL” |
| serialized PHP | data yang dapat diproses unserialize() |
Jika sebuah migrator memasukkan:
"NULL"
sebagai string, MySQL dapat menyimpannya sebagai:
NULL
secara visual, padahal sebenarnya itu adalah empat karakter.
Cara paling mudah membedakannya adalah:
SELECT
labels,
LENGTH(labels),
HEX(labels)
FROM search_biblio;
String "NULL" akan terlihat sebagai:
LENGTH = 4
HEX = 4E554C4C
Sedangkan SQL NULL tidak mempunyai panjang empat karakter tersebut.
Kesimpulan
Jika SLiMS menampilkan error:
unserialize(): Error at offset 0 of 4 bytes
khususnya dari:
biblio_utils.inc.php
→ showTitleAuthors()
jangan langsung mengubah source code SLiMS.
Periksa terlebih dahulu:
biblio.labels
dan terutama:
search_biblio.labels
Pada kasus yang saya temui, biblio.labels sudah benar, tetapi search_biblio.labels berisi string:
'NULL'
Solusinya cukup mengubah string tersebut menjadi SQL NULL:
UPDATE search_biblio
SET labels = NULL
WHERE labels = 'NULL';
Setelah data indeks diperbaiki, halaman Bibliographic List dapat dibuka kembali tanpa error.
Catatan: selalu backup database sebelum menjalankan query
UPDATE, terutama pada instalasi SLiMS produksi.