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_idtitlelabelspanjanghex_labels
1Radiative transfer in the atmosphere and oceanNULL44E554C4C
2The Scalar-tensor theory of gravitationNULL44E554C4C
3Introduction to spectropolarimetryNULL44E554C4C

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:

NilaiArti
NULLSQL NULL / tidak ada nilai
''string kosong
'NULL'teks “NULL”
serialized PHPdata 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.