Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
IMPLEMENTASI SISTEM PAKAR MENGGUNAKAN
METODE DEMSTER SHAFER UNTUK
MENDETEKSI PENYAKIT GIGI
SKRIPSI
untuk memenuhi sebagian persyaratan mencapai
derajat Sarjana S1 pada jurusan Teknik Informatika
Oleh:
UNI WAHYUNI
311610792
TEKNIK INFORMATIKA
SEKOLAH TINGGI TEKNOLOGI PELITA BANGSA
BEKASI
2018
MOTTO
“Remember Me, I will remember you”
(QS: Al-Baqarah : 152)
“Melangkahlah, Allah akan berikan jalan. Semua karena Allah”
(Triningsih)
“Hajar. Jangan takut gagal”
(Edi Santoso)
“Jangan takut. Takutlah hanya kepada Allah SWT”
(Penulis)
PERSEMBAHAN
Segala puji Syukur atas berkah dan rahmat dari Allah Subhanalllah Wata’ala,
Kupersembahkan Skripsi Ini Untuk Orang-Orang Yang Selalu Kuharapkan
Cinta dan Kasih Sayangnya…
Teruntuk Ibu dan Ayah yang tidak pernah memutus doa untuk anakanaknya,
terimakasih untuk menopang jatuhku dan menuntunku, terimakasih
untuk jadi saksi langkah-langkahku…
Teruntuk adikku, terima kasih untuk dukungan dan doanya…
Teruntuk teman-temanku tercinta, terimakasih untuk selalu ada menunggu dan menemani…
Almamater Tercinta,
Kampus STT Pelita Bangsa
iii
Abstraksi
Sistem pakar merupakan sebuah sistem penyelesaian masalah dengan
menuangkan pengetahuan manusia ke dalam sebuah sistem seperti yang biasa di
lakukan oleh para ahli. Sistem pakar memudahkan manusia untuk menyelesaikan
masalah yang biasanya dilakukan oleh para ahli walaupun hanya dilakukan oleh
orang yang awam. Sistem pakar juga dapat membantu tugas para ahli atau sebagai
asisten yang dapat diandalkan untuk menangani masalah tanpa harus konsultasi
langsung dengan para ahli. Penelitian ini bertujuan untuk mengembangkan sistem
pakar diagnosa penyakit gigi menggunakan algoritma Dempster Shafer untuk
mendiagnosa penyakit gigi berdasarkan presentasi terbesar dari gejala yang
dialami. Sistem pakar ini diimplementasikan pada komputer menggunakan bahasa
pemrograman berbasis Website dengan menggunakan PHP dan database MySQL.
Hasil dari sistem pakar ini diharapkan dapat memudahkan pengguna dalam
melakukan konsultasi dan pengguna mendapatkan hasil diagnosa yang akurat
tentang penyakit gigi yang dialami serta penanganan yang tepat menggunakan
algoritma Dempster Shafer.
Kata Kunci : Sistem pakar, Penyakit gigi, Dempster Shafer
iv
Abstraction
Expert system is one of the problem solving system with pour out human
scientific knowledge into a system which usually done by the expert. Expert
system make common people being feel easier to do and finish their tasks, even
though usually the expert who finish and complete the problem.
Expert system also can help the expert job task or as an assistant which can count
on to handle the problem without direct discuss with the expert. This research’s
purpose is to develop the expert system for dental disease diagnose by using the
“Dempter Shafer” to diagnose dental disease based on biggest presentation from
the symptom. This expert system is implemented to the computer using website
programmer language with PHP and database MySQL.
The result from this expert system are expected can make the user feel easier to do
the consulting and get accurate result diagnose about the suffer dental disease and
also the proper handling use the algoritma dempster Shafer
Kata Kunci : Sistem pakar, Penyakit gigi, Dempster Shafer
vi
KATA PENGANTAR
Puji syukur penulis panjatkan ke hadiran Allah SWT. yang telah
melimpahkan segala rahmat dan hidayah-Nya, sehingga tersusunlah Skripsi yang
berjudul IMPLEMENTASI SISTEM PAKAR MENGGUNAKAN METODE
DEMPSTER SHAFER UNTUK MENDETEKSI PENYAKIT GIGI”.
Skripsi tersusun dalam rangka melengkapi salah satu persyaratan dalam
rangka menempuh ujian akhir untuk memperoleh gelar Sarjana Komputer
(S.Kom.) pada Program Studi Teknik Informatika di Sekolah Tinggi Teknologi
Pelita Bangsa.
Penulis sungguh sangat menyadari, bahwa penulisan Skripsi ini tidak akan
terwujud tanpa adanya dukungan dan bantuan dari berbagai pihak. Sudah
selayaknya, dalam kesempatan ini penulis menghaturkan penghargaan dan ucapan
terima kasih yang sebesar-besarnya kepada:
a. Bapak Dr. Ir. Suprianto, M.P selaku Ketua STT Pelita Bangsa
b. Bapak Aswan Supriyadi Sunge, S, M.Kom selaku Ketua Program Studi
Teknik Informatika STT Pelita Bangsa.
c. Bapak Muhammad Fatchan, S.Kom, M.Kom selaku Pembimbing 1 (satu)
yang telah banyak memberikan arahan dan bimbingan kepada penulis
dalam penyusunan Skripsi ini.
d. Bapak Ikhsan Romli, S. Si, M.Sc, selaku Pembimbing 2 (dua) yang telah
meluangkan waktunya dalam penyelesaiaan skripsi sampai selesai, terima
kasih sudah memberikan arahan dan sudah memotivasi saya dalam
penyusunan skripsi ini.
e. Seluruh Dosen STT Pelita Bangsa yang telah membekali penulis dengan
wawasan dan ilmu di bidang teknik informatika.
f. Seluruh staf STT Pelita Bangsa yang telah memberikan pelayanan terbaiknya
kepada penulis selama perjalanan studi jenjang Strata 1.
g. Rekan-rekan mahasiswa STT Pelita Bangsa, khususnya angkatan 2018, yang
telah banyak memberikan inspirasi dan semangat kepada penulis untuk dapat
menyelesaikan studi jenjang Strata 1.
vii
h. Ibu dan Ayah tercinta yang senantiasa mendo’akan dan memberikan semangat
dalam perjalanan studi Strata 1 maupun dalam kehidupan penulis.
Akhir kata, penulis mohon maaf atas kekeliruan dan kesalahan yang
terdapat dalam Skripsi ini dan berharap semoga Skripsi ini dapat memberikan
manfaat bagi khasanah pengetahuan Teknologi Informasi di lingkungan STT
Pelita Bangsa khususnya dan Indonesia pada umumnya.
Bekasi, September 2018
Penulis
viii
Daftar Tabel
Halaman
Tabel 2.1 : Jenis-Jenis Penyakit Gigi .................................................... 18
Tabel 2.2 : Hasil Perhitungan ................................................................ 21
Tabel 2.3 : Use Case Diagram ............................................................... 23
Tabel 2.4 : Activity Diagram ................................................................. 24
Tabel 2.5 : Sequence Diagram .............................................................. 25
Tabel 2.6 : Class Diagram ..................................................................... 26
Tabel 2.7 : Perbandingan Studi Literature ............................................. 34
Tabel 3.1 : Use Case Sistem Berjalan ................................................... 39
Tabel 3.2 : Kode Penyakit Gigi .............................................................. 46
Tabel 3.3 : Kode Gejala Penyakit Gigi .................................................. 46
Tabel 3.4 : Gejala Penyakit Gigi ............................................................ 47
Tabel 3.5 : Contoh Tabel Perhitungan Gejala Penyakit Gigi ................ 47
Tabel 3.6 : Tabel tbl_diagnosa ............................................................... 57
Tabel 3.7 : Tabel tbl_gejala .................................................................... 57
Tabel 3.8 : Tabel tbl_penyebab penyakit ............................................... 57
Tabel 3.9 : Tabel tbl_admin ................................................................... 58
Tabel 3.10 : Tabel Rencana Pengujian ..................................................... 58
Tabel 3.11 : Tabel Hasil Pengujian ........................................................... 59
Tabel 4.1 : Use Case Sistem Pakar Gigi ................................................. 62
Tabel 4.2 : Sequence konsultasi .............................................................. 63
Tabel 4.3 : Sequence Basis Aturan ........................................................ 64
Tabel 4.4 : Sequence Daftar Gejala......................................................... 65
Tabel 4.5 : Sequence Buku Tamu ........................................................... 66
Tabel 4.6 : Sequence Laporan ................................................................. 67
Tabel 4.7 : Sequence Pengaturan ............................................................ 68
Tabel 4.8 : Sequence Keluar ................................................................... 69
Tabel 4.9 : Diagram Activity Diagnosa .................................................. 70
Tabel 4.10 : Diagram Activity Basis Aturan ............................................. 71
ix
Tabel 4.11: Diagram Activity Daftar Penyakit ......................................... 72
Tabel 4.12: Diagram Activity Gejala ........................................................ 73
Tabel 4.13 : Diagram Activity Buku Tamu .............................................. 74
Tabel 4.14 : Diagram Activity Hasil Diagnosa ......................................... 75
Tabel 4.15 : Diagram Activity Keluar....................................................... 76
Tabel 4.16 : Pengujian Menu Konsultasi .................................................. 94
Tabel 4.17 : Pengujian Menu Daftar Penyakit ........................................ 95
Tabel 4.18 : Pengujian Menu Buku Tamu ............................................... 95
Tabel 4.19 : Pengujian Menu Mulai Diagnosa ........................................ 95
Tabel 4.20 : Pengujian Menu Gejala ....................................................... 96
Tabel 4.21 : Pengujian Menu Keluar ....................................................... 96
x
Daftar Gambar
Halaman
Gambar 2.1 : Struktur Dan Arsitektur Sistem Pakar ............................... 11
Gambar 2.2 : Bagian-Bagian Gigi .......................................................... 17
Gambar 3.1 : Struktur Organisasi Praktek Drg. Priska .......................... 38
Gambar 3.2 : Use Case Praktek Drg. Priska .......................................... 35
Gambar 3.3 : Desaign Penelitian ............................................................ 40
Gambar 3.4 : Model Waterfall .............................................................. 43
Gambar 3.5 : ERD Implementasi Sistem Pakar Gigi ............................. 49
Gambar 3.6 : Diagram Konteks Implementasi Sistem Pakar Gigi.......... 50
Gambar 3.7 : DFD Level 1 Implementasi Sistem Pakar Gigi ................. 51
Gambar 3.8 : DFD Level 1 Proses 3 Pengelolahan Data ........................ 52
Gambar 3.9 : DFD Level 1 Proses 5 Konsultasi ..................................... 53
Gambar 3.10 : DFD Level 1 Proses 3.1 (Pengelolahan Data Penyebab) .. 53
Gambar 3.11 : DFD Level 1 Proses 3.2 (Pengelolahan Data Gejala) ....... 54
Gambar 3.12 : DFD Level 1 Proses 3.3 (Data Gejala Penyebab) ............. 54
Gambar 3.13 : DFD Level 1 Proses 5.1 (Konsultasi) ............................... 53
Gambar 3.14 : Diagram Relasi Implementasi Sistem Pakar Gigi ............. 56
Gambar 4.1 : Use Case Sistem Pakar Penyakit Gigi .............................. 59
Gambar 4.2 : Diagram Sequence Mulai Diagnosa .................................. 60
Gambar 4.3 : Diagram Sequence Basis Aturan ....................................... 61
Gambar 4.4 : Diagram Sequence Daftar Gejala ...................................... 62
Gambar 4.5 : Diagram Sequence Buku Tamu ....................................... 63
Gambar 4.6 : Diagram Sequence Laporan ............................................. 64
Gambar 4.7 : Diagram Sequence Profile Pengaturan ............................. 65
Gambar 4.8 : Diagram Sequence Keluar ................................................ 66
Gambar 4.9 : Diagram Activity Mulai Diagnosa .................................... 67
Gambar 4.10 : Diagram Activity Basis Aturan ........................................ 68
Gambar 4.11 : Diagram Activity Daftar Penyakit ................................... 69
Gambar 4.12 : Diagram Activity Gejala ................................................. 70
xi
Gambar 4.13: Diagram Activity Buku Tamu ........................................... 71
Gambar 4.14: Diagram Activity Hasil Diagnosa ..................................... 72
Gambar 4.15: Diagram Activity Keluar ................................................... 73
Gambar 4.16: Class Diagram Sistem Pakar Gigi ..................................... 74
Gambar 4.17: Rancangan Tampilan Login .............................................. 75
Gambar 4.18: Rancangan Tampilan Menu Utama ................................... 75
Gambar 4.19: Rancangan Tampilan Menu Mulai Diagnosa .................... 76
Gambar 4.20: Rancangan Tampilan Hasil Diagnosa ............................... 76
Gambar 4.21: Rancangan Tampilan Basis Aturan ................................... 77
Gambar 4.22: Rancangan Tampilan Daftar Gejala .................................. 77
Gambar 4.23: Rancangan Tampilan Buku Tamu ..................................... 78
Gambar 4.24: Rancangan Tampilan Penyakit ........................................... 78
Gambar 4.25: Rancangan Tampilan Hasil Diagnosa ............................... 79
Gambar 4.26: Rancangan Tampilan Keluar ............................................. 80
Gambar 4.27: Tampilan Login ................................................................. 81
Gambar 4.28: Tampilan Menu Utama ..................................................... 81
Gambar 4.29: Tampilan Menu Penyakit .................................................. 82
Gambar 4.30: Tampilan Menu Gejala ....................................................... 82
Gambar 4.31: Tampilan Menu Basis Aturan ........................................... 83
Gambar 4.32: Tampilan Menu Hasil Diagnosa......................................... 83
Gambar 4.33: Tampilan Menu Laporan ................................................... 84
Gambar 4.34: Contoh Tampilan Menu Hasil Laporan ............................. 84
Gambar 4.35: Tampilan Menu Buku Tamu ............................................. 85
Gambar 4.36: Tampilan Menu Pengaturan Admin .................................. 85
Gambar 4.37: Tampilan Menu Logout ..................................................... 86
Gambar 4.38: Tampilan Menu Utama ..................................................... 86
Gambar 4.39: Tampilan Menu Diagnosa ................................................. 87
Gambar 4.40: Tampilan Tampilan Hasil Dignosa ................................... 88
Gambar 4.41: Tampilan Basis Aturan ....................................................... 88
Gambar 4.42: Tampilan Daftar Gejala ...................................................... 89
Gambar 4.43: Tampilan Buku Tamu ........................................................ 89
xii
DAFTAR ISI
Halaman
Lembar Persetujuan .................................................................................. i
Lembar Pengesahan ................................................................................. ii
Abstraksi ( Bahasa Indonesia ) ................................................................. iii
Abstraksi ( Bahasa English ) .................................................................... iv
Surat Pernyataan Keaslian Penelitian........................................................ v
Kata Pengantar .......................................................................................... vi
Daftar Tabel ............................................................................................. viii
Daftar Gambar .......................................................................................... x
Daftar Isi ................................................................................................... xii
BAB I: Pendahuluan ................................................................................ 1
1.1 Latar Belakang ....................................................................... 1
1.2 Identifikasi Masalah ............................................................... 4
1.3 Rumusan Masalah .................................................................. 5
1.4 Batasan Masalah ..................................................................... 5
1.5 Tujuan dan Manfaat Penelitian .............................................. 6
1.5.1 Tujuan Penelitian .......................................................... 6
1.5.2 Manfaat Penelitian ........................................................ 6
1.6 Teknik Pengumpulan Data ..................................................... 6
1.7 Sistematik Penulisan .............................................................. 7
BAB II : Tinjauan Pustaka ....................................................................... 9
2.1 Kecerdasan Buatan ................................................................. 9
2.2 Sistem Pakar ............................................................................ 9
2.2.1 Pengertian Sistem Pakar ................................................ 9
2.2.2 Ciri-Ciri Sistem Pakar .................................................. 10
2.2.3 Struktur Sistem Pakar ................................................... 10
2.2.4 Manfaat Sistem Pakar ................................................... 12
xiii
2.2.5 Konsep Dasar Sistem Pakar .......................................... 13
2.2.5.1 Kepakaran ........................................................ 13
2.2.5.2 Pakar ................................................................ 13
2.2.5.3 Pemindahan Kepakaran ................................... 13
2.2.5.4 Inferensi ............................................................ 14
2.2.5.5 Aturan .............................................................. 14
2.2.5.6 Kemampuan Menjelaskan ................................ 14
2.2.6 Bentuk Sistem Pakar .................................................... 14
2.2.7 Klasifikasi Sistem Pakar .............................................. 15
2.2.8 Kelebihan Sistem Pakar ................................................ 16
2.2.9 Kelebihan Sistem Pakar ................................................ 16
2.3 Gigi ........................................................................................ 17
2.4 Jenis-Jenis Penyakit Gigi ...................................................... 18
2.5 Metode Dempster Shafer ....................................................... 19
2.5.1 Belief.............................................................................. 19
2.5.2 Mass Funcition .............................................................. 20
2.6 UML (Unified Modeling Language) ..................................... 22
2.7 Hypertext Prepocessor (PHP) ............................................... 26
2.8 Hyper Text Markup Language (HTML) ............................... 27
2.9 Diagnosa ................................................................................. 28
2.10 Penyakit ................................................................................ 28
2.11 Database dan MySQL .......................................................... 28
2.12 PHPMyAdmin ...................................................................... 30
2.13 Localhost .............................................................................. 31
2.14 Pengujian Perangkat Lunak .................................................. 31
2.15 Black Box Testing ................................................................ 32
2.16 Tinjauan Objek Penelitian .................................................... 33
BAB III : Analisa Masalah ....................................................................... 36
3.1 Analisa Objek Penelitian ........................................................ 36
3.1.1 Sejarah Praktek Drg. Priska .......................................... 36
3.1.2 Visi dan Misi ................................................................. 36
3.1.3 Struktur Organisasi ....................................................... 37
xiv
3.2 Analisa Sistem Berjalan ......................................................... 38
3.3 Desain Penelitian .................................................................... 39
3.4 Metode Penelitian ................................................................... 43
3.4.1 Metode Pengumpulan Data .......................................... 43
3.4.2 Metode Pengembangan Perangkat Lunak ..................... 43
3.5 Analisis Sistem ....................................................................... 44
3.5.1 Sumber Infomasi .......................................................... 45
3.5.2 Identifikasi Masalah ..................................................... 45
3.5.3 Analisis data Penyebab Penyakit Gigi ......................... 45
3.5.4 Indentifikasi Input ........................................................ 48
3.5.5 Indentifikasi Output....................................................... 48
3.5.6 Analisis Kebutuhan Non Fungsional ............................ 48
3.5.6.1 Analisis Pengguna............................................. 48
3.5.6.2 Analisis Perangkat Keras .................................. 48
3.5.6.3 Analisis Perangkat Lunak ................................. 49
3.5.6.4 Analisis Basis Data ........................................... 49
3.5.6.5 Analisis Kebutuhan Fungsional ........................ 50
3.5.6.5.1 Diagram Konteks ............................... 50
3.5.6.5.2 Data Flow Diagram (DFD) ................ 50
3.6 Pengujian Perangkat Lunak .................................................... 55
3.6.1 Rencana Pengujian ........................................................ 55
3.6.2 Hasil Pengujian ............................................................. 56
3.6.3 Metode Pengembangan Perangkat Lunak ..................... 58
BAB IV : Perancangan dan Implementasi Sistem ................................... 59
4.1 Perancangan Sistem ................................................................ 59
4.2 Design Sistem ......................................................................... 74
4.2.1 Rancangan Tampilan Login ......................................... 74
4.2.2 Rancangan Menu Utama .............................................. 75
4.2.3 Rancangan Menu Mulai Diagnosa ................................ 75
4.2.4 Rancangan Menu Basis Aturan .................................... 77
4.2.5 Rancangan Menu Daftar Gejala ................................... 77
4.2.6 Rancangan Menu Buku Tamu ....................................... 78
xv
4.2.7 Rancangan Menu Penyakit ........................................... 78
4.2.8 Rancangan Menu Hasil Diagnosa ................................. 79
4.2.9 Rancangan Menu Keluar ............................................... 80
4.3 Implementasi Sistem .............................................................. 80
4.3.1 Tampilan Pada Administrator ...................................... 80
4.3.1.1 Tampilan Login Pada Administrator ............... 81
4.3.1.2 Tampilan Menu Utama Pada Administrator ..... 81
4.3.1.3 Tampilan Daftar Penyakit ................................ 82
4.3.1.4 Tampilan Menu Gejala .................................... 82
4.3.1.5 Tampilan Menu Basis Aturan ........................... 83
4.3.1.6 Tampilan Menu Hasil Diagnosa ...................... 83
4.3.1.7 Tampilan Menu Laporan ................................. 84
4.3.1.8 Tampilan Menu Buku Tamu ............................ 85
4.3.1.9 Tampilan Menu Pengaturan ............................. 85
4.2.1.10 Tampilan Menu Logout ................................. 86
4.3.2 Tampilan Pada User ...................................................... 86
4.3.2.1 Tampilan Menu Utama Pada User ................... 86
4.3.2.2 Tampilan Menu Mulai Diagnosa ...................... 87
4.3.2.3 Tampilan Basis Aturan .................................... 88
4.3.2.4 Tampilan Daftar Gejala ................................... 89
4.3.2.5 Tampilan Buku Tamu ....................................... 89
4.4 Pengujian Sistem .................................................................... 90
4.4.1 Spesifikasi Hardware dan Software ............................. 90
4.4.2 Pengujian Pada Menu Konsultasi ................................. 91
4.4.3 Pengujian Pada Menu Daftar Penyakit ......................... 91
4.4.4 Pengujian Pada Menu Buku Tamu ................................ 92
4.4.5 Pengujian Pada Menu Mulai Diagnosa ......................... 92
4.4.6 Pengujian Pada Menu Pada Gejala ............................... 93
4.4.7 Pengujian Pada Menu Keluar ....................................... 93
BAB V : Penutup ..................................................................................... 94
5.1 Kesimpulan ............................................................................. 97
5.2 Saran ....................................................................................... 98
xvi
Daftar Pustaka .......................................................................................... 99
Lampiran 1 ........................................................................................... 101
1
BAB I
PENDAHULUAN
1.1 Latar Belakang
Gigi merupakan salah satu organ terpenting yang ada di dalam tubuh
manusia. Sebagai satu satunya organ yang tidak bisa menyembuhkan dirinya
sendiri, gigi menjadi organ tubuh yang sangat dijaga dan dirawat kondisinya
selama kehidupan seseorang berlangsung. Gigi juga termasuk organ yang sangat
penting dalam proses pengolahan makanan. Seseorang dapat dipastikan akan sulit
mengunyah makanan tanpa adanya gigi. Kesehatan gigi dan mulut penting untuk
diperhatikan dan merupakan bagian integral dari kesehatan secara keseluruhan
yang memerlukan penanganan segera sebelum terlambat dan dapat mempengaruhi
kondisi kesehatan seseorang. Setiap orang perlu mengetahui cara menjaga
kesehatan gigi dan mulut mereka. Pengetahuan tentang kesehatan gigi merupakan
salah satu usaha untuk mencegah dan menanggulangi masalah kesehatan gigi
melalui pendekatan pendidikan kesehatan gigi (Azhary, 2016). Kondisi gigi yang
tidak terjaga dengan baik dapat menyebabkan masalah yang lain di sekitar mulut,
diantaranya timbul gigi yang berlubang, sakit gigi, karang gigi, plak gigi,
peradangan pada gusi, sariawan, dan kelainan-kelainan yang lain disekitar gigi
(Setyaningsih, 2007).
Berdasarkan data yang diperoleh dari analisis lanjut Riskesdas tahun
2007, karakreristik seseorang (umur, pendidikan, tempat tinggal, serta sosial
ekonomi) responden memengaruhi terjadinya penyakit gigi. Semakin tinggi
pendidikan dan semakin tinggi tingkat sosial ekonomi responden semakin kecil
risiko terjadinya penyakit gigi, responden yang tinggal di kota beresiko untuk
terjadinya karies lebih besar dibandingkan responden yang tinggal di desa
(Oktarina, 2010).
Data informasi kesehatan gigi di Indonesia yang diperoleh dari Pusat Data
dan Informasi (Pusdatin) Kementerian Kesehatan RI tahun 2014 mengungkapkan
bahwa presentase penduduk Indonesia yang memiliki masalah kesehatan gigi
2
tahun 2015 dan 2018 meningkat dari 23,2% menjadi 25,9%. Penduduk yang
menerima perawatan medis gigi meningkat dari 29,7% tahun2007 menjadi 31,1%
pada tahun 2018 (Kemenkes RI, 2014).
Pusdatin dan Badan PPSDM (Pengembangan dan Pemberdayaan Sumber
Daya Manusia) melakukan analisis sederhana untuk melihat persebaran tenaga
kesehatan dokter gigi di puskesmas berdasarkan data olahan yang diperoleh pada
tahun 2017. Hasil dari analisis Pusdatin dan PPSDM menunjukkan bahwa
sebagian besar puskesmas di 33 Provinsi masih ada yang “kurang” tenaga dokter
gigi sedangkan provinsi lain memiliki tenaga kesehatan gigi (dokter gigi/ perawat
gigi) berlebih (Kemenkes RI, 2014).
Hasil prevalensi yang telah dilakukan oleh Kemenkes dan PPSDM
menunjukkan bahwa Indonesia memiliki peningkatan pada masalah kesehatan
gigi serta penyebaran tenaga kerja dokter gigi yang ternyata kurang seimbang di
setiap provinsi. Hal ini bisa berdampak pada sulitnya jangkauan dokter gigi pada 3
sebagian daerah pedesaan yang sebetulnya memiliki tingkat kesehatan gigi yang
lebih buruk dibanding di kota.
Idealnya masyarakat seperti ini membutuhkan langkah cepat dalam
memeriksakan gigi mereka sebelum pergi ke dokter gigi yang lokasinya dapat
dibilang jauh dari jangkauan. Hal ini diperuntukan dalam penanggulangan awal
dalam mengatasi penyakit gigi yang mungkin diderita. Oleh karena itu dibutuhkan
cara cepat dalam mendiagnosa penyakit gigi yang dapat dilakukan oleh setiap
individu.
Teknologi sudah semakin berkembang pada era sekarang. Sebagian besar
pekerjaan telah melibatkan teknologi. Sistem pakar menjadi salah satu bagian dari
ilmu kecerdasan buatan yang berkembang pesat dalam dunia teknologi. Dengan
sistem pakar, seseorang dapat terbantu sesuai dengan kebutuhan disaat sulit untuk
menemui para pakar secara langsung. Sistem pakar dapat membantu dalam
menyelesaikan masalah dan juga sebagai perwakilan dari para pakar. Dengan
adanya teknologi kecerdasan semacam ini seseorang dapat menghemat waktu
serta biaya. Sistem pakar menyediakan solusi yang disederhanakan dalam kasus
3
rumit yang berulang – ulang. Implementasinya dapat dibangun dalam bentuk web
based ataupun mobile.
Silvia dkk (2015) telah melakukan penelitian untuk mendiagnosa karies
sesorang melalui aplikasi berbasis web yang ditulis dalam sebuah jurnal yang
berjudul “Aplikasi Diagnosis Karies pada Gigi Manusia Berbasis Web”.
Pengguna diminta untuk menjawab pertanyaan dan jawaban yang diperoleh akan
disesuaikan dengan rules dalam sistem untuk memberikan kesimpulan.
Penelitian sistem pakar juga dibuat oleh (Masykur, 2012) menggunaka
metode lain dengan judul ”Implementasi Sistem Pakar Diagnosis Penyakit
Diabetes Mellitus Menggunakan Metode Fuzzy Logic Berbasis Web”. Sistem
pakar fuzzy logic dapat diterapkan menggunakan aplikasi web karena dengan
aplikasi web bisa mudah digunakan oleh semua pihak tanpa batasan waktu.
Dengan digunakan aplikasi web, pengguna dapat dengan mudah dan cepat
mengakses sistem.
Penelitian sistem pakar juga dibuat oleh (Masykur, 2012) menggunakan
metode lain dengan judul ”Implementasi Sistem Pakar Diagnosis Penyakit
Diabetes Mellitus Menggunakan Metode Fuzzy Logic Berbasis Web”. Sistem
pakar fuzzy logic dapat diterapkan menggunakan aplikasi web karena dengan
aplikasi web bisa mudah digunakan oleh semua pihak tanpa batasan waktu.
Dengan digunakan aplikasi web, pengguna dapat dengan mudah dan cepat
mengakses sistem.
Maka didasarkan oleh fakta – fakta yang ada serta penelitian-penelitian
sebelumnya yang berkaitan, penulis berinisiatif untuk membuat suatu sistem pakar
diagnosa penyakit gigi berbasis web menggunakan metode Dempster Shafer
yang berguna bagi penderita penyakit gigi dalam mendiagnosa penyakit giginya
sendiri. Data mengenai nama penyakit, gejala, serta penanganannya didapatkan
langsung dari pakar yang memahami ilmu penyakit gigi. Diharapkan dengan
adanya sistem ini masyarakat bisa memperoleh gambaran akan penyakit gigi
yang sedang dialami dan dengan mudah dapat mengonsultasikan kepada dokter
gigi setelahnya.
4
Dengan adanya masalah tersebut maka perlu adanya solusi yang tepat dan
mudah bagi masyarakat dalam membatu menangani masalah penyakit gigi.
Masyarakat memerlukan sebuah sistem pendeteksi penyakit gigi berbasis Website
untuk mengetahui gejala serta cara penanganan yang tepat yang dapat membantu
memberikan informasi tentang penyakit gigi tersebut. Sistem pakar pendeteksi
penyakit gigi ini menggunakan metode Dempster Shafer, suatu teori matematika
untuk pembuktian berdasarkan belief function and plausible reasoning (fungsi
kepercayaan dan pemikiran yang masuk akal), yang digunakan untuk menyatukan
potongan informasi yang terpisah (bukti) untuk menghitung kemungkinan dari
suatu peristiwa. Teori ini dikembangkan oleh Arthur P.Dempster dan glenn
Shafer. Berdasarkan latar belakang di atas, timbul pemikiran penulis untuk
membuat suatu sistem kepakaran untuk mendeteksi penyakit gigi serta cara
penanganan yang tepat, tujuan dari penelitian ini adalah membangun suatu sistem
berbasis pengetahuan kedokteran dalam mendiagnosa penyakit gigi yang
ditampilkan dalam website menggunakan pemograman PHP dengan database
MySQL dan menjadikannya materi skripsi dengan judul “IMPLEMENTASI
SISTEM PAKAR MENGGUNAKAN METODE DEMPSTER SHAFER
UNTUK MENDETEKSI PENYAKIT GIGI”. Dengan sistem ini diharapkan dapat
membantu manusia dalam menangani masalah penyakit gigi secara akurat,
sebagai mana telah diterapkan sistem kepakaran dibidang - bidang lainnya.
1.2. Identifikasi Masalah
Dari hasil pemaparan latar belakang maka dapat identifikasikan
permasalahan sebagai berikut :
(1) Rendahnya kesadaran masyarakat serta informasi yang kurang akan
kesehatan gigi.
(2) Mahalnya biaya untuk memeriksakan kesehatan gigi ke ke dokter, sehingga
masyarakat cenderung mengobati sendiri dengan cara yang belum tentu
benar.
5
(3) Perlu adanya sistem kepakaran gigi yang mudah diakses, untuk mendiagnosa
penyakit gigi guna menjaga kesehatan gigi bagi masyarakat.
1.3. Rumusan Masalah
Berdasarkan latar belakang masalah yang diuraikan di atas, maka penulis
selanjutnya menyimpulkan masalah - masalah yang terjadi sebagai berikut :
(1) Bagaimana menerapkan suatu sistem pakar yang mudah diakses oleh
masyarakat ?
(2) Bagaimana mengimplementasikan sebuah sistem ke perangkat komputer
dengan metode Dempster Shafer ?
(3) Bagaimana membuat sistem pakar untuk mendiagnosa penyakit gigi dengan
akurasi tinggi ?
(4) Bagaimana membuat sistem pakar yang dapat mengetahui jenis penyakit gigi
serta penanganan yang tepat ?
1.4. Batasan Masalah
Untuk memfokuskan penelitian ini maka penulis membatasi masalah -
masalah yang timbul, adapun batasan masalah dari pembuatan sistem ini sebagai
berikut:
(1) Aplikasi hanya menganalisa jenis penyakit gigi yang umum pada manusia.
Sistem kepakaran ini dapat dijalankan dengan baik melalui aplikasi browser
seperti Internet Explorer, Mozila Firefox, Opera, Google Chrome, Netscape
Navigator, Mozaic, Avant Browser dan lain-lain.
(2) Hasil dari sistem ini berupa jenis penyakit, visualisasi penyakit serta cara
penanggulanganya.
(3) Aplikasi program berbasis Website dengan menggunakan PHP dan database
MySQL.
6
1.5. Tujuan dan Manfaat Penelitian
1.5.1. Tujuan Penelitian
Berdasarkan latar belakang dan penjelasan yang menjadi dasar
pengembangan sistem pakar ini, tentunya ada tujuan yang ingin dicapai penulis
dalam pengembangan sistem pakar untuk mendiagnosa penyakit gigi, adapun
target atau hasil yang ingin dicapai bertujuan untuk :
(1) Membangun sistem pakar untuk menganalisa penyakit gigi yang dapat
membantu masyarakat dalam mengetahui jenis penyakit gigi yang
dideritanya.
(2) Dapat memberikan peran untuk meningkatkan kesehatan masyarakat
Indonesia terutama dalam penyakit gigi.
(3) Untuk membantu agar penderita penyakit gigi dapat mengambil tindakan
dengan cepat, sehingga penyakitnya dapat segera diatasi.
1.5.2. Manfaat Penelitian
(1) Hasil penelitian ini diharapkan menjadi bahan masukan, sehingga sistem ini
menjadi acuan untuk para peneliti lainnya yang ingin mengembangkan sistem
yang sejenis.
(2) Penelitian ini diharapkan bisa menghasilkan sistem yang benar - benar dapat
memberikan solusi bagi masyarakat khususnya dalam mengurangi tingginya
angka penderita penyakit gigi.
1.6 Teknik Pengumpulan Data
Teknik pengumpulan data yang dilakukan penulis adalah metode
deskriptif yaitu metode penelitian yang dilakukan untuk menggambarkan proses
peristiwa yang sedang terjadi pada saat dilakukan penelitian.
Untuk mendapatkan informasi–informasi dan mengumpulkan data yang
diperlukan guna menyelesaikan skripsi ini, maka penulis melakukan teknik
pengumpulan data seperti berikut :
7
1. Wawancara (Interview)
Untuk memperolah kelengkapan data yang lebih rinci lagi, penulis bertanya
langsung pada pihak-pihak yang terkait untuk memperoleh data yang lebih
akurat.
2. Pengamatan (Observation)
Metode observation yaitu salah satu tehnik pengumpulan data yang efektif
dalam mempelajari sistem, dengan cara mengamati langsung kegiatan.
3. Studi Kepustakaan (Library Research)
Untuk melengkapi data yang didapatkan dalam penulisan skripsi ini, penulis
juga menggunakan metode kepustakaan yaitu mengumpulkan data yang
diperlukan melalui buku–buku diktat, serta sumber lain yang menunjang dan
berhubungan dalam penulisan skripsi.
1.7 Sistematika Penulisan
Dalam penyusunan laporan skripsi ini akan diuraikan dalam bentuk bab, dan
masing - masing bab akan dipaparkan dalam beberapa sub bab, diantaranya :
BAB I
PENDAHULUAN
Bab ini berisikan paparan mengenai latar belakang masalah, identifikasi
masalah, rumusan masalah, batasan masalah, tujuan dan manfaat penelitian, tata
urut penulisan.
BAB II
TINJAUAN PUSTAKA
Dalam bab ini akan membahas referensi terkait dengan topik sistem pakar
untuk mendiagnosa penyakit gigi, dan juga referensi dari sistem yang telah dibuat
sebelumnya dengan algoritma yang berbeda.
8
BAB III
ANALISA MASALAH
Bab ini terdiri dari analisa sistem dan perancangan dari sistem yang sedang
berjalan. Serta memaparkan sistem yang diusulkan untuk menangani masalah
yang ada. Pada bagian perancangan sistem, membahas tentang perancangan
variabel indikator penentu penyakit gigi ke dalam himpunan dempster shafer dan
perancangan yang akan diimplementasikan pada sistem.
BAB IV
IMPLEMENTASI DAN PENGUJIAN SISTEM
Menjelaskan tentang perancangan, implementasi sistem, pengujian sistem
serta analisa terhadap permasalahan yang dibahas dalam penelitian, interpretasi
masalah penelitian serta implikasi dari penelitian.
BAB V
PENUTUP
Bab ini merupakan penutup yang memuat kesimpulan dari keseluruhan
uraian bab - bab sebelumnya.
9
BAB II
TINJAUAN PUSTAKA
2.1 Kecerdasan Buatan
Kecerdasan buatan berasal dari bahasa Inggris “Artificial Intelligence” atau
singkatan AI, yaitu intelligence adalah kata sifat yang berarti cerdas, sedangkan
artificial artinya buatan. Kecerdasan buatan yang dimaksud di sini merujuk pada
mesin yang mampu berpikir, menimbang tindakan yang akan diambil dan mampu
mengambil keputusan seperti yang dilakukan oleh manusia (Sutojo dkk, 2011).
Menurut Handojo dan Irawan (2009), kecerdasan buatan adalah cabang ilmu
komputer yang bertujuan untuk membuat sebuah komputer dapat berpikir dan
bernalar seperti manusia. Kecerdasan buatan dapat membantu manusia dalam
membuat keputusan, mencari informasi secara lebih akurat, atau membuat
komputer lebih mudah digunakan dengan tampilan yang menggunakan bahasa
natural sehingga mudah dipahami. Salah satu bagian dari sistem kecerdasan
buatan adalah sistem pakar dimana sistem pakar adalah bagian dari ilmu
kecerdasan buatan yang secara spesifik berusaha mengadopsi kepakaran
seseorang di bidang tertentu ke dalam suatu sistem atau program komputer.
2.2 Sistem Pakar
2.2.1. Pengertian Sistem Pakar
Sistem pakar merupakan sebuah program yang berfungsi untuk menirukan
seorang pakar atau ahli sehingga program tersebut dapat melakukan apa yang
dikerjakan oleh seorang pakar. Pembentukan sistem pakar didasarkan pada suatu
ide dengan mentransfer pengetahuan seorang pakar ke dalam komputer.
Pengetahuan yang tersimpan itu digunakan untuk menyelesaikan masalah yang
sesuai dengan pengetahuan yang telah diperoleh. Dengan adanya sistem pakar,
maka keluaran yang akan dihasilkan lebih efektif, terorganisir, dan
10
tepatdibandingkan dengan keluaran yang dihasilkan oleh manusia (Hartati dkk,
2008).
Sistem pakar merupakan cabang dari Artificial Intelligence (AI) yang
dikembangkan pada pertengahan 1960. Sistem pakar berasal dari istilah
knowledge-based expert system, yaitu sebuah sistem yang menggunakan
pengetahuan manusia dimana pengetahuan tersebut dimasukkan kedalam
komputer dan kemudian digunakan unruk menyelesaikan masalah-masalah yang
biasanya membutuhkan kepakaran atau keahlian manusia (Sutojo dkk, 2011).
2.2.2 Ciri-Ciri Sistem Pakar
Menurut Sutojo dkk (2011), ciri-ciri sistem pakar adalah :
1. Terbatas pada domain keahlian tertentu,
2. Dapat memberikan penalaran-penalaran untuk data-data yang tidak lengkap
atau tidak pasti,
3. Dapat mengemukakan rangkaian alasan-alasan yang diberikannya dengan cara
yang dapat dipahami,
4. Berdasarkan pada kaidah/ketentuan/rule tertentu,
5. Dirancang untuk dapat dikembangkan secara bertahap,
6. Pengetahuan dan mekanisme penalaran (inference) jelas terpisah,
7. Keluarannya bersifat anjuran,
8. Sistem dapat mengaktifkan kaidah secara searah yang sesuai dituntun oleh
dialog dengan user.
2.2.3 Struktur Sistem Pakar
Menurut Sutojo dkk. (2011) dan Siswanto (2010), sistem pakar disusun
oleh dua bagian utama, yaitu bagian lingkungan pengembangan (development
environment) dan lingkungan konsultasi (consulation environment). Lingkungan
pengembang digunakan oleh pembuat sistem pakar untuk membangun komponen
komponennya dan memperkenalkan pengetahuan ke dalam knowledge base (basis
pengetahuan). Sedangkan lingkungan konsultasi digunakan oleh pengguna untuk
11
berkonsultasi sehingga pengguna mendapatkan pengetahuan dan nasihat
darisistem pakar layaknya berkonsultasi dengan seorang pakar.
Gambar 2.1 Struktur dan arsitektur sistem pakar
Sumber : Seminar Nasional Ilmu Komputer UNDIP, Agustus 2010
Pada Gambar 2.1 dapat dijelaskan sebagai berikut :
1. Akuisisi Pengetahuan
Subsistem ini digunakan untuk memasukkan pengetahuan dari seorang pakar
dengan cara merekayasa pengetahuan agar bisa diproses oleh komputer dan
meletakkannya ke dalam basis pengetahuan dengan format tertentu.
2. Basis pengetahuan (knowledge base)
Basis pengetahuan berisi pengetahuan yang diperlukan untuk memahami,
memformulasikan dan menyelesaikan masalah. Basis pengetahuan terdiri dari
dua elemen dasar yaitu fakta dan rule atau aturan.
3. Mesin inferensi (Interference Engine)
Mesin inferensi adalah sebuah program yang berisi metodologi yang digunakan
untuk melakukan penalaran terhadap informasi-informasi dalam basis
pengetahuan untuk memformulasikan konklusi.
4. Daerah kerja (Blackboard)
Daerah kerja yaitu area pada memori yang berfungsi sebagai basis data. Ada
tiga tipe keputusan yang dapat direkam pada blackboard yaitu rencana, agenda
dan solusi.
LINGKUNGAN KONSULTASI LINGKUNGAN PENGEMBANGAN
Fakta tentang
Kejadian tertentu Akuisisi
Pengetahuan
Pemakai
Antar Muka
Aksi Yang
Direkomendasikan
Pasilitas
Penjelasan
Mesin Inferensi
Workspace
Basis pengetahuan fakta
dan aturan
Perbaikan
pengetahuan
Pakar
Knowledge
Engineer
12
5. Antarmuka (User Interface)
Antarmuka digunakan sebagai media komunikasi antara pengguna dan sistem
pakar. Program akan mengajukan pertanyaan-pertanyaan dnan sistem pakar
akan mengambil kesimpulan berdasarkan jawaban dari user.
6. Subsistem penjelasan (Explanation Subsystem)
Subsistem penjelasan berfungsi memberi penjelasan kepada user, bagaimana
suatu kesimpulan dapat diambil.
2.2.4 Manfaat Sistem Pakar
Menurut Sutojo dkk (2011) sistem pakar menjadi populer karena sangat banyak
kemampuan dan manfaat yang diberikannya, di antaranya sebagai berikut.
1. Meningkatkan produktivitas, karena sistem pakar dapat bekerja lebih cepat
daripada manusia.
2. Membuat seorang yang awam bekerja seperti layaknya seorang pakar.
3. Meningkatkan kualitas, dengan memberi nasihat yang konsisten dan
mengurangi kesalahan.
4. Mampu menangkap pengetahuan dan kepakaran seseorang.
5. Dapat beroperasi di lingkungan yang berbahaya.
6. Memudahkan akses pengetahuan seorang pakar.
7. Handal, sistem pakar tidak pernah menjadi bosan dan kelelahan atau sakit.
8. Meningkatkan kapabilitas sistem komputer. Integrasi sistem pakar dengan
sistem komputer lain membuat sistem lebih efektif dan mencakup lebih
banyak aplikasi.
9. Mampu bekerja dengan informasi yang tidak lengkap atau tidak pasti.
10. Bisa digunakan sebagai media pelengkap dalam pelatihan. Pengguna pemula
yang bekerja dengan sistem pakar akan menjadi lebih berpengalaman karena
adanya fasilitas penjelas yang berfungsi sebagai guru.
11. Meningkatkan kemampuan untuk menyelesaikan masalah
13
2.2.5 Konsep Dasar Sistem Pakar
Menurut Sutojo dkk (2011) konsep dasar sistem pakar meliputi enam hal
sebagai berikut.
2.2.5.1 Kepakaran
Kepakaran merupakan suatu pengetahuan yang diperoleh dari pelatihan,
membaca, dan pengalaman. Kepakaran inilah yang memungkinkan para ahli dapat
mengambil keputusan lebih cepat dan lebih baik daripada seseorang yang bukan
pakar. Kepakaran itu sendiri meliputi pengetahuan sebagai berikut.
1. Fakta-fakta pada lingkup permasalahan tertentu.
2. Teori-teori pada lingkup permasalahan tertentu.
3. Prosedur-prosedur dan aturan-aturan berkenaan dengan lingkup permasalahan
1. tertentu.
4. Strategi-strategi global untuk menyelesaikan masalah.
5. Meta-knowledge (pengetahuan tentang pengetahuan).
2.2.5.2 Pakar
Pakar adalah seseorang yang mempunyai pengetahuan, pengalaman, dan
metode khusus serta mampu menerapkannya untuk memecahkan masalah atau
memberi nasihat. Seorang pakar harus mampu menjelaskan dan mempelajari hal-
hal baru yang berkaitan dengan topik permasalahan, jika perlu harus mampu
menyusun kembali pengetahuan-pengetahuan yang didapatkan, dan dapat
memecahkan aturan-aturan serta menentukan relevansi kepakarannya.
2.2.5.3 Pemindahan Kepakaran
Tujuan dari sistem pakar adalah memindahkan kepakaran dari seorang
pakar ke dalam komputer, kemudian ditransfer kepada orang lain yang bukan
pakar. Proses ini melibatkan empat kegiatan, yaitu :
1. Akuisisi pengetahuan (dari pakar atau sumber lain),
2. Representasi pengetahuan (pada komputer),
3. Inferensi pengetahuan,
4. Pemindahan pengetahuan ke pengguna.
14
2.2.5.4 Inferensi
Inferensi adalah sebuah prosedur yang mempunyai kemampuan dalam
melakukan penalaran. Inferensi ditampilkan pada suatu komponen yang disebut
mesin inferensi yang mencakup prosedur-prosedur mengenai pemecahan masalah.
Semua pengetahuan yang dimiliki oleh seorang pakar disimpan pada basis
pengetahuan oleh sistem pakar. Tugas mesin inferensi adalah mengambil
kesimpulan berdasarkan basis pengetahuan yang dimilikinya.
2.2.5.5 Aturan-aturan
Kebanyakan aplikasi sistem pakar komersial adalah sistem yang berbasis
rule (rulebased system), yaitu pengetahuan disimpan terutama dalam bentuk rule,
sebagai prosedur-prosedur pemecahan masalah.
2.2.5.6 Kemampuan Menjelaskan
Fasilitas lain dari sistem pakar adalah kemampuannya untuk menjelaskan
saran atau rekomendasi yang diberikannya. Penjelasan dilakukan dalam subsistem
yang disebut subsistem penjelasan (explanation). Bagian dari sistem ini
memungkinkan sistem untuk memeriksa penalaran yang dibuatnya sendiri dan
menjelaskan operasioperasinya.
2.2.6 Bentuk Sistem Pakar
Sistem pakar dibagi menjadi empat bentuk, yaitu sebagai berikut.
1. Berdiri Sendiri
Sistem pakar jenis ini merupakan perangkat lunak yang berdiri sendiri tidak
bergabung dengan software lainnya.
2. Tergabung
Sistem pakar jenis ini merupakan bagian program yang terkandung di dalam
suatu algoritma (konvensional), atau merupakan program dimana di dalamnya
memanggil algoritma subrutin lain (konvensional).
3. Menghubungkan ke perangkat lunak lain
Bentuk ini biasanya merupakan sistem pakar yang menghubungkan ke suatu
paket program tertentu, misalnya DBMS.
15
4. Sistem Mengabdi
Sistem pakar merupakan bagian dari komputer khusus yang dihubungkan
dengan suatu fungsi tertentu. Misalnya sistem pakar yang digunakan untuk
membantu menganalisis data radar.
2.2.7 Klasifikasi Sistem Pakar
Menurut Siswanto (2005), klasifikasi sistem pakar berdasarkan
kegunaannya adalah sebagai berikut.
1. Diagnosis
Diagnosis digunakan untuk merekomendasikan obat untuk orang sakit,
kerusakan mesin, kerusakan rangkaian elektronik. Bertujuan menemukan
masalah/kerusakan yang terjadi. Biasanya menggunakan pohon keputusan
(decision tree) sebagai representasi pengetahuannya.
2. Pengajaran
Pengajaran digunakan untuk pengajaran, mulai dari SD s/d PT. Membuat
diagnosa apa kekurangan dari siswa, kemudian memberikan solusi atau cara
untuk memperbaikinya.
3. Interpretasi
Untuk menganalisa data yang tidak lengkap, tidak teratur, dan data yang
kontradiktif. Misal : untuk interpretasi citra.
5. Prediksi
Misalnya bagaimana seorang pakar meteorologi memprediksi cuaca besok
berdasarkan data-data sebelumnya. Untuk melakukan peramalan suatu kasus.
5. Perencanaan
Digunakan untuk merencanakan suatu pekerjaan misalnya, perencanaan
mesinmesin dan manajemen bisnis. Untuk menghemat biaya, waktu, &
material, sebab pembuatan model sudah tidak diperlukan. Contoh : sistEM
konfigurasi komputer.
6. Kontrol
Digunakan untuk mengontrol kegiatan yang membutuhkan presisi waktu
tinggi. Misal: pengontrolan pada industri-industri berteknologi tinggi.
16
2.2.8 Kelebihan Sistem Pakar
Menurut Kusumadewi, 2003 dalam bukunya mengatakan sistem pakar
memiliki kemampuan atau kelebihan sebagai berikut :
a. Dapat melakukan proses berulang secara otomatis
b. Mampu meningkatkan output dan suatu produktivitas
c. Dapat menyimpan pengetahuan dan keahlian para pakar
d. Bisa dilakukan oleh orang awam selayaknya mengerjakan pekerjaan para
ahli
e. Meningkatkan kapabilitas dalam menyelesaikan masalah
f. Mampu mengambil dan melestarikan keahlian para pakar
g. Meningkatkan kualitas
h. Mempunyai kemampuan dalam bekerja dengan informasi yang kurang
lengkap dan mengandung ketidakpastian
i. Relatif mempunyai kemampuan dalam mengakses pengetahuan
j. Mampu beroperasi dalam lingkungan yang berbahaya
k. Meningkatkan kapasitas komputer
l. Memiliki reliabilitas
m. Menjadi media pelengkap dalam pelatihan
n. Proses sangat cepat dalam pengambilan keputusan sehingga dapat
menghemat waktu
2.2.9 Kelemahan Sistem Pakar
a. Terkadang sistem tidak dapat membuat keputusan
b. Sulit dikembangkan
c. Sangat sulit dalam pembuatan aplikasi sistem pakar yang berkualitas tinggi
dan membutuhkan biaya yang tinggi dalam pemeliharaan dan
pengembangannya
d. Proses mendapatkan pengetahuan tidak bisa di dapat dengan mudah
e. Sistem pakar tidak 100% benar dalam pengaplikasianya sehingga perlu
selalu diuji ulang secara teliti sebelum digunaka.
17
2.3 Gigi
Gigi adalah jaringan tubuh yang paling keras dibanding yang lainya.
Strukturnya berlapis - lapis mulai dari email yang amat keras, dentin (tulang gigi)
di dalamnya, pulpa yang berisi pembuluh darah, pembuluh saraf, dan bagian lain
yang memperkokoh gigi. Namun demikian, gigi merupakan jaringan tubuh yang
mudah sekali mengalami kerusakan. Ini terjadi ketika gigi tidak memeperoleh
perawatan semestinya (Kusumawardani, 2011).
Gigi merupakan bagian keras yang terdapat didalam mulut yang berfungsi
untuk mengunyah makanan. Gigi terdiri dari beberapa bagian - bagian, berikut ini
gambar dari bagian - bagian gigi :
Gambar 2.2 Bagian - bagian gigi
Sumber : http://id.wikipedia.org/wiki/Gigi
Gigi tersusun atas lapisan-lapisan yang terdiri dari :
(1) Email : merupakan lapisan terluar yang kuat dan keras.
(2) Dentin : Lapisan di bawah email yang lebih lunak dan mudah rusak.
(3) Pulpa : Lapisan yang berisi pembuluh darah dan saraf.
(4) Gusi : Jaringan lunak yang ada dalam mulut.
(5) Cementum : Lapisan luar akar gigi.
(6) Jaringan periodontal : Jaringan yeng memegang gigi sehingga melekat
dalam tulang rahang.
(7) Tulang alveolar : Tulang tempat melekatnya gigi
18
Gigi terbagi atas beberapa jenis yang terdiri dari :
(1) Gigi seri, yaitu jenis gigi yang berbentuk seperti pahat gigi.
(2) Taring, yaitu jenis gigi yang berbentuk runcing.
(1) Geraham, yaitu jenis gigi dengan berbentuk permukaan yang berlekuk –
lekuk (Kusumawardani, 2011) .
2.4 Jenis-jenis Penyakit Gigi
Berdasarkan modul Penyakit Gigi oleh Kristiani dkk (2010) dipaparkan
beberapa jenis penyakit gigi diantaranya adalah sebagai berikut :
Tabel 2.1 Jenis-Jenis Penyakit Gigi
No Penyakit Uraian Contoh Penyakit
1 Caries
Caries adalah kerusakan
yang terbatas apada
jaringan gigi mulai dari
email gigi hingga menjalar
ke dentin (tulang gigi)
2 Abses
periapikal
Abses periapikal adalah
pengumpulan nanah yang
telah menyebar dari
sebuah gigi ke jaringan di
sekitarnya, biasanya
berasal dari suatu infeksi
3 Gigivitis (gusi
bengkak)
Gingivitis adalah
peradangan pada gusi.
Gingivitis terjadidan bisa
timbul kapan saja setelah
tumbuhnya gigi atau
akibat penggosokan dan
cara memebersihkan gigi
yang tidak benar sehingga
plak masih ada di
sepanjang garis gusi.
19
4
Pulpitis
(radang pulpa
gigi)
Pulpitis adalah
peradangan pada pulpa
gigi yang menimbulkan
rasa nyeri. Pulpa adalh
bagian gigi paling dalam,
yang mengandung saraf
dan pembuluh darah
5 Periodontitis
Periodontitis terjadi jika
gingivitis (Gusi bengkak)
meyebar ke seluruh
struktur penyangga gigi
6 Malocclusion
Malocclusion adalah
Kelainan susunan bagian
atas dan bawah rahang
yang mencegah gigi
bertemu dengan
semestinya
2.5 Metode Dempster Shafer
Teori Dempster-Shafer adalah suatu teori matematika untuk pembuktian
berdasarkan belief functions and plausible reasoning (fungsi kepercayaan dan
pemikiran yang masuk akal), yang digunakan untuk mengkombinasikan potongan
informasi yang terpisah (bukti) untuk mengkalkulasi kemungkinan dari suatu
peristiwa. Teori ini dikembangkan oleh Arthur P. Dempster dan Glenn Shafer.
Secara umum Teori Dempster-Shafer ditulis dalam suatu interval:
[Belief, Plausibility]
2.5.1 Belief
Belief Adalah ukuran kekuatan evidence (gejala) dalam mendukung suatu
himpunan bagian. Jika bernilai 0 maka mengindikasikan bahwa tidak ada
evidence, dan jika bernilai 1 menunjukkan adanya kepastian.
Plausibility (Pl) dinotasikan sebagai : Pl(s)= 1 – Bel(¬s)
Plausibility juga bernilai 0 sampai 1. Jika kita yakin akan ¬s, maka dapat
dikatakan bahwa Bel(¬s)=1, dan Pl(¬s)=0. Plausability akan mengurangi tingkat
20
kepercayaan dari evidence. Pada teori Dempster-Shafer kita mengenal adanya
frame of discernment yang dinotasikan dengan θ dan mass function yang
dinotasikan dengan m. Frame ini merupakan semesta pembicaraan dari
sekumpulan hipotesis sehingga disebut dengan environment.
Misalkan: θ = {A, B, C, D, E, F, G, H}
Dengan :
A = Caries/ Gigi berlubang
B = Pulpitis
C = Gingivitis
D = Abses gigi
E = Malocclusion
F = Gigi berjejal
G = Impaksi
H = Malposisi akibat trauma
2.5.2 Mass Function
Sedangkan mass function (m) dalam teori Dempster-Shafer adalah tingkat
kepercayaan dari suatu evidence measure sehingga dinotasikan dengan (m). Untuk
mengatasi sejumlah evidence pada teori Dempster-Shafer menggunakan aturan
yang lebih dikenal dengan Dempster’s Rule of Combination.
Dengan :
m1 (X) adalah mass function dari evidence X
m2 (Y) adalah mass function dari evidence Y
m3 (Z) adalah mass function dari evidence Z
κ adalah jumlah conflict evidence
Contoh Kasus Konsultasi Penyebab Penyakit
Untuk mengetahui hasil konsultasi penyebab penyakit ini, maka dilakukan
pengujian proses konsultasi. Proses pengujian sistem berupa masukkan data gejala
21
yang dialami pada anak yang sering menkonsumsi permen. Pada pegujian pertama
diberikan beberapa gejala yang dialami oleh anak antara lain :
G-1 (Terasa ngilu saat makan dan minum)
G-2 ( Gigi tampak cokelat dan membentuk lubang)
Dari hasil konsultasi, total gejala yang dipilih sebanyak 2 gejala, maka
untuk memperoleh nilai kepercayaan dengan Dempster’s rule of combination dari
gejala yang dipilih, dihitung:
Dimisalkan :
m1(G-1) = 0.15
m1(ѳ) = 1- m1(G-1) = 1- 0.15 = 0.85
m2(G-2) = 0.4
m2(ѳ) = 1- m2 (G-2)= 1- 0.4=0.6
Hasil perhitungan dapat dilihat pada tabel dibawah :
Tabel 2.2 Hasil Perhitungan
Sumber : Jurnal UNIKOM Fitria Nur Ellyani
Langkah pertama hitung nilai dari K-1
K-1
= 1- 0.06 = 0.94
Selanjutnya akan menghitung tingkat kepercayaan (m) combine dengan rumus:
∑ m1(G-1).m2(ѳ)
G-1n ѳ =G-1
m1 ⊕ m2(G-1) = 1 - K
= 0.09/0.94
= 0.0957
kemudian menghitung :
∑ m1(ѳ).m2(G-2)
G-1n ѳ =G-1
22
m1 ⊕ m2(G-2) = 1 - K
= 0.34/0.94
= 0.3617
Jika menggunakan rumus :
bel(X) = ∑ m(Y)
Y⊆X
bel({G-1,G-2}) = bel(G-1) + bel (G-2)
= m1⊕ m2(G-1) + m1⊕ m2(G-2)
= 0.0957 + 0.3617 = 0.4574
= 0.457 * 100 % = 45.7 %
Maka nilai kepastian kombinasi Dempster-Shafer bahwa anak Anda
terkena penyakit yang disebabkan oleh caries/gigi berlubang adalah sebesar
45.7%.
2.6 UML ( Unified Modeling Language )
Unified Modelling Language (UML) adalah sebuah “bahasa” yang telah
menjadi standar dalam industri untuk visualisasi, merancang dan men-
dokumentasikan sistem piranti lunak. UML menawarkan sebuah standar untuk
merancang model sebuah sistem. Dengan menggunakan UML dapat dibuat model
untuk semua jenis aplikasi piranti lunak, dimana aplikasi tersebut dapat berjalan
pada piranti keras, sistem operasi dan jaringan apapun, serta ditulis dalam bahasa
pemrograman apapun (Prastuti, 2009).
UML merupakan sebuah bahasa untuk mensfesifikasikan standar atau
mendokumentasikan standar sebuah sistem.
Ada beberapa jenis diagram yang dapat digunakan sebagai permodelan
sistem, pada sistem ini menggunakan empat jenis diagram yaitu :
(1) Diagram Use-Case bersifat statis. Diagram ini memperlihatkan himpunan
use-case dan aktor - aktor (Prabowo, 2013).
23
(2) Diagram interaksi dan Sequence ( urutan ). Bersifat dinamis. Diagram
urutan adalah diagram interaksi yang menekankan pada pengiriman pesan
dalam suatu waktu tertentu (Prabowo, 2013).
(3) Diagram Aktivitas ( Activity Diagram ). Bersifat dinamis. Diagram
aktivitas adalah tipe khusus dari diagram status yang memperlihatkan
aliran dari suatu aktivitas ke aktivitas lainnya dalam suatu sistem
(Prabowo, 2013).
(4) Diagram kelas. Bersifat statis. Diagram ini memperlihatkan himpunan
kelas - kelas, antarmuka - antarmuka, kolaborasi - kolaborasi, serta relasi -
relasi (Prabowo, 2013).
Simbol - simbol yang digunakan dalam pembuatan diagram - diagram di
atas dideskripsikan pada tabel di bawah ini :
Tabel 2.3 Use Case Diagram
Notasi Keterangan Simbol
Actor
Pengguna sistem atau yang
berinteraksi langsung dengan sistem,
bisa manusia, aplikasi, ataupun objek
lain
Use Case
Digambarkan dengan lingkaran elips
dengan nama use case nya tertulis di
tengah lingkaran
Assocation
Digambarkan dengan sebuah garis
yang berfungsi menghubungkan actor
dengan use case.
Sumber : Jurnal Unikom
24
Tabel 2.4 Activity Diagram
Sumber : Jurnal Unikom
Notasi Keterangan Simbol
Initial State Titik awal untuk
memulai suatu aktivitas
Final State Titik akhir untuk
mengakhiri suatu
aktivitas
Activity Menandakan sebuah
aktivitas
Decision Pilihan untuk
pengambilan
keputusan
Fork/ Join Menunjukkan
kegiatan
menggabungkan dua
panel activity menjadi
satu atau satu panel
activity menjadi dua
Send Tanda pengiriman
Receive Tanda penerimaan
Control Flow Arus aktivitas
25
Tabel 2.5 Sequence Diagram
Notasi Keterangan Simbol
Object Object adalah instance
dari sebuah class yang
dituliskan tersusun secara
horizontal diikuti lifeline
Activation Indikasi dari sebuah
objek yang melakukan
suatu aksi
Lifeline Indikasi keberadaan
sebuah objek dalam basis
waktu
Message Indikasi untuk
komunikasi antar object
Self-Message Komunikasi kembali
kedalam object itu sendiri
Sumber : Jurnal Unikom
Object1
26
Tabel 2.6 Class Diagram
Notasi Keterangan Simbol
Class Object adalah instance
dari sebuah class yang
dituliskan tersusun secara
horizontal diikuti lifeline
Association Indikasi dari sebuah
objek yang melakukan
suatu aksi
Dependency Indikasi keberadaan
sebuah objek dalam basis
waktu
Generalization Indikasi untuk
komunikasi antar object
Sumber : Jurnal Unikom
2.7 Hypertext Prepocessor (PHP)
PHP merupakan akronim dari PHP yaitu Hypertext Preprocessor. PHP
merupakan bahasa pemrograman berbasis web yang sudah sering digunakan.
Terdapat perbedaan antara web yang menggunakan PHP dan web yang hanya
sekedar menggunakan HTML saja. Hal tersebut dapat dilihat pada proses saat web
server memenuhi permintaan client untuk menampilkan halaman web. Pada
halaman web yang hanya menggunakan HTML, server langsung mengirimkan
halaman yang diminta oleh client dalam bentuk script HTML. Sedangkan pada
web yang menggunakan PHP sebelum server mengirimkan script HTML kepada
client, server membaca terlebih dahulu script PHP yang ada pada server tersebut
27
kemudian mengirimkan hasil dari script PHP tersebut kepada client berupa
HTML (Kadir, 2007).
1. Kelebihan PHP
Bahasa pemrograman PHP adalah sebuah bahasa script yang tidak
melakukan sebuah kompilasi dalam penggunaanya.
Web server yang mendukung PHP dapat ditemukan diberbagai macam
web server.
Dalam sisi pengembangan lebih mudah
Dalam sisi pemahaman, PHP adalah bahasa scripting yang mudah
digunakan.
PHP dapat membuat aplikasi di desktop, dan mendukung banyak
(Database).
2. Kelemahan PHP
PHP tidak mengenal package.
Jika tidak encoding, maka kode PHP dapat dibaca semua orang. dan
untuk meng encoding diperlukan tool berbayar.
2.8 Hyper Text Markup Language (HTML)
HTML (Hyper Text Markup Language) merupakan bahasa standart yang
dapat digunakan untuk menampilkan halaman web [15].
Kegunaanya yaitu :
Mengatur tampilan dari halaman web dan isinya..
Membuat tabel dalam halaman web.
Mempublikasikan halaman web secara online..
Membuat form yang bisa di gunakan untuk menangani registrasi dan
transaksi via web.
Menambahkan objek-objek seperti citra, audio, video, animasi, java applet
dalam halaman web.
Menampilkan area gambar (canvas) di browser.
28
2.9 Diagnosa
Diagnosa atau diagnosis dalam kamus besar bahasa Indonesia adalah
suatu penyakit dengan meneliti (memeriksa) gejala-gejalanya (Sugono,
2008:350)
2.10 Penyakit
Penyakit adalah suatu keadaaan abnormal dari tubuh atau pikiran yang
menyebabkan ketidaknyamanan, disfungsi atau kesukaran terhadap orang yang
dipengaruhinya.
2.11 Database dan MySQL
Database adalah kumpulan data yang tersusun secara sistematis sehingga
dapat memudahkan pengguna dalam mengakses dan mengelola serta untuk
mendapatkan informasi yang efektif dan efisien. Database dapat berdiri sendiri
dan dapat juga digabung menjadi satu kesatuan, penggabungan antar database
disebut dengan relasi, sebagai contoh data costumer digabung dengan data order.
Untuk menggabungkan data harus ada penghubung yang disebut dengan indeks.
Syarat dari indeks adalah tidak boleh ada data yang sama dan data yang digabung
masing-masing harus mempunyai indeks yang sama.
DBMS (Database Management System) merupakan software yang banyak
digunakan dalam pengolahan data. Contoh manajemen database adalah sistem
manajemen database relasi. Komponen dalam sistem manajemen database relasi
adalah sebagai berikut :
1. Database sebagai tempat untuk menyimpan data yang terstruktur, data
tersimpan dalam tabel, tabel tersebut terdiri dari baris dan kolom yang di
dalamnya terdapat field dan record.
2. System management adalah software yang digunakan untuk mengelola
database tersebut.
Relasi adalah hubungan antara tabel- tabel yang ada di dalam database.
Fungsi MySQL dapat dikatakan sebagai interpreter query, karena setiap
29
menggunakan query SQL (perintah SQL) harus meletakkannya di dalam fungsi
ini. Dengan kata lain, SQL tidak dapat dijadikan tanpa adanya fungsi MySQL.
MySQL termasuk jenis relational database management system (RDBMS).
Sehingga istilah seperti tabel, baris dan kolom tetap digunakan dalam MySQL.
Pada MySQL, SQL merupakan kependekan Structured Query Language. SQL
digunakan untuk berkomunikasi dengan sebuah database. SQL adalah bahasa
yang meliputi perintah-perintah untuk menyimpan, menerima, memelihara, dan
mengatur akses ke database serta digunakan untuk memanipulasi dan
menampilkan data dari database (Puspitasari, 2011).
DBMS mempunyai kamampuan seperti:
a) Membuat, menambah, menghapus, dan memodifikasi basis data
b) Pada beberapa DBMS pengelolanya berbasis windows (berbentuk jendela-
jendela) sehingga lebih mudah digunakan
c) Tidak semua orang bisa mengakses basis data yang ada sehingga dapat
memberikan keamanan
d) Kapabilitas berkomunikasi dengan program aplikasi yang lain. Misalnya
dimungkinkan untuk mengakses basis data MySQL, menggunakan aplikasi
yang dibuat menggunakan PHP
e) Kemampuan pengaksesan melalui komunikasi antar komputer (client
server)
1. Kelebihan MySQL
a) Gratis dan handal
b) Selalu di-update
c) Banyak forum yang memfasilitasi para pengguna jika memiliki kendala
d) MySQL juga menjadi DBMS yang sering dibundling dengan web server
sehingga proses instalasinya jadi lebih mudah
e) Bisa mendeteksi kesalahan pesan terhadap client dengan menggunakan
beberapa bahasa walaupun bahasa indonesia belum termasuk didalam
MySQL.
30
f) Dapat digunakan dan dijalankan dengan spesifikasi hardware yang relatif
rendah karena MySQL penggunaan databasenya lebih hemat resource
memory (dibandingkan dengan database lain).
2. Kelemahan MySQL
a) Tidak menerapkan konsep Technology Cluster Server sehingga
mempunyai keterbatasan kinerja dalam server ketika data yang telah
disimpan melebihi batas maksimal
b) Fitur-fitur belum lengkap dan belum sesuai standar
c) Dari segi keamanan masih terlalu sederhana bagi sebuah SQL Engine
2.12 PHPMyAdmin
Sibero (2011) “phpMyAdmin adalah aplikasi yang dibuat oleh
PHPMyAdmin.net. PHPMyAdmin digunakan untuk administrasi database
MySql”. Program ini digunakan untuk mengakses database MySql.Perintah untuk
membuat table dapat menggunakan form yang sudah tersedia pada PHPMyAdmin
atau dapat langsung menuliskan script pada menu SQL. PHPMyAdmin dijalankan
dengan mengetik http://localhost/PHPmyadmin web browser padalocallhost.
Menurut Arief, M.Rudyanto (2011). PHPMyAdmin adalah salah satu aplikasi GUI
(Graphical User Interface) yang digunakan untuk mengelola database MySql”.
Menurut Kurniawan (2008:8) “PHPMyAdmin adalah halaman yang terdapat
pada web server”. Fungsi dari hal aman ini adalah sebagai pengendali database
MySql menggunakan web server. XAMPP adalah perangkat lunak bebas, yang
mendukung banyak sistem operasi, merupakan kompilasi dari beberapa program.
Fungsinya adalah sebagai server yang berdiri sendiri (localhost), yang terdiri atas
program Apache HTTP Server, MySQL database, dan penerjemah bahasa yang
ditulis dengan Bahasa pemrograman PHP dan Perl. Nama XAMPP merupakan
singkatan dari X (empat sistem operasi apapun), Apache, MySQL, PHP dan Perl.
Program ini tersedia dalam GNU General Public License dan bebas, merupakan
web server yang mudah digunakan yang dapat melayani tampilan halaman web
31
yang dinamis. Untuk mendapatkanya dapat mendownload langsung dari web
resminya.
2.13 Localhost
Localhost merupakan istilah dalam computer jaringan yang berarti
komputer ini. localhost adalah nama standar yang diberikan sebagai alamat
loopback network interface. Localhost selalu menerjemahkan loopback ip
address 127.0.0.1 dalam IPv4, atau dalam IPv6. Localhost digunakan untuk
mengantarkan web browser pada HTTP server yang terinstall di komputer lokal.
Alamat http://localhost akan menampilkan website lokal pada komputer yang
bersangkutan.
Jadi, ketika computer 1 sebagai localserver dan lainnya sebagai client,
kemudian menghostingkan web didalamnya (localhost) untuk dijadikan tempat
membangun website sementara dan kemudian dihostingkan secara online ke
internet.
Dengan demikian menjadikan komputer kita sebagai localserver, kita
dapat bekerja secara offline tanpa harus takut menghadapi masalah biaya,
waktu,dan kenyamanan.
2.14 Pengujian Perangkat Lunak
Pengujian perangkat lunak adalah elemen kritis dari jaminan kualitas
perangkat lunak dan merepresentasikan kajian pokok dari spesifikasi, desain, dan
pengkodean. Sejumlah aturan yang berfungsi sebagai sasaran pengujian pada
perangkat lunak adalah (Sukamto, 2009) :
1) Pengujian adalah proses eksekusi suatu program dengan maksud menemukan
kesalahan.
2) Test case yang baik adalah test case yang memiliki probabilitas tinggi untuk
menemukan kesalahan yang belum pernah ditemukan sebelumnya.
3) Pengujian yang sukses adalah pengujian yang mengungkap semua kesalahan
yang belum pernah ditemukan sebelumnya.
32
Karakteristik umum dari pengujian perangkat lunak adalah sebagai berikut
(Sukamto, 2009) :
1) Pengujian dimulai pada level modul dan bekerja keluar kearah integrasi pada
sistem berbasiskan komputer.
2) Teknik pengujian yang berbeda sesuai dengan poin-poin yang berbeda pada
waktunya.
3) Pengujian diadakan oleh software developer dan untuk proyek yang besar
oleh group testing yang independent.
4) Testing dan Debugging adalah aktivitas yang berbeda tetapi debugging harus
diakomodasikan pada setiap strategi testing.
Metode pengujian perangkat lunak ada 3 jenis, yaitu (Sukamto, 2009) :
1) White Box/Glass Box -pengujian operasi
2) Black Box -untuk menguji sistem
3) Use case-untuk membuat input dalam perancangan black box dan pengujian
statebased
2.1.13 Black Box Testing
Pengujian menggunakan sekumpulan aktifitas validasi, dengan
pendekatan black box testing. Menurut Shalahuddin dan Rosa (2011), black box
testing adalah menguji perangkat lunak dari segi spesifikasi fungsional tanpa
menguji desain dan kode program. Pengujian dimaksudkan untuk mengetahui
apakah fungsi-fungsi, masukan, dan keluaran dari perangkat lunak sesuai dengan
spesifikasi yang dibutuhkan. Pengujian kotak hitam dilakukan dengan membuat
kasus uji yang bersifat mencoba semua fungsi dengan memakai perangkat lunak
apakahsesuai dengan spesifikasi yang dibutuhkan. Kasus uji yang dibuat untuk
melakukan pengujian black box testing harus dibuat dengan kasus benar dan
kasus salah.
Menurut Pressman (2010), black box testing juga disebut pengujian
tingkah laku, memusat pada kebutuhan fungsional perangkat lunak. Teknik
pengujian black box memungkinkan memperoleh serangkaian kondisi masukan
33
yang sepenuhnya menggunakan semua persyaratan fungsional untuk suatu
program. Beberapa jenis kesalahan yang dapat diidentifikasi adalah fungsi tidak
benar atau hilang, kesalahan antar muka, kesalahan pada struktur data
(pengaksesan basis data), kesalahan performasi, kesalahan inisialisasi dan akhir
program.
2.16 Tinjauan Objek Penelitian
Penulis meninjau penelitian ini dengan melihat hasil dari penelitian -
penelitian sebelumnya yang pernah dilakukan. Ini dilakukan untuk mencari
metode serta cara yang lebih tepat. Berikut ini hasil dari penelitian yang pernah
dilakukan sebelumnya menggunakan beberapa metode:
Penelitian sistem pakar juga dibuat oleh (Masykur, 2012) menggunakan
metode lain dengan judul ”Implementasi Sistem Pakar Diagnosis Penyakit
Diabetes Mellitus Menggunakan Metode Fuzzy Logic Berbasis Web”. Sistem
pakar fuzzy logic dapat diterapkan menggunakan aplikasi web karena dengan
aplikasi web bisa mudah digunakan oleh semua pihak tanpa batasan waktu.
Dengan digunakan aplikasi web, pengguna dapat dengan mudah dan cepat
mengakses sistem.
Penelitian sistem pakar lain juga dikemukakan oleh (Nurhasanah, 2010)
Metode yang digunakan dalam sistem pakar yang dikembangkan menggunakan
metode Backward Chaining. Dengan judul “Sistem Pakar Untuk Memprediksi
Awal Penyakit Gigi Dan Mulut Berbasis Web Dengan Metode Backward
Chaining”. Backward Chaining (Pelacakan ke belakang) adalah pencocokan
fakta atau pernyataan dimulai dari bagian sebelah kanan (THEN dulu). Dengan
kata lain, penalaran dimulai dari hipotesis terlebih dahulu, dan untuk menguji
kebenaran hipotesis tersebut, harus dicari fakta-fakta yang ada.
Adapun pengembang sistem pakar dengan metode yang lain (Khotimah,
2010) judul yang diangkat adalah “Sistem Pakar Troubleshooting Komputer
dengan metode Certainty Factor Menggunakan Probabilitas Bayesian”, untuk
mengukur tingkat kepastian dalam menganalisa suatu masalah. Aplikasi yang
dikembangkan berbasis desktop.
34
Dari ketiga penelitian di atas dapat disimpulkan sebagai berikut. Pada
penelitian yang pertama melakukan perancangan sistem pakar untuk diagnosa
penyakit diabetes melitus menggunakan metode fuzzy logic menggunakan sistem
berbasis web. Sedangkan penelitian yang ke dua Perancangan sistem pakar
mendiagnosa penyakit gigi dan mulut menggunakan metode Backward Chaining
berbasis web. Pada penelitian sistem pakar yang ke tiga mendiagnosa
Trobleshooting komputer menggunakan metode Certainty Factor dengan sistem
berbasis desktop.
Dari ketiga penelitian di atas peneliti mencoba mencari metode yang
belum digunakan oleh ketiga peneliti tersebut. Dan untuk masalah yang coba
diteliti sama dengan penelitian kedua (Nurhasanah, 2010) hanya saja peneliti coba
memfokuskan kepada penyakit gigi saja. Sedangkan untuk metode yang
digunakan, peneliti menggunakan metode Dempster Shafer berbeda dengan ketiga
metode yang digunakan di atas. Begitu juga dengan bahasa pemrograman peneliti
coba meggunakan pemrograman mobile Android sebagai alat implementasinya.
Studi literature dimaksudkan sebagai bahan pembanding penulis dalam
pengembangan aplikasi yang dibangun. Studi literature ini dilakukan dengan
mengumpulkan adata dari skirpsi atau jurnal hasil ppenelitian orang lain yang
berkesesuain dengan penelitian ini.
Table 2.7 Perbandingan Studi Literature
No
. Judul Penulis
Pebandingan
Studi Literatur Skripsi Penulis
1
Perancangan
sistem pakar
untuk
diagnosa
penyakit gigi
menggunakan
bahasa
pemogrmaran
Clips
I Nyoman
Kususma
Wardana
Penulis menggunakan
metode penalaran
forward chainiing dan
penelusuran generate
and test. Pada kasus
diagnosa belum dapat
belum dapat
menentukan diagnosa
banding, tapi diagnosa
banding ini dapat
ditemukan saat jalur
penelusuran generate
and test sudah terdefinisikan pada
Metode yang
digunakan penulis
dalam penalaran
adalah forward
chaining dan
penelusuran
dengan best first
search hal ini
memungkinkan
aplikasi data
diagnosa banding
tidak hanya satu
35
jalur penelusurannya
sementara, jika belum
akan ditemukan. Data
diagnosis yang sering
muncul di daerah tropis
khusunya Indonesia.
diagnosa tunggal.
Dan diagnosa
yang digunakan
yang digunakan
mempresentasika
n data dignosa
yang sering
muncul di daerah
tropis khususnya
Indonesia.
2
Sitem Pakar
penyakit gigi
menggunakan
metode
forward
chaining
Fetty Tri
Anggraen
y
Penulis menggunakan
metode penalaran
forward chaining pada
software delphi 7.0`
Tidak ditemukan pola
penelusuran data pada
penelitian ini.
Penelitian ini penelitian
ini. Penelitian ini juga
belum menghasilkan
diagnosa banding pada
hasil diagnosanya.
Penulis
menggunakan
media web
sehingga mampu
diaplikasikan
menggunakan
media
berteknologi
internet.
3
Pengembanga
n sistem pakar
pada
perangkat
mobile untuk
mendiagnosa
penyakit gigi
Bambang
Yuwono
Penulis menggunakan
metode penalaran
backward chaining
dengan metode
penelusuran depth first
search sudah
menggunakan teknologi
internet dan mobile
phone. Tapi hanya
mampu mampu
menampilkan satu
diagnosa banding
sesuai dengan karekter
pola penelusuran depth
firsh search.
Penulis
menggunakan
media forward
chaining dan best
first search
sebagai penambah
kekurangan pada
penelitian
Bambang
Yuwono.
36
BAB III
ANALISA MASALAH
3.1 Analisa Objek Penelitian
3.1.1 Sejarah Praktek Dokter Gigi Drg. Priska Widhi Anindya Santi
Praktek pengobatan Dokter gigi Drg. Priska merupakan praktek dokter
gigi rumahan, membuka praktek pribadi setelah menyelesaikan pendidikan
fakultas kedokteran gigi di Universitas Trisakti. merupakan lulusan fakultas
kedokteran gigi di Universitas Trisakti pada tahun 2012, Setelah menjalani
pendidikan selama 4 tahun untuk mendapatkan gelar Sarjana Kedokteran Gigi
(S.KG). Dan pernah mengikuti masa magang/ kepaniteraan (ko-ass) di Rumah
Sakit Mitra Keluarga selama kurang lebih 2 tahun untuk mendapatkan gelar
dokter gigi (Drg).
Untuk megimplementasikan ilmunya dibidang kedokteran gigi, maka
saya bersama rekan Drg. Melvin Leonardo membuka praktek Dokter gigi pribadi
di sebuah gedung yang beralamat Jl.Anggrek Raya No. 10 Jababeka2, Cikarang.
Adapun pembukaan praktek pertama kali pada 17 November 2013 sebagai awal
berdirinya Praktek Dokter Gigi Drg. Priska Widhi Anindya santi. Dan tidak
menutup kemungkinan untuk menjadikan Praktek Dokter Gigi ini sebagai
KLINIK apabila memang sudah memenuhi persyaratan, untuk menjadikan
praktek ini menuju kearah yang lebih baik lagi.
3.1.2 Visi dan Misi
Visi
Memberikan pelayanan terbaik dan professional untuk kesehatan gigi dan mulut
anda.
37
Dokter Penanggung Jawab
Drg. Priska Widhi Anindya
Pelaksana Medis
1.Drg. Priska Widhi Anindya
2.Drg. Melvin Leonardo
Administrasi
Nita sari
Pelaksana Farmasi
Wulandari
Misi
1. Memberikan pelayanan terbaik kepada semua lapisan masyarakat.
2. Menyediakan fasilitas yang baik untuk menunjang kinerja agar mendapatkan
hasil yang optimal.
3. Memberikan informasi seputar gigi kepada masyarakat.
3.1.3 Struktur Organisasi
Struktur organisasi merupakan kerangka dan susunan terwujudnya pola
tetap hubungan-hubungan antara fungsi-fungsi, bagian-bagian atau posisi-posisi
maupun orang-orang yang menunjukan kedudukan, tugas, tugas, wewenang dan
tanggung jawab yang berbeda-beda dalam suatu organisasi akan mempunyai suatu
peranan dan fungsi yang berbeda dalam instansi-instansi maupun perusahaan-
perusahan kecil maupun beasr.
Gambar 3.1 Struktur organisasi Praktek Drg. Priska Widhi Anindya santi
Sumber : Struktur Organisasi Praktek Drg. Priska Widhi Anindya santi
38
3.2 Analisa Sistem Berjalan
Sistem yang berjalan saat ini masih bersifat manual, digambarkan dengan diagram
use case di bawah ini :
Gambar 3.2 Use Case Sistem Praktek Drg. Priska Widhi Anindya santi
Pasien
Mendaftarkan diri
Catat data pasien
Menyampaikan gejala
Periksa kondisi pasien
Dokter
Administrasi
Diagnosa penyakit
Catat hasil diagnosa & pengobatan
Use Case Sistem Praktek Drg. Priska Widhi Anindya Santi
39
Dari uses case diatas dapat dijelaskan sebagai berikut :
Tabel 3.1 Use Case Sistem Berjalan
Nama Use Case
Use Case Sistem Berjalan
Aksi pasien Aksi Sistem
1. Daftar ke bagian administrasi
2. Admin mencatat data pasien dan
memberikannya ke dokter
3. Admin memanggil pasien
berdasarkan urutan
4. Pasien konsultasi dengan dokter
perihal keluhanya
5. Dokter memeriksa kondisi
pasien
6. Dokter mendiagnosa penyakit
pasien
7. Dokter mencatat hasil diagnosa
dan pengobatanya
3.3 Desain Penelitian
Desain penelitian yaitu gambaran tahapan yang akan dilakukan peneliti
untuk mempermudah dalam melakukan penelitian. Berikut adalah tahapan
penelitian yang akan dilakukan.
40
Gambar 3.3 Desain Penelitian
Penjelasan desain penelitian :
1. Proses pertama
a. Menganalisis permasalahan kesehatan gigi dan mulut berdasarkan fakta-
fakta yang ada
1. Analisis permasalahan
Rumusan Masalah
1. Studi Literatur
2. Menentukan lokasi penelitian
3. Mempersiapkan alat dan bahan penelitian
4. Wawancara
5. Mengumpulkan data penelitian
Hasil studi literatur dan
data penelitian
1. Pengujian implementasi metode dempster shafer
2. Pengujian perangkat lunak
3. Pengujian tingkat akurasi hasil diagnosa
4. Menganalisa hasil pengujian
5. Pengambilan kesempulan
6. Menyertakan saran
Pengujian Penelitian
Analisis Hasil Uji
2. Menentukan kebutuhan data penelitian & faktor
apa saya yang akan diangkat
Mengimplementasikan metode Demper shafer
41
b. Menentukan kebutuhan data penelitian
Menentukan kebutuhan data yang akan digunakan dalam penelitian seperti
data jenis penyakit, data gejala, data solusi dari penyakit, data pasien dan
menentukan faktor apa saja yang harus diperhatian pada permasalahan yang
akan diangkat di penelitian
Output dari proses pertama adalah rumusan masalah penelitian
2. Proses ke-dua
a. Studi literatur
Proses pembelajaran mengenai literatur-literatur yang mendukung
pelaksanaan penelitan untuk memahami dan memperdalam teori maupun
metode yang akan digunakan yaitu metode dempster shafer. Proses
pembelajaran dilakukan dengan mencari teori dan referensi dari textbook,
jurnal, dan sumber lainnya yang berkaitan dengan penyakit gigi dan mulut
dan metode yang akan digunakan
b. Menentukan lokasi penelitian
Untuk lokasi penelitian berada di Rumah Sakit Umum Daerah Soreang, Jl.
Alun-Alun Utara No.1, Soreang, Bandung, Jawa Barat.
c. Mempersiapkan alat dan bahan penelitian
Mempersiapkan perangkat yang akan digunakan untuk penelitian dan bahan
penelitian yaitu data-data yang dibutuhkan
d. Wawancara
Wawancara dilakukan untuk mendapatkan informasi tentang berbagai
penyakit gigi dan mulut beserta gejalanya dan juga solusi untuk penanganan
penyakit tersebut. Wawancara juga dilakukan untuk mengetahui nilai MB
dan nilai MD setiap gejala dari penyakit gigi dan mulut. Nilai tersebut akan
digunakan sebagai parameter metode dempster shafer untuk melakukan
perhitungan kemungkinan penyakit.
e. Mengumpulkan data penelitian
Data-data yang sudah diperoleh dari semua proses diatas dikumpulkan
dan diolah agar dapat memenuhi kebutuhan penelitian.
42
Output dari proses ke-dua adalah hasil studi literatur mengenai metode-
metode yang akan digunakan untuk menyelesaikan permasalahan yaitu
metode Dempter Shafer. Selain itu output lain juga berupa hasil wawancara
pakar mengenai data penyakit gigi dan mulut beserta gejala dari setiap
penyakitnya dan data nilai MB dan nilai MD setiap gejalanya, solusi dari
setiap penyakit, dan penjelasan dari setiap penyakit yang sudah diolah dan
siap digunakan untuk proses selanjutnya
3. Proses selanjutnya adalah merangkai data-data dan teori yang sudah didapatkan
dari proses wawancara dan studi literatur untuk membangun sebuah perangkat
lunak. Pada proses ini metode Dempter Shafer diimplementasikan ke dalam
perangkat dan dibangunlah sebuah aplikasi sistem pakar untuk mendiagnosis
penyakit gigi dan mulut. Perangkat lunak dibangun dengan menggunakan
metode Waterfall dengan tahapan pengumpulan kebutuhan sistem,
pembentukan desain & arsitektur sistem, mengimplementasikan desain sistem
yang sudah dibuat menjadi unit program, pengintegrasian unit program dan
pengujian setiap unitnya, dan terakhir instalasi dan pemeliharaan sistem.
Output dari tahap ini adalah aplikasi Sistem Pakar diagnosis penyakit Gigi dan
Mulut (SIPAGIMU).
4. Pengujian penelitian
Setelah perangkat lunak berhasil dibangun, tahap selanjutnya adalah pengujian
penelitian penerapan metode certainty factor dan metode rulebased reasoning
ke dalam sistem dan pengujian perangkat lunak. Selain itu diuji juga seberapa
akurat hasil diagnosis sistem dibandingkan dengan diagnosis yang dilakukan
oleh pakar`
1. Tahap terakhir adalah tahap analisis hasil uji. Pada tahap analisis hasil uji akan
dilihat bagaimana hasil dari pengujian penelitian, ada berapa sample data yang
berhasil dan ada berapa sample data yang gagal. Setelah itu akan ditarik
kesimpulan dari penelitian yang telah dilakukan dan menyertakan saran untuk
penelitian kedepannya.
43
3.4 Metode Penelitian
Metode penelitian ini dibagi menjadi dua, yaitu metode pengumpulan data dan
metode pengembangan perangkat lunak.
3.4.1 Metode Pengumpulan Data
Dalam penelitian ini proses pengumpulan data dilakukan dengan cara
sebagai berikut:
a. Wawancara
Wawancara dilakukan dengan melakukan tanya jawab dengan pakar yaitu
dokter gigi untuk mendapatkan informasi yang dibutuhkan dan data yang
akurat mengenai penyakit-penyakit gigi dan mulut. Kemudian pakar
memberikan nilai MB dan MD pada setiap gejala penyakit gigi dan mulut.
b. Studi literatur
Dengan melakukan studi mengenai kecerdasan buatan, sistem pakar, metode
certainty factor, metode rule-based reasoning dan penyakit gigi dan mulut
melalui literatur seperti buku, jurnal, dan sumber ilmiah lain.
3.4.2 Metode Pengembangan Perangkat Lunak
Pembangunan perangkat lunak dalam penelitian ini menggunakan model
waterfall. Model waterfall adalah sebuah contoh dari proses perencanaan, dimana
semua proses kegiatan harus terlebih dahulu direncanakan dan dijadwalkan
sebelum dikerjakan (Sommerville, 2011). Dalam model waterfall Sommerville
terdapat kemungkinan untuk kembali ke tahap sebelumnya apabila terjadi
kesalahan atau perbaikan, dimana alur prosesnya seperti pada gambar berikut ini.
Gambar 3.4 Model Waterfall (Sommerville, 2011)
44
1. Requirements definition (Definisi kebutuhan)
Mengumpulkan kebutuhan, penetapan fitur, kendala dan tujuan sistem melalui
konsultasi dengan pengguna sistem. Semua hal tersebut akan ditetapkan secara
rinci dan berfungsi sebagai spesifikasi sistem.
2. System and software design (Desain sistem dan perangkat lunak)
Dalam tahapan ini akan dibentuk suatu arsitektur sistem berdasarkan
persyaratan yang telah ditetapkan. Dan juga mengidentifikasi dan
menggambarkan abstraksi dasar sistem perangkat lunak dan hubungan-
hubungannya.
3. Implementation and unit testing (Tes implementasi dan unit)
Hasil dari desain perangkat lunak akan direalisasikan sebagai satu set program
atau unit program. Setiap unit akan diuji apakah sudah memenuhi
spesifikasinya.
4. Integration and unit testing (Tes integrasi dan unit)
Setiap unit program akan diintegrasikan satu sama lain dan diuji sebagai satu
sistem yang utuh untuk memastikan sistem sudah memenuhi persyaratan yang
ada. Setelah itu sistem akan dikirim ke pengguna sistem.
5. Operation and maintenance (Operasi dan maintenance)
Dalam Operation and maintenance, sistem diinstal dan mulai digunakan. Selain
itu juga memperbaiki error yang tidak ditemukan pada tahap pembuatan.
Dalam tahap ini juga dilakukan pemeliharaan software serta pengembangan
sistem seperti penambahan fitur dan fungsi bar.
3.5 Analisis Sistem
Dalam membangun sebuah aplikasi untuk mengidentifikasi penyebab
penyakit gigi dengan menggunakan metode Dempster-Shafer berbasis web
dilakukan beberapa tahap analisis yaitu :
1. Menentukan masalah yang akan dibangun untuk sebuah aplikasi. Sistem yang
akan dibangun merupakan sebuah aplikasi untuk mengidentifikasi penyebab
penyakit gigi dengan menggunakan metode Dempster-Shafer berbasis web.
45
2. Mengumpulkan data yang diperlukan untuk membangun sistem, yaitu berupa
informasi tentang gejala, penyebab, dan jenis penyakit melalui studi literatur
dan observasi yang digunakan sebagai base knowledge.
3. Mempresentasikan pengetahuan ke dalam tabel gejala yang telah dianalisis,
penelusuran gejala dan jenis penyebab penyakit.
4. Usulan sistem yang akan dibuat.
3.5.1 Sumber Informasi
Data mengenai penyebab penyakit pada gigi yaitu pengertian jenis
penyakit, gejala, penyebab serta penanganannya yang didapat dari buku, artikel,
dan situs internet.
3.5.2 Identifikasi Masalah
Langkah pertama dalam mengembangkan aplikasi adalah
mengidentifikasikan masalah yang akan dikaji, dalam hal ini adalah dengan
mengidentifikasikan permasalahan yang akan dibuat terlebih dahulu, adapun
masalah-masalah yang akan diambil dalam aplikasi untuk mengidentifikasi
penyebab penyakit pada ikan air tawar.
3.5.3 Analisis data Penyebab Penyakit dan Gejala
Keberhasilan suatu aplikasi terletak pada pengetahuan dan bagaimana
mengolah pengetahuan tersebut agar dapat ditarik suatu kesimpulan. Pengetahuan
yang diperoleh dari hasil wawancara dan analisa lewat buku dikonversi kedalam
sebuah tabel penyakit dan gejala guna mempermudah proses pencarian solusi.
Tabel jenis penyebab penyakit dan gejala ini digunakan sebagai pola pencocokan
informasi yang dimasukan oleh pemakai dan basis pengetahuan.
Pada tabel jenis penyebab penyakit dan gejala terdapat 6 jenis penyebab
penyakit yang ditunjukkan oleh PI-1, PI-2,...,PI-6 dan 21 gejala yang ditunjukkan
oleh G-1,G-2,...,G-21. Dari 21 jenis penyebab penyakit disusun sebagai
pernyataan dan 21 gejala disusun sebagai kesimpulan. Gejala ini merupakan basis
pengetahuan untuk membuat suatu kesimpulan yang menjadi goal. Berikut ini
46
adalah tabel jenis penyebab penyakit dan gejala pada Tabel 3.1 yaitu tabel gejala
dan jenis penyebab penyakit pada ikan air tawar.
Tabel 3.2 Kode Penyakit Gigi
KODE PENYAKIT
P001 Caries/Gigi berlubang
P002 Abses gigi
P003 Gingivitis (Gusi Bengkak)
P004 Pulpitis(radang pulpa gigi)
P005 Gigi pernah retak,copot,goyah
P006 malocclusion
Tabel 3.3 Kode Gejala Penyakit Gigi
KODE GEJALA
G001 Timbul bercak coklat atau putih digigi
G002 Muncul lubang cokelat
G003 Terasa ngilu saat makan dan minum
G004 Rasa sakit yang kadang-kadang dibagian gigi
G005 Sakit gigi berdenyut
G006 Sakit saat mengunyah
G007 pembengkakan kelenjar getah bening di leher
G008 Demam
G009 Mulut kering
G010 Gusi tampak merah
G011 Gusi membengkak
G012 Gusi mudah berdarah
G013 Rasa sakit yang timbul spontan dalam waktu lama
G014 Rasa sakit bila terkena rangsangan panas,dingin atau manis
G015 Rasa sakit kambuhan berbulan - bulan
G016 Gigi memiliki patahan tidak lengkap
G017 Nyeri singkat dan tajam saat makan yang dingin
G018 Rasa tidak nyaman saat mengunyah
G019 Posisi gigi bengkok
G020 Posisi gigi ramai
G021 Gigi menonjol
47
Tabel 3.4 Gejala Penyakit Gigi
Tabel 3.5 Contoh Tabel Perhitungan Gejala Penyakit Gigi
G001 G002 G003 G004 G005 G006 G007 G008 G009 G010 G011 G012 G013 G014 G015 G016 G017 G018 G019 G020 G021
1 Caries/Gigi berlubang √ 0.8 √ 0.9 √ 0.7 √ 0.5
3 Abses gigi √ 0.7 √ 0.6 √ 0.9 √ 0.8
4 Gingivitis (Gusi Bengkak) √ 0.6 √ 0.8 √ 0.9 √ 0.7
5 Pulpitis(radang pulpa gigi) √ 0.8 √ 0.7 √ 0.9
6 Gigi pernah retak,copot,goyah √ 0.5 √ 0.9 √ 0.4
7 malocclusion √ 0.6 √ 0.8 √ 0.7 √ 0.9
Tabel Gejala Penyakit Gigi
No PenyakitGejala
1 2 3 4 5 6 7 8 9 10 11 12
No Penyakittimbul bercak
coklat atau
putih digigi
muncul
lubang
cokelat
Terasa ngilu
saat makan
dan minum
Rasa sakit
yang kadang-
kadang
dibagian gigi
Sakit gigi
berdenyut
Sakit saat
mengunyah
Gusi terasa
gataldemam Gigi goyang
Gusi tampak
merah
Gusi
membengkak
Gusi mudah
berdarah
1 Caries/Gigi berlubang 1 (0,2) 1(0,3) 1(0,6) 1(0,5) 1(0,4)
2 Abses gigi 2(0,8) 2(0,7) 2(0,4) 2(0,5) 2(0,6)
3 Gingivitis (Gusi Bengkak) 3(0,3) 3(0,8) 3(0,7) 3(0,9)
4 Pulpitis(radang pulpa gigi)
5 Periodontitis 5(0,5) 5(0,9)
6 malocclusion
13 14 15 16 17 18 19 20 21
No Penyakit
Rasa sakit
yang timbul
spontan
dalam waktu
lama
Rasa sakit
bila terkena
rangsangan
panas,dingin
atau manis
Rasa sakit
kambuhan
berbulan -
bulan
Gigi memiliki
patahan tidak
lengkap
Nyeri singkat
dan tajam
saat makan
yang dingin
Rasa tidak
nyaman saat
mengunyah
Posisi gigi
bengkok
Posisi gigi
ramai /
berjejal
Gigi menonjol
1 Caries/Gigi berlubang 1 (0,9) 1 (0,8) 1 (0,1) 1 (0,7)
2 Abses gigi 2(0,9)
3 Gingivitis (Gusi Bengkak)
4 Pulpitis(radang pulpa gigi) 4(0,9) 4(0,8) 4(0,5) 4(0,1)
5 Periodontitis
6 malocclusion 6(0,7) 6(0,9) 6(0,8) 6(0,1)
ket :
angka di kolom penanda gejala penyakit yang di derita
angka di dalam kurung merupakan presentasi gejala dari penyakit tersebut
Tabel Gejala Penyakit Gigi
Dibuat Diperiksa
48
3.5.4 Identifikasi Input
Untuk proses mengidentifikasikan keluaran yang diperlukan adalah
melakukan pengumpulan data atau informasi yang mendukung dalam pembuatan
aplikasi untuk memecahkan masalah dan selanjutnya akan diproses oleh aplikasi.
Aplikasi akan mengajukan gejala-gejala penyebab penyakit yang timbul pada gigi,
gejala tersebut akan disimpan sebagai rule dalam bentuk database, dimana gejala
ini adalah salah satu cara sistem mengumpulkan informasi tentang suatu masalah
yang ingin dipecahkan.
3.5.5 Identifikasi Output
Setelah aplikasi menerima masukan dari pengguna melalui gejala yang
diajukan oleh aplikasi, maka aplikasi akan memberikan kesimpulan dari gejala
yang dijawab tersebut. Untuk kesimpulan dari gejala yang benar, maka aplikasi
akan memberikan informasi indentifikasi, dan penyebab.
3.5.6 Analisis Kebutuhan Non Fungsional
Kebutuhan non fungsional adalah usulan yang direkomendasikan kepada
pengguna agar aplikasi yang akan dibangun menjadi user friendly dan perangkat
kerasnya yang mendukung secara maksimal terhadap kinerja perangkat lunak.
3.5.6.1 Analisis Pengguna
Penyuluh yang menjadi Pakar yaitu :
Nama : Drg. Priska Widhi Anindya Santi
Jabatan : Peneliti Penyakit Gigi
Alamat : Jl.Anggrek Raya No. 10 Jababeka2, Cikarang
Pengalaman menggunakan Komputer : Windows 98, Windows 2000, Windows XP,
Windows vista.
Software yang pernah atau sering digunakan : Microsoft Office 2003, 2007.
3.5.6.2 Analisis Perangkat Keras
Perangkat keras minimum yang direkomendasikan untuk menjalankan aplikasi ini
adalah sebagai berikut :
49
Processor : Dengan kecepatan 2.0 GHz
Kapasitas Harddisk : 20 GB
RAM : 256 MB
VGA Card : 64 MB
Monitor
Mouse
Keyboard
3.5.6.3 Analisis Perangkat Lunak
Pemodelan Analisis Perangkat lunak yang digunakan adalah sistem operasi
Microsoft windows XP Professional, Bahasa Pemrogramannya menggunakan
PHP dengan toolnya Macromedia dreamweaver 8, serta menggunakan
databasenya yaitu MySQL.
3.5.6.4 Analisis Basis Data
Entity Relational Diagram (ERD) merupakan cara untuk
mengorganisasikan data, dimana diagram ini akan memperlihatkan hubungan
entitas yang terdapat dalam sistem. ERD yang diusulkan untuk sistem yang akan
dibangun dapat dilihat pada gambar 3.1 dibawah ini.
Gambar 3.5 ERD Implementasi Sistem Pakar Menggunakan Metode
Demptershafer Untuk Mendeteksi Penyakit Gigi
50
3.5.6.5 Analisis Kebutuhan Fungsional
Dalam langkah ini dilakukan penentuan entitas-entitas, atribut yang
mengalir serta prosedur-prosedur yang bisa dilakukan oleh masing-masing entitas.
3.5.6.5.1.Diagram Konteks
Diagram konteks adalah alur data yang berfungsi untuk menggambarkan
keterkaitan aliran-aliran data antara sistem dengan bagian-bagian luar. Adapun
diagram konteks untuk sistem yang akan dibangun.
Gambar 3.6 Diagram Konteks Implementasi Sistem Pakar Menggunakan
Metode Demptershafer Untuk Mendeteksi Penyakit Gigi
Implementasi Sistem
Pakar Gigi
Menggunakan
Metode
Demptershafer
Untuk Mendeteksi
Penyakit Gigi
User Admin
-data user
-konsultasi
-informasi gejala
penyaki gigi
-Info login valid
-Info login gagal
-info gejala yang harus dijawab
-info hasil konsultasi
-Informasi Gejala penyaki gigi
-Data tambah gejala dan
penyebab
-Data ubah gejala, penyebab
gejala
-Data login
-Data berita ditambah,diubah,
dihapus
-Data ganti password
-Info gejala, penyebab telah
ditambahkan
--Info gejala, penyebab telah diubah
-info login valid
-info berita telah ditambahkan,
diubah, dihapus
-Informasi password telah diganti
51
3.5.6.5.2.Data Flow Diagram (DFD)
DFD adalah sebuah teknik yang menggambarkan aliran data dan
transformasi yang digunakan sebagai perjalanan data dari masukan menuju
keluaran.
a) DFD Level 1
DFD Level 1 dibuat jika pada diagram Konteks masih terdapat proses yang
harus dijelaskan lebih rinci. Pada DFD Level, berikut ini :
Gambar 3.7 DFD Level 1 Implementasi Sistem Pakar Menggunakan
Metode Demptershafer Untuk Mendeteksi Penyakit Gigi
52
b) DFD Level 2 Proses 3 Pengolahan Data Master
Proses yang terdapat pada DFD level 2 proses 3 adalah proses pengolahan data
master yang terdiri atas proses 3.1 pengolahan data penyebab, proses 3.2
pengolahan data gejala, proses 3.3 pengobatan dan proses 3.4 data pertanyaan.
dapat dilihat pada gambar 3.4.
Gambar 3.8 DFD Level 1 Proses 3 Pengolahan Data Master
c) DFD Level 2 Proses 5 Pengolahan Konsultasi
Proses yang terdapat pada DFD level 2 proses 5 adalah proses konsultasi yang
terdiri atas proses 5.1 konsultasi, proses 5.2 hasil konsultasi. dapat dilihat pada
gambar 3.5.
53
Gambar 3.9 DFD Level 2 Proses 5 Konsultasi
d) DFD Level 3 Pros 3.1
Proses yang terdapat pada DFD level 3 proses 3.1 adalah proses pengolahan
data penyebab yang terdiri atas proses 3.1.1 tambah data penyebab, proses 3.1.2
ubah data penyebab, dapat dilihat pada gambar 3.6.
Gambar 3.10 DFD Level 3 Pros 3.1 (Pengolahan Data Penyebab)
54
e) DFD Level 3 Pros 3.2
Proses yang terdapat pada DFD level 3 proses 3.2 adalah proses pengolahan
data gejala yang terdiri atas proses 3.2.1 tambah data gejala, proses 3.2.2 ubah
data gejala, dapat dilihat pada gambar 3.7.
Gambar 3.11 DFD Level 3 Pros 3.2 (Pengolahan Data Gejala)
f) DFD Level 3 Pros 3.3
Proses yang terdapat pada DFD level 3 proses 3.3 adalah proses pengolahan
data gejala penyebab yang terdiri atas proses 3.3.1 tambah data gejala penyebab,
proses 3.3.2 ubah data gejala penyebab, proses 3.3.3 hapus data gejala penyebab
dapat dilihat pada gambar 3.8.
Gambar 3.12 DFD Level 3 Pros 3.3 (Pengolahan Data Gejala Penyebab)
55
g) DFD Level 3 Pros 5.1
Proses yang terdapat pada DFD level 3 proses 5.1 adalah proses perhitungan
nilai kepercayaan hasil konsultasi dengan menggunakan metode Dempster-Shafer
yang terdiri atas proses 5.1.1 pengumpulan data gejala, proses 5.5.2 perhitungan
nilai kepercayaan dengan menggunakan metode Dempster- Shafer, dapat dilihat
pada gambar 3.8.
Gambar 3.13 DFD Level 3 Pros 5.1 (Konsultasi)
3.6 Perancangan Sistem
Perancangan aplikasi untuk mengidentifikasi penyebab penyakit pada gigi
menggunakan metode Dempster-Shafer bertujuan untuk menerapkan solusi
pemecahan masalah yang telah diajukan pada analisis sistem.
3.6.1 Perancangan Data
Perancangan data terdiri dari Tabel Relasi dan struktur tabel yang terdapat
pada ERD dari aplikasi untuk mengidentifikasi penyebab penyakit pada gigi.
3.6.1.1 Diagram Relasi
Diagram Relasi menggambarkan suatu hubungan antar tabel yang sudah
ada dalam keadaan normal. Perancangan tabel relasi dalam membangun sebuah
aplikasi untuk mengidentifikasi penyebab penyakit pada gigi adalah sebagai
berikut :
56
Gambar 3.14 Digram relasi Implementasi Sistem Pakar Menggunakan
Metode Demptershafer Untuk Mendeteksi Penyakit Gigi
3.6.1.2 Struktur Tabel
Tabel merupakan tempat penyimpanan informasi dari sebuah aliran data
dalam sebuah sistem. Berikut merupakan struktur dari beberapa tabel sistem yang
akan dibangun.
a). Tabel tbl_diagnosa
Tabel ini berfungsi untuk menghubungkan antara tabel member dan
pertanyaan pada proses diagnosa.
57
Tabel 3.6 Tabel tbl_diagnosa
b). Tabel tbl_gejala
Tabel ini berfungsi untuk menyimpan data gejala pada penyebab penyakit
gigi.
Tabel 3.7 Tabel tbl_gejala
b). Tabel tbl_penyebab penyakit
Tabel ini berfungsi untuk menyimpan data penyebab penyakit.
Tabel 3.8 Tabel tbl_penyebab penyakit
c). Tabel tbl_admin
Tabel ini berfungsi untuk menyimpan data administrator yang nanti akan
mengelola program ini.
58
Tabel 3.9 Tabel tbl_admin
3.7 Pengujian Perangkat Lunak
Pengujian merupakan bagian yang sangat penting dalam siklus
pembangunan perangkat lunak untuk menjamin kualitas dan pemenuhan tujuan
dibangunnya perangkat lunak. Pengujian dilakukan untuk menjamin kualitas dan
juga mengetahui kelemahan dari perangkat lunak. Tujuan dari pengujian ini
adalah untuk menjamin bahwa perangkat lunak yang dibangun memiliki kualitas
yang baik, yaitu sesuai dengan analisis, perancangan dan pengkodean serta
mampu memenuhi kebutuhan pengguna.
3.7.1 Rencana Pengujian
Berikut ini pengujian perangkat lunak pada implementasi sistem pakar
menggunakan metode Dempter Shafer untuk mendekteksi penyakit gigi terdiri
dari :
Tabel 3.10 Tabel Rencana Pengujian
Requirement yang diajukan Butir uji
Login User -Pengisian Username
-Pengisisan Password
Master Data Utama -Pengisian home, penyakit, gejala, basis
aturan, hasil diagnosa, laporan, buku
tamu, pengaturan admin
Penyakit -Berisi table penyakit dan tombol button
59
daftar penyakit, hapus serta ubah
Gejala -Berisi detail data gejala dan tombol
button daftar gejala, hapus serta ubah
Basis Aturan - Berisi detail basis aturan dan tombol
button daftar aturan, hapus serta ubah
Hasil Diagnosa -Berisi data hasil diagnosa dan tombol
button hapus serta ubah
Laporan Hasil Diagnosa Menampilkan laporan hasil diagnosa
Buku Tamu Berisi data tamu yang masuk dan tombol
button hapus serta ubah
Pengaturan Admin Unttuk merubah password
3.7.2 Hasil Pengujian
Berikut adalah hasil pengujian perangkat lunak berdasarkan requirement
pada rencana pengujian :
Tabel 3.11 Tabel Hasil Pengujian
Requirement Diajukan Hasil yang
diharapkan
Hasil
pengujian
Login User 1 Input
username,
password
& level
Masuk sesuai id
yang diakses
(y) diterima
( ) ditolak
Mulai Diagnosa 1
2
Isi Data
Pasien
Klik
Ya/Tidak
gejala
yang
dialami
pasien
Data tersimpan
ke database
Data akan
tersimpan
dibatalkan
(y) diterima
( ) ditolak
(y) diterima
( ) ditolak
Basis Aturan
1
2
Klik
tombol
Add daftar
Gejala
Klik
tombol
Data tersimpan
ke database
Data akan
dirubah/ tidak
(y) diterima
( ) ditolak
(y) diterima
( ) ditolak
60
3
ubah
Klik
tombol
hapus
Otomatis data
akan terhapus
(y) diterima
( ) ditolak
Master data customer 1
2
3
Klik
tombol
Add daftar
Basis
Aturan
Klik
tombol
ubah
Klik
tombol
hapus
Data tersimpan
ke database
Data akan
dirubah/ tidak
Otomatis data
akan terhapus
(y) diterima
( ) ditolak
(y) diterima
( ) ditolak
(y) diterima
( ) ditolak
Hasil Diagnosa
1
2
3
Klik
tombol
Hasil
Diagnosa
Klik
tombol
ubah
Klik
tombol
lihat
diagnosa
Akan tampil
data detail hasil
diagnosa
Data akan
dirubah/ tidak
Tampil data
hasil diagnosa
(y) diterima
( ) ditolak
(y) diterima
( ) ditolak
(y) diterima
( ) ditolak
Laporan 1
Klik di
tombol
laporan
Menampilkan
hasil laporan
hasil diagnosa
(y) diterima
( ) ditolak
Buku Tamu 1
2
Klik di
tombol
buku tamu
Klik
tombol
hapus
Menampilkan
data buku tamu
Otomatis data
akan terhapus
(y) diterima
( ) ditolak
(y) diterima
( ) ditolak
Pengaturan Admin 1
Klik
tombol
pengaturan
admin
Data tersimpan
ke database
(y) diterima
( ) ditolak
61
2
Klik
tombol
ubah
Data password
lama akan
diganti dengan
password baru
(y) diterima
( ) ditolak
2.5.3 Kesimpulan dan Hasil Pengujian
Berdasarkan hasil pengujian pada ssetiap inputan proses yang dilakukan,
baik dari sisi administrator maupun dari sisi user, dapat diambil kesimpulan
bahwa sistem yang dibuat telah memenuhi standar pengujian. Sehingga dapat
ditarik kesimpulan bahwa perangkat lunak bebas dari kesalahan sintaks dan secara
fungsional mengeluarkan hasil yang sesuai dengan yang diharapkan.
62
BAB IV
PERANCANGAN DAN IMPLEMENTASI SISTEM
4.1 Perancangan Sistem
Untuk menjawab permasalahan yang timbul baik dari latar belakang serta
rumusan yang telah dijelaskan, berikut gambaran pemecahan masalahnya :
Gambar 4.1 Use Case Sistem Pakar Penyakit Gigi
Dari uses case diatas dapat dijelaskan sebagai berikut :
Tabel 4.1 Use Case Sistem Pakar Gigi
Nama Use Case
Use Case Sistem Pakar gigi
Aksi actor Aksi sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen, lalu
masuk ke menu utama
3. Klik button mulai diagnose
4. Tampil tampilan menu mulai
diagnosa
User
Menu utama
Pilih konsultasi
Pilih gejala
Hasil diagnosa
Buka aplikasi
Pilih lanjut konsultasi
Use Case Sistem Pakar Penyakit Gigi Santi
Pilih mulai diagnosa
63
5. Isi data pasien dan pilih gejala
dengan di centang
6. Klik button konsultasi
7. Sistem mengkalkulasi inputan
menggunakan metode
8. Muncul hasil diagnose
Untuk menggambarkan interaksi antar objek termasuk pengguna dan
tampilan agar lebih jelas Alur proses konsultasi digambarkan Menggunakan
Sequence diagram sebagai berikut :
(1) Sequence Mulai Diagnosa
Gambar 4.2 Diagram Sequence Mulai Diagnosa
Dari diagram sequence mulai Diagnosa di atas dapat diuraikan sebagai berikut :
Tabel 4.2 Sequence Konsultasi
Nama Use Case
Sequence konsultasi
Aksi actor Aksi Sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen,
lalu masuk ke menu utama
3. Klik button mulai diagnosa
4. Tampil tampilan menu mulai
Menu Konsultasi Gejala Proses data
: User
1 : Buka aplikasi()
2 : Pilih konsultasi()
3 : Pilih gejala()
4 : Proses data()
5 : Tampil hasil diagnosa()
Diagnosa
Use
Case
Siste
m
Pakar
Penya
kit
Gigi
Use
Case
Siste
m
Pakar
Penya
kit
Gigi sa
Menu
Gejala Proses Data
64
dignosa
5. Klik Lanjut konsultasi
6. Tampil Pilihan gejala
7. Pilih gejala yang dialami
8. Klik button proses
9. Metode sistem pakar
menentukan presentase
penyakit yang diderita
10. Tampil hasil diagnosa
(2) Sequence Basis Aturan
Gambar 4.3 Diagram Sequence Basis Aturan
Dari diagram sequence di atas dapat diuraikan sebagai berikut :
Tabel 4.3 Sequence Basis Aturan
Nama Use Case
Sequence Basis Aturan
Aksi actor Aksi sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen, lalu
masuk ke menu utama
Menu utama Kosultasi Riwayat
: user
1 : Buka aplikasi()
2 : Klik konsultasi()
3 : Klik riwayat()
4 : Tampil Riwayat()
Klik Basis Aturan ()
Tampil Basis Aturan()
Menu
Utama Basis Aturan Riwayat
65
3. Klik button Basis Aturan
4. Tampil tampilan data basis
aturan per enyakit
(3) Sequence Diagram Daftar Gejala
Gambar 4.4 Diagram Sequence Daftar Gejala
Dari diagram sequence di atas dapat diuraikan sebagai berikut :
Tabel 4.4 Sequence Daftar Gejala
Nama Use Case
Sequence daftar gejala
Aksi actor Aksi sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen, lalu
masuk ke menu utama
3. Klik button daftargejala
4. Tampil tampilan menu daftar
gejala gigi
Menu utama Daftar penyakit Penyakit
: user
1 : Buka aplikasi()
2 : Klik daftar penyakit()
3 : Pilih penyakit()
4 : Tampil penyakit()
Menu
Utama Daftar Gejala Penyakit
Klik daftar gejala()
Tampil daftar gejala()
66
Menu utama Profile
: user
1 : Buka aplikasi()
2 : Klik Profile pembuat()
3 : Tampil proofile pembuat()
(4) Sequence Digram Buku Tamu
Gambar 4.5 Diagram Sequence Buku Tamu
Dari diagram sequence pembuat di atas dapat diuraikan sebagai berikut :
Tabel 4.5 Sequence Buku Tamu
Nama Use Case
Sequence Buku Tamu
Aksi actor Aksi Sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen,
lalu masuk ke menu utama
3. Klik button buku tamu
4. Tampil tampilan menu buku
tamu
Menu Utama Buku Tamu
Klik buku tamu()
Tampil buku tamu()
67
(5) Sequence Diagram Info
Gambar 4.6 Diagram Sequence Laporan
Dari diagram sequence info di atas dapat diuraikan sebagai berikut :
Tabel 4.6 Sequence Laporan
Nama Use Case
Sequence Laporan
Aksi actor Aksi sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen,
lalu masuk ke menu utama
3. Klik button laporan
4. Tampil tampilan menu cetak
laporan hasil diagnosa
5. Klik button proses dan pilih
tanggal yang ingin diliat
laporannya
6. Tampil tampilan menu laporan
Menu utama Info
: user
1 : Buka aplikasi()
2 : Klik info()
3 : Tampil info()
Klik Laporan()
Laporan
Tampil Laporan()
Menu Utama Laporan
68
(6) Sequence Diagram Pengaturan
Gambar 4.7 Diagram Sequence Pengaturan
Dari diagram sequence di atas dapat diuraikan sebagai berikut :
Tabel 4.7 Sequence Pengaturan
Nama Use Case
Sequence Pengaturan
Aksi actor Aksi Sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen,
lalu masuk ke menu utama
3. Klik button pengaturan
4. Tampil tampilan menu
pengaturan
Menu utama tips
: user1 : Buka aplikasi()
2 : Klik tips()
3 : Tampil tips()
Klik Pengaturan()
Tampil Pengaturan()
Menu Utama Pengaturan
69
(7) Sequence Diagram Keluar
Gambar 4.8 Diagram Sequence Keluar
Dari diagram sequence di atas dapat diuraikan sebagai berikut :
Tabel 4.8 Sequence Keluar
Nama Use Case
Sequence keluar
Aksi actor Aksi Sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen, lalu
masuk ke menu utama
3. Klik button keluar
4. Muncul message box yes/no
5. Klik yes
6. Keluar aplikasi
Untuk mengetahui alur aktivitas dan proses paralel yang mungkin terjadi
pada beberapa eksekusi digambarkan menggunakan diagram activity sebagai
berikut:
Menu utama Keluar
: user1 : Buka aplikasi()
2 : Pilih keluar()
3 : Keluar aplikasi()
70
(1) Activity Diagram Mulai Diagnosa
Gambar 4.9 Diagram activity mulai diagnosa
Dari diagram activity di atas dapat diuraikan sebagai berikut :
Tabel 4.9 Diagram Activity Diagnosa
Nama Use Case
Diagram Activity Mulai Diagnosa
Aksi actor Aksi system
1. Pengguna membuka aplikasi
2. Akan muncul splash screen, lalu
masuk ke menu utama
3. Klik butto mulai diagnose
4. Tampil tampilan menu mulai
dignosa
5. Pilih gejala dengan centang
6. Klik button konsultasi
7. Sistem menyimpan nilai ke dalam
database
8. Sistem mengkalkulasi inputan
menggunakan metode
9. Muncul hasil diagnosa
User Sistem
Menu konsultasi
Pilih gejala
Simpan nilai
Kalkulasi
Hasil diagnosa
Buka aplikasi Menu utama
Klik Konsultasi
Klik proses
71
(2) Activity Diagram Basis Aturan
v
Gambar 4.10 Diagram Activity Basis Aturan
Dari diagram activity di atas dapat diuraikan sebagai berikut :
Tabel 4.10 Diagram Activity Basis Aturan
Nama Use Case
Diagram Activity Basis Aturan
Aksi actor Aksi Sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen, lalu
masuk ke menu utama
3. Klik button basis aturan
4. Tampil tampilan menu basis aturan
5. Klik button basis aturan
6. Tampil tampilan detail basis aturan
User Sistem
Buka aplikasi Menu utama
Tampil pembuatKlik pembuatKlik Basis Aturan
Menu Utama
Tampilan Basis
Aturan
Buka Aplikasi
72
(3) Activity Diagram Daftar Penyakit
Gambar 4.11 Diagram Activity Daftar Penyakit
Dari diagram activity di atas dapat diuraikan sebagai berikut :
Tabel 4.11 Diagram Activity Daftar Penyakit
Nama Use Case
Diagram Activity Daftar Penyakit
Aksi actor Aksi sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen, lalu
masuk ke menu utama
3. Klik button daftar penyakit
4. Tampil tampilan menu daftar
penyakit
5. Klik button penyakitnya
6. Tampil penyakit, gambar dan
keteranganya
User Sistem
Buka aplikasi Menu utama
klik penyakit Tampil penyakit
Klik daftar penyakit Daftar penyakit
73
(4) Activity Diagram Gejala
Gambar 4.12 Diagram Activity Gejala
Dari diagram activity di atas dapat diuraikan sebagai berikut :
Tabel 4.12 Diagram Activity Gejala
Nama Use Case
Diagram Activity Gejala
Aksi actor Aksi sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen, lalu
masuk ke menu utama
3. Klik button Gejala
4. Tampil tampilan detail data gejala
User Sistem
Buka aplikasi Menu utama
Tampil pembuatKlik pembuatKlik Gejala
Buka Aplikasi
Klik Gejala
Menu Utama
Tampil Gejala
74
(5) Activity Diagram Buku Tamu
Gambar 4.13 Diagram Activity Buku Tamu
Dari diagram activity di atas dapat diuraikan sebagai berikut :
Tabel 4.13 Diagram Activity Buku Tamu
Nama Use Case
Diagram Activity Buku Tamu
Aksi actor Aksi Sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen, lalu
masuk ke menu utama
3. Klik button buku tamu
4. Tampil tampilan menu buku tamu
User Sistem
Buka aplikasi Menu utama
Tampil pembuatKlik pembuatKlik Buku tamu
Tampil Buku tamu
Buka Aplikasi
Klik Buku Tamu
Menu Utama
Tampil Buku Tamu
75
(6) Activity Diagram Hasil Diagnosa
Gambar 4.14 Diagram Activity Hasil Dignosa
Dari diagram activity di atas dapat diuraikan sebagai berikut :
Tabel 4.14 Diagram activity Hasil Diagnosa
Nama Use Case
Diagram activity Hasil Diagnosa
Aksi actor Aksi sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen, lalu
masuk ke menu utama
3. Klik button hasil diagnose
4. Tampil tampilan menu detail hasil
diagnosa
User Sistem
Buka aplikasi Menu utama
Tampil pembuatKlik pembuat
Buka Aplikasi
Klik Hasil Diagnosa
Menu Utama
Tampil Hasil
Diagnosa
76
(7) Activity Diagram Keluar
Gambar 4.15 Diagram Activity Keluar
Dari diagram activity di atas dapat diuraikan sebagai berikut :
Tabel 4.15 Diagram Activity Keluar
Nama Use Case
Diagram Activity Keluar
Aksi actor Aksi sistem
1. Pengguna membuka aplikasi
2. Akan muncul splash screen, lalu
masuk ke menu utama
3. Klik button keluar
4. Muncul pesan apakah anda yakin
akan keluar? Ya/tidak
5. Pilih ya apabila ingin keluar
6. Keluar aplikasi
7. Pilih tidak jika batal
8. Akan muncul splash screen, lalu
masuk ke menu utama
User Sistem
Menu utama
Klik Keluar
Keluar aplikasi
Ya
Tidak
Buka aplikasi
77
Untuk menentukan kelas - kelas serta relasi antar kelas untuk menentukan
struktur dari sistem yang akan dibuat digambarkan menggunakan class diagram
sebagai berikut :
Gambar 4.16 Class Diagram Sistem Pakar Gigi
4.2 Design Sistem
Merupakan bagian yang menggambarkan bentuk rancangan atau tampilan
dari sistem yang ingin di buat. Pembuatan perancangan ini untuk mempermudah
kita dalam proses pembuatan program nantinya, dan juga sebagai alat komunasi
sistem dengan user. Perancangan ini berisi tampilan serta form - form apa saja
yang di butuhkan serta fitur-fitur yang di sediakan dalam rancangan program agar
lebih efektif dan sesuai dengan harapan.
4.2.1. Rancangan Tampilan Login
Tampilan Login merupakan form tampilan awal pada saat aplikasi pertama
kali di jalankan, form ini hanya muncul dalam durasi beberapa detik dengan
masukan username dan password.
Penyakit
+id+kode+penyakit+status+persen
+simpanstatus()+simpanpersen()+updatenilaistatus()+updatepersen()
Gejala
+id+kode+gejala+status
+deleteid()+deletekode()+deletegejala()+deletestatus()+simpanstatus()+updatenilaistatus()
User
+id+nama+penyakit
+simpannama()+simpanid()+simpanpenyakit()
* 1
*
z
Z
z
z
78
Gambar 4.17 Rancangan Tampilan Login
4.2.2 Rancangan Menu Utama
Menu utama merupakan tampilan menu dari sistem yang di buat, berisikan
beberapa sub - sub form pilihan. Form ini juga dimaksudkan untuk membantu
user dalam memilih menu - menu selanjutnya
Gambar 4.18 Rancangan Tampilan Menu Utama
4.2.3 Rancangan Menu Mulai Diagnosa
Menu mulai dignosa berfungsi untuk melakukan konsultasi, dimana user
harus mengisi data pasien dan memilih gejala - gejala yang di alami dengan cara
mengisi data pasien dan klik pada bagian gejala yang dipilih lalu akan muncul
Home Penyakit Gejala Basis Aturan Hasil Diagnosa Laporan Buku Tamu Pengaturan Admin Logout
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SISTEM PAKAR DIAGNOSA PENYAKIT GIGI
DEMPSTER SHAFER
Username :
Password :
LOGIN
LOGIN ADMIN
79
contreng biru pada gejala yang dipilih. Setelah user selesai memilih gejala,
kemudian klik button konsultasi maka sistem akan menampilkan hasil diagnosa
berupa gejala yang dipilih, presentasi kemungkinan penyakit .
Gambar 4.19 Rancangan Tampilan Menu Mulai Diagnosa
Setelah gejala di pilih, lalu tekan tombol konsultasi maka muncul hasil
diagnosanya seperti gambar di bawah ini :
Gambar 4.20 Rancangan Tampilan Hasil Diagnosa
Keterangan
Data Pasien :
XXXXXXXXXXXXXXXXXXX
Hasil Diagnosai :
XXXXXXXXXXXXXXXXXXX XXXXX xxxxxx
Kesimpulan hasil konsultasi
KODE GEJALA
Nama
Jenis Kelamin
Usia
Alamat Pasien
Laki-laki
Berikut Daftar Data Gejala :
Konsultasi
Keterangan
DATA PASIEN :
Perempuan
GEJALA PENYAKIT PILIHAN
YA TIDAK E001 Bau Mulut Busuk
Gejala Yang Dihadapi :
80
4.2.4 Rancangan Menu Basis Aturan
Menu Basis Aturan menampilkan penyakit sesuai dengan hasil nilai
densitas gigi. User dapat melihat hasil penyakit sesuai gejala penyakitnya.
Gambar 4.21 Rancangan Tampilan Basis Aturan
4.2.5 Rancangan Menu Daftar Gejala
Gambar 4.22 Rancangan Tampilan Daftar Gejala
Keterangan
Penyakit Gejala
Kode Nama Gejala Nilai Idensitas
Keterangan
DAFTAR GEJALA GIGI :
Penyakit :
No. Gejala
81
4.2.6 Rancangan Menu Buku Tamu
Menu buku tamu menampilkan pesan dari pasien dari hasil menggunakan
aplikasi ini.
Gambar 4.23 Rancangan Tampilan Buku Tamu
4.2.7 Rancangan Menu Penyakit
Menu penyakit menampilkan daftar penyakit pada gigi. Pada menu
penyakit ini administrator dapat menambahkan daftar penyakit dengan klik pada
buttom tambah daftar penyakit serta dapat menghapus daftar penyakit dengan klik
buttom hapus. Dalam menu penyakit juga dapat mengubah daftar penyakit dengan
cara klik button ubah akan muncul form yang akan di isi sesuai dengan hasil dari
nilai believenya.
BUKU TAMU
Nama Tamu :
Email :
Pesan :
f1af63
(masukan 6 kode diatas)
Kirim
82
Gambar 4.24 Rancangan Tampilan Penyakit
4.2.8 Rancangan Menu Hasil Diagnosa
Menu hasil diagnosa berisikan informasi tentang hasil dari data hasil
diagnosa pasien. Adapun fungsi dari form ini untuk melihat data pasien yang
menggunakan sistem ini.
Gambar 4.25 Rancangan Tampilan Hasil Diagnosa
DAFTAR PENYAKIT GIGI :
Tambah Daftar Penyakit Hapus
No. Kode Penyakit Nama Penyakit Pencegahan Pengobatan Nilai Beive Ubah
Jumlah Data :
Halaman :
BERIKUT DETAIL DATA HASIL DIAGNOSA :
Hapus
No. Nama Jenis Kelamin Usia Alamat
Jumlah Data :
Halaman :
Lihat Diagnosa
83
4.2.9 Rancangan Menu Keluar
Menu keluar merupakan menu pilihan untuk keluar dari aplikasi, pada saat
di klik akan muncul pesan “Anda sudah berhasil keluar ?” .
Gambar 4.26 Rancangan Tampilan Keluar
4.3 Implementasi Sistem
Implementasi sistem merupakan tahap pembuatan semua rancangan
yang sudah ada ke dalam sistem sesungguhya. Tampilan yang di buat di bagi
menjadi beberapa modul dan setiap modul berisikan beberapa form.
4.3.1 Tampilan Pada Administrator
4.3.1.1 Tampilan Login
Menu ini sebagai tampilan awal atau pembuka aplikasi, agar bias
membuka menu ini harus mengisi username dan paswordnya kemudian klik
button loginya.
Minggu, 29 Juli 2018 - 2:53:40
Anda sudah berhasil keluar.
Username :
Password :
Login
LOGIN ADMIN
84
Gambar 4.27 Tampilan Login
4.3.1.2 Tampilan Menu Utama
Menu utama sebagai tampilan pilihan untuk melanjutkan ke menu -
menu selanjutnya.
Gambar 4.28 Tampilan Menu Utama
85
4.3.1.3 Tampilan Menu Penyakit
Tampilan ini berisi tentang daftar penyakit pasien yang di derita dan
disini administrator dapat menambahkan daftar penyakit serta menghapusnya.
Gambar 4.29 Tampilan Menu Penyakit
4.3.1.4 Tampilan Menu Gejala
Tampilan menu gejala ini berisi tentang detail data gejala pasien,
disini administrator dapat menambah daftar gejala, hapus dan ubah daftar
gejalanya.
Gambar 4.30 Tampilan Menu Gejala
86
4.3.1.5 Tampilan Menu Basis Aturan
Tampilan menu basis aturan ini berisi tentang detail data basis aturan
pasien, disini administrator dapat menambah daftar gejala, hapus dan ubah
daftar gejalanya.
Gambar 4..31 Tampilan Menu Basis Aturan
4.3.1.6 Tampilan Menu Hasil Diagnosa
Tampilan menu hasil diagnosa ini berisi tentang detail data hasil
diagnosa pasien, disini administrator dapat menghapus dan melihat dignosa
pasien.
Gambar 4.32 Tampilan Menu Hasil Diagnosa
87
4.3.1.7 Tampilan Menu Laporan
Tampilan menu laporan ini berisi tentang laporan hasil diagnosa
pasien dan bisa dilihat sesuai kebutuhan yang ingin dilihat laporan data
pasiennya karena bisa kita search sesuai dengan per minggu, bulan, dan tahun.
Gambar 4.33 Tampilan Menu Laporan
Gambar 4.34 Contoh Tampilan Menu Hasil Laporan
88
4.3.1.8 Tampilan Menu Buku Tamu
Tampilan buku tamu ini berisi tentang data buku tamu pasien dan
administrator dapat menghapus serta melihat data buku tamu pasien.
Gambar 4.35 Tampilan Menu Buku Tamu
4.3.1.9 Tampilan Menu Pengaturan Admin
Tampilan menu pengaturan detail data admin pada saat login dan
administrator dapat mengubah username dan password sesuai kebutuhan.
Gambar 4.36 Tampilan Menu Pengaturan Admin
89
4.3.1.10Tampilan Menu Logout
Tampilan menu logout berfungsi untuk dapat keluar dari aplikasi
tersebut.
Gambar 4.37 Tampilan Menu Logout
4.3.2 Tampilan Pada User
4.3.2.1 Tampilan Menu Utama
Menu utama sebagai tampilan pilihan untuk melanjutkan ke menu -
menu selanjutnya.
Gambar 4.38 Tampilan Menu Utama
90
Untuk konsultasi dengan sistem pakar dapat memilih menu mulai
diagnosa, apabila user ingin melihat hasil dari nilai idensitas per penyakit yang
dikeluhkan dapat dilihat dari data basis aturan , sedangkan menu daftar gejala
berisikan daftar gejala penyakit pasien, menu buku tamu berisikan pesan
terhadap pemakaian aplikasi tersebut, user dapat memilih menu info dan
apabila ingin keluar aplikasi maka pilih keluar.
4.3.2.2 Tampilan Menu Mulai Diagnosa
Menu mulai diagnosa berisikan data pasien dan daftar gejala penyakit
gigi yang sedang diderita pasien, dimana user harus memilih gejala yang di
alami untuk melakukan proses konsultasi lalu di lanjutkan klik tombol
konsultasi.
User dapat memilih beberapa gejala sekaligus dengan klik pada gejala
yang ingin di pilih, gejala yang telah di pilih akan terdapat tanda contreng
hitam.
Gambar 4.39 Tampilan Menu mulai dignosa
91
Setelah di proses maka akan mucul hasil kemungkinan diagnosa
penyakit yang dialami menggunakan presentasi, penyakit dengan presentasi
terbanyak memiliki kemungkinan terbesar penyakit gigi yang di derita.
Gambar 4.40 Tampilan Hasil Diagnosa
4.3.2.3 Tampilan Basis Aturan
Menu Basis aturan berisikan tentang data basis aturan per penyakit
dengan 4.melihat hasil dari nilai densitasnya.
Gambar 4.41 Tampilan Basis Aturan
92
4.3.2.4 Tampilan Daftar Gejala
Menu daftar gejala berisi tentang daftar gejala penyakit gigi yang di
derita pasien.
Gambar 4.42Tampilan Daftar Gejala
4.3.2.5 Tampilan Buku Tamu
Tampilan buku tamu berisi tentang pesan dari pasien yang telah
menggunakan aplikasi program tersebut.
Gambar 4.43 Tampilan Buku Tamu
93
4.4 Pengujian Sistem
Pengujian sistem bertujuan untuk memastikan apakah sistem yang
dirancang sudah sesuai dengan harapan, selain itu untuk memastikan kualitas serta
kehandalan dari sistem ini. Tidak hanya input data tetapi juga berfungsi sesuai
dengan sistem untuk menentukan output yang di harapkan. Untuk pengujian
dilakukan setelah sistem selesai dan siap diuji. Dan hasil dari pengujian tersebut
dituangkan ke dalam sebuah tabel.
4.4.1 Spesifikasi Hardware dan Software
Perangkat keras yang dibutuhkan oleh sistem adalah suatu unit komputer.
Perangkat keras dan perangkat lunak yang diusulkan ini dibuat berdasarkan
kebutuhan sistem saat ini dan antisipasi kabutuhan di masa yang akan datang.
Konfigurasi yang dibutuhkan pada design sistem yang diusulkan, yaitu:
4.3.1.1 Spesifikasi Perangkat Keras
a. Laptop dengan prosesor Intel Dual Core CPU 2.1 GHz 32bit
b. Memory RAM 1 GB
c. Hardisk 160 GB
d. VGA 256 MB
e. Modem/ Wifi/ Hotspot
f. Monitor
g. Mouse & Keyboard
4.3.1.2 Spesifikasi Perangkat Lunak
a. Micrososft Windows xp Sp 3, system operasi yang digunakan pada
website ini
b. Adobe Dreamweaver CS5 digunakan untuk membuat program dan
tampilan website
c. MySQL server
d. Internet Google Chrome sebagai browser internet.
94
4.4.2 Pengujian Pada Menu Konsultasi
Berikut ini hasil dari pengujian sistem yang berupa tabel pengujian pada
menu konsultasi sebagai berikut :
Tabel 4.16 Pengujian Menu Konsultasi
No Skenario
Pengujian Kegiatan
Hasil Yang
Diharapkan
Hasil
Pengujian Kesimpulan
1
Saat klik button
mulai diagnose
akan tampil form
lanjutan
Klik
Tampil form
lanjutan
Tampil
form
lanjutan
Sesuai
2
Saat klik button
lanjut konsultasi
akan tampil form
konsultasi yeng
berisi gejala -
gejala
Klik
Tampil form
konsultasi
Tampil
form
konsultasi
Sesuai
3
Saat klik button
basis aturan akan
mucul data basis
aturan per
penyakit
Klik
Tampil form
basis aturan
per penyakit
Tampil
form basis
aturan per
penyakit
Sesuai
4
Saat pilih daftar
gejala lalu klik
button proses
maka akan
muncul daftar
penyakit gigi
Klik
Tampil form
daftar gejala
Tampil
form daftar
gejala
Sesuai
5
Saat klik buku
tamu akan tampil
form isi buku
tamu
Klik
Tampil form
buku tamu
Tampil
form buku
tamu
Sesuai
4.4.3 Pengujian Pada Menu Daftar Penyakit
Berikut ini hasil dari pengujian sistem yang berupa tabel pengujian pada
menu daftar penyakit sebagai berikut :
95
Tabel 4.17 Pengujian Menu Daftar Penyakit
No Skenario
Pengujian Kegiatan
Hasil Yang
Diharapkan
Hasil
Pengujian Kesimpulan
1
Saat klik
button daftar
penyakit maka
akan tampil
form daftar
penyakit
Klik
Tampil form
daftar penyakit
Tampil
form daftar
penyakit
Sesuai
2
Saat klik
button
penyakit maka
akan tampil
penyakit
Klik
Tampil
penyakit
Tampil
penyakit
Sesuai
4.4.4 Pengujian Pada Menu Buku Tamu
Berikut ini hasil dari pengujian sistem yang berupa tabel pengujian pada
menu buku tamu sebagai berikut :
Tabel 4.18 Pengujian Menu Buku Tamu
No Skenario
Pengujian Kegiatan
Hasil Yang
Diharapkan
Hasil
Pengujian Kesimpulan
1
Saat klik button
buku tamu
maka akan
tampil form
buku tamu
Klik
Tampil form
buku tamu
Tampil form
buku tamu
Sesuai
4.4.5 Pengujian Pada Menu Mulai Dignosa
Berikut ini hasil dari pengujian sistem yang berupa tabel pengujian pada
menu mulai diagnosa sebagai berikut.
Tabel 4.19 Pengujian Menu Menu Mulai Dignosa
No Skenario
Pengujian Kegiatan
Hasil Yang
Diharapkan
Hasil
Pengujian Kesimpulan
1
Saat klik
button mulai
diagnosa
maka akan
Klik
Tampil form
mulai
diagnosa
Tampil form
mulai diagnosa
Sesuai
96
tampil form
diagnosa
2
Saat klik
button
konsultasi
maka menuju
ke hasil
diagnosa
Klik
Tampil form
hasil dignosa
Tampil form
hasil dignosa
Sesuai
4.4.6 Pengujian Menu Pada Gejala
Berikut ini hasil dari pengujian sistem yang berupa tabel pengujian pada
menu gejala sebagai berikut :
Tabel 4.20 Pengujian Menu Gejala
No Skenario
Pengujian Kegiatan
Hasil Yang
Diharapkan
Hasil
Pengujian Kesimpulan
1
Saat klik button
menu gejala
maka akan
tampil form
menu gejala
Klik
Tampil form
menu detail
data gejala
Tampil
form menu
detail data
gejala
Sesuai
4.4.7 Pengujian Pada Menu Keluar
Berikut ini hasil dari pengujian sistem yang berupa tabel pengujian pada
menu keluar sebagai berikut :
Tabel 4.21 Pengujian Menu Keluar
No Skenario
Pengujian Kegiatan
Hasil Yang
Diharapkan
Hasil Pe=-
ngujian Kesimpulan
1
Saat klik
button
Logout Klik
Maka anda
sudah keluar
dari aplikasi
Maka anda
sudah keluar
dari aplikasi
Sesuai
97
BAB V
PENUTUP
5.1 Kesimpulan
Berdasarkan hasil pengembangan dan pembahasan sistem untuk mendiagnosa
penyakit gigi dengan metode Dempster Shafer, maka dapat ditarik kesimpulan
sebagai berikut:
(1) Sistem tidak memerlukan biaya yang mahal karena dapat dijalankan
menggunakan perangkat berbasis Website dengan menggunakan PHP dan
database MySQL.
(2) Hasil dari penelitian ini mampu memberikan informasi seputar gigi sehingga
memberikan pengetahuan gigi kepada penggunanya.
(3) Sistem diimplementasikan ke perangkat website menggunakan metode
Dempster Shafer.
(4) Sistem dapat memberikan hasil diagnosa dengan akurasi tinggi. Sebagai
perhitungan nilai probabilitasnya menggunakan metode Dempster Shafer
yang mengkombinasikan penyakit, gejala dan nilai probabilitas.
(5) Sistem dapat mengetahui jenis penyakit gigi serta penanganan yang tepat
sesuai gejala yang dipilih.
98
5.2 Saran
Berdasarkan penelitian dan pembahasan yang telah dilakukan maka penulis
ingin memberikan saran yang diharapkan dapat berguna untuk pengembang
berikutnya :
(1) Sebaiknya sistem lebih dikembangkan lagi cakupannya, tidak hanya penyakit
gigi tapi juga bisa ditambahkan penyakit mulut pada manusia.
(2) Untuk sistem yang lebih baik mungkin bisa diterapkan sistem database yang
dinamis, sehingga lebih memberikan kemudahan apabila ada perubahan serta
bila ada penambahan - penambahan baik gejala maupun penyakit.
99
DAFTAR PUSTAKA
1. Dahria, Muhammad , Silalahi, Rosindah ,Ramadhan, Mukhlis 2013,
SISTEM PAKAR METODE DEMPSTER SHAFER UNTUK
MENENTUKAN JENIS GANGGUAN PADA ANAK, Medan, Jurnal
STMIK Triguna Dharma.
2. Fadli, Ari 2010, Sistem Pakar Dasar, IlmuKomputer.com.
3. Irawan 2012, Membuat Aplikasi Android Untuk Orang Awam,
Palembang, Maxicom.
4. Khotimah, Bain Khusnul 2010, Sistem Pakar Troubleshooting Komputer
dengan metode Certainty Factor Menggunakan Probabilitas Bayesian,
Madura, Jurnal Universitas Trunojoyo.
5. Kusumawardani, Endah 2011, Buruknya Kesehatan GIGI dan MULUT
Memicu Penyakit Diabetes, Stroke dan Jantung, Yogyakarta, SIKLUS.
6. Masykur, Fauzan 2012, IMPLEMENTASI SISTEM PAKAR
DIAGNOSIS PENYAKIT DIABETES MELLITUS MENGGUNAKAN
METODE FUZZY LOGIC, Semarang, Jurnal UNIVERSITAS
DIPONEGORO SEMARANG.
7. Nurhasanah, Youllia Indrawaty , & Fujiansyah Frenky 2010,
PEMBUATAN SISTEM PAKAR UNTUK MEMPREDIKSI AWAL
PENYAKIT GIGI DAN MULUT BERBASIS WEB DENGAN
METODA BACKWARD CHAINING, Semarang, SEMINAR NASIONAL
ILMU KOMPUTER UNIVERSITAS DIPONEGORO.
100
8. Safaat H, Nazruddin 2012, Pemrograman Aplikasi Mobile Smartphone dan
Tablet PC Berbasis Android, Bandung, Informatika Bandung.
9. Sulistyorini, Prastuti 2009, Pemodelan Visual dengan Menggunakan UML
dan Rational Rose, Yogyakarta, Jurnal Teknologi Informasi DINAMIK
Volume XIV, No.1, Januari 2009 : 23-29.
10. Tim Penerbit ANDI 2009, Pengembangan Sistem Pakar Menggunakan
VISUAL BASIC, Yogyakarta, ANDI.
11. Widodo, Prabowo Pudjo , Herlawati 2011, MENGGUNAKAN UML
Secara Luas Digunakan Untuk Memodelkan Analisis & Desain Sistem
Berorientasi Objek, Bandung, Infromatika Bandung.
101
4.4. Potongan Koding Program
Dari desain yang telah di buat di atas di tambahkan koding program agar
aplikasi dapat berjalan seperti yang di inginkan. Koding program yang di gunakan
adalah sebagai berikut :
4.4.1 Koding Home
<div class='sputih'><div class='judul'>
<h3><p>Selamat Datang <?php echo $_SESSION['nama_lengkap'] ?> di
Halaman Administrator</p></h3>
<p></p>
<br />
Disini anda bisa mengolah data baik dari Penyakit maupun Data Gejala , anda bisa
merubah menghapus dan menambahkan data
<p> Silahkan Lihat menu diatas </p>
</div></div>
4.4.2 Koding Main Menu
<?php
include "../../config/class_paging.php";
include "../../config/inc.library.php";
$main = $_GET['main'];
if ($main == 'home'){
include "home.php";
}
elseif($main == 'setuser'){
include "main/main_admin/setadmin.php";
}
elseif($main == 'penyakit'){
include "main/main_penyakit/penyakit.php";
102
}
elseif($main == 'addpenyakit'){
include "main/main_penyakit/add_penyakit.php";
}
elseif($main == 'simpanpenyakit'){
include "main/main_penyakit/proses_addpenyakit.php";
}
elseif($main == 'updatepenyakit'){
include "main/main_penyakit/proses_updatepenyakit.php";
}
elseif($main == 'gejala'){
include "main/main_gejala/gejala.php";
}
elseif($main == 'simpangejala'){
include "main/main_gejala/proses_addgejala.php";
}
elseif($main == 'updategejala'){
include "main/main_gejala/proses_updategejala.php";
}
elseif($main == 'aturan'){
include "main/main_aturan/aturan.php";
}
elseif($main == 'add_aturan'){
include "main/main_aturan/add_aturan.php";
}
103
elseif($main == 'edit_aturan'){
include "main/main_aturan/edit_aturan.php";
}
elseif($main == 'simpanaturan'){
include "main/main_aturan/proses_addaturan.php";
}
elseif($main == 'updateaturan'){
include "main/main_aturan/proses_updateaturan.php";
}
elseif($main == 'bukutamu'){
include "main/main_bukutamu/bukutamu.php";
}
elseif($main == 'hasildiagnosa'){
include "main/main_hasildiagnosa/hasildiagnosa.php";
}
elseif($main == 'laporandiagnosa'){
include "main/main_laporan/laporan.php";
}
else {
echo "Halaman tidak Ada";
}
?>
4.4.3 Logout
<?php
session_start();
session_destroy();
header('location:../../index.php?logout=1');
?>
104
4.4.4 Main_admin
a. Proses_updateadmin
<?php
include "../../../../config/koneksi.php";
if ($_GET['main'] == 'private'){
$id= $_POST['id'];
$r = mysql_fetch_array(mysql_query("SELECT * FROM admin
WHERE id_session = '$id' "));
$pass_lama=md5($_POST['passold']);
$pass_baru=md5($_POST['passnew']);
if (empty($_POST["passnew"]) OR empty($_POST["passold"]) OR
empty($_POST["passnew2"])){
echo "<script>window.alert('Wajib isikan password lama
sebelumnya dan Password Baru sebanyak dua kali ');
window.location=('../../index.php?main=setuser')</script>";
} else {
// Apabila password lama cocok dengan password admin di database
if ($r['password'] == $pass_lama){
// Pastikan bahwa password baru yang dimasukkan sebanyak dua kali
sudah cocok
if ($_POST["passnew"]==$_POST["passnew2"]){
mysql_query("UPDATE admin SET password = '$pass_baru'
WHERE id_session = '$id'");
session_start();
session_destroy();
header('location:../../../index.php?reset=3');
}
else{
105
echo "<script>window.alert('Password baru yang Anda
masukkan sebanyak dua kali belum cocok.');
window.location=('../../index.php?main=setuser')</script>";
}
} else {
echo "<script>window.alert('Anda salah memasukkan Password
Lama Anda ');
window.location=('../../index.php?main=setuser')</script>";
}
}
} else {
$id= $_POST['id'];
$nm = $_POST['nama'];
$telp = $_POST['telp'];
$email = $_POST['email'];
mysql_query("UPDATE admin SET nama_lengkap = '$nm', no_telp =
'$telp', email = '$email' WHERE id_session = '$id'");
echo "<script>window.alert('Anda telah berhasil update data');
window.location=('../../index.php?main=setuser')</script>";
}
?>
b. Setadmin
<script src="../ajax/jquery.validate.min.js"
type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#frm").validate({
debug: false,
rules: {
106
nama: "required",
user: "required",
telp : "required"
},
messages: {
nama: "<font
style='color:#FF0000;'>* Masukan nama lengkap Anda</font>",
user: "<font
style='color:#FF0000;'>* Username Tidal boleh kosong</font>",
telp: "<font
style='color:#FF0000;'>* Kosong</font>"
},
submitHandler: function(form) {
// do other stuff for a valid
form
$.post('logistik_data/log_users/prosses_update.php',
$("#frm").serialize(), function(data) {
$('#hasil').html(data);
$('#divResult').text('Data berhasil
diupdate').css({'color':'#000000','background-
color':'#FFFF00'}).fadeIn();
});
}
});
});
</script>
107
<?php
require "../../config/koneksi.php";
$qryuser = mysql_query ("select * from admin ") or die('MySql Error' .
mysql_error());
$us = mysql_fetch_array($qryuser);
?>
<div class=judul><h2>Berikut detail data
admin:</h2></div><br/><br/><br/><br/>
<form method="POST"
action="main/main_admin/proses_updateadmin.php?main=nama"
name="frm">
<table>
<tr><td width="150px">Nama Lengkap</td><td> : <input
value='<?php echo $us['nama_lengkap']; ?>' type="text"
name="nama"></td></tr>
<tr><td>No. Telp</td><td> : <input value='<?php echo
$us['no_telp']; ?>' type="text" name="telp"></td></tr>
<tr><td>Email</td><td> : <input value='<?php echo
$us['email']; ?>' type="text" name="email"></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td>
<td>
<input type=hidden name="id" value='<?php echo
$us['id_session'] ?>' >
<input type="submit" name="submit"
value="Ubah" >
</td></tr>
</table>
</form><br/><br/>
108
<form method="POST"
action="main/main_admin/proses_updateadmin.php?main=private"
name="frm">
<table>
<tr><td width="150px">Username</td><td> : <input
type="text" value=<?php echo $us['username']; ?>
disabled></td></tr>
<tr><td>Password Lama</td><td> : <input
type="password" name="passold"></td></tr>
<tr><td>Password Baru</td><td> : <input
type="password" name="passnew" ></td></tr>
<tr><td>Ulangi Password Baru</td><td> : <input
type=password name="passnew2" ></td></tr>
<tr><td></td><td></td></tr>
<tr><td></td>
<td>
<input type=hidden name="id" value='<?php echo
$us['id_session'] ?>' >
<input type="submit" name="submit"
value="Ubah" >
</td></tr>
</table>
</form>
4.4.5 Main_aturan
a. Add_aturan
<?php
require "../../../../config/koneksi.php";
$dataPenyakit = isset($_POST['cmbPenyakit']) ?
$_POST['cmbPenyakit'] : '';
109
$dataGejala = isset($_POST['cmbGejala']) ?
$_POST['cmbGejala'] : '';
$dataProbabilitas = isset($_POST['txtProbabilitas']) ?
$_POST['txtProbabilitas'] : '';
?>
<div class="add">
<fieldset>
<legend>Tambah Daftar Basis Aturan</legend>
<div ></div>
<form action="?main=simpanaturan" method="post"
name="form1" target="_self">
<table class="table-list" width="100%">
<tr>
<th colspan="3">TAMBAH DATA ATURAN </th>
</tr>
<tr>
<td width="15%"><b>Nama Penyakit </b></td>
<td width="1%"><b>:</b></td>
<td width="84%"><select name="cmbPenyakit">
<option value="Kosong"> .... </option>
<?php
$daftarSql = "SELECT * FROM penyakit ORDER BY
kd_penyakit";
$daftarQry = mysql_query($daftarSql, $koneksidb) or die ("Gagal
Query".mysql_error());
while ($daftarData = mysql_fetch_array($daftarQry)) {
if ($daftarData['kd_penyakit'] == $dataPenyakit) {
$cek = " selected";
} else { $cek=""; }
110
echo "<option value='$daftarData[kd_penyakit]'
$cek>$daftarData[kd_penyakit] | $daftarData[nm_penyakit]</option>";
}
?>
</select></td>
</tr>
<tr>
<td><b>Nama Gejala </b></td>
<td><b>:</b></td>
<td><select name="cmbGejala">
<option value="Kosong"> .... </option>
<?php
$daftarSql = "SELECT * FROM gejala ORDER BY kd_gejala";
$daftarQry = mysql_query($daftarSql, $koneksidb) or die ("Gagal
Query".mysql_error());
while ($daftarData = mysql_fetch_array($daftarQry)) {
if ($daftarData['kd_gejala'] == $dataGejala) {
$cek = " selected";
} else { $cek=""; }
echo "<option value='$daftarData[kd_gejala]'
$cek>$daftarData[kd_gejala] | $daftarData[nm_gejala]</option>";
}
?>
</select></td>
</tr>
<tr>
<td><b>Nilai Densitas </b></td>
<td><b>:</b></td>
<td><input name="txtProbabilitas" type="text" value="<?php
echo $dataProbabilitas; ?>" size="10" maxlength="10" /></td>
</tr>
111
<tr><td> </td>
<td> </td>
<td><input type="submit" name="btnSimpan" value=" SIMPAN
"></td>
</tr>
</table>
</form>
</fieldset>
</div>
b. Aturan
<script type="text/javascript">
$(document).ready(function(){
//Examples of how to assign the ColorBox
event to elements
$(".thickbox").colorbox({width:"50%",
height:"75%"});
});
</script>
<script type="text/javascript">
$(document).ready(function(){
//Examples of how to assign the ColorBox
event to elements
$(".colorbox").colorbox({width:"50%",
height:"75%"});
});
</script>
<?php
112
if (isset($_POST['Del'])) {
if ($_POST['cex'] == NULL) {
echo "<script>window.alert('Data yang akan dihapus belum di
pilih')
javascript:history.go(-1);</script>";
} else {
$a = join(",", $_POST['cex']);
$tampil=mysql_query("SELECT * FROM aturan
Where id_aturan IN(" . $a . ")");
while($r=mysql_fetch_array($tampil)){
}
mysql_query("DELETE FROM aturan WHERE
id_aturan='$a'");
print "<script>alert('Data berhasil di dihapus');
javascript:history.go(-
1);</script>";
}
}else{
echo "
<div class=judul><h2>Berikut Detail Basis Aturan:</h2></div>
<br/>
<form action='' method='post'>
<div style='float:right; padding:10px; width:250px; margin-top:5px;'>
<a class='thickbox' href='main/main_aturan/add_aturan.php'>Add
Daftar Aturan</a>
<input type='submit' name='Del' value='Hapus' onclick='return
confirmDelete();'>
</div><br/>
<table id=o width=100%><tbody>
113
<tr>
<th width='1%' class=th>No</th>
<th width='1%' class=th>Kode Penyakit</th>
<th width='1%' class=th>Kode Gejala</th>
<th width='10%' class=th>Nilai Densitas</th>
<th width='1%' bgcolor='#8DAD9C'><div
align='center'><span class='style1'>Ubah</span></div></th>
<th width='1%' bgcolor='#8DAD9C'><div
align='center'><span class='style1'><input type='checkbox'
name='checkbox[]' class='checkall'></span></div></th>
</tr>";
$p = new Paging;
$batas = 15;
$posisi = $p->cariPosisi($batas);
$tampil=mysql_query("SELECT aturan.*, penyakit.nm_penyakit,
gejala.nm_gejala FROM aturan
LEFT JOIN penyakit ON aturan.kd_penyakit =
penyakit.kd_penyakit
LEFT JOIN gejala ON aturan.kd_gejala =
gejala.kd_gejala
ORDER BY aturan.kd_penyakit, aturan.kd_gejala
desc LIMIT $posisi,$batas");
$no=1;
$i = $posisi;
while ($r=mysql_fetch_array($tampil)){
if (($no % 2) > 0)
$bg = '#FFFFFF'; else
$bg = '#cccccc';
echo "<tr bgcolor=" . $bg . "><td class=td align=center>$no</td>
<td class=td>$r[kd_penyakit]</td>
<td class=td>$r[kd_gejala]</td>
114
<td class=td>$r[nilai_probabilitas]</td>
<td><div align='center' style='background-
color:none;'><a class='colorbox'
href=main/main_aturan/edit_aturan.php?Kode=" . $r['id_aturan'] . "
><img src='../images/edit.png' border='0' width='16' height='16'
/></a></div></td>
<td><div align='center'><input type='checkbox' name='cex[]'
value='" . $r['id_aturan'] . "'></div></td>
</tr></tr>";
$no++;
}
echo "</tbody></table></form>";
$sql_pagging = mysql_query("SELECT COUNT(*) AS jml FROM
aturan");
$pagging = mysql_fetch_array($sql_pagging);
$jml = $pagging['jml'];
echo"
</br>
<div class='results'> <span>Jumlah Data : $jml</span><br/><br/>
";
$jmldata = mysql_num_rows(mysql_query("SELECT * from
aturan"));
$jmlhalaman = $p->jumlahHalaman($jmldata, $batas);
$linkHalaman = $p->navHalaman($_GET['halaman'], $jmlhalaman);
echo" Halaman : $linkHalaman </div>";
}
?>
115
c. Edit_aturan
<?php
require "../../../../config/koneksi.php";
$Kode = isset($_GET['Kode']) ? $_GET['Kode'] :
$_POST['txtKode'];
$mySql = "SELECT * FROM aturan WHERE id_aturan='$Kode'";
$myQry = mysql_query($mySql, $koneksidb) or die ("Query ambil
data salah : ".mysql_error());
$myData = mysql_fetch_array($myQry);
// Menyimpan data ke variabel temporary (sementara)
$dataKode = $myData['id_aturan'];
$dataPenyakit = isset($_POST['cmbPenyakit']) ?
$_POST['cmbPenyakit'] : $myData['kd_penyakit'];
$dataGejala = isset($_POST['cmbGejala']) ?
$_POST['cmbGejala'] : $myData['kd_gejala'];
$dataProbabilitas = isset($_POST['txtProbabilitas']) ?
$_POST['txtProbabilitas'] : $myData['nilai_probabilitas'];
?>
<div class="add">
<fieldset>
<legend>Edit Basis Aturan <?php echo $q['id_aturan'] ?></legend>
<div ></div>
<form action="?main=updateaturan" method="post"
name="form1">
<table class="table-list" width="100%">
<tr>
<th colspan="3">UBAH DATA ATURAN </th>
</tr>
116
<tr>
<td width="15%"><b>Nama Penyakit </b></td>
<td width="1%"><b>:</b></td>
<td width="84%"><select name="cmbPenyakit">
<option value="Kosong"> .... </option>
<?php
$daftarSql = "SELECT * FROM penyakit ORDER BY
kd_penyakit";
$daftarQry = mysql_query($daftarSql, $koneksidb) or die ("Gagal
Query".mysql_error());
while ($daftarData = mysql_fetch_array($daftarQry)) {
if ($daftarData['kd_penyakit'] == $dataPenyakit) {
$cek = " selected";
} else { $cek=""; }
echo "<option value='$daftarData[kd_penyakit]'
$cek>$daftarData[kd_penyakit] | $daftarData[nm_penyakit]</option>";
}
?>
</select>
<input name="txtKode" type="hidden" value="<?php echo
$dataKode; ?>" /></td></tr>
<tr>
<td><b>Nama Gejala </b></td>
<td><b>:</b></td>
<td><select name="cmbGejala">
<option value="Kosong"> .... </option>
<?php
$daftarSql = "SELECT * FROM gejala ORDER BY kd_gejala";
$daftarQry = mysql_query($daftarSql, $koneksidb) or die ("Gagal
Query".mysql_error());
while ($daftarData = mysql_fetch_array($daftarQry)) {
117
if ($daftarData['kd_gejala'] == $dataGejala) {
$cek = " selected";
} else { $cek=""; }
echo "<option value='$daftarData[kd_gejala]'
$cek>$daftarData[kd_gejala] | $daftarData[nm_gejala]</option>";
}
?>
</select>
<input name="txtLama" type="hidden" value="<?php echo
$myData['kd_gejala']; ?>" /></td>
</tr>
<tr>
<td><b>Nilai Densistas (%) </b></td>
<td><b>:</b></td>
<td><input name="txtProbabilitas" type="text" value="<?php
echo $dataProbabilitas; ?>" size="10" maxlength="10" /></td>
</tr>
<tr><td> </td>
<td> </td>
<td><input type="submit" name="btnSimpan" value=" SIMPAN
"></td>
</tr>
</table>
</form>
</fieldset>
</div>
d. Proses_addaturan
<?php
session_start();
118
require "../../config/koneksi.php";
# Tombol Simpan diklik
if(isset($_POST['btnSimpan'])){
# Baca Variabel Form
$cmbPenyakit = $_POST['cmbPenyakit'];
$cmbGejala = $_POST['cmbGejala'];
$txtProbabilitas= $_POST['txtProbabilitas'];
$txtProbabilitas= str_replace(",",".",$txtProbabilitas); // mengubah
tanda koma(,) menjadi titik (.), misalnya: 0,5 menjadi 0.5 (desimal)
# Validasi form, jika kosong sampaikan pesan error
$pesanError = array();
if (trim($cmbPenyakit)=="Kosong") {
$pesanError[] = "Data <b>Nama Penyakit</b> belum ada
yang dipilih !";
}
if (trim($cmbGejala)=="Kosong") {
$pesanError[] = "Data <b>Nama Gejala</b> belum ada
yang dipilih !";
}
if (trim($txtProbabilitas)=="") {
$pesanError[] = "Data <b>Nilai Densitas (%)</b> tidak
boleh kosong !";
}
# Validasi Nama aturan, jika sudah ada akan ditolak
$cekSql="SELECT * FROM aturan WHERE
kd_penyakit='$cmbPenyakit' AND kd_gejala='$cmbGejala'";
$cekQry=mysql_query($cekSql, $koneksidb) or die ("Eror
Query".mysql_error());
if(mysql_num_rows($cekQry)>=1){
119
$pesanError[] = "Maaf, aturan <b> $cmbPenyakit</b> dan
<b>$cmbGejala</b> sudah ada, ganti dengan yang lain";
}
# JIKA ADA PESAN ERROR DARI VALIDASI
if (count($pesanError)>=1 ){
echo "<div class='mssgBox'>";
echo "<img src='../images/attention.png'> <br><hr>";
$noPesan=0;
foreach ($pesanError as $indeks=>$pesan_tampil) {
$noPesan++;
echo " $noPesan.
$pesan_tampil<br>";
}
echo "</div> <br>";
}
else {
# SIMPAN DATA KE DATABASE.
// Jika tidak menemukan error, simpan data ke database
$mySql = "INSERT INTO aturan (kd_penyakit,
kd_gejala, nilai_probabilitas)
VALUES ('$cmbPenyakit',
'$cmbGejala', '$txtProbabilitas')";
$myQry = mysql_query($mySql, $koneksidb) or die
("Gagal query".mysql_error());
if($myQry){
echo "<meta http-equiv='refresh' content='0;
url=?main=aturan'>";
}
exit;
}
120
} // Penutup Tombol Simpan
?>
e. Proses_updateaturan
<?php
require "../../config/koneksi.php";
# Tombol Simpan diklik
if(isset($_POST['btnSimpan'])){
# Baca Variabel Form
$cmbPenyakit = $_POST['cmbPenyakit'];
$cmbGejala = $_POST['cmbGejala'];
$txtProbabilitas= $_POST['txtProbabilitas'];
$txtProbabilitas= str_replace(",",".",$txtProbabilitas); // mengubah
tanda koma(,) menjadi titik (.), misalnya: 0,5 menjadi 0.5 (desimal)
# Validasi form, jika kosong sampaikan pesan error
$pesanError = array();
if (trim($cmbPenyakit)=="Kosong") {
$pesanError[] = "Data <b>Nama Penyakit</b> belum ada
yang dipilih !";
}
if (trim($cmbGejala)=="Kosong") {
$pesanError[] = "Data <b>Nama Gejala</b> belum ada
yang dipilih !";
}
if (trim($txtProbabilitas)=="") {
$pesanError[] = "Data <b>Nilai Densitas (%)</b> tidak
boleh kosong !";
}
# Validasi Nama aturan, jika sudah ada akan ditolak
$txtLama = $_POST['txtLama'];
121
$cekSql="SELECT * FROM aturan WHERE
kd_penyakit='$cmbPenyakit' AND kd_gejala='$cmbGejala' AND
NOT(kd_gejala='$txtLama')";
$cekQry=mysql_query($cekSql, $koneksidb) or die ("Eror
Query".mysql_error());
if(mysql_num_rows($cekQry)>=1){
$pesanError[] = "Maaf, aturan <b> $cmbPenyakit</b> dan
<b>$cmbGejala</b> sudah ada, ganti dengan yang lain";
}
# JIKA ADA PESAN ERROR DARI VALIDASI
if (count($pesanError)>=1 ){
echo "<div class='mssgBox'>";
echo "<img src='../images/attention.png'> <br><hr>";
$noPesan=0;
foreach ($pesanError as $indeks=>$pesan_tampil) {
$noPesan++;
echo " $noPesan.
$pesan_tampil<br>";
}
echo "</div> <br>";
}
else {
# SIMPAN PERUBAHAN DATA, Jika jumlah error
pesanError tidak ada, simpan datanya
$Kode = $_POST['txtKode'];
$mySql = "UPDATE aturan SET
kd_penyakit='$cmbPenyakit', kd_gejala='$cmbGejala',
nilai_probabilitas='$txtProbabilitas'
WHERE id_aturan ='$Kode'";
122
$myQry = mysql_query($mySql, $koneksidb) or die
("Gagal query".mysql_error());
if($myQry){
echo "<meta http-equiv='refresh' content='0;
url=?main=aturan'>";
}
exit;
}
} // Penutup Tombol Simpan
?>
4.4.6 Main_bukutamu
a. Bukutamu
<script type="text/javascript">
$(document).ready(function(){
//Examples of how to assign the ColorBox
event to elements
$(".thickbox").colorbox({width:"50%",
height:"75%"});
});
</script>
<script type="text/javascript">
$(document).ready(function(){
//Examples of how to assign the ColorBox
event to elements
$(".colorbox").colorbox({width:"50%",
height:"75%"});
});
</script>
123
<?php
if (isset($_POST['Del'])) {
if ($_POST['cex'] == NULL) {
echo "<script>window.alert('Data yang akan dihapus belum di
pilih')
javascript:history.go(-1);</script>";
} else {
$a = join(",", $_POST['cex']);
mysql_query("DELETE FROM bukutamu WHERE
id_bukutamu IN(" . $a . ")");
print "<script>alert('Data berhasil di dihapus');
javascript:history.go(-
1);</script>";
}
}else{
echo "
<body>
<div class='judul'><h1>DATA BUKU TAMU</h1></div><br/>
<br/>
<form action='' method='post'>
<div style='float:right; padding:10px; width:70px; margin-top:5px;'>
<input type='submit' name='Del' value='Hapus' onclick='return
confirmDelete();'>
</div><br/>
<table width='100%' border='0' align='center'
style='margin-bottom:50px;'>
<tr>
124
<th width='1%' bgcolor='#8DAD9C'><div align='center'
class='style1'>NO</div></th>
<th width='20%' bgcolor='#8DAD9C'><div align='center'
class='style1'>Nama</div></th>
<th width='20%' bgcolor='#8DAD9C'><div align='center'
class='style1'>Email</div></th>
<th width='10%' bgcolor='#8DAD9C'><div align='center'
class='style1'>Tanggal</div></th>
<th width='2%' bgcolor='#8DAD9C'><div align='center'
class='style1'>Status</div></th>
<th width='1%' bgcolor='#8DAD9C'><div align='center'><span
class='style1'>Lihat</span></div></th>
<th width='1%' bgcolor='#8DAD9C'><div align='center'><span
class='style1'><input type='checkbox' name='checkbox[]'
class='checkall'></span></div></th>
</tr>";
$p = new Paging;
$batas = 10;
$posisi = $p->cariPosisi($batas);
$sql = mysql_query("SELECT * FROM bukutamu order by
id_bukutamu desc LIMIT $posisi,$batas");
$i = 0;
$i = $posisi;
while ($r = mysql_fetch_array($sql)) {
if (($i % 2) > 0)
$bg = '#FFFFFF'; else
$bg = '#cccccc';
$pilihan_status = array('Y','N');
$pilih_status = '';
125
foreach ($pilihan_status as $status) {
$pilih_status .= "<option value='$status'";
if ($status == $r['publish']) {
$pilih_status .= " selected";
}
$pilih_status .= ">$status</option>\r\n";
}
echo"
<tr bgcolor=" . $bg . ">
<td><div align='center'>" . ++$i . "</div></td>
<td><div align='left'>" . $r['nama'] . "</div></td>
<td><div align='left'>" . $r['email'] . "</div></td>
<td><div align='center'>". $r['tanggal'] . "</div></td>
<td><div align='center'>". $r['publish'] . "</div></td>
<td><div align='center' style='background-color:none;'><a
class='colorbox' href=main/main_bukutamu/view_bukutamu.php?id=" .
$r['id_bukutamu'] . " ><img src='../images/dt.png' border='0' width='16'
height='16' /></a></div></td>
<td><div align='center'><input type='checkbox' name='cex[]'
value='" . $r['id_bukutamu'] . "'></div></td>
</tr>";
} echo"</table></form>";
$sql_pagging = mysql_query("SELECT COUNT(*) AS jml FROM
bukutamu");
$pagging = mysql_fetch_array($sql_pagging);
$jml = $pagging['jml'];
echo"
126
<div class='results'> <span>Jumlah Data : $jml</span><br/><br/>
";
$jmldata = mysql_num_rows(mysql_query("SELECT * from
bukutamu"));
$jmlhalaman = $p->jumlahHalaman($jmldata, $batas);
$linkHalaman = $p->navHalaman($_GET['halaman'], $jmlhalaman);
echo" Halaman : $linkHalaman
</div>";
}
?>
b. Proses_bukutamu
<?php
require "../../../../config/koneksi.php";
$id = $_REQUEST['id'];
$val = $_REQUEST['val'];
$query = mysql_query("UPDATE bukutamu SET publish = '$val'
Where id_bukutamu = '$id'");
if ($val == '') $val = "_show";
if ($query){
echo "Fields" . "$id" . "|" . stripslashes($val);
}
echo "<meta http-equiv='refresh' content='0;
url=../../index.php?main=bukutamu'>";
?>
c. View_bukutamu
<?php
session_start();
require "../../../../config/koneksi.php";
127
$id = $_GET['id'];
$sql = mysql_query("SELECT * FROM bukutamu Where id_bukutamu
= '$id'");
$r = mysql_fetch_array($sql);
?>
<div class="add">
<fieldset>
<legend>Edit Buku Tamu</legend>
<div ></div>
<form method="POST"
action="main/main_bukutamu/proses_bukutamu.php">
<input type=hidden name="id" value='<?php echo
$r['id_bukutamu'] ?>'>
<table class="in">
<tr><td>Nama</td><td> : <?php echo $r['nama'] ?></td></tr>
<tr><td>Email</td><td> : <?php echo $r['email'] ?></td></tr>
<tr><td>Pesan</td><td> : <?php echo $r['pesan']
?></td></tr>
<tr><td>Tanggal</td><td> : <?php echo $r['tanggal']
?></td></tr>
<?php if ($r['publish']=='N'){
echo "<tr><td>Tampilkan</td> <td> : <input type=radio name='val'
value='N' checked> N
<input type=radio name='val' value='Y'>
Y</td></tr>";
}
else{
echo "<tr><td>Tampilkan</td> <td> : <input type=radio name='val'
value='N'> N
128
<input type=radio name='val' value='Y'
checked> Y</td></tr>";
} ?>
<tr><td></td>
<td>
<input type="submit" name="submit"
value="Simpan">
</td></tr>
</table>
</form>
</fieldset>
</div>
4.4.7 Main_gejala
a. Add_gejala
<?php
session_start();
require "../../../../config/koneksi.php";
require "../../../../config/inc.library.php";
$dataKode = buatKode("gejala", "E");
$dataNama = isset($_POST['txtNama']) ? $_POST['txtNama'] : '';
?>
<script type="text/javascript">
function harusangka(jumlah){
var karakter = (jumlah.which) ? jumlah.which : event.keyCode
if (karakter > 31 && (karakter < 46 || karakter > 57))
return (false);
return (true);
}
129
</script>
<link href="../../../../style/style.css" rel="stylesheet" type="text/css" />
<div class="add">
<fieldset>
<legend>Tambah Daftar Gejala</legend>
<div ></div>
<form action="?main=simpangejala" method="post"
name="form1" target="_self">
<table class="table-list" width="100%">
<tr>
<th colspan="3">TAMBAH GEJALA </th>
</tr>
<tr>
<td width="15%"><b>Kode</b></td>
<td width="1%"><b>:</b></td>
<td width="84%"><input name="textfield" value="<?php echo
$dataKode; ?>" size="10" maxlength="4"
readonly="readonly"/></td></tr>
<tr>
<td><b>Nama Gejala </b></td>
<td><b>:</b></td>
<td><input name="txtNama" value="<?php echo $dataNama; ?>"
size="80" maxlength="100" /></td>
</tr>
<tr><td> </td>
<td> </td>
<td><input type="submit" name="btnSimpan" value=" SIMPAN
"></td>
</tr>
</table>
130
</form>
</fieldset>
</div>
b. Edit_gejala
<?php
session_start();
require "../../../../config/koneksi.php";
require "../../../../config/inc.library.php";
# TAMPILKAN DATA LOGIN UNTUK DIEDIT
$Kode = isset($_GET['Kode']) ? $_GET['Kode'] :
$_POST['txtKode'];
$mySql = "SELECT * FROM gejala WHERE kd_gejala='$Kode'";
$myQry = mysql_query($mySql, $koneksidb) or die ("Query ambil
data salah : ".mysql_error());
$myData = mysql_fetch_array($myQry);
// Menyimpan data ke variabel temporary (sementara)
$dataKode = $myData['kd_gejala'];
$dataNama = isset($_POST['txtNama']) ? $_POST['txtNama'] :
$myData['nm_gejala'];
?>
<script type="text/javascript">
function harusangka(jumlah){
var karakter = (jumlah.which) ? jumlah.which : event.keyCode
if (karakter > 31 && (karakter < 46 || karakter > 57))
return (false);
return (true);
}
</script>
131
<link href="../../../../style/style.css" rel="stylesheet" type="text/css" />
<div class="add">
<fieldset>
<legend>Edit Gejala : <?php echo $myData['nm_gejala'] ?></legend>
<div ></div>
<form action="?main=updategejala" method="post"
name="form1">
<table class="table-list" width="100%">
<tr>
<th colspan="3">UBAH GEJALA </th>
</tr>
<tr>
<td width="15%"><b>Kode</b></td>
<td width="1%"><b>:</b></td>
<td width="84%"><input name="textfield" value="<?php echo
$dataKode; ?>" size="8" maxlength="4" readonly="readonly"/>
<input name="txtKode" type="hidden" value="<?php echo
$dataKode; ?>" /></td></tr>
<tr>
<td><b>Nama Gejala </b></td>
<td><b>:</b></td>
<td><input name="txtNama" type="text" value="<?php echo
$dataNama; ?>" size="80" maxlength="100" />
<input name="txtLama" type="hidden" value="<?php echo
$myData['nm_gejala']; ?>" /></td></tr>
<tr><td> </td>
<td> </td>
<td><input type="submit" name="btnSimpan" value=" SIMPAN
"></td>
</tr>
132
</table>
</form>
</fieldset>
</div>
c. Gejala
<script type="text/javascript">
$(document).ready(function(){
//Examples of how to assign the ColorBox
event to elements
$(".thickbox").colorbox({width:"50%",
height:"75%"});
});
</script>
<script type="text/javascript">
$(document).ready(function(){
//Examples of how to assign the ColorBox
event to elements
$(".colorbox").colorbox({width:"50%",
height:"75%"});
});
</script>
<?php
if (isset($_POST['Del'])) {
if ($_POST['cex'] == NULL) {
echo "<script>window.alert('Data yang akan dihapus belum di
pilih')
javascript:history.go(-1);</script>";
133
} else {
$a = join(",", $_POST['cex']);
mysql_query("DELETE FROM gejala WHERE kd_gejala='$a'
");
print "<script>alert('Data berhasil di dihapus');
javascript:history.go(-
1);</script>";
}
}else{
echo "
<div class=judul><h2>Berikut detail data Gejala:</h2></div>
<br/>
<form action='' method='post'>
<div style='float:right; padding:10px; width:250px; margin-top:5px;'>
<a class='thickbox' href='main/main_gejala/add_gejala.php'>Add
Daftar Gejala</a>
<input type='submit' name='Del' value='Hapus' onclick='return
confirmDelete();'>
</div><br/>
<table id=o width=100%><tbody>
<tr>
<th width='1%' class=th>no</th>
<th width='7%' class=th>Kode Gejala</th>
<th width='13%' class=th>Nama Gejala</th>
<th width='1%' bgcolor='#8DAD9C'><div
align='center'><span class='style1'>ubah</span></div></th>
134
<th width='1%' bgcolor='#8DAD9C'><div
align='center'><span class='style1'><input type='checkbox'
name='checkbox[]' class='checkall'></span></div></th>
</tr>";
$p = new Paging;
$batas = 15;
$posisi = $p->cariPosisi($batas);
$tampil=mysql_query("SELECT * FROM gejala order by
kd_gejala desc LIMIT $posisi,$batas");
$i = 0;
$i = $posisi;
while ($r=mysql_fetch_array($tampil)){
if (($i % 2) > 0)
$bg = '#ffffff'; else
$bg = '#cccccc';
echo "<tr bgcolor=" . $bg . ">
<td class=td align=center>" . ++$i ."</td>
<td class=td>$r[kd_gejala]</td>
<td class=td>$r[nm_gejala]</td>
<td><div align='center' style='background-
color:none;'><a class='colorbox'
href=main/main_gejala/edit_gejala.php?Kode=" . $r['kd_gejala'] . "
><img src='../images/edit.png' border='0' width='16' height='16'
/></a></div></td>
<td><div align='center'><input type='checkbox' name='cex[]'
value='" . $r['kd_gejala'] . "'></div></td>
</tr></tr>";
}
echo "</tbody></table></form>";
135
$sql_pagging = mysql_query("SELECT COUNT(*) AS jml FROM
gejala");
$pagging = mysql_fetch_array($sql_pagging);
$jml = $pagging['jml'];
echo"
</br>
<div class='results'> <span>Jumlah Data : $jml</span><br/><br/>
";
$jmldata = mysql_num_rows(mysql_query("SELECT * from
gejala"));
$jmlhalaman = $p->jumlahHalaman($jmldata, $batas);
$linkHalaman = $p->navHalaman($_GET['halaman'], $jmlhalaman);
echo" Halaman : $linkHalaman </div>";
}
?>
d. Proses_addgejala
<?php
require "../../config/koneksi.php";
# Tombol Simpan diklik
if(isset($_POST['btnSimpan'])){
# Baca Variabel Form
$txtNama = $_POST['txtNama'];
# Validasi form, jika kosong sampaikan pesan error
$pesanError = array();
if (trim($txtNama)=="") {
136
$pesanError[] = "Data <b>Nama Gejala</b> tidak boleh
kosong !";
}
# Validasi Nama gejala, jika sudah ada akan ditolak
$cekSql="SELECT * FROM gejala WHERE
nm_gejala='$txtNama'";
$cekQry=mysql_query($cekSql, $koneksidb) or die ("Eror
Query".mysql_error());
if(mysql_num_rows($cekQry)>=1){
$pesanError[] = "Maaf, Gejala <b> $txtNama </b> sudah
ada, ganti dengan yang lain";
}
# JIKA ADA PESAN ERROR DARI VALIDASI
if (count($pesanError)>=1 ){
echo "<div class='mssgBox'>";
echo "<img src='../images/attention.png'> <br><hr>";
$noPesan=0;
foreach ($pesanError as $indeks=>$pesan_tampil) {
$noPesan++;
echo " $noPesan.
$pesan_tampil<br>";
}
echo "</div> <br>";
}
else {
# SIMPAN DATA KE DATABASE.
// Jika tidak menemukan error, simpan data ke database
$kodeBaru = buatKode("gejala", "E");
137
$mySql = "INSERT INTO gejala (kd_gejala,
nm_gejala) VALUES ('$kodeBaru', '$txtNama')";
$myQry = mysql_query($mySql, $koneksidb) or die
("Gagal query".mysql_error());
if($myQry){
echo "<meta http-equiv='refresh' content='0;
url=?main=gejala'>";
}
exit;
}
} // Penutup Tombol Simpan
?>
e. Proses_updategejala
<?php
require "../../config/koneksi.php";
# Tombol Simpan diklik
if(isset($_POST['btnSimpan'])){
# Baca Variabel Form
$txtNama = $_POST['txtNama'];
# Validasi form, jika kosong sampaikan pesan error
$pesanError = array();
if (trim($txtNama)=="") {
$pesanError[] = "Data <b>Nama Gejala</b> tidak boleh
kosong !";
}
# Validasi Nama gejala, jika sudah ada akan ditolak
$cekSql="SELECT * FROM gejala WHERE
nm_gejala='$txtNama' AND
NOT(nm_gejala='".$_POST['txtLama']."')";
138
$cekQry=mysql_query($cekSql, $koneksidb) or die ("Eror
Query".mysql_error());
if(mysql_num_rows($cekQry)>=1){
$pesanError[] = "Maaf, Gejala <b> $txtNama </b> sudah
ada, ganti dengan yang lain";
}
# JIKA ADA PESAN ERROR DARI VALIDASI
if (count($pesanError)>=1 ){
echo "<div class='mssgBox'>";
echo "<img src='../images/attention.png'> <br><hr>";
$noPesan=0;
foreach ($pesanError as $indeks=>$pesan_tampil) {
$noPesan++;
echo " $noPesan.
$pesan_tampil<br>";
}
echo "</div> <br>";
}
else {
# SIMPAN PERUBAHAN DATA, Jika jumlah error
pesanError tidak ada, simpan datanya
$Kode = $_POST['txtKode'];
$mySql = "UPDATE gejala SET
nm_gejala='$txtNama' WHERE kd_gejala ='$Kode'";
$myQry = mysql_query($mySql, $koneksidb) or die
("Gagal query".mysql_error());
if($myQry){
echo "<meta http-equiv='refresh' content='0;
url=?main=gejala'>";
}
139
exit;
}
} // Penutup Tombol Simpan
?>
4.4.8 Main_hasildiagnosa
a. Cetak
<?php
session_start();
require "../../../../config/koneksi.php";
$NOIP = $_GET['id'];
$sql = "SELECT diagnosa.*, pasien.* , penyakit.*
FROM diagnosa,pasien,penyakit
WHERE pasien.idpasien=diagnosa.idpasien
AND diagnosa.idpasien='$NOIP' AND
diagnosa.kd_penyakit=penyakit.kd_penyakit
ORDER BY diagnosa.idpasien DESC LIMIT 1";
$qry = mysql_query($sql, $koneksidb)
or die ("Query Hasil salam".mysql_error());
$data1= mysql_fetch_array($qry);
?>
<html>
<head>
<title>Hasil Analisa Pasien</title>
<style type="text/css">
<!--
.style1 {
color: #FFFFFF;
font-weight: bold;
140
}
-->
</style>
</head>
<body>
<table width="100%" border="0" cellpadding="2" cellspacing="1"
bgcolor="#DBEAF5">
<tr align="center" bgcolor="#0099CC">
<td height="35" colspan="2" align="left" valign="top"><div
align="center">
<h3 class="style1">Laporan Hasil Dianogsa </h3>
</div></td>
</tr>
<tr>
<td colspan="2"><b>DATA :</b></td>
</tr>
<tr bgcolor="#FFFFFF">
<td width="188">Nama</td>
<td width="870"><?php echo $data1['nama']; ?></td>
</tr>
<tr bgcolor="#FFFFFF">
<td>Kelamin</td>
<td><?php echo $data1['jenis_kelamin']; ?></td>
</tr>
<tr bgcolor="#FFFFFF">
<td>Usia</td>
<td><?php echo $data1['usia']; ?> Tahun</td>
</tr>
<tr bgcolor="#FFFFFF">
<td>Alamat</td>
<td><?php echo $data1['alamat']; ?></td>
141
</tr>
<tr bgcolor="#FFFFFF">
<td> </td>
<td> </td>
</tr>
<tr>
<td colspan="2"><b>HASIL ANALISA TERAKHIR :</b></td>
</tr>
<tr bgcolor="#FFFFFF">
<td>Penyakit</td>
<td><?php echo $data1['nm_penyakit']; ?></td>
</tr>
<tr bgcolor="#FFFFFF">
<td valign="top">Penyebab </td>
<td><?php echo $data1['pencegahan']; ?></td>
</tr>
<tr bgcolor="#FFFFFF">
<td valign="top">Solusi</td>
<td><?php echo $data1['pengobatan']; ?></td>
</tr>
</table>
</body>
</html>
b. Hasildiagnosa
<script type="text/javascript">
$(document).ready(function(){
//Examples of how to assign the ColorBox
event to elements
$(".thickbox").colorbox({width:"50%",
height:"75%"});
142
});
</script>
<script type="text/javascript">
$(document).ready(function(){
//Examples of how to assign the ColorBox
event to elements
$(".colorbox").colorbox({width:"50%",
height:"75%"});
});
</script>
<?php
if (isset($_POST['Del'])) {
if ($_POST['cex'] == NULL) {
echo "<script>window.alert('Data yang akan dihapus belum di
pilih')
javascript:history.go(-1);</script>";
} else {
$a = join(",", $_POST['cex']);
$tampil=mysql_query("SELECT * FROM pasien
Where idpasien='$a'");
while($r=mysql_fetch_array($tampil)){
//unlink("../../../gambar/small_$r[gambar]");
}
mysql_query("DELETE FROM pasien WHERE idpasien='$a'");
print "<script>alert('Data berhasil di dihapus');
javascript:history.go(-
1);</script>";
143
}
}else{
echo "
<div class=judul><h2>Berikut Detail Data Hasil Diagnosa:</h2></div>
<br/>
<form action='' method='post'>
<div style='float:right; padding:10px; width:100px; margin-top:5px;'>
<input type='submit' name='Del' value='Hapus' onclick='return
confirmDelete();'>
</div><br/>
<table id=o width=100%><tbody>
<tr>
<th width='1%' class=th>no</th>
<th width='5%' class=th>Nama</th>
<th width='1%' class=th>Jenis Kelamin</th>
<th width='1%' class=th>Usia</th>
<th width='10%' class=th>Alamat</th>
<th width='1%' class=th>Lihat Diagnosa</th>
<th width='1%' bgcolor='#8DAD9C'><div
align='center'><span class='style1'><input type='checkbox'
name='checkbox[]' class='checkall'></span></div></th>
</tr>";
$p = new Paging;
$batas = 15;
$posisi = $p->cariPosisi($batas);
$tampil=mysql_query("SELECT * FROM pasien order by
idpasien desc LIMIT $posisi,$batas");
$no=1;
$i = $posisi;
while ($r=mysql_fetch_array($tampil)){
144
if (($no % 2) > 0)
$bg = '#FFFFFF'; else
$bg = '#cccccc';
echo "<tr bgcolor=" . $bg . "><td class=td align=center>$no</td>
<td class=td>$r[nama]</td>
<td class=td>$r[jenis_kelamin]</td>
<td class=td>$r[usia]</td>
<td class=td>$r[alamat]</td>
<td align='center' class=td><div align='center'
style='background-color:none;'><a class='colorbox'
href=main/main_hasildiagnosa/cetak.php?id=" . $r['idpasien'] . " ><img
src='../images/dt.png' border='0' width='16' height='16' title='Lihat Hasil
Diagnosa' /></a></div></td>
<td><div align='center'><input type='checkbox' name='cex[]'
value='" . $r['idpasien'] . "'></div></td>
</tr></tr>";
$no++;
}
echo "</tbody></table></form>";
$sql_pagging = mysql_query("SELECT COUNT(*) AS jml FROM
pasien");
$pagging = mysql_fetch_array($sql_pagging);
$jml = $pagging['jml'];
echo"
</br>
<div class='results'> <span>Jumlah Data : $jml</span><br/><br/>
";
145
$jmldata = mysql_num_rows(mysql_query("SELECT * from
pasien"));
$jmlhalaman = $p->jumlahHalaman($jmldata, $batas);
$linkHalaman = $p->navHalaman($_GET['halaman'], $jmlhalaman);
echo" Halaman : $linkHalaman </div>";
}
?>
4.4.9 Main_laporan
a. Class.ezpdf
<?php
include_once('class.pdf.php');
class Cezpdf extends Cpdf {
//==================================================
============================
// this class will take the basic interaction facilities of the Cpdf class
// and make more useful functions so that the user does not have to
// know all the ins and outs of pdf presentation to produce something
pretty.
//
// IMPORTANT NOTE
// there is no warranty, implied or otherwise with this software.
//
// version 009 (versioning is linked to class.pdf.php)
//
// released under a public domain licence.
//
// Wayne Munro, R&OS Ltd, http://www.ros.co.nz/pdf
146
//==================================================
============================
var $ez=array('fontSize'=>10); // used for storing most of the page
configuration parameters
var $y; // this is the current vertical positon on the page of the writing
point, very important
var $ezPages=array(); // keep an array of the ids of the pages, making it
easy to go back and add page numbers etc.
var $ezPageCount=0;
// ------------------------------------------------------------------------------
function Cezpdf($paper='a4',$orientation='portrait'){
// Assuming that people don't want to specify the paper size using
the absolute coordinates
// allow a couple of options:
// orientation can be 'portrait' or 'landscape'
// or, to actually set the coordinates, then pass an array in as the
first parameter.
// the defaults are as shown.
//
// -------------------------
// 2002-07-24 - Nicola Asuni ([email protected]):
// Added new page formats (45 standard ISO paper formats and 4
american common formats)
// paper cordinates are calculated in this way: (inches * 72) where 1
inch = 2.54 cm
//
// Now you may also pass a 2 values array containing the page
width and height in centimeters
147
// -------------------------
if (!is_array($paper)){
switch (strtoupper($paper)){
case '4A0': {$size = array(0,0,4767.87,6740.79);
break;}
case '2A0': {$size = array(0,0,3370.39,4767.87);
break;}
case 'A0': {$size = array(0,0,2383.94,3370.39);
break;}
case 'A1': {$size = array(0,0,1683.78,2383.94);
break;}
case 'A2': {$size = array(0,0,1190.55,1683.78);
break;}
case 'A3': {$size = array(0,0,841.89,1190.55);
break;}
case 'A4': default: {$size =
array(0,0,595.28,841.89); break;}
case 'A5': {$size = array(0,0,419.53,595.28);
break;}
case 'A6': {$size = array(0,0,297.64,419.53);
break;}
case 'A7': {$size = array(0,0,209.76,297.64);
break;}
case 'A8': {$size = array(0,0,147.40,209.76);
break;}
case 'A9': {$size = array(0,0,104.88,147.40);
break;}
case 'A10': {$size = array(0,0,73.70,104.88);
break;}
148
case 'B0': {$size = array(0,0,2834.65,4008.19);
break;}
case 'B1': {$size = array(0,0,2004.09,2834.65);
break;}
case 'B2': {$size = array(0,0,1417.32,2004.09);
break;}
case 'B3': {$size = array(0,0,1000.63,1417.32);
break;}
case 'B4': {$size = array(0,0,708.66,1000.63);
break;}
case 'B5': {$size = array(0,0,498.90,708.66);
break;}
case 'B6': {$size = array(0,0,354.33,498.90);
break;}
case 'B7': {$size = array(0,0,249.45,354.33);
break;}
case 'B8': {$size = array(0,0,175.75,249.45);
break;}
case 'B9': {$size = array(0,0,124.72,175.75);
break;}
case 'B10': {$size = array(0,0,87.87,124.72);
break;}
case 'C0': {$size = array(0,0,2599.37,3676.54);
break;}
case 'C1': {$size = array(0,0,1836.85,2599.37);
break;}
case 'C2': {$size = array(0,0,1298.27,1836.85);
break;}
case 'C3': {$size = array(0,0,918.43,1298.27);
break;}
149
case 'C4': {$size = array(0,0,649.13,918.43);
break;}
case 'C5': {$size = array(0,0,459.21,649.13);
break;}
case 'C6': {$size = array(0,0,323.15,459.21);
break;}
case 'C7': {$size = array(0,0,229.61,323.15);
break;}
case 'C8': {$size = array(0,0,161.57,229.61);
break;}
case 'C9': {$size = array(0,0,113.39,161.57);
break;}
case 'C10': {$size = array(0,0,79.37,113.39);
break;}
case 'RA0': {$size = array(0,0,2437.80,3458.27);
break;}
case 'RA1': {$size = array(0,0,1729.13,2437.80);
break;}
case 'RA2': {$size = array(0,0,1218.90,1729.13);
break;}
case 'RA3': {$size = array(0,0,864.57,1218.90);
break;}
case 'RA4': {$size = array(0,0,609.45,864.57);
break;}
case 'SRA0': {$size = array(0,0,2551.18,3628.35);
break;}
case 'SRA1': {$size = array(0,0,1814.17,2551.18);
break;}
case 'SRA2': {$size = array(0,0,1275.59,1814.17);
break;}
150
case 'SRA3': {$size = array(0,0,907.09,1275.59);
break;}
case 'SRA4': {$size = array(0,0,637.80,907.09);
break;}
case 'LETTER': {$size = array(0,0,612.00,792.00);
break;}
case 'LEGAL': {$size = array(0,0,612.00,1008.00);
break;}
case 'EXECUTIVE': {$size =
array(0,0,521.86,756.00); break;}
case 'FOLIO': {$size = array(0,0,612.00,936.00);
break;}
}
switch (strtolower($orientation)){
case 'landscape':
$a=$size[3];
$size[3]=$size[2];
$size[2]=$a;
break;
}
} else {
if (count($paper)>2) {
// then an array was sent it to set the size
$size = $paper;
}
else { //size in centimeters has been passed
$size[0] = 0;
$size[1] = 0;
$size[2] = ( $paper[0] / 2.54 ) * 72;
$size[3] = ( $paper[1] / 2.54 ) * 72;
}
151
}
$this->Cpdf($size);
$this->ez['pageWidth']=$size[2];
$this->ez['pageHeight']=$size[3];
// also set the margins to some reasonable defaults
$this->ez['topMargin']=30;
$this->ez['bottomMargin']=30;
$this->ez['leftMargin']=30;
$this->ez['rightMargin']=30;
// set the current writing position to the top of the first page
$this->y = $this->ez['pageHeight']-$this->ez['topMargin'];
// and get the ID of the page that was created during the instancing
process.
$this->ezPages[1]=$this->getFirstPageId();
$this->ezPageCount=1;
}
// ------------------------------------------------------------------------------
// 2002-07-24: Nicola Asuni ([email protected])
// Set Margins in centimeters
function ezSetCmMargins($top,$bottom,$left,$right){
$top = ( $top / 2.54 ) * 72;
$bottom = ( $bottom / 2.54 ) * 72;
$left = ( $left / 2.54 ) * 72;
$right = ( $right / 2.54 ) * 72;
$this->ezSetMargins($top,$bottom,$left,$right);
}
// ------------------------------------------------------------------------------
152
function ezColumnsStart($options=array()){
// start from the current y-position, make the set number of columne
if (isset($this->ez['columns']) && $this->ez['columns']==1){
// if we are already in a column mode then just return.
return;
}
$def=array('gap'=>10,'num'=>2);
foreach($def as $k=>$v){
if (!isset($options[$k])){
$options[$k]=$v;
}
}
// setup the columns
$this->ez['columns']=array('on'=>1,'colNum'=>1);
// store the current margins
$this->ez['columns']['margins']=array(
$this->ez['leftMargin']
,$this->ez['rightMargin']
,$this->ez['topMargin']
,$this->ez['bottomMargin']
);
// and store the settings for the columns
$this->ez['columns']['options']=$options;
// then reset the margins to suit the new columns
// safe enough to assume the first column here, but start from the
current y-position
$this->ez['topMargin']=$this->ez['pageHeight']-$this->y;
153
$width=($this->ez['pageWidth']-$this->ez['leftMargin']-$this-
>ez['rightMargin']-($options['num']-
1)*$options['gap'])/$options['num'];
$this->ez['columns']['width']=$width;
$this->ez['rightMargin']=$this->ez['pageWidth']-$this-
>ez['leftMargin']-$width;
}
// ------------------------------------------------------------------------------
function ezColumnsStop(){
if (isset($this->ez['columns']) && $this->ez['columns']['on']==1){
$this->ez['columns']['on']=0;
$this->ez['leftMargin']=$this->ez['columns']['margins'][0];
$this->ez['rightMargin']=$this->ez['columns']['margins'][1];
$this->ez['topMargin']=$this->ez['columns']['margins'][2];
$this->ez['bottomMargin']=$this->ez['columns']['margins'][3];
}
}
// ------------------------------------------------------------------------------
function ezInsertMode($status=1,$pageNum=1,$pos='before'){
// puts the document into insert mode. new pages are inserted until this
is re-called with status=0
// by default pages wil be inserted at the start of the document
switch($status){
case '1':
if (isset($this->ezPages[$pageNum])){
$this->ez['insertMode']=1;
$this->ez['insertOptions']=array('id'=>$this-
>ezPages[$pageNum],'pos'=>$pos);
}
break;
154
case '0':
$this->ez['insertMode']=0;
break;
}
}
// ------------------------------------------------------------------------------
function ezNewPage(){
$pageRequired=1;
if (isset($this->ez['columns']) && $this->ez['columns']['on']==1){
// check if this is just going to a new column
// increment the column number
//echo 'HERE<br>';
$this->ez['columns']['colNum']++;
//echo $this->ez['columns']['colNum'].'<br>';
if ($this->ez['columns']['colNum'] <= $this-
>ez['columns']['options']['num']){
// then just reset to the top of the next column
$pageRequired=0;
} else {
$this->ez['columns']['colNum']=1;
$this->ez['topMargin']=$this->ez['columns']['margins'][2];
}
$width = $this->ez['columns']['width'];
$this->ez['leftMargin']=$this->ez['columns']['margins'][0]+($this-
>ez['columns']['colNum']-1)*($this-
>ez['columns']['options']['gap']+$width);
$this->ez['rightMargin']=$this->ez['pageWidth']-$this-
>ez['leftMargin']-$width;
}
155
//echo 'left='.$this->ez['leftMargin'].' right='.$this-
>ez['rightMargin'].'<br>';
if ($pageRequired){
// make a new page, setting the writing point back to the top
$this->y = $this->ez['pageHeight']-$this->ez['topMargin'];
// make the new page with a call to the basic class.
$this->ezPageCount++;
if (isset($this->ez['insertMode']) && $this->ez['insertMode']==1){
$id = $this->ezPages[$this->ezPageCount] = $this-
>newPage(1,$this->ez['insertOptions']['id'],$this-
>ez['insertOptions']['pos']);
// then manipulate the insert options so that inserted pages follow
each other
$this->ez['insertOptions']['id']=$id;
$this->ez['insertOptions']['pos']='after';
} else {
$this->ezPages[$this->ezPageCount] = $this->newPage();
}
} else {
$this->y = $this->ez['pageHeight']-$this->ez['topMargin'];
}
}
// ------------------------------------------------------------------------------
function ezSetMargins($top,$bottom,$left,$right){
// sets the margins to new values
$this->ez['topMargin']=$top;
$this->ez['bottomMargin']=$bottom;
$this->ez['leftMargin']=$left;
156
$this->ez['rightMargin']=$right;
// check to see if this means that the current writing position is outside
the
// writable area
if ($this->y > $this->ez['pageHeight']-$top){
// then move y down
$this->y = $this->ez['pageHeight']-$top;
}
if ( $this->y < $bottom){
// then make a new page
$this->ezNewPage();
}
}
// ------------------------------------------------------------------------------
function ezGetCurrentPageNumber(){
// return the strict numbering (1,2,3,4..) number of the current page
return $this->ezPageCount;
}
// ------------------------------------------------------------------------------
function
ezStartPageNumbers($x,$y,$size,$pos='left',$pattern='{PAGENUM} of
{TOTALPAGENUM}',$num=''){
// put page numbers on the pages from here.
// place then on the 'pos' side of the coordinates (x,y).
// pos can be 'left' or 'right'
// use the given 'pattern' for display, where (PAGENUM} and
{TOTALPAGENUM} are replaced
157
// as required.
// if $num is set, then make the first page this number, the number of
total pages will
// be adjusted to account for this.
// Adjust this function so that each time you 'start' page numbers then
you effectively start a different batch
// return the number of the batch, so that they can be stopped in a
different order if required.
if (!$pos || !strlen($pos)){
$pos='left';
}
if (!$pattern || !strlen($pattern)){
$pattern='{PAGENUM} of {TOTALPAGENUM}';
}
if (!isset($this->ez['pageNumbering'])){
$this->ez['pageNumbering']=array();
}
$i = count($this->ez['pageNumbering']);
$this->ez['pageNumbering'][$i][$this-
>ezPageCount]=array('x'=>$x,'y'=>$y,'pos'=>$pos,'pattern'=>$pattern,'
num'=>$num,'size'=>$size);
return $i;
}
// ------------------------------------------------------------------------------
function ezWhatPageNumber($pageNum,$i=0){
// given a particular generic page number (ie, document numbered
sequentially from beginning),
// return the page number under a particular page numbering scheme
($i)
158
$num=0;
$start=1;
$startNum=1;
if (!isset($this->ez['pageNumbering']))
{
$this->addMessage('WARNING: page numbering called for and
wasn\'t started with ezStartPageNumbers');
return 0;
}
foreach($this->ez['pageNumbering'][$i] as $k=>$v){
if ($k<=$pageNum){
if (is_array($v)){
// start block
if (strlen($v['num'])){
// a start was specified
$start=$v['num'];
$startNum=$k;
$num=$pageNum-$startNum+$start;
}
} else {
// stop block
$num=0;
}
}
}
return $num;
}
// ------------------------------------------------------------------------------
function ezStopPageNumbers($stopTotal=0,$next=0,$i=0){
159
// if stopTotal=1 then the totalling of pages for this number will stop
too
// if $next=1, then do this page, but not the next, else do not do this
page either
// if $i is set, then stop that particular pagenumbering sequence.
if (!isset($this->ez['pageNumbering'])){
$this->ez['pageNumbering']=array();
}
if ($next && isset($this->ez['pageNumbering'][$i][$this-
>ezPageCount]) && is_array($this->ez['pageNumbering'][$i][$this-
>ezPageCount])){
// then this has only just been started, this will over-write the start,
and nothing will appear
// add a special command to the start block, telling it to stop as well
if ($stopTotal){
$this->ez['pageNumbering'][$i][$this->ezPageCount]['stoptn']=1;
} else {
$this->ez['pageNumbering'][$i][$this->ezPageCount]['stopn']=1;
}
} else {
if ($stopTotal){
$this->ez['pageNumbering'][$i][$this->ezPageCount]='stopt';
} else {
$this->ez['pageNumbering'][$i][$this->ezPageCount]='stop';
}
if ($next){
$this->ez['pageNumbering'][$i][$this->ezPageCount].='n';
}
}
}
160
// ------------------------------------------------------------------------------
function ezPRVTpageNumberSearch($lbl,&$tmp){
foreach($tmp as $i=>$v){
if (is_array($v)){
if (isset($v[$lbl])){
return $i;
}
} else {
if ($v==$lbl){
return $i;
}
}
}
return 0;
}
// ------------------------------------------------------------------------------
function ezPRVTaddPageNumbers(){
// this will go through the pageNumbering array and add the page
numbers are required
if (isset($this->ez['pageNumbering'])){
$totalPages1 = $this->ezPageCount;
$tmp1=$this->ez['pageNumbering'];
$status=0;
foreach($tmp1 as $i=>$tmp){
// do each of the page numbering systems
// firstly, find the total pages for this one
$k = $this->ezPRVTpageNumberSearch('stopt',$tmp);
if ($k && $k>0){
161
$totalPages = $k-1;
} else {
$l = $this->ezPRVTpageNumberSearch('stoptn',$tmp);
if ($l && $l>0){
$totalPages = $l;
} else {
$totalPages = $totalPages1;
}
}
foreach ($this->ezPages as $pageNum=>$id){
if (isset($tmp[$pageNum])){
if (is_array($tmp[$pageNum])){
// then this must be starting page numbers
$status=1;
$info = $tmp[$pageNum];
$info['dnum']=$info['num']-$pageNum;
// also check for the special case of the numbering stopping and
starting on the same page
if (isset($info['stopn']) || isset($info['stoptn']) ){
$status=2;
}
} else if ($tmp[$pageNum]=='stop' || $tmp[$pageNum]=='stopt'){
// then we are stopping page numbers
$status=0;
} else if ($status==1 && ($tmp[$pageNum]=='stoptn' ||
$tmp[$pageNum]=='stopn')){
// then we are stopping page numbers
$status=2;
}
}
if ($status){
162
// then add the page numbering to this page
if (strlen($info['num'])){
$num=$pageNum+$info['dnum'];
} else {
$num=$pageNum;
}
$total = $totalPages+$num-$pageNum;
$pat = str_replace('{PAGENUM}',$num,$info['pattern']);
$pat = str_replace('{TOTALPAGENUM}',$total,$pat);
$this->reopenObject($id);
switch($info['pos']){
case 'right':
$this->addText($info['x'],$info['y'],$info['size'],$pat);
break;
default:
$w=$this->getTextWidth($info['size'],$pat);
$this->addText($info['x']-$w,$info['y'],$info['size'],$pat);
break;
}
$this->closeObject();
}
if ($status==2){
$status=0;
}
}
}
}
}
// ------------------------------------------------------------------------------
163
function ezPRVTcleanUp(){
$this->ezPRVTaddPageNumbers();
}
// ------------------------------------------------------------------------------
function ezStream($options=''){
$this->ezPRVTcleanUp();
$this->stream($options);
}
// ------------------------------------------------------------------------------
function ezOutput($options=0){
$this->ezPRVTcleanUp();
return $this->output($options);
}
// ------------------------------------------------------------------------------
function ezSetY($y){
// used to change the vertical position of the writing point.
$this->y = $y;
if ( $this->y < $this->ez['bottomMargin']){
// then make a new page
$this->ezNewPage();
}
}
// ------------------------------------------------------------------------------
164
function ezSetDy($dy,$mod=''){
// used to change the vertical position of the writing point.
// changes up by a positive increment, so enter a negative number to go
// down the page
// if $mod is set to 'makeSpace' and a new page is forced, then the
pointed will be moved
// down on the new page, this will allow space to be reserved for
graphics etc.
$this->y += $dy;
if ( $this->y < $this->ez['bottomMargin']){
// then make a new page
$this->ezNewPage();
if ($mod=='makeSpace'){
$this->y += $dy;
}
}
}
// ------------------------------------------------------------------------------
function
ezPrvtTableDrawLines($pos,$gap,$x0,$x1,$y0,$y1,$y2,$col,$inner,$o
uter,$opt=1){
$x0=1000;
$x1=0;
$this->setStrokeColor($col[0],$col[1],$col[2]);
$cnt=0;
$n = count($pos);
foreach($pos as $x){
$cnt++;
if ($cnt==1 || $cnt==$n){
165
$this->setLineStyle($outer);
} else {
$this->setLineStyle($inner);
}
$this->line($x-$gap/2,$y0,$x-$gap/2,$y2);
if ($x>$x1){ $x1=$x; };
if ($x<$x0){ $x0=$x; };
}
$this->setLineStyle($outer);
$this->line($x0-$gap/2-$outer/2,$y0,$x1-$gap/2+$outer/2,$y0);
// only do the second line if it is different to the first, AND each row
does not have
// a line on it.
if ($y0!=$y1 && $opt<2){
$this->line($x0-$gap/2,$y1,$x1-$gap/2,$y1);
}
$this->line($x0-$gap/2-$outer/2,$y2,$x1-$gap/2+$outer/2,$y2);
}
// ------------------------------------------------------------------------------
function
ezPrvtTableColumnHeadings($cols,$pos,$maxWidth,$height,$decende
r,$gap,$size,&$y,$optionsAll=array()){
// uses ezText to add the text, and returns the height taken by the
largest heading
// this page will move the headings to a new page if they will not fit
completely on this one
// transaction support will be used to implement this
if (isset($optionsAll['cols'])){
166
$options = $optionsAll['cols'];
} else {
$options = array();
}
$mx=0;
$startPage = $this->ezPageCount;
$secondGo=0;
// $y is the position at which the top of the table should start, so the
base
// of the first text, is $y-$height-$gap-$decender, but ezText starts by
dropping $height
// the return from this function is the total cell height, including gaps,
and $y is adjusted
// to be the postion of the bottom line
// begin the transaction
$this->transaction('start');
$ok=0;
// $y-=$gap-$decender;
$y-=$gap;
while ($ok==0){
foreach($cols as $colName=>$colHeading){
$this->ezSetY($y);
if (isset($options[$colName]) &&
isset($options[$colName]['justification'])){
$justification = $options[$colName]['justification'];
} else {
$justification = 'left';
167
}
$this->ezText($colHeading,$size,array('aleft'=>
$pos[$colName],'aright'=>($maxWidth[$colName]+$pos[$colName]),'j
ustification'=>$justification));
$dy = $y-$this->y;
if ($dy>$mx){
$mx=$dy;
}
}
$y = $y - $mx - $gap + $decender;
// $y -= $mx-$gap+$decender;
// now, if this has moved to a new page, then abort the transaction,
move to a new page, and put it there
// do not check on the second time around, to avoid an infinite loop
if ($this->ezPageCount != $startPage && $secondGo==0){
$this->transaction('rewind');
$this->ezNewPage();
$y = $this->y - $gap-$decender;
$ok=0;
$secondGo=1;
// $y = $store_y;
$mx=0;
} else {
$this->transaction('commit');
$ok=1;
}
}
return $mx+$gap*2-$decender;
168
}
// ------------------------------------------------------------------------------
function ezPrvtGetTextWidth($size,$text){
// will calculate the maximum width, taking into account that the text
may be broken
// by line breaks.
$mx=0;
$lines = explode("\n",$text);
foreach ($lines as $line){
$w = $this->getTextWidth($size,$line);
if ($w>$mx){
$mx=$w;
}
}
return $mx;
}
// ------------------------------------------------------------------------------
function ezTable(&$data,$cols='',$title='',$options=''){
// add a table of information to the pdf document
// $data is a two dimensional array
// $cols (optional) is an associative array, the keys are the names of the
columns from $data
// to be presented (and in that order), the values are the titles to be
given to the columns
// $title (optional) is the title to be put on the top of the table
//
// $options is an associative array which can contain:
169
// 'showLines'=> 0,1,2, default is 1 (show outside and top lines only),
2=> lines on each row
// 'showHeadings' => 0 or 1
// 'shaded'=> 0,1,2,3 default is 1 (1->alternate lines are shaded, 0->no
shading, 2-> both shaded, second uses shadeCol2)
// 'shadeCol' => (r,g,b) array, defining the colour of the shading,
default is (0.8,0.8,0.8)
// 'shadeCol2' => (r,g,b) array, defining the colour of the shading of the
other blocks, default is (0.7,0.7,0.7)
// 'fontSize' => 10
// 'textCol' => (r,g,b) array, text colour
// 'titleFontSize' => 12
// 'rowGap' => 2 , the space added at the top and bottom of each row,
between the text and the lines
// 'colGap' => 5 , the space on the left and right sides of each cell
// 'lineCol' => (r,g,b) array, defining the colour of the lines, default,
black.
// 'xPos' => 'left','right','center','centre',or coordinate, reference
coordinate in the x-direction
// 'xOrientation' => 'left','right','center','centre', position of the table
w.r.t 'xPos'
// 'width'=> <number> which will specify the width of the table, if it
turns out to not be this
// wide, then it will stretch the table to fit, if it is wider then each cell
will be made
// proportionalty smaller, and the content may have to wrap.
// 'maxWidth'=> <number> similar to 'width', but will only make table
smaller than it wants to be
// 'options' =>
array(<colname>=>array('justification'=>'left','width'=>100,'link'=>link
DataName),<colname>=>....)
170
// allow the setting of other paramaters for the individual
columns
// 'minRowSpace'=> the minimum space between the bottom of each
row and the bottom margin, in which a new row will be started
// if it is less, then a new page would be started, default=-
100
// 'innerLineThickness'=>1
// 'outerLineThickness'=>1
// 'splitRows'=>0, 0 or 1, whether or not to allow the rows to be split
across page boundaries
// 'protectRows'=>number, the number of rows to hold with the
heading on page, ie, if there less than this number of
// rows on the page, then move the whole lot onto the next
page, default=1
//
// note that the user will have had to make a font selection already or
this will not
// produce a valid pdf file.
if (!is_array($data)){
return;
}
if (!is_array($cols)){
// take the columns from the first row of the data set
reset($data);
list($k,$v)=each($data);
if (!is_array($v)){
return;
}
$cols=array();
171
foreach($v as $k1=>$v1){
$cols[$k1]=$k1;
}
}
if (!is_array($options)){
$options=array();
}
$defaults = array(
'shaded'=>1,'showLines'=>1,'shadeCol'=>array(0.8,0.8,0.8),'shadeCol2'
=>array(0.7,0.7,0.7),'fontSize'=>10,'titleFontSize'=>12
,'titleGap'=>5,'lineCol'=>array(0,0,0),'gap'=>5,'xPos'=>'centre','xOrient
ation'=>'centre'
,'showHeadings'=>1,'textCol'=>array(0,0,0),'width'=>0,'maxWidth'=>0,'
cols'=>array(),'minRowSpace'=>-100,'rowGap'=>2,'colGap'=>5
,'innerLineThickness'=>1,'outerLineThickness'=>1,'splitRows'=>0,'prot
ectRows'=>1
);
foreach($defaults as $key=>$value){
if (is_array($value)){
if (!isset($options[$key]) || !is_array($options[$key])){
$options[$key]=$value;
}
} else {
if (!isset($options[$key])){
172
$options[$key]=$value;
}
}
}
$options['gap']=2*$options['colGap'];
$middle = ($this->ez['pageWidth']-$this->ez['rightMargin'])/2+($this-
>ez['leftMargin'])/2;
// figure out the maximum widths of the text within each column
$maxWidth=array();
foreach($cols as $colName=>$colHeading){
$maxWidth[$colName]=0;
}
// find the maximum cell widths based on the data
foreach($data as $row){
foreach($cols as $colName=>$colHeading){
$w = $this-
>ezPrvtGetTextWidth($options['fontSize'],(string)$row[$colName])*1.
01;
if ($w > $maxWidth[$colName]){
$maxWidth[$colName]=$w;
}
}
}
// and the maximum widths to fit in the headings
foreach($cols as $colName=>$colTitle){
$w = $this-
>ezPrvtGetTextWidth($options['fontSize'],(string)$colTitle)*1.01;
if ($w > $maxWidth[$colName]){
$maxWidth[$colName]=$w;
}
173
}
// calculate the start positions of each of the columns
$pos=array();
$x=0;
$t=$x;
$adjustmentWidth=0;
$setWidth=0;
foreach($maxWidth as $colName => $w){
$pos[$colName]=$t;
// if the column width has been specified then set that here, also total
the
// width avaliable for adjustment
if (isset($options['cols'][$colName]) &&
isset($options['cols'][$colName]['width']) &&
$options['cols'][$colName]['width']>0){
$t=$t+$options['cols'][$colName]['width'];
$maxWidth[$colName] = $options['cols'][$colName]['width']-
$options['gap'];
$setWidth += $options['cols'][$colName]['width'];
} else {
$t=$t+$w+$options['gap'];
$adjustmentWidth += $w;
$setWidth += $options['gap'];
}
}
$pos['_end_']=$t;
// if maxWidth is specified, and the table is too wide, and the width
has not been set,
// then set the width.
174
if ($options['width']==0 && $options['maxWidth'] && ($t-
$x)>$options['maxWidth']){
// then need to make this one smaller
$options['width']=$options['maxWidth'];
}
if ($options['width'] && $adjustmentWidth>0 &&
$setWidth<$options['width']){
// first find the current widths of the columns involved in this mystery
$cols0 = array();
$cols1 = array();
$xq=0;
$presentWidth=0;
$last='';
foreach($pos as $colName=>$p){
if (!isset($options['cols'][$last]) ||
!isset($options['cols'][$last]['width']) ||
$options['cols'][$last]['width']<=0){
if (strlen($last)){
$cols0[$last]=$p-$xq -$options['gap'];
$presentWidth += ($p-$xq - $options['gap']);
}
} else {
$cols1[$last]=$p-$xq;
}
$last=$colName;
$xq=$p;
}
// $cols0 contains the widths of all the columns which are not set
$neededWidth = $options['width']-$setWidth;
175
// if needed width is negative then add it equally to each column, else
get more tricky
if ($presentWidth<$neededWidth){
foreach($cols0 as $colName=>$w){
$cols0[$colName]+= ($neededWidth-
$presentWidth)/count($cols0);
}
} else {
$cnt=0;
while ($presentWidth>$neededWidth && $cnt<100){
$cnt++; // insurance policy
// find the widest columns, and the next to widest width
$aWidest = array();
$nWidest=0;
$widest=0;
foreach($cols0 as $colName=>$w){
if ($w>$widest){
$aWidest=array($colName);
$nWidest = $widest;
$widest=$w;
} else if ($w==$widest){
$aWidest[]=$colName;
}
}
// then figure out what the width of the widest columns would have
to be to take up all the slack
$newWidestWidth = $widest - ($presentWidth-
$neededWidth)/count($aWidest);
if ($newWidestWidth > $nWidest){
// then there is space to set them to this
176
foreach($aWidest as $colName){
$cols0[$colName] = $newWidestWidth;
}
$presentWidth=$neededWidth;
} else {
// there is not space, reduce the size of the widest ones down to
the next size down, and we
// will go round again
foreach($aWidest as $colName){
$cols0[$colName] = $nWidest;
}
$presentWidth=$presentWidth-($widest-
$nWidest)*count($aWidest);
}
}
}
// $cols0 now contains the new widths of the constrained columns.
// now need to update the $pos and $maxWidth arrays
$xq=0;
foreach($pos as $colName=>$p){
$pos[$colName]=$xq;
if (!isset($options['cols'][$colName]) ||
!isset($options['cols'][$colName]['width']) ||
$options['cols'][$colName]['width']<=0){
if (isset($cols0[$colName])){
$xq += $cols0[$colName] + $options['gap'];
$maxWidth[$colName]=$cols0[$colName];
}
} else {
if (isset($cols1[$colName])){
$xq += $cols1[$colName];
177
}
}
}
$t=$x+$options['width'];
$pos['_end_']=$t;
}
// now adjust the table to the correct location across the page
switch ($options['xPos']){
case 'left':
$xref = $this->ez['leftMargin'];
break;
case 'right':
$xref = $this->ez['pageWidth'] - $this->ez['rightMargin'];
break;
case 'centre':
case 'center':
$xref = $middle;
break;
default:
$xref = $options['xPos'];
break;
}
switch ($options['xOrientation']){
case 'left':
$dx = $xref-$t;
break;
case 'right':
$dx = $xref;
break;
178
case 'centre':
case 'center':
$dx = $xref-$t/2;
break;
}
foreach($pos as $k=>$v){
$pos[$k]=$v+$dx;
}
$x0=$x+$dx;
$x1=$t+$dx;
$baseLeftMargin = $this->ez['leftMargin'];
$basePos = $pos;
$baseX0 = $x0;
$baseX1 = $x1;
// ok, just about ready to make me a table
$this-
>setColor($options['textCol'][0],$options['textCol'][1],$options['textCol
'][2]);
$this-
>setStrokeColor($options['shadeCol'][0],$options['shadeCol'][1],$optio
ns['shadeCol'][2]);
$middle = ($x1+$x0)/2;
// start a transaction which will be used to regress the table, if there are
not enough rows protected
if ($options['protectRows']>0){
179
$this->transaction('start');
$movedOnce=0;
}
$abortTable = 1;
while ($abortTable){
$abortTable=0;
$dm = $this->ez['leftMargin']-$baseLeftMargin;
foreach($basePos as $k=>$v){
$pos[$k]=$v+$dm;
}
$x0=$baseX0+$dm;
$x1=$baseX1+$dm;
$middle = ($x1+$x0)/2;
// if the title is set, then do that
if (strlen($title)){
$w = $this->getTextWidth($options['titleFontSize'],$title);
$this->y -= $this->getFontHeight($options['titleFontSize']);
if ($this->y < $this->ez['bottomMargin']){
$this->ezNewPage();
// margins may have changed on the newpage
$dm = $this->ez['leftMargin']-$baseLeftMargin;
foreach($basePos as $k=>$v){
$pos[$k]=$v+$dm;
}
$x0=$baseX0+$dm;
$x1=$baseX1+$dm;
$middle = ($x1+$x0)/2;
$this->y -= $this->getFontHeight($options['titleFontSize']);
180
}
$this->addText($middle-$w/2,$this-
>y,$options['titleFontSize'],$title);
$this->y -= $options['titleGap'];
}
// margins may have changed on the newpage
$dm = $this->ez['leftMargin']-$baseLeftMargin;
foreach($basePos as $k=>$v){
$pos[$k]=$v+$dm;
}
$x0=$baseX0+$dm;
$x1=$baseX1+$dm;
$y=$this->y; // to simplify the code a bit
// make the table
$height = $this->getFontHeight($options['fontSize']);
$decender = $this->getFontDecender($options['fontSize']);
$y0=$y+$decender;
$dy=0;
if ($options['showHeadings']){
// this function will move the start of the table to a new page if it does
not fit on this one
$headingHeight = $this-
>ezPrvtTableColumnHeadings($cols,$pos,$maxWidth,$height,$decend
er,$options['rowGap'],$options['fontSize'],$y,$options);
$y0 = $y+$headingHeight;
181
$y1 = $y;
$dm = $this->ez['leftMargin']-$baseLeftMargin;
foreach($basePos as $k=>$v){
$pos[$k]=$v+$dm;
}
$x0=$baseX0+$dm;
$x1=$baseX1+$dm;
} else {
$y1 = $y0;
}
$firstLine=1;
// open an object here so that the text can be put in over the shading
if ($options['shaded']){
$this->saveState();
$textObjectId = $this->openObject();
$this->closeObject();
$this->addObject($textObjectId);
$this->reopenObject($textObjectId);
}
$cnt=0;
$newPage=0;
foreach($data as $row){
$cnt++;
// the transaction support will be used to prevent rows being split
if ($options['splitRows']==0){
182
$pageStart = $this->ezPageCount;
if (isset($this->ez['columns']) && $this->ez['columns']['on']==1){
$columnStart = $this->ez['columns']['colNum'];
}
$this->transaction('start');
$row_orig = $row;
$y_orig = $y;
$y0_orig = $y0;
$y1_orig = $y1;
}
$ok=0;
$secondTurn=0;
while(!$abortTable && $ok == 0){
$mx=0;
$newRow=1;
while(!$abortTable && ($newPage || $newRow)){
$y-=$height;
if ($newPage || $y<$this->ez['bottomMargin'] ||
(isset($options['minRowSpace']) && $y<($this-
>ez['bottomMargin']+$options['minRowSpace'])) ){
// check that enough rows are with the heading
if ($options['protectRows']>0 && $movedOnce==0 &&
$cnt<=$options['protectRows']){
// then we need to move the whole table onto the next page
$movedOnce = 1;
$abortTable = 1;
}
$y2=$y-$mx+2*$height+$decender-$newRow*$height;
183
if ($options['showLines']){
if (!$options['showHeadings']){
$y0=$y1;
}
$this-
>ezPrvtTableDrawLines($pos,$options['gap'],$x0,$x1,$y0,$y1,$y2,$op
tions['lineCol'],$options['innerLineThickness'],$options['outerLineThic
kness'],$options['showLines']);
}
if ($options['shaded']){
$this->closeObject();
$this->restoreState();
}
$this->ezNewPage();
// and the margins may have changed, this is due to the possibility
of the columns being turned on
// as the columns are managed by manipulating the margins
$dm = $this->ez['leftMargin']-$baseLeftMargin;
foreach($basePos as $k=>$v){
$pos[$k]=$v+$dm;
}
// $x0=$x0+$dm;
// $x1=$x1+$dm;
$x0=$baseX0+$dm;
$x1=$baseX1+$dm;
if ($options['shaded']){
$this->saveState();
$textObjectId = $this->openObject();
$this->closeObject();
184
$this->addObject($textObjectId);
$this->reopenObject($textObjectId);
}
$this-
>setColor($options['textCol'][0],$options['textCol'][1],$options['textCol
'][2],1);
$y = $this->ez['pageHeight']-$this->ez['topMargin'];
$y0=$y+$decender;
$mx=0;
if ($options['showHeadings']){
$this-
>ezPrvtTableColumnHeadings($cols,$pos,$maxWidth,$height,$decend
er,$options['rowGap'],$options['fontSize'],$y,$options);
$y1=$y;
} else {
$y1=$y0;
}
$firstLine=1;
$y -= $height;
}
$newRow=0;
// write the actual data
// if these cells need to be split over a page, then $newPage will be
set, and the remaining
// text will be placed in $leftOvers
$newPage=0;
$leftOvers=array();
foreach($cols as $colName=>$colTitle){
$this->ezSetY($y+$height);
$colNewPage=0;
185
if (isset($row[$colName])){
if (isset($options['cols'][$colName]) &&
isset($options['cols'][$colName]['link']) &&
strlen($options['cols'][$colName]['link'])){
$lines = explode("\n",$row[$colName]);
if (isset($row[$options['cols'][$colName]['link']]) &&
strlen($row[$options['cols'][$colName]['link']])){
foreach($lines as $k=>$v){
$lines[$k]='<c:alink:'.$row[$options['cols'][$colName]['link']].'>'.$v.'</
c:alink>';
}
}
} else {
$lines = explode("\n",$row[$colName]);
}
} else {
$lines = array();
}
$this->y -= $options['rowGap'];
foreach ($lines as $line){
$line = $this->ezProcessText($line);
$start=1;
while (strlen($line) || $start){
$start=0;
if (!$colNewPage){
$this->y=$this->y-$height;
}
if ($this->y < $this->ez['bottomMargin']){
186
// $this->ezNewPage();
$newPage=1; // whether a new page is required for any of the
columns
$colNewPage=1; // whether a new page is required for this
column
}
if ($colNewPage){
if (isset($leftOvers[$colName])){
$leftOvers[$colName].="\n".$line;
} else {
$leftOvers[$colName] = $line;
}
$line='';
} else {
if (isset($options['cols'][$colName]) &&
isset($options['cols'][$colName]['justification']) ){
$just = $options['cols'][$colName]['justification'];
} else {
$just='left';
}
$line=$this->addTextWrap($pos[$colName],$this-
>y,$maxWidth[$colName],$options['fontSize'],$line,$just);
}
}
}
$dy=$y+$height-$this->y+$options['rowGap'];
if ($dy-$height*$newPage>$mx){
$mx=$dy-$height*$newPage;
}
187
}
// set $row to $leftOvers so that they will be processed onto the new
page
$row = $leftOvers;
// now add the shading underneath
if ($options['shaded'] && $cnt%2==0){
$this->closeObject();
$this-
>setColor($options['shadeCol'][0],$options['shadeCol'][1],$options['sha
deCol'][2],1);
$this->filledRectangle($x0-
$options['gap']/2,$y+$decender+$height-$mx,$x1-$x0,$mx);
$this->reopenObject($textObjectId);
}
if ($options['shaded']==2 && $cnt%2==1){
$this->closeObject();
$this-
>setColor($options['shadeCol2'][0],$options['shadeCol2'][1],$options['s
hadeCol2'][2],1);
$this->filledRectangle($x0-
$options['gap']/2,$y+$decender+$height-$mx,$x1-$x0,$mx);
$this->reopenObject($textObjectId);
}
if ($options['showLines']>1){
// then draw a line on the top of each block
// $this->closeObject();
$this->saveState();
188
$this-
>setStrokeColor($options['lineCol'][0],$options['lineCol'][1],$options['l
ineCol'][2],1);
// $this->line($x0-$options['gap']/2,$y+$decender+$height-
$mx,$x1-$x0,$mx);
if ($firstLine){
$this->setLineStyle($options['outerLineThickness']);
$firstLine=0;
} else {
$this->setLineStyle($options['innerLineThickness']);
}
$this->line($x0-$options['gap']/2,$y+$decender+$height,$x1-
$options['gap']/2,$y+$decender+$height);
$this->restoreState();
// $this->reopenObject($textObjectId);
}
} // end of while
$y=$y-$mx+$height;
// checking row split over pages
if ($options['splitRows']==0){
if ( ( ($this->ezPageCount != $pageStart) || (isset($this-
>ez['columns']) && $this->ez['columns']['on']==1 && $columnStart !=
$this->ez['columns']['colNum'] )) && $secondTurn==0){
// then we need to go back and try that again !
$newPage=1;
$secondTurn=1;
$this->transaction('rewind');
$row = $row_orig;
$y = $y_orig;
$y0 = $y0_orig;
189
$y1 = $y1_orig;
$ok=0;
$dm = $this->ez['leftMargin']-$baseLeftMargin;
foreach($basePos as $k=>$v){
$pos[$k]=$v+$dm;
}
$x0=$baseX0+$dm;
$x1=$baseX1+$dm;
} else {
$this->transaction('commit');
$ok=1;
}
} else {
$ok=1; // don't go round the loop if splitting rows is allowed
}
} // end of while to check for row splitting
if ($abortTable){
if ($ok==0){
$this->transaction('abort');
}
// only the outer transaction should be operational
$this->transaction('rewind');
$this->ezNewPage();
break;
}
} // end of foreach ($data as $row)
190
} // end of while ($abortTable)
// table has been put on the page, the rows guarded as required,
commit.
$this->transaction('commit');
$y2=$y+$decender;
if ($options['showLines']){
if (!$options['showHeadings']){
$y0=$y1;
}
$this-
>ezPrvtTableDrawLines($pos,$options['gap'],$x0,$x1,$y0,$y1,$y2,$op
tions['lineCol'],$options['innerLineThickness'],$options['outerLineThic
kness'],$options['showLines']);
}
// close the object for drawing the text on top
if ($options['shaded']){
$this->closeObject();
$this->restoreState();
}
$this->y=$y;
return $y;
}
// ------------------------------------------------------------------------------
function ezProcessText($text){
// this function will intially be used to implement underlining support,
but could be used for a range of other
191
// purposes
$search = array('<u>','<U>','</u>','</U>');
$replace = array('<c:uline>','<c:uline>','</c:uline>','</c:uline>');
return str_replace($search,$replace,$text);
}
// ------------------------------------------------------------------------------
function ezText($text,$size=0,$options=array(),$test=0){
// this will add a string of text to the document, starting at the current
drawing
// position.
// it will wrap to keep within the margins, including optional offsets
from the left
// and the right, if $size is not specified, then it will be the last one
used, or
// the default value (12 I think).
// the text will go to the start of the next line when a return code "\n" is
found.
// possible options are:
// 'left'=> number, gap to leave from the left margin
// 'right'=> number, gap to leave from the right margin
// 'aleft'=> number, absolute left position (overrides 'left')
// 'aright'=> number, absolute right position (overrides 'right')
// 'justification' => 'left','right','center','centre','full'
// only set one of the next two items (leading overrides spacing)
// 'leading' => number, defines the total height taken by the line,
independent of the font height.
// 'spacing' => a real number, though usually set to one of 1, 1.5, 2
(line spacing as used in word processing)
192
// if $test is set then this should just check if the text is going to flow
onto a new page or not, returning true or false
// apply the filtering which will make the underlining function.
$text = $this->ezProcessText($text);
$newPage=false;
$store_y = $this->y;
if (is_array($options) && isset($options['aleft'])){
$left=$options['aleft'];
} else {
$left = $this->ez['leftMargin'] + ((is_array($options) &&
isset($options['left']))?$options['left']:0);
}
if (is_array($options) && isset($options['aright'])){
$right=$options['aright'];
} else {
$right = $this->ez['pageWidth'] - $this->ez['rightMargin'] -
((is_array($options) && isset($options['right']))?$options['right']:0);
}
if ($size<=0){
$size = $this->ez['fontSize'];
} else {
$this->ez['fontSize']=$size;
}
if (is_array($options) && isset($options['justification'])){
$just = $options['justification'];
} else {
193
$just = 'left';
}
// modifications to give leading and spacing based on those given by
Craig Heydenburg 1/1/02
if (is_array($options) && isset($options['leading'])) { ## use leading
instead of spacing
$height = $options['leading'];
} else if (is_array($options) && isset($options['spacing'])) {
$height = $this->getFontHeight($size) * $options['spacing'];
} else {
$height = $this->getFontHeight($size);
}
$lines = explode("\n",$text);
foreach ($lines as $line){
$start=1;
while (strlen($line) || $start){
$start=0;
$this->y=$this->y-$height;
if ($this->y < $this->ez['bottomMargin']){
if ($test){
$newPage=true;
} else {
$this->ezNewPage();
// and then re-calc the left and right, in case they have changed
due to columns
}
}
if (is_array($options) && isset($options['aleft'])){
194
$left=$options['aleft'];
} else {
$left = $this->ez['leftMargin'] + ((is_array($options) &&
isset($options['left']))?$options['left']:0);
}
if (is_array($options) && isset($options['aright'])){
$right=$options['aright'];
} else {
$right = $this->ez['pageWidth'] - $this->ez['rightMargin'] -
((is_array($options) && isset($options['right']))?$options['right']:0);
}
$line=$this->addTextWrap($left,$this->y,$right-
$left,$size,$line,$just,0,$test);
}
}
if ($test){
$this->y=$store_y;
return $newPage;
} else {
return $this->y;
}
}
// ------------------------------------------------------------------------------
function ezImage($image,$pad = 5,$width = 0,$resize = 'full',$just =
'center',$border = ''){
//beta ezimage function
if (stristr($image,'://'))//copy to temp file
{
195
$fp = @fopen($image,"rb");
while(!feof($fp))
{
$cont.= fread($fp,1024);
}
fclose($fp);
$image = tempnam ("/tmp", "php-pdf");
$fp2 = @fopen($image,"w");
fwrite($fp2,$cont);
fclose($fp2);
$temp = true;
}
if (!(file_exists($image))) return false; //return immediately if
image file does not exist
$imageInfo = getimagesize($image);
switch ($imageInfo[2]){
case 2:
$type = "jpeg";
break;
case 3:
$type = "png";
break;
default:
return false; //return if file is not jpg or png
}
if ($width == 0) $width = $imageInfo[0]; //set width
$ratio = $imageInfo[0]/$imageInfo[1];
//get maximum width of image
if (isset($this->ez['columns']) && $this->ez['columns']['on'] == 1)
196
{
$bigwidth = $this->ez['columns']['width'] - ($pad * 2);
}
else
{
$bigwidth = $this->ez['pageWidth'] - ($pad * 2);
}
//fix width if larger than maximum or if $resize=full
if ($resize == 'full' || $resize == 'width' || $width > $bigwidth)
{
$width = $bigwidth;
}
$height = ($width/$ratio); //set height
//fix size if runs off page
if ($height > ($this->y - $this->ez['bottomMargin'] - ($pad * 2)))
{
if ($resize != 'full')
{
$this->ezNewPage();
}
else
{
$height = ($this->y - $this->ez['bottomMargin'] -
($pad * 2)); //shrink height
$width = ($height*$ratio); //fix width
}
}
197
//fix x-offset if image smaller than bigwidth
if ($width < $bigwidth)
{
//center if justification=center
if ($just == 'center')
{
$offset = ($bigwidth - $width) / 2;
}
//move to right if justification=right
if ($just == 'right')
{
$offset = ($bigwidth - $width);
}
//leave at left if justification=left
if ($just == 'left')
{
$offset = 0;
}
}
//call appropriate function
if ($type == "jpeg"){
$this->addJpegFromFile($image,$this->ez['leftMargin'] +
$pad + $offset, $this->y + $this->getFontHeight($this->ez['fontSize']) -
$pad - $height,$width);
}
if ($type == "png"){
198
$this->addPngFromFile($image,$this->ez['leftMargin'] +
$pad + $offset, $this->y + $this->getFontHeight($this->ez['fontSize']) -
$pad - $height,$width);
}
//draw border
if ($border != '')
{
if (!(isset($border['color'])))
{
$border['color']['red'] = .5;
$border['color']['blue'] = .5;
$border['color']['green'] = .5;
}
if (!(isset($border['width']))) $border['width'] = 1;
if (!(isset($border['cap']))) $border['cap'] = 'round';
if (!(isset($border['join']))) $border['join'] = 'round';
$this-
>setStrokeColor($border['color']['red'],$border['color']['green'],$border[
'color']['blue']);
$this->setLineStyle($border['width'],$border['cap'],$border['join']);
$this->rectangle($this->ez['leftMargin'] + $pad + $offset, $this->y
+ $this->getFontHeight($this->ez['fontSize']) - $pad -
$height,$width,$height);
}
// move y below image
$this->y = $this->y - $pad - $height;
//remove tempfile for remote images
if ($temp == true) unlink($image);
199
}
// ------------------------------------------------------------------------------
// note that templating code is still considered developmental - have not
really figured
// out a good way of doing this yet.
function loadTemplate($templateFile){
// this function will load the requested template ($file includes full or
relative pathname)
// the code for the template will be modified to make it name safe, and
then stored in
// an array for later use
// The id of the template will be returned for the user to operate on it
later
if (!file_exists($templateFile)){
return -1;
}
$code = implode('',file($templateFile));
if (!strlen($code)){
return;
}
$code = trim($code);
if (substr($code,0,5)=='<?php'){
$code = substr($code,5);
}
if (substr($code,-2)=='?>'){
$code = substr($code,0,strlen($code)-2);
}
200
if (isset($this->ez['numTemplates'])){
$newNum = $this->ez['numTemplates'];
$this->ez['numTemplates']++;
} else {
$newNum=0;
$this->ez['numTemplates']=1;
$this->ez['templates']=array();
}
$this->ez['templates'][$newNum]['code']=$code;
return $newNum;
}
// ------------------------------------------------------------------------------
function execTemplate($id,$data=array(),$options=array()){
// execute the given template on the current document.
if (!isset($this->ez['templates'][$id])){
return;
}
eval($this->ez['templates'][$id]['code']);
}
// ------------------------------------------------------------------------------
function ilink($info){
$this->alink($info,1);
}
function alink($info,$internal=0){
201
// a callback function to support the formation of clickable links within
the document
$lineFactor=0.05; // the thickness of the line as a proportion of the
height. also the drop of the line.
switch($info['status']){
case 'start':
case 'sol':
// the beginning of the link
// this should contain the URl for the link as the 'p' entry, and will
also contain the value of 'nCallback'
if (!isset($this->ez['links'])){
$this->ez['links']=array();
}
$i = $info['nCallback'];
$this->ez['links'][$i] =
array('x'=>$info['x'],'y'=>$info['y'],'angle'=>$info['angle'],'decender'=>
$info['decender'],'height'=>$info['height'],'url'=>$info['p']);
if ($internal==0){
$this->saveState();
$this->setColor(0,0,1);
$this->setStrokeColor(0,0,1);
$thick = $info['height']*$lineFactor;
$this->setLineStyle($thick);
}
break;
case 'end':
case 'eol':
// the end of the link
// assume that it is the most recent opening which has closed
$i = $info['nCallback'];
$start = $this->ez['links'][$i];
202
// add underlining
if ($internal){
$this-
>addInternalLink($start['url'],$start['x'],$start['y']+$start['decender'],$in
fo['x'],$start['y']+$start['decender']+$start['height']);
} else {
$a = deg2rad((float)$start['angle']-90.0);
$drop = $start['height']*$lineFactor*1.5;
$dropx = cos($a)*$drop;
$dropy = -sin($a)*$drop;
$this->line($start['x']-$dropx,$start['y']-$dropy,$info['x']-
$dropx,$info['y']-$dropy);
$this-
>addLink($start['url'],$start['x'],$start['y']+$start['decender'],$info['x'],$
start['y']+$start['decender']+$start['height']);
$this->restoreState();
}
break;
}
}
// ------------------------------------------------------------------------------
function uline($info){
// a callback function to support underlining
$lineFactor=0.05; // the thickness of the line as a proportion of the
height. also the drop of the line.
switch($info['status']){
case 'start':
case 'sol':
203
// the beginning of the underline zone
if (!isset($this->ez['links'])){
$this->ez['links']=array();
}
$i = $info['nCallback'];
$this->ez['links'][$i] =
array('x'=>$info['x'],'y'=>$info['y'],'angle'=>$info['angle'],'decender'=>
$info['decender'],'height'=>$info['height']);
$this->saveState();
$thick = $info['height']*$lineFactor;
$this->setLineStyle($thick);
break;
case 'end':
case 'eol':
// the end of the link
// assume that it is the most recent opening which has closed
$i = $info['nCallback'];
$start = $this->ez['links'][$i];
// add underlining
$a = deg2rad((float)$start['angle']-90.0);
$drop = $start['height']*$lineFactor*1.5;
$dropx = cos($a)*$drop;
$dropy = -sin($a)*$drop;
$this->line($start['x']-$dropx,$start['y']-$dropy,$info['x']-
$dropx,$info['y']-$dropy);
$this->restoreState();
break;
}
}
// ------------------------------------------------------------------------------
204
}
?>
b. Class.pdf
<?php
/**
* Cpdf
*
* http://www.ros.co.nz/pdf
*
* A PHP class to provide the basic functionality to create a pdf
document without
* any requirement for additional modules.
*
* Note that they companion class CezPdf can be used to extend this
class and dramatically
* simplify the creation of documents.
*
* IMPORTANT NOTE
* there is no warranty, implied or otherwise with this software.
*
* LICENCE
* This code has been placed in the Public Domain for all to enjoy.
*
* @author Wayne Munro <[email protected]>
* @version 009
* @package Cpdf
*/
class Cpdf {
/**
205
* the current number of pdf objects in the document
*/
var $numObj=0;
/**
* this array contains all of the pdf objects, ready for final assembly
*/
var $objects = array();
/**
* the objectId (number within the objects array) of the document
catalog
*/
var $catalogId;
/**
* array carrying information about the fonts that the system currently
knows about
* used to ensure that a font is not loaded twice, among other things
*/
var $fonts=array();
/**
* a record of the current font
*/
var $currentFont='';
/**
* the current base font
*/
var $currentBaseFont='';
/**
* the number of the current font within the font array
*/
var $currentFontNum=0;
/**
206
*
*/
var $currentNode;
/**
* object number of the current page
*/
var $currentPage;
/**
* object number of the currently active contents block
*/
var $currentContents;
/**
* number of fonts within the system
*/
var $numFonts=0;
/**
* current colour for fill operations, defaults to inactive value, all three
components should be between 0 and 1 inclusive when active
*/
var $currentColour=array('r'=>-1,'g'=>-1,'b'=>-1);
/**
* current colour for stroke operations (lines etc.)
*/
var $currentStrokeColour=array('r'=>-1,'g'=>-1,'b'=>-1);
/**
* current style that lines are drawn in
*/
var $currentLineStyle='';
/**
* an array which is used to save the state of the document, mainly the
colours and styles
207
* it is used to temporarily change to another state, the change back to
what it was before
*/
var $stateStack = array();
/**
* number of elements within the state stack
*/
var $nStateStack = 0;
/**
* number of page objects within the document
*/
var $numPages=0;
/**
* object Id storage stack
*/
var $stack=array();
/**
* number of elements within the object Id storage stack
*/
var $nStack=0;
/**
* an array which contains information about the objects which are not
firmly attached to pages
* these have been added with the addObject function
*/
var $looseObjects=array();
/**
* array contains infomation about how the loose objects are to be added
to the document
*/
var $addLooseObjects=array();
208
/**
* the objectId of the information object for the document
* this contains authorship, title etc.
*/
var $infoObject=0;
/**
* number of images being tracked within the document
*/
var $numImages=0;
/**
* an array containing options about the document
* it defaults to turning on the compression of the objects
*/
var $options=array('compression'=>1);
/**
* the objectId of the first page of the document
*/
var $firstPageId;
/**
* used to track the last used value of the inter-word spacing, this is so
that it is known
* when the spacing is changed.
*/
var $wordSpaceAdjust=0;
/**
* the object Id of the procset object
*/
var $procsetObjectId;
/**
* store the information about the relationship between font families
209
* this used so that the code knows which font is the bold version of
another font, etc.
* the value of this array is initialised in the constuctor function.
*/
var $fontFamilies = array();
/**
* track if the current font is bolded or italicised
*/
var $currentTextState = '';
/**
* messages are stored here during processing, these can be selected
afterwards to give some useful debug information
*/
var $messages='';
/**
* the ancryption array for the document encryption is stored here
*/
var $arc4='';
/**
* the object Id of the encryption information
*/
var $arc4_objnum=0;
/**
* the file identifier, used to uniquely identify a pdf document
*/
var $fileIdentifier='';
/**
* a flag to say if a document is to be encrypted or not
*/
var $encrypted=0;
/**
210
* the ancryption key for the encryption of all the document content
(structure is not encrypted)
*/
var $encryptionKey='';
/**
* array which forms a stack to keep track of nested callback functions
*/
var $callback = array();
/**
* the number of callback functions in the callback array
*/
var $nCallback = 0;
/**
* store label->id pairs for named destinations, these will be used to
replace internal links
* done this way so that destinations can be defined after the location
that links to them
*/
var $destinations = array();
/**
* store the stack for the transaction commands, each item in here is a
record of the values of all the
* variables within the class, so that the user can rollback at will (from
each 'start' command)
* note that this includes the objects array, so these can be large.
*/
var $checkpoint = '';
/**
* class constructor
* this will start a new document
211
* @var array array of 4 numbers, defining the bottom left and upper
right corner of the page. first two are normally zero.
*/
function Cpdf ($pageSize=array(0,0,612,792)){
$this->newDocument($pageSize);
// also initialize the font families that are known about already
$this->setFontFamily('init');
// $this->fileIdentifier = md5('xxxxxxxx'.time());
}
/**
* Document object methods (internal use only)
*
* There is about one object method for each type of object in the pdf
document
* Each function has the same call list ($id,$action,$options).
* $id = the object ID of the object, or what it is to be if it is being
created
* $action = a string specifying the action to be performed, though ALL
must support:
* 'new' - create the object with the id $id
* 'out' - produce the output for the pdf object
* $options = optional, a string or array containing the various
parameters for the object
*
* These, in conjunction with the output function are the ONLY way for
output to be produced
* within the pdf 'file'.
*/
212
/**
*destination object, used to specify the location for the user to jump to,
presently on opening
*/
function o_destination($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch($action){
case 'new':
$this->objects[$id]=array('t'=>'destination','info'=>array());
$tmp = '';
switch ($options['type']){
case 'XYZ':
case 'FitR':
$tmp = ' '.$options['p3'].$tmp;
case 'FitH':
case 'FitV':
case 'FitBH':
case 'FitBV':
$tmp = ' '.$options['p1'].' '.$options['p2'].$tmp;
case 'Fit':
case 'FitB':
$tmp = $options['type'].$tmp;
$this->objects[$id]['info']['string']=$tmp;
$this->objects[$id]['info']['page']=$options['page'];
}
break;
case 'out':
$tmp = $o['info'];
213
$res="\n".$id." 0 obj\n".'['.$tmp['page'].' 0 R
/'.$tmp['string']."]\nendobj\n";
return $res;
break;
}
}
/**
* set the viewer preferences
*/
function o_viewerPreferences($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this->objects[$id]=array('t'=>'viewerPreferences','info'=>array());
break;
case 'add':
foreach($options as $k=>$v){
switch ($k){
case 'HideToolbar':
case 'HideMenubar':
case 'HideWindowUI':
case 'FitWindow':
case 'CenterWindow':
case 'NonFullScreenPageMode':
case 'Direction':
$o['info'][$k]=$v;
break;
}
214
}
break;
case 'out':
$res="\n".$id." 0 obj\n".'<< ';
foreach($o['info'] as $k=>$v){
$res.="\n/".$k.' '.$v;
}
$res.="\n>>\n";
return $res;
break;
}
}
/**
* define the document catalog, the overall controller for the document
*/
function o_catalog($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this->objects[$id]=array('t'=>'catalog','info'=>array());
$this->catalogId=$id;
break;
case 'outlines':
case 'pages':
case 'openHere':
$o['info'][$action]=$options;
break;
215
case 'viewerPreferences':
if (!isset($o['info']['viewerPreferences'])){
$this->numObj++;
$this->o_viewerPreferences($this->numObj,'new');
$o['info']['viewerPreferences']=$this->numObj;
}
$vp = $o['info']['viewerPreferences'];
$this->o_viewerPreferences($vp,'add',$options);
break;
case 'out':
$res="\n".$id." 0 obj\n".'<< /Type /Catalog';
foreach($o['info'] as $k=>$v){
switch($k){
case 'outlines':
$res.="\n".'/Outlines '.$v.' 0 R';
break;
case 'pages':
$res.="\n".'/Pages '.$v.' 0 R';
break;
case 'viewerPreferences':
$res.="\n".'/ViewerPreferences '.$o['info']['viewerPreferences'].'
0 R';
break;
case 'openHere':
$res.="\n".'/OpenAction '.$o['info']['openHere'].' 0 R';
break;
}
}
$res.=" >>\nendobj";
return $res;
break;
216
}
}
/**
* object which is a parent to the pages in the document
*/
function o_pages($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this->objects[$id]=array('t'=>'pages','info'=>array());
$this->o_catalog($this->catalogId,'pages',$id);
break;
case 'page':
if (!is_array($options)){
// then it will just be the id of the new page
$o['info']['pages'][]=$options;
} else {
// then it should be an array having 'id','rid','pos', where rid=the
page to which this one will be placed relative
// and pos is either 'before' or 'after', saying where this page will fit.
if (isset($options['id']) && isset($options['rid']) &&
isset($options['pos'])){
$i = array_search($options['rid'],$o['info']['pages']);
if (isset($o['info']['pages'][$i]) &&
$o['info']['pages'][$i]==$options['rid']){
// then there is a match
// make a space
switch ($options['pos']){
217
case 'before':
$k = $i;
break;
case 'after':
$k=$i+1;
break;
default:
$k=-1;
break;
}
if ($k>=0){
for ($j=count($o['info']['pages'])-1;$j>=$k;$j--){
$o['info']['pages'][$j+1]=$o['info']['pages'][$j];
}
$o['info']['pages'][$k]=$options['id'];
}
}
}
}
break;
case 'procset':
$o['info']['procset']=$options;
break;
case 'mediaBox':
$o['info']['mediaBox']=$options; // which should be an array of 4
numbers
break;
case 'font':
$o['info']['fonts'][]=array('objNum'=>$options['objNum'],'fontNum'=>$
options['fontNum']);
218
break;
case 'xObject':
$o['info']['xObjects'][]=array('objNum'=>$options['objNum'],'label'=>$
options['label']);
break;
case 'out':
if (count($o['info']['pages'])){
$res="\n".$id." 0 obj\n<< /Type /Pages\n/Kids [";
foreach($o['info']['pages'] as $k=>$v){
$res.=$v." 0 R\n";
}
$res.="]\n/Count ".count($this->objects[$id]['info']['pages']);
if ((isset($o['info']['fonts']) && count($o['info']['fonts'])) ||
isset($o['info']['procset'])){
$res.="\n/Resources <<";
if (isset($o['info']['procset'])){
$res.="\n/ProcSet ".$o['info']['procset']." 0 R";
}
if (isset($o['info']['fonts']) && count($o['info']['fonts'])){
$res.="\n/Font << ";
foreach($o['info']['fonts'] as $finfo){
$res.="\n/F".$finfo['fontNum']." ".$finfo['objNum']." 0 R";
}
$res.=" >>";
}
if (isset($o['info']['xObjects']) && count($o['info']['xObjects'])){
$res.="\n/XObject << ";
foreach($o['info']['xObjects'] as $finfo){
$res.="\n/".$finfo['label']." ".$finfo['objNum']." 0 R";
}
219
$res.=" >>";
}
$res.="\n>>";
if (isset($o['info']['mediaBox'])){
$tmp=$o['info']['mediaBox'];
$res.="\n/MediaBox [".sprintf('%.3f',$tmp[0]).'
'.sprintf('%.3f',$tmp[1]).' '.sprintf('%.3f',$tmp[2]).'
'.sprintf('%.3f',$tmp[3]).']';
}
}
$res.="\n >>\nendobj";
} else {
$res="\n".$id." 0 obj\n<< /Type /Pages\n/Count 0\n>>\nendobj";
}
return $res;
break;
}
}
/**
* define the outlines in the doc, empty for now
*/
function o_outlines($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this-
>objects[$id]=array('t'=>'outlines','info'=>array('outlines'=>array()));
$this->o_catalog($this->catalogId,'outlines',$id);
220
break;
case 'outline':
$o['info']['outlines'][]=$options;
break;
case 'out':
if (count($o['info']['outlines'])){
$res="\n".$id." 0 obj\n<< /Type /Outlines /Kids [";
foreach($o['info']['outlines'] as $k=>$v){
$res.=$v." 0 R ";
}
$res.="] /Count ".count($o['info']['outlines'])." >>\nendobj";
} else {
$res="\n".$id." 0 obj\n<< /Type /Outlines /Count 0 >>\nendobj";
}
return $res;
break;
}
}
/**
* an object to hold the font description
*/
function o_font($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this-
>objects[$id]=array('t'=>'font','info'=>array('name'=>$options['name'],'
SubType'=>'Type1'));
221
$fontNum=$this->numFonts;
$this->objects[$id]['info']['fontNum']=$fontNum;
// deal with the encoding and the differences
if (isset($options['differences'])){
// then we'll need an encoding dictionary
$this->numObj++;
$this->o_fontEncoding($this->numObj,'new',$options);
$this->objects[$id]['info']['encodingDictionary']=$this->numObj;
} else if (isset($options['encoding'])){
// we can specify encoding here
switch($options['encoding']){
case 'WinAnsiEncoding':
case 'MacRomanEncoding':
case 'MacExpertEncoding':
$this->objects[$id]['info']['encoding']=$options['encoding'];
break;
case 'none':
break;
default:
$this->objects[$id]['info']['encoding']='WinAnsiEncoding';
break;
}
} else {
$this->objects[$id]['info']['encoding']='WinAnsiEncoding';
}
// also tell the pages node about the new font
$this->o_pages($this-
>currentNode,'font',array('fontNum'=>$fontNum,'objNum'=>$id));
break;
case 'add':
foreach ($options as $k=>$v){
222
switch ($k){
case 'BaseFont':
$o['info']['name'] = $v;
break;
case 'FirstChar':
case 'LastChar':
case 'Widths':
case 'FontDescriptor':
case 'SubType':
$this->addMessage('o_font '.$k." : ".$v);
$o['info'][$k] = $v;
break;
}
}
break;
case 'out':
$res="\n".$id." 0 obj\n<< /Type /Font\n/Subtype
/".$o['info']['SubType']."\n";
$res.="/Name /F".$o['info']['fontNum']."\n";
$res.="/BaseFont /".$o['info']['name']."\n";
if (isset($o['info']['encodingDictionary'])){
// then place a reference to the dictionary
$res.="/Encoding ".$o['info']['encodingDictionary']." 0 R\n";
} else if (isset($o['info']['encoding'])){
// use the specified encoding
$res.="/Encoding /".$o['info']['encoding']."\n";
}
if (isset($o['info']['FirstChar'])){
$res.="/FirstChar ".$o['info']['FirstChar']."\n";
}
if (isset($o['info']['LastChar'])){
223
$res.="/LastChar ".$o['info']['LastChar']."\n";
}
if (isset($o['info']['Widths'])){
$res.="/Widths ".$o['info']['Widths']." 0 R\n";
}
if (isset($o['info']['FontDescriptor'])){
$res.="/FontDescriptor ".$o['info']['FontDescriptor']." 0 R\n";
}
$res.=">>\nendobj";
return $res;
break;
}
}
/**
* a font descriptor, needed for including additional fonts
*/
function o_fontDescriptor($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this->objects[$id]=array('t'=>'fontDescriptor','info'=>$options);
break;
case 'out':
$res="\n".$id." 0 obj\n<< /Type /FontDescriptor\n";
foreach ($o['info'] as $label => $value){
switch ($label){
case 'Ascent':
case 'CapHeight':
224
case 'Descent':
case 'Flags':
case 'ItalicAngle':
case 'StemV':
case 'AvgWidth':
case 'Leading':
case 'MaxWidth':
case 'MissingWidth':
case 'StemH':
case 'XHeight':
case 'CharSet':
if (strlen($value)){
$res.='/'.$label.' '.$value."\n";
}
break;
case 'FontFile':
case 'FontFile2':
case 'FontFile3':
$res.='/'.$label.' '.$value." 0 R\n";
break;
case 'FontBBox':
$res.='/'.$label.' ['.$value[0].' '.$value[1].' '.$value[2].'
'.$value[3]."]\n";
break;
case 'FontName':
$res.='/'.$label.' /'.$value."\n";
break;
}
}
$res.=">>\nendobj";
return $res;
225
break;
}
}
/**
* the font encoding
*/
function o_fontEncoding($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
// the options array should contain 'differences' and maybe
'encoding'
$this->objects[$id]=array('t'=>'fontEncoding','info'=>$options);
break;
case 'out':
$res="\n".$id." 0 obj\n<< /Type /Encoding\n";
if (!isset($o['info']['encoding'])){
$o['info']['encoding']='WinAnsiEncoding';
}
if ($o['info']['encoding']!='none'){
$res.="/BaseEncoding /".$o['info']['encoding']."\n";
}
$res.="/Differences \n[";
$onum=-100;
foreach($o['info']['differences'] as $num=>$label){
if ($num!=$onum+1){
// we cannot make use of consecutive numbering
$res.= "\n".$num." /".$label;
226
} else {
$res.= " /".$label;
}
$onum=$num;
}
$res.="\n]\n>>\nendobj";
return $res;
break;
}
}
/**
* the document procset, solves some problems with printing to old PS
printers
*/
function o_procset($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this-
>objects[$id]=array('t'=>'procset','info'=>array('PDF'=>1,'Text'=>1));
$this->o_pages($this->currentNode,'procset',$id);
$this->procsetObjectId=$id;
break;
case 'add':
// this is to add new items to the procset list, despite the fact that this
is considered
// obselete, the items are required for printing to some postscript
printers
227
switch ($options) {
case 'ImageB':
case 'ImageC':
case 'ImageI':
$o['info'][$options]=1;
break;
}
break;
case 'out':
$res="\n".$id." 0 obj\n[";
foreach ($o['info'] as $label=>$val){
$res.='/'.$label.' ';
}
$res.="]\nendobj";
return $res;
break;
}
}
/**
* define the document information
*/
function o_info($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this->infoObject=$id;
$date='D:'.date('Ymd');
228
$this->objects[$id]=array('t'=>'info','info'=>array('Creator'=>'R and
OS php pdf writer, http://www.ros.co.nz','CreationDate'=>$date));
break;
case 'Title':
case 'Author':
case 'Subject':
case 'Keywords':
case 'Creator':
case 'Producer':
case 'CreationDate':
case 'ModDate':
case 'Trapped':
$o['info'][$action]=$options;
break;
case 'out':
if ($this->encrypted){
$this->encryptInit($id);
}
$res="\n".$id." 0 obj\n<<\n";
foreach ($o['info'] as $k=>$v){
$res.='/'.$k.' (';
if ($this->encrypted){
$res.=$this->filterText($this->ARC4($v));
} else {
$res.=$this->filterText($v);
}
$res.=")\n";
}
$res.=">>\nendobj";
return $res;
break;
229
}
}
/**
* an action object, used to link to URLS initially
*/
function o_action($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
if (is_array($options)){
$this-
>objects[$id]=array('t'=>'action','info'=>$options,'type'=>$options['type
']);
} else {
// then assume a URI action
$this-
>objects[$id]=array('t'=>'action','info'=>$options,'type'=>'URI');
}
break;
case 'out':
if ($this->encrypted){
$this->encryptInit($id);
}
$res="\n".$id." 0 obj\n<< /Type /Action";
switch($o['type']){
case 'ilink':
// there will be an 'label' setting, this is the name of the destination
230
$res.="\n/S /GoTo\n/D ".$this-
>destinations[(string)$o['info']['label']]." 0 R";
break;
case 'URI':
$res.="\n/S /URI\n/URI (";
if ($this->encrypted){
$res.=$this->filterText($this->ARC4($o['info']));
} else {
$res.=$this->filterText($o['info']);
}
$res.=")";
break;
}
$res.="\n>>\nendobj";
return $res;
break;
}
}
/**
* an annotation object, this will add an annotation to the current page.
* initially will support just link annotations
*/
function o_annotation($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
// add the annotation to the current page
$pageId = $this->currentPage;
231
$this->o_page($pageId,'annot',$id);
// and add the action object which is going to be required
switch($options['type']){
case 'link':
$this->objects[$id]=array('t'=>'annotation','info'=>$options);
$this->numObj++;
$this->o_action($this->numObj,'new',$options['url']);
$this->objects[$id]['info']['actionId']=$this->numObj;
break;
case 'ilink':
// this is to a named internal link
$label = $options['label'];
$this->objects[$id]=array('t'=>'annotation','info'=>$options);
$this->numObj++;
$this->o_action($this-
>numObj,'new',array('type'=>'ilink','label'=>$label));
$this->objects[$id]['info']['actionId']=$this->numObj;
break;
}
break;
case 'out':
$res="\n".$id." 0 obj\n<< /Type /Annot";
switch($o['info']['type']){
case 'link':
case 'ilink':
$res.= "\n/Subtype /Link";
break;
}
$res.="\n/A ".$o['info']['actionId']." 0 R";
$res.="\n/Border [0 0 0]";
$res.="\n/H /I";
232
$res.="\n/Rect [ ";
foreach($o['info']['rect'] as $v){
$res.= sprintf("%.4f ",$v);
}
$res.="]";
$res.="\n>>\nendobj";
return $res;
break;
}
}
/**
* a page object, it also creates a contents object to hold its contents
*/
function o_page($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this->numPages++;
$this->objects[$id]=array('t'=>'page','info'=>array('parent'=>$this-
>currentNode,'pageNum'=>$this->numPages));
if (is_array($options)){
// then this must be a page insertion, array shoudl contain
'rid','pos'=[before|after]
$options['id']=$id;
$this->o_pages($this->currentNode,'page',$options);
} else {
$this->o_pages($this->currentNode,'page',$id);
}
233
$this->currentPage=$id;
//make a contents object to go with this page
$this->numObj++;
$this->o_contents($this->numObj,'new',$id);
$this->currentContents=$this->numObj;
$this->objects[$id]['info']['contents']=array();
$this->objects[$id]['info']['contents'][]=$this->numObj;
$match = ($this->numPages%2 ? 'odd' : 'even');
foreach($this->addLooseObjects as $oId=>$target){
if ($target=='all' || $match==$target){
$this->objects[$id]['info']['contents'][]=$oId;
}
}
break;
case 'content':
$o['info']['contents'][]=$options;
break;
case 'annot':
// add an annotation to this page
if (!isset($o['info']['annot'])){
$o['info']['annot']=array();
}
// $options should contain the id of the annotation dictionary
$o['info']['annot'][]=$options;
break;
case 'out':
$res="\n".$id." 0 obj\n<< /Type /Page";
$res.="\n/Parent ".$o['info']['parent']." 0 R";
if (isset($o['info']['annot'])){
$res.="\n/Annots [";
foreach($o['info']['annot'] as $aId){
234
$res.=" ".$aId." 0 R";
}
$res.=" ]";
}
$count = count($o['info']['contents']);
if ($count==1){
$res.="\n/Contents ".$o['info']['contents'][0]." 0 R";
} else if ($count>1){
$res.="\n/Contents [\n";
foreach ($o['info']['contents'] as $cId){
$res.=$cId." 0 R\n";
}
$res.="]";
}
$res.="\n>>\nendobj";
return $res;
break;
}
}
/**
* the contents objects hold all of the content which appears on pages
*/
function o_contents($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch ($action){
case 'new':
$this->objects[$id]=array('t'=>'contents','c'=>'','info'=>array());
if (strlen($options) && intval($options)){
235
// then this contents is the primary for a page
$this->objects[$id]['onPage']=$options;
} else if ($options=='raw'){
// then this page contains some other type of system object
$this->objects[$id]['raw']=1;
}
break;
case 'add':
// add more options to the decleration
foreach ($options as $k=>$v){
$o['info'][$k]=$v;
}
case 'out':
$tmp=$o['c'];
$res= "\n".$id." 0 obj\n";
if (isset($this->objects[$id]['raw'])){
$res.=$tmp;
} else {
$res.= "<<";
if (function_exists('gzcompress') && $this-
>options['compression']){
// then implement ZLIB based compression on this content stream
$res.=" /Filter /FlateDecode";
$tmp = gzcompress($tmp);
}
if ($this->encrypted){
$this->encryptInit($id);
$tmp = $this->ARC4($tmp);
}
foreach($o['info'] as $k=>$v){
$res .= "\n/".$k.' '.$v;
236
}
$res.="\n/Length ".strlen($tmp)."
>>\nstream\n".$tmp."\nendstream";
}
$res.="\nendobj\n";
return $res;
break;
}
}
/**
* an image object, will be an XObject in the document, includes
description and data
*/
function o_image($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch($action){
case 'new':
// make the new object
$this-
>objects[$id]=array('t'=>'image','data'=>$options['data'],'info'=>array())
;
$this->objects[$id]['info']['Type']='/XObject';
$this->objects[$id]['info']['Subtype']='/Image';
$this->objects[$id]['info']['Width']=$options['iw'];
$this->objects[$id]['info']['Height']=$options['ih'];
if (!isset($options['type']) || $options['type']=='jpg'){
if (!isset($options['channels'])){
$options['channels']=3;
237
}
switch($options['channels']){
case 1:
$this->objects[$id]['info']['ColorSpace']='/DeviceGray';
break;
default:
$this->objects[$id]['info']['ColorSpace']='/DeviceRGB';
break;
}
$this->objects[$id]['info']['Filter']='/DCTDecode';
$this->objects[$id]['info']['BitsPerComponent']=8;
} else if ($options['type']=='png'){
$this->objects[$id]['info']['Filter']='/FlateDecode';
$this->objects[$id]['info']['DecodeParms']='<< /Predictor 15
/Colors '.$options['ncolor'].' /Columns '.$options['iw'].'
/BitsPerComponent '.$options['bitsPerComponent'].'>>';
if (strlen($options['pdata'])){
$tmp = ' [ /Indexed /DeviceRGB '.(strlen($options['pdata'])/3-1).'
';
$this->numObj++;
$this->o_contents($this->numObj,'new');
$this->objects[$this->numObj]['c']=$options['pdata'];
$tmp.=$this->numObj.' 0 R';
$tmp .=' ]';
$this->objects[$id]['info']['ColorSpace'] = $tmp;
if (isset($options['transparency'])){
switch($options['transparency']['type']){
case 'indexed':
$tmp=' [ '.$options['transparency']['data'].'
'.$options['transparency']['data'].'] ';
$this->objects[$id]['info']['Mask'] = $tmp;
238
break;
}
}
} else {
$this->objects[$id]['info']['ColorSpace']='/'.$options['color'];
}
$this-
>objects[$id]['info']['BitsPerComponent']=$options['bitsPerComponent'
];
}
// assign it a place in the named resource dictionary as an external
object, according to
// the label passed in with it.
$this->o_pages($this-
>currentNode,'xObject',array('label'=>$options['label'],'objNum'=>$id))
;
// also make sure that we have the right procset object for it.
$this->o_procset($this->procsetObjectId,'add','ImageC');
break;
case 'out':
$tmp=$o['data'];
$res= "\n".$id." 0 obj\n<<";
foreach($o['info'] as $k=>$v){
$res.="\n/".$k.' '.$v;
}
if ($this->encrypted){
$this->encryptInit($id);
$tmp = $this->ARC4($tmp);
}
$res.="\n/Length ".strlen($tmp)."
>>\nstream\n".$tmp."\nendstream\nendobj\n";
239
return $res;
break;
}
}
/**
* encryption object.
*/
function o_encryption($id,$action,$options=''){
if ($action!='new'){
$o =& $this->objects[$id];
}
switch($action){
case 'new':
// make the new object
$this->objects[$id]=array('t'=>'encryption','info'=>$options);
$this->arc4_objnum=$id;
// figure out the additional paramaters required
$pad =
chr(0x28).chr(0xBF).chr(0x4E).chr(0x5E).chr(0x4E).chr(0x75).chr(0x8
A).chr(0x41).chr(0x64).chr(0x00).chr(0x4E).chr(0x56).chr(0xFF).chr(0
xFA).chr(0x01).chr(0x08).chr(0x2E).chr(0x2E).chr(0x00).chr(0xB6).ch
r(0xD0).chr(0x68).chr(0x3E).chr(0x80).chr(0x2F).chr(0x0C).chr(0xA9)
.chr(0xFE).chr(0x64).chr(0x53).chr(0x69).chr(0x7A);
$len = strlen($options['owner']);
if ($len>32){
$owner = substr($options['owner'],0,32);
} else if ($len<32){
$owner = $options['owner'].substr($pad,0,32-$len);
} else {
$owner = $options['owner'];
240
}
$len = strlen($options['user']);
if ($len>32){
$user = substr($options['user'],0,32);
} else if ($len<32){
$user = $options['user'].substr($pad,0,32-$len);
} else {
$user = $options['user'];
}
$tmp = $this->md5_16($owner);
$okey = substr($tmp,0,5);
$this->ARC4_init($okey);
$ovalue=$this->ARC4($user);
$this->objects[$id]['info']['O']=$ovalue;
// now make the u value, phew.
$tmp = $this-
>md5_16($user.$ovalue.chr($options['p']).chr(255).chr(255).chr(255).$
this->fileIdentifier);
$ukey = substr($tmp,0,5);
$this->ARC4_init($ukey);
$this->encryptionKey = $ukey;
$this->encrypted=1;
$uvalue=$this->ARC4($pad);
$this->objects[$id]['info']['U']=$uvalue;
$this->encryptionKey=$ukey;
// initialize the arc4 array
break;
case 'out':
241
$res= "\n".$id." 0 obj\n<<";
$res.="\n/Filter /Standard";
$res.="\n/V 1";
$res.="\n/R 2";
$res.="\n/O (".$this->filterText($o['info']['O']).')';
$res.="\n/U (".$this->filterText($o['info']['U']).')';
// and the p-value needs to be converted to account for the twos-
complement approach
$o['info']['p'] = (($o['info']['p']^255)+1)*-1;
$res.="\n/P ".($o['info']['p']);
$res.="\n>>\nendobj\n";
return $res;
break;
}
}
/**
* ARC4 functions
* A series of function to implement ARC4 encoding in PHP
*/
/**
* calculate the 16 byte version of the 128 bit md5 digest of the string
*/
function md5_16($string){
$tmp = md5($string);
$out='';
for ($i=0;$i<=30;$i=$i+2){
$out.=chr(hexdec(substr($tmp,$i,2)));
}
242
return $out;
}
/**
* initialize the encryption for processing a particular object
*/
function encryptInit($id){
$tmp = $this->encryptionKey;
$hex = dechex($id);
if (strlen($hex)<6){
$hex = substr('000000',0,6-strlen($hex)).$hex;
}
$tmp.=
chr(hexdec(substr($hex,4,2))).chr(hexdec(substr($hex,2,2))).chr(hexdec
(substr($hex,0,2))).chr(0).chr(0);
$key = $this->md5_16($tmp);
$this->ARC4_init(substr($key,0,10));
}
/**
* initialize the ARC4 encryption
*/
function ARC4_init($key=''){
$this->arc4 = '';
// setup the control array
if (strlen($key)==0){
return;
}
$k = '';
while(strlen($k)<256){
$k.=$key;
243
}
$k=substr($k,0,256);
for ($i=0;$i<256;$i++){
$this->arc4 .= chr($i);
}
$j=0;
for ($i=0;$i<256;$i++){
$t = $this->arc4[$i];
$j = ($j + ord($t) + ord($k[$i]))%256;
$this->arc4[$i]=$this->arc4[$j];
$this->arc4[$j]=$t;
}
}
/**
* ARC4 encrypt a text string
*/
function ARC4($text){
$len=strlen($text);
$a=0;
$b=0;
$c = $this->arc4;
$out='';
for ($i=0;$i<$len;$i++){
$a = ($a+1)%256;
$t= $c[$a];
$b = ($b+ord($t))%256;
$c[$a]=$c[$b];
$c[$b]=$t;
$k = ord($c[(ord($c[$a])+ord($c[$b]))%256]);
$out.=chr(ord($text[$i]) ^ $k);
244
}
return $out;
}
/**
* functions which can be called to adjust or add to the document
*/
/**
* add a link in the document to an external URL
*/
function addLink($url,$x0,$y0,$x1,$y1){
$this->numObj++;
$info =
array('type'=>'link','url'=>$url,'rect'=>array($x0,$y0,$x1,$y1));
$this->o_annotation($this->numObj,'new',$info);
}
/**
* add a link in the document to an internal destination (ie. within the
document)
*/
function addInternalLink($label,$x0,$y0,$x1,$y1){
$this->numObj++;
$info =
array('type'=>'ilink','label'=>$label,'rect'=>array($x0,$y0,$x1,$y1));
$this->o_annotation($this->numObj,'new',$info);
}
/**
245
* set the encryption of the document
* can be used to turn it on and/or set the passwords which it will have.
* also the functions that the user will have are set here, such as print,
modify, add
*/
function setEncryption($userPass='',$ownerPass='',$pc=array()){
$p=bindec(11000000);
$options = array(
'print'=>4
,'modify'=>8
,'copy'=>16
,'add'=>32
);
foreach($pc as $k=>$v){
if ($v && isset($options[$k])){
$p+=$options[$k];
} else if (isset($options[$v])){
$p+=$options[$v];
}
}
// implement encryption on the document
if ($this->arc4_objnum == 0){
// then the block does not exist already, add it.
$this->numObj++;
if (strlen($ownerPass)==0){
$ownerPass=$userPass;
}
$this->o_encryption($this-
>numObj,'new',array('user'=>$userPass,'owner'=>$ownerPass,'p'=>$p))
;
246
}
}
/**
* should be used for internal checks, not implemented as yet
*/
function checkAllHere(){
}
/**
* return the pdf stream as a string returned from the function
*/
function output($debug=0){
if ($debug){
// turn compression off
$this->options['compression']=0;
}
if ($this->arc4_objnum){
$this->ARC4_init($this->encryptionKey);
}
$this->checkAllHere();
$xref=array();
$content="%PDF-1.3\n%âãÏÓ\n";
// $content="%PDF-1.3\n";
$pos=strlen($content);
foreach($this->objects as $k=>$v){
$tmp='o_'.$v['t'];
247
$cont=$this->$tmp($k,'out');
$content.=$cont;
$xref[]=$pos;
$pos+=strlen($cont);
}
$content.="\nxref\n0 ".(count($xref)+1)."\n0000000000 65535 f \n";
foreach($xref as $p){
$content.=substr('0000000000',0,10-strlen($p)).$p." 00000 n \n";
}
$content.="\ntrailer\n << /Size ".(count($xref)+1)."\n /Root 1 0 R\n
/Info ".$this->infoObject." 0 R\n";
// if encryption has been applied to this document then add the marker
for this dictionary
if ($this->arc4_objnum > 0){
$content .= "/Encrypt ".$this->arc4_objnum." 0 R\n";
}
if (strlen($this->fileIdentifier)){
$content .= "/ID[<".$this->fileIdentifier."><".$this-
>fileIdentifier.">]\n";
}
$content .= " >>\nstartxref\n".$pos."\n%%EOF\n";
return $content;
}
/**
* intialize a new document
* if this is called on an existing document results may be unpredictable,
but the existing document would be lost at minimum
* this function is called automatically by the constructor function
*
* @access private
248
*/
function newDocument($pageSize=array(0,0,612,792)){
$this->numObj=0;
$this->objects = array();
$this->numObj++;
$this->o_catalog($this->numObj,'new');
$this->numObj++;
$this->o_outlines($this->numObj,'new');
$this->numObj++;
$this->o_pages($this->numObj,'new');
$this->o_pages($this->numObj,'mediaBox',$pageSize);
$this->currentNode = 3;
$this->numObj++;
$this->o_procset($this->numObj,'new');
$this->numObj++;
$this->o_info($this->numObj,'new');
$this->numObj++;
$this->o_page($this->numObj,'new');
// need to store the first page id as there is no way to get it to the user
during
// startup
$this->firstPageId = $this->currentContents;
}
249
/**
* open the font file and return a php structure containing it.
* first check if this one has been done before and saved in a form more
suited to php
* note that if a php serialized version does not exist it will try and make
one, but will
* require write access to the directory to do it... it is MUCH faster to
have these serialized
* files.
*
* @access private
*/
function openFont($font){
// assume that $font contains both the path and perhaps the extension
to the file, split them
$pos=strrpos($font,'/');
if ($pos===false){
$dir = './';
$name = $font;
} else {
$dir=substr($font,0,$pos+1);
$name=substr($font,$pos+1);
}
if (substr($name,-4)=='.afm'){
$name=substr($name,0,strlen($name)-4);
}
$this->addMessage('openFont: '.$font.' - '.$name);
if (file_exists($dir.'php_'.$name.'.afm')){
250
$this->addMessage('openFont: php file exists
'.$dir.'php_'.$name.'.afm');
$tmp = file($dir.'php_'.$name.'.afm');
$this->fonts[$font]=unserialize($tmp[0]);
if (!isset($this->fonts[$font]['_version_']) || $this-
>fonts[$font]['_version_']<1){
// if the font file is old, then clear it out and prepare for re-creation
$this->addMessage('openFont: clear out, make way for new
version.');
unset($this->fonts[$font]);
}
}
if (!isset($this->fonts[$font]) && file_exists($dir.$name.'.afm')){
// then rebuild the php_<font>.afm file from the <font>.afm file
$this->addMessage('openFont: build php file from
'.$dir.$name.'.afm');
$data = array();
$file = file($dir.$name.'.afm');
foreach ($file as $rowA){
$row=trim($rowA);
$pos=strpos($row,' ');
if ($pos){
// then there must be some keyword
$key = substr($row,0,$pos);
switch ($key){
case 'FontName':
case 'FullName':
case 'FamilyName':
case 'Weight':
case 'ItalicAngle':
case 'IsFixedPitch':
251
case 'CharacterSet':
case 'UnderlinePosition':
case 'UnderlineThickness':
case 'Version':
case 'EncodingScheme':
case 'CapHeight':
case 'XHeight':
case 'Ascender':
case 'Descender':
case 'StdHW':
case 'StdVW':
case 'StartCharMetrics':
$data[$key]=trim(substr($row,$pos));
break;
case 'FontBBox':
$data[$key]=explode(' ',trim(substr($row,$pos)));
break;
case 'C':
//C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ;
$bits=explode(';',trim($row));
$dtmp=array();
foreach($bits as $bit){
$bits2 = explode(' ',trim($bit));
if (strlen($bits2[0])){
if (count($bits2)>2){
$dtmp[$bits2[0]]=array();
for ($i=1;$i<count($bits2);$i++){
$dtmp[$bits2[0]][]=$bits2[$i];
}
} else if (count($bits2)==2){
$dtmp[$bits2[0]]=$bits2[1];
252
}
}
}
if ($dtmp['C']>=0){
$data['C'][$dtmp['C']]=$dtmp;
$data['C'][$dtmp['N']]=$dtmp;
} else {
$data['C'][$dtmp['N']]=$dtmp;
}
break;
case 'KPX':
//KPX Adieresis yacute -40
$bits=explode(' ',trim($row));
$data['KPX'][$bits[1]][$bits[2]]=$bits[3];
break;
}
}
}
$data['_version_']=1;
$this->fonts[$font]=$data;
$fp = fopen($dir.'php_'.$name.'.afm','w');
fwrite($fp,serialize($data));
fclose($fp);
} else if (!isset($this->fonts[$font])){
$this->addMessage('openFont: no font file found');
// echo 'Font not Found '.$font;
}
}
/**
* if the font is not loaded then load it and make the required object
253
* else just make it the current font
* the encoding array can contain 'encoding'=>
'none','WinAnsiEncoding','MacRomanEncoding' or
'MacExpertEncoding'
* note that encoding='none' will need to be used for symbolic fonts
* and 'differences' => an array of mappings between numbers 0->255
and character names.
*
*/
function selectFont($fontName,$encoding='',$set=1){
if (!isset($this->fonts[$fontName])){
// load the file
$this->openFont($fontName);
if (isset($this->fonts[$fontName])){
$this->numObj++;
$this->numFonts++;
$pos=strrpos($fontName,'/');
// $dir=substr($fontName,0,$pos+1);
$name=substr($fontName,$pos+1);
if (substr($name,-4)=='.afm'){
$name=substr($name,0,strlen($name)-4);
}
$options=array('name'=>$name);
if (is_array($encoding)){
// then encoding and differences might be set
if (isset($encoding['encoding'])){
$options['encoding']=$encoding['encoding'];
}
if (isset($encoding['differences'])){
$options['differences']=$encoding['differences'];
}
254
} else if (strlen($encoding)){
// then perhaps only the encoding has been set
$options['encoding']=$encoding;
}
$fontObj = $this->numObj;
$this->o_font($this->numObj,'new',$options);
$this->fonts[$fontName]['fontNum']=$this->numFonts;
// if this is a '.afm' font, and there is a '.pfa' file to go with it ( as
there
// should be for all non-basic fonts), then load it into an object and
put the
// references into the font object
$basefile = substr($fontName,0,strlen($fontName)-4);
if (file_exists($basefile.'.pfb')){
$fbtype = 'pfb';
} else if (file_exists($basefile.'.ttf')){
$fbtype = 'ttf';
} else {
$fbtype='';
}
$fbfile = $basefile.'.'.$fbtype;
// $pfbfile = substr($fontName,0,strlen($fontName)-4).'.pfb';
// $ttffile = substr($fontName,0,strlen($fontName)-4).'.ttf';
$this->addMessage('selectFont: checking for - '.$fbfile);
if (substr($fontName,-4)=='.afm' && strlen($fbtype) ){
$adobeFontName = $this->fonts[$fontName]['FontName'];
// $fontObj = $this->numObj;
$this->addMessage('selectFont: adding font file - '.$fbfile.' -
'.$adobeFontName);
// find the array of fond widths, and put that into an object.
255
$firstChar = -1;
$lastChar = 0;
$widths = array();
foreach ($this->fonts[$fontName]['C'] as $num=>$d){
if (intval($num)>0 || $num=='0'){
if ($lastChar>0 && $num>$lastChar+1){
for($i=$lastChar+1;$i<$num;$i++){
$widths[] = 0;
}
}
$widths[] = $d['WX'];
if ($firstChar==-1){
$firstChar = $num;
}
$lastChar = $num;
}
}
// also need to adjust the widths for the differences array
if (isset($options['differences'])){
foreach($options['differences'] as $charNum=>$charName){
if ($charNum>$lastChar){
for($i=$lastChar+1;$i<=$charNum;$i++){
$widths[]=0;
}
$lastChar=$charNum;
}
if (isset($this->fonts[$fontName]['C'][$charName])){
$widths[$charNum-$firstChar]=$this-
>fonts[$fontName]['C'][$charName]['WX'];
}
}
256
}
$this->addMessage('selectFont: FirstChar='.$firstChar);
$this->addMessage('selectFont: LastChar='.$lastChar);
$this->numObj++;
$this->o_contents($this->numObj,'new','raw');
$this->objects[$this->numObj]['c'].='[';
foreach($widths as $width){
$this->objects[$this->numObj]['c'].=' '.$width;
}
$this->objects[$this->numObj]['c'].=' ]';
$widthid = $this->numObj;
// load the pfb file, and put that into an object too.
// note that pdf supports only binary format type 1 font files,
though there is a
// simple utility to convert them from pfa to pfb.
$fp = fopen($fbfile,'rb');
$tmp = get_magic_quotes_runtime();
set_magic_quotes_runtime(0);
$data = fread($fp,filesize($fbfile));
set_magic_quotes_runtime($tmp);
fclose($fp);
// create the font descriptor
$this->numObj++;
$fontDescriptorId = $this->numObj;
$this->numObj++;
$pfbid = $this->numObj;
// determine flags (more than a little flakey, hopefully will not
matter much)
$flags=0;
257
if ($this->fonts[$fontName]['ItalicAngle']!=0){ $flags+=pow(2,6);
}
if ($this->fonts[$fontName]['IsFixedPitch']=='true'){ $flags+=1; }
$flags+=pow(2,5); // assume non-sybolic
$list =
array('Ascent'=>'Ascender','CapHeight'=>'CapHeight','Descent'=>'Desc
ender','FontBBox'=>'FontBBox','ItalicAngle'=>'ItalicAngle');
$fdopt = array(
'Flags'=>$flags
,'FontName'=>$adobeFontName
,'StemV'=>100 // don't know what the value for this should be!
);
foreach($list as $k=>$v){
if (isset($this->fonts[$fontName][$v])){
$fdopt[$k]=$this->fonts[$fontName][$v];
}
}
if ($fbtype=='pfb'){
$fdopt['FontFile']=$pfbid;
} else if ($fbtype=='ttf'){
$fdopt['FontFile2']=$pfbid;
}
$this->o_fontDescriptor($fontDescriptorId,'new',$fdopt);
// embed the font program
$this->o_contents($this->numObj,'new');
$this->objects[$pfbid]['c'].=$data;
// determine the cruicial lengths within this file
if ($fbtype=='pfb'){
258
$l1 = strpos($data,'eexec')+6;
$l2 = strpos($data,'00000000')-$l1;
$l3 = strlen($data)-$l2-$l1;
$this->o_contents($this-
>numObj,'add',array('Length1'=>$l1,'Length2'=>$l2,'Length3'=>$l3));
} else if ($fbtype=='ttf'){
$l1 = strlen($data);
$this->o_contents($this->numObj,'add',array('Length1'=>$l1));
}
// tell the font object about all this new stuff
$tmp = array('BaseFont'=>$adobeFontName,'Widths'=>$widthid
,'FirstChar'=>$firstChar,'LastChar'=>$lastChar
,'FontDescriptor'=>$fontDescriptorId);
if ($fbtype=='ttf'){
$tmp['SubType']='TrueType';
}
$this->addMessage('adding extra info to font.('.$fontObj.')');
foreach($tmp as $fk=>$fv){
$this->addMessage($fk." : ".$fv);
}
$this->o_font($fontObj,'add',$tmp);
} else {
$this->addMessage('selectFont: pfb or ttf file not found, ok if this
is one of the 14 standard fonts');
}
259
// also set the differences here, note that this means that these will
take effect only the
//first time that a font is selected, else they are ignored
if (isset($options['differences'])){
$this->fonts[$fontName]['differences']=$options['differences'];
}
}
}
if ($set && isset($this->fonts[$fontName])){
// so if for some reason the font was not set in the last one then it will
not be selected
$this->currentBaseFont=$fontName;
// the next line means that if a new font is selected, then the current
text state will be
// applied to it as well.
$this->setCurrentFont();
}
return $this->currentFontNum;
}
/**
* sets up the current font, based on the font families, and the current
text state
* note that this system is quite flexible, a <b><i> font can be
completely different to a
* <i><b> font, and even <b><b> will have to be defined within the
family to have meaning
* This function is to be called whenever the currentTextState is
changed, it will update
* the currentFont setting to whatever the appropriatte family one is.
260
* If the user calls selectFont themselves then that will reset the
currentBaseFont, and the currentFont
* This function will change the currentFont to whatever it should be,
but will not change the
* currentBaseFont.
*
* @access private
*/
function setCurrentFont(){
if (strlen($this->currentBaseFont)==0){
// then assume an initial font
$this->selectFont('./fonts/Helvetica.afm');
}
$cf = substr($this->currentBaseFont,strrpos($this-
>currentBaseFont,'/')+1);
if (strlen($this->currentTextState)
&& isset($this->fontFamilies[$cf])
&& isset($this->fontFamilies[$cf][$this->currentTextState])){
// then we are in some state or another
// and this font has a family, and the current setting exists within it
// select the font, then return it
$nf = substr($this->currentBaseFont,0,strrpos($this-
>currentBaseFont,'/')+1).$this->fontFamilies[$cf][$this-
>currentTextState];
$this->selectFont($nf,'',0);
$this->currentFont = $nf;
$this->currentFontNum = $this->fonts[$nf]['fontNum'];
} else {
// the this font must not have the right family member for the current
state
// simply assume the base font
261
$this->currentFont = $this->currentBaseFont;
$this->currentFontNum = $this->fonts[$this-
>currentFont]['fontNum'];
}
}
/**
* function for the user to find out what the ID is of the first page that
was created during
* startup - useful if they wish to add something to it later.
*/
function getFirstPageId(){
return $this->firstPageId;
}
/**
* add content to the currently active object
*
* @access private
*/
function addContent($content){
$this->objects[$this->currentContents]['c'].=$content;
}
/**
* sets the colour for fill operations
*/
function setColor($r,$g,$b,$force=0){
if ($r>=0 && ($force || $r!=$this->currentColour['r'] || $g!=$this-
>currentColour['g'] || $b!=$this->currentColour['b'])){
262
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$r).'
'.sprintf('%.3f',$g).' '.sprintf('%.3f',$b).' rg';
$this->currentColour=array('r'=>$r,'g'=>$g,'b'=>$b);
}
}
/**
* sets the colour for stroke operations
*/
function setStrokeColor($r,$g,$b,$force=0){
if ($r>=0 && ($force || $r!=$this->currentStrokeColour['r'] ||
$g!=$this->currentStrokeColour['g'] || $b!=$this-
>currentStrokeColour['b'])){
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$r).'
'.sprintf('%.3f',$g).' '.sprintf('%.3f',$b).' RG';
$this->currentStrokeColour=array('r'=>$r,'g'=>$g,'b'=>$b);
}
}
/**
* draw a line from one set of coordinates to another
*/
function line($x1,$y1,$x2,$y2){
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x1).'
'.sprintf('%.3f',$y1).' m '.sprintf('%.3f',$x2).' '.sprintf('%.3f',$y2).' l S';
}
/**
* draw a bezier curve based on 4 control points
*/
function curve($x0,$y0,$x1,$y1,$x2,$y2,$x3,$y3){
263
// in the current line style, draw a bezier curve from (x0,y0) to (x3,y3)
using the other two points
// as the control points for the curve.
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x0).'
'.sprintf('%.3f',$y0).' m '.sprintf('%.3f',$x1).' '.sprintf('%.3f',$y1);
$this->objects[$this->currentContents]['c'].= ' '.sprintf('%.3f',$x2).'
'.sprintf('%.3f',$y2).' '.sprintf('%.3f',$x3).' '.sprintf('%.3f',$y3).' c S';
}
/**
* draw a part of an ellipse
*/
function
partEllipse($x0,$y0,$astart,$afinish,$r1,$r2=0,$angle=0,$nSeg=8){
$this->ellipse($x0,$y0,$r1,$r2,$angle,$nSeg,$astart,$afinish,0);
}
/**
* draw a filled ellipse
*/
function
filledEllipse($x0,$y0,$r1,$r2=0,$angle=0,$nSeg=8,$astart=0,$afinish=
360){
return $this-
>ellipse($x0,$y0,$r1,$r2=0,$angle,$nSeg,$astart,$afinish,1,1);
}
/**
* draw an ellipse
* note that the part and filled ellipse are just special cases of this
function
264
*
* draws an ellipse in the current line style
* centered at $x0,$y0, radii $r1,$r2
* if $r2 is not set, then a circle is drawn
* nSeg is not allowed to be less than 2, as this will simply draw a line
(and will even draw a
* pretty crappy shape at 2, as we are approximating with bezier curves.
*/
function
ellipse($x0,$y0,$r1,$r2=0,$angle=0,$nSeg=8,$astart=0,$afinish=360,$c
lose=1,$fill=0){
if ($r1==0){
return;
}
if ($r2==0){
$r2=$r1;
}
if ($nSeg<2){
$nSeg=2;
}
$astart = deg2rad((float)$astart);
$afinish = deg2rad((float)$afinish);
$totalAngle =$afinish-$astart;
$dt = $totalAngle/$nSeg;
$dtm = $dt/3;
if ($angle != 0){
$a = -1*deg2rad((float)$angle);
$tmp = "\n q ";
265
$tmp .= sprintf('%.3f',cos($a)).' '.sprintf('%.3f',(-1.0*sin($a))).'
'.sprintf('%.3f',sin($a)).' '.sprintf('%.3f',cos($a)).' ';
$tmp .= sprintf('%.3f',$x0).' '.sprintf('%.3f',$y0).' cm';
$this->objects[$this->currentContents]['c'].= $tmp;
$x0=0;
$y0=0;
}
$t1 = $astart;
$a0 = $x0+$r1*cos($t1);
$b0 = $y0+$r2*sin($t1);
$c0 = -$r1*sin($t1);
$d0 = $r2*cos($t1);
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$a0).'
'.sprintf('%.3f',$b0).' m ';
for ($i=1;$i<=$nSeg;$i++){
// draw this bit of the total curve
$t1 = $i*$dt+$astart;
$a1 = $x0+$r1*cos($t1);
$b1 = $y0+$r2*sin($t1);
$c1 = -$r1*sin($t1);
$d1 = $r2*cos($t1);
$this->objects[$this-
>currentContents]['c'].="\n".sprintf('%.3f',($a0+$c0*$dtm)).'
'.sprintf('%.3f',($b0+$d0*$dtm));
$this->objects[$this->currentContents]['c'].= ' '.sprintf('%.3f',($a1-
$c1*$dtm)).' '.sprintf('%.3f',($b1-$d1*$dtm)).' '.sprintf('%.3f',$a1).'
'.sprintf('%.3f',$b1).' c';
$a0=$a1;
$b0=$b1;
266
$c0=$c1;
$d0=$d1;
}
if ($fill){
$this->objects[$this->currentContents]['c'].=' f';
} else {
if ($close){
$this->objects[$this->currentContents]['c'].=' s'; // small 's' signifies
closing the path as well
} else {
$this->objects[$this->currentContents]['c'].=' S';
}
}
if ($angle !=0){
$this->objects[$this->currentContents]['c'].=' Q';
}
}
/**
* this sets the line drawing style.
* width, is the thickness of the line in user units
* cap is the type of cap to put on the line, values can be
'butt','round','square'
* where the diffference between 'square' and 'butt' is that 'square'
projects a flat end past the
* end of the line.
* join can be 'miter', 'round', 'bevel'
* dash is an array which sets the dash pattern, is a series of length
values, which are the lengths of the
* on and off dashes.
* (2) represents 2 on, 2 off, 2 on , 2 off ...
267
* (2,1) is 2 on, 1 off, 2 on, 1 off.. etc
* phase is a modifier on the dash pattern which is used to shift the point
at which the pattern starts.
*/
function setLineStyle($width=1,$cap='',$join='',$dash='',$phase=0){
// this is quite inefficient in that it sets all the parameters whenever 1 is
changed, but will fix another day
$string = '';
if ($width>0){
$string.= $width.' w';
}
$ca = array('butt'=>0,'round'=>1,'square'=>2);
if (isset($ca[$cap])){
$string.= ' '.$ca[$cap].' J';
}
$ja = array('miter'=>0,'round'=>1,'bevel'=>2);
if (isset($ja[$join])){
$string.= ' '.$ja[$join].' j';
}
if (is_array($dash)){
$string.= ' [';
foreach ($dash as $len){
$string.=' '.$len;
}
$string.= ' ] '.$phase.' d';
}
$this->currentLineStyle = $string;
$this->objects[$this->currentContents]['c'].="\n".$string;
}
268
/**
* draw a polygon, the syntax for this is similar to the GD polygon
command
*/
function polygon($p,$np,$f=0){
$this->objects[$this->currentContents]['c'].="\n";
$this->objects[$this->currentContents]['c'].=sprintf('%.3f',$p[0]).'
'.sprintf('%.3f',$p[1]).' m ';
for ($i=2;$i<$np*2;$i=$i+2){
$this->objects[$this->currentContents]['c'].= sprintf('%.3f',$p[$i]).'
'.sprintf('%.3f',$p[$i+1]).' l ';
}
if ($f==1){
$this->objects[$this->currentContents]['c'].=' f';
} else {
$this->objects[$this->currentContents]['c'].=' S';
}
}
/**
* a filled rectangle, note that it is the width and height of the rectangle
which are the secondary paramaters, not
* the coordinates of the upper-right corner
*/
function filledRectangle($x1,$y1,$width,$height){
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x1).'
'.sprintf('%.3f',$y1).' '.sprintf('%.3f',$width).' '.sprintf('%.3f',$height).' re
f';
}
/**
269
* draw a rectangle, note that it is the width and height of the rectangle
which are the secondary paramaters, not
* the coordinates of the upper-right corner
*/
function rectangle($x1,$y1,$width,$height){
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$x1).'
'.sprintf('%.3f',$y1).' '.sprintf('%.3f',$width).' '.sprintf('%.3f',$height).' re
S';
}
/**
* add a new page to the document
* this also makes the new page the current active object
*/
function newPage($insert=0,$id=0,$pos='after'){
// if there is a state saved, then go up the stack closing them
// then on the new page, re-open them with the right setings
if ($this->nStateStack){
for ($i=$this->nStateStack;$i>=1;$i--){
$this->restoreState($i);
}
}
$this->numObj++;
if ($insert){
// the id from the ezPdf class is the od of the contents of the page, not
the page object itself
// query that object to find the parent
$rid = $this->objects[$id]['onPage'];
270
$opt= array('rid'=>$rid,'pos'=>$pos);
$this->o_page($this->numObj,'new',$opt);
} else {
$this->o_page($this->numObj,'new');
}
// if there is a stack saved, then put that onto the page
if ($this->nStateStack){
for ($i=1;$i<=$this->nStateStack;$i++){
$this->saveState($i);
}
}
// and if there has been a stroke or fill colour set, then transfer them
if ($this->currentColour['r']>=0){
$this->setColor($this->currentColour['r'],$this-
>currentColour['g'],$this->currentColour['b'],1);
}
if ($this->currentStrokeColour['r']>=0){
$this->setStrokeColor($this->currentStrokeColour['r'],$this-
>currentStrokeColour['g'],$this->currentStrokeColour['b'],1);
}
// if there is a line style set, then put this in too
if (strlen($this->currentLineStyle)){
$this->objects[$this->currentContents]['c'].="\n".$this-
>currentLineStyle;
}
// the call to the o_page object set currentContents to the present page,
so this can be returned as the page id
return $this->currentContents;
}
271
/**
* output the pdf code, streaming it to the browser
* the relevant headers are set so that hopefully the browser will
recognise it
*/
function stream($options=''){
// setting the options allows the adjustment of the headers
// values at the moment are:
// 'Content-Disposition'=>'filename' - sets the filename, though not too
sure how well this will
// work as in my trial the browser seems to use the filename of the
php file with .pdf on the end
// 'Accept-Ranges'=>1 or 0 - if this is not set to 1, then this header is
not included, off by default
// this header seems to have caused some problems despite tha fact
that it is supposed to solve
// them, so I am leaving it off by default.
// 'compress'=> 1 or 0 - apply content stream compression, this is on
(1) by default
if (!is_array($options)){
$options=array();
}
if ( isset($options['compress']) && $options['compress']==0){
$tmp = $this->output(1);
} else {
$tmp = $this->output();
}
header("Content-type: application/pdf");
header("Content-Length: ".strlen(ltrim($tmp)));
272
$fileName = (isset($options['Content-
Disposition'])?$options['Content-Disposition']:'file.pdf');
header("Content-Disposition: inline; filename=".$fileName);
if (isset($options['Accept-Ranges']) && $options['Accept-
Ranges']==1){
header("Accept-Ranges: ".strlen(ltrim($tmp)));
}
echo ltrim($tmp);
}
/**
* return the height in units of the current font in the given size
*/
function getFontHeight($size){
if (!$this->numFonts){
$this->selectFont('./fonts/Helvetica');
}
// for the current font, and the given size, what is the height of the font
in user units
$h = $this->fonts[$this->currentFont]['FontBBox'][3]-$this-
>fonts[$this->currentFont]['FontBBox'][1];
return $size*$h/1000;
}
/**
* return the font decender, this will normally return a negative number
* if you add this number to the baseline, you get the level of the bottom
of the font
* it is in the pdf user units
*/
function getFontDecender($size){
273
// note that this will most likely return a negative value
if (!$this->numFonts){
$this->selectFont('./fonts/Helvetica');
}
$h = $this->fonts[$this->currentFont]['FontBBox'][1];
return $size*$h/1000;
}
/**
* filter the text, this is applied to all text just before being inserted into
the pdf document
* it escapes the various things that need to be escaped, and so on
*
* @access private
*/
function filterText($text){
$text = str_replace('\\','\\\\',$text);
$text = str_replace('(','\(',$text);
$text = str_replace(')','\)',$text);
$text = str_replace('<','<',$text);
$text = str_replace('>','>',$text);
$text = str_replace(''','\'',$text);
$text = str_replace('"','"',$text);
$text = str_replace('&','&',$text);
return $text;
}
/**
* given a start position and information about how text is to be laid out,
calculate where
274
* on the page the text will end
*
* @access private
*/
function PRVTgetTextPosition($x,$y,$angle,$size,$wa,$text){
// given this information return an array containing x and y for the end
position as elements 0 and 1
$w = $this->getTextWidth($size,$text);
// need to adjust for the number of spaces in this text
$words = explode(' ',$text);
$nspaces=count($words)-1;
$w += $wa*$nspaces;
$a = deg2rad((float)$angle);
return array(cos($a)*$w+$x,-sin($a)*$w+$y);
}
/**
* wrapper function for PRVTcheckTextDirective1
*
* @access private
*/
function PRVTcheckTextDirective(&$text,$i,&$f){
$x=0;
$y=0;
return $this->PRVTcheckTextDirective1($text,$i,$f,0,$x,$y);
}
/**
* checks if the text stream contains a control directive
* if so then makes some changes and returns the number of characters
involved in the directive
275
* this has been re-worked to include everything neccesary to fins the
current writing point, so that
* the location can be sent to the callback function if required
* if the directive does not require a font change, then $f should be set to
0
*
* @access private
*/
function
PRVTcheckTextDirective1(&$text,$i,&$f,$final,&$x,&$y,$size=0,$an
gle=0,$wordSpaceAdjust=0){
$directive = 0;
$j=$i;
if ($text[$j]=='<'){
$j++;
switch($text[$j]){
case '/':
$j++;
if (strlen($text) <= $j){
return $directive;
}
switch($text[$j]){
case 'b':
case 'i':
$j++;
if ($text[$j]=='>'){
$p = strrpos($this->currentTextState,$text[$j-1]);
if ($p !== false){
// then there is one to remove
$this->currentTextState = substr($this-
>currentTextState,0,$p).substr($this->currentTextState,$p+1);
276
}
$directive=$j-$i+1;
}
break;
case 'c':
// this this might be a callback function
$j++;
$k = strpos($text,'>',$j);
if ($k!==false && $text[$j]==':'){
// then this will be treated as a callback directive
$directive = $k-$i+1;
$f=0;
// split the remainder on colons to get the function name and
the paramater
$tmp = substr($text,$j+1,$k-$j-1);
$b1 = strpos($tmp,':');
if ($b1!==false){
$func = substr($tmp,0,$b1);
$parm = substr($tmp,$b1+1);
} else {
$func=$tmp;
$parm='';
}
if (!isset($func) || !strlen(trim($func))){
$directive=0;
} else {
// only call the function if this is the final call
if ($final){
// need to assess the text position, calculate the text width to
this point
// can use getTextWidth to find the text width I think
277
$tmp = $this-
>PRVTgetTextPosition($x,$y,$angle,$size,$wordSpaceAdjust,substr($t
ext,0,$i));
$info =
array('x'=>$tmp[0],'y'=>$tmp[1],'angle'=>$angle,'status'=>'end','p'=>$p
arm,'nCallback'=>$this->nCallback);
$x=$tmp[0];
$y=$tmp[1];
$ret = $this->$func($info);
if (is_array($ret)){
// then the return from the callback function could set the
position, to start with, later will do font colour, and font
foreach($ret as $rk=>$rv){
switch($rk){
case 'x':
case 'y':
$$rk=$rv;
break;
}
}
}
// also remove from to the stack
// for simplicity, just take from the end, fix this another day
$this->nCallback--;
if ($this->nCallback<0){
$this->nCallBack=0;
}
}
}
}
break;
278
}
break;
case 'b':
case 'i':
$j++;
if ($text[$j]=='>'){
$this->currentTextState.=$text[$j-1];
$directive=$j-$i+1;
}
break;
case 'C':
$noClose=1;
case 'c':
// this this might be a callback function
$j++;
$k = strpos($text,'>',$j);
if ($k!==false && $text[$j]==':'){
// then this will be treated as a callback directive
$directive = $k-$i+1;
$f=0;
// split the remainder on colons to get the function name and the
paramater
// $bits = explode(':',substr($text,$j+1,$k-$j-1));
$tmp = substr($text,$j+1,$k-$j-1);
$b1 = strpos($tmp,':');
if ($b1!==false){
$func = substr($tmp,0,$b1);
$parm = substr($tmp,$b1+1);
} else {
$func=$tmp;
$parm='';
279
}
if (!isset($func) || !strlen(trim($func))){
$directive=0;
} else {
// only call the function if this is the final call, ie, the one
actually doing printing, not measurement
if ($final){
// need to assess the text position, calculate the text width to
this point
// can use getTextWidth to find the text width I think
// also add the text height and decender
$tmp = $this-
>PRVTgetTextPosition($x,$y,$angle,$size,$wordSpaceAdjust,substr($t
ext,0,$i));
$info =
array('x'=>$tmp[0],'y'=>$tmp[1],'angle'=>$angle,'status'=>'start','p'=>$
parm,'f'=>$func,'height'=>$this-
>getFontHeight($size),'decender'=>$this->getFontDecender($size));
$x=$tmp[0];
$y=$tmp[1];
if (!isset($noClose) || !$noClose){
// only add to the stack if this is a small 'c', therefore is a start-
stop pair
$this->nCallback++;
$info['nCallback']=$this->nCallback;
$this->callback[$this->nCallback]=$info;
}
$ret = $this->$func($info);
if (is_array($ret)){
// then the return from the callback function could set the
position, to start with, later will do font colour, and font
280
foreach($ret as $rk=>$rv){
switch($rk){
case 'x':
case 'y':
$$rk=$rv;
break;
}
}
}
}
}
}
break;
}
}
return $directive;
}
/**
* add text to the document, at a specified location, size and angle on the
page
*/
function addText($x,$y,$size,$text,$angle=0,$wordSpaceAdjust=0){
if (!$this->numFonts){$this->selectFont('./fonts/Helvetica');}
// if there are any open callbacks, then they should be called, to show
the start of the line
if ($this->nCallback>0){
for ($i=$this->nCallback;$i>0;$i--){
// call each function
281
$info =
array('x'=>$x,'y'=>$y,'angle'=>$angle,'status'=>'sol','p'=>$this-
>callback[$i]['p'],'nCallback'=>$this-
>callback[$i]['nCallback'],'height'=>$this-
>callback[$i]['height'],'decender'=>$this->callback[$i]['decender']);
$func = $this->callback[$i]['f'];
$this->$func($info);
}
}
if ($angle==0){
$this->objects[$this->currentContents]['c'].="\n".'BT
'.sprintf('%.3f',$x).' '.sprintf('%.3f',$y).' Td';
} else {
$a = deg2rad((float)$angle);
$tmp = "\n".'BT ';
$tmp .= sprintf('%.3f',cos($a)).' '.sprintf('%.3f',(-1.0*sin($a))).'
'.sprintf('%.3f',sin($a)).' '.sprintf('%.3f',cos($a)).' ';
$tmp .= sprintf('%.3f',$x).' '.sprintf('%.3f',$y).' Tm';
$this->objects[$this->currentContents]['c'] .= $tmp;
}
if ($wordSpaceAdjust!=0 || $wordSpaceAdjust != $this-
>wordSpaceAdjust){
$this->wordSpaceAdjust=$wordSpaceAdjust;
$this->objects[$this->currentContents]['c'].='
'.sprintf('%.3f',$wordSpaceAdjust).' Tw';
}
$len=strlen($text);
$start=0;
for ($i=0;$i<$len;$i++){
$f=1;
$directive = $this->PRVTcheckTextDirective($text,$i,$f);
282
if ($directive){
// then we should write what we need to
if ($i>$start){
$part = substr($text,$start,$i-$start);
$this->objects[$this->currentContents]['c'].=' /F'.$this-
>currentFontNum.' '.sprintf('%.1f',$size).' Tf ';
$this->objects[$this->currentContents]['c'].=' ('.$this-
>filterText($part).') Tj';
}
if ($f){
// then there was nothing drastic done here, restore the contents
$this->setCurrentFont();
} else {
$this->objects[$this->currentContents]['c'] .= ' ET';
$f=1;
$xp=$x;
$yp=$y;
$directive = $this-
>PRVTcheckTextDirective1($text,$i,$f,1,$xp,$yp,$size,$angle,$wordS
paceAdjust);
// restart the text object
if ($angle==0){
$this->objects[$this->currentContents]['c'].="\n".'BT
'.sprintf('%.3f',$xp).' '.sprintf('%.3f',$yp).' Td';
} else {
$a = deg2rad((float)$angle);
$tmp = "\n".'BT ';
$tmp .= sprintf('%.3f',cos($a)).' '.sprintf('%.3f',(-1.0*sin($a))).'
'.sprintf('%.3f',sin($a)).' '.sprintf('%.3f',cos($a)).' ';
$tmp .= sprintf('%.3f',$xp).' '.sprintf('%.3f',$yp).' Tm';
283
$this->objects[$this->currentContents]['c'] .= $tmp;
}
if ($wordSpaceAdjust!=0 || $wordSpaceAdjust != $this-
>wordSpaceAdjust){
$this->wordSpaceAdjust=$wordSpaceAdjust;
$this->objects[$this->currentContents]['c'].='
'.sprintf('%.3f',$wordSpaceAdjust).' Tw';
}
}
// and move the writing point to the next piece of text
$i=$i+$directive-1;
$start=$i+1;
}
}
if ($start<$len){
$part = substr($text,$start);
$this->objects[$this->currentContents]['c'].=' /F'.$this-
>currentFontNum.' '.sprintf('%.1f',$size).' Tf ';
$this->objects[$this->currentContents]['c'].=' ('.$this-
>filterText($part).') Tj';
}
$this->objects[$this->currentContents]['c'].=' ET';
// if there are any open callbacks, then they should be called, to show
the end of the line
if ($this->nCallback>0){
for ($i=$this->nCallback;$i>0;$i--){
// call each function
$tmp = $this-
>PRVTgetTextPosition($x,$y,$angle,$size,$wordSpaceAdjust,$text);
284
$info =
array('x'=>$tmp[0],'y'=>$tmp[1],'angle'=>$angle,'status'=>'eol','p'=>$th
is->callback[$i]['p'],'nCallback'=>$this-
>callback[$i]['nCallback'],'height'=>$this-
>callback[$i]['height'],'decender'=>$this->callback[$i]['decender']);
$func = $this->callback[$i]['f'];
$this->$func($info);
}
}
}
/**
* calculate how wide a given text string will be on a page, at a given
size.
* this can be called externally, but is alse used by the other class
functions
*/
function getTextWidth($size,$text){
// this function should not change any of the settings, though it will
need to
// track any directives which change during calculation, so copy them
at the start
// and put them back at the end.
$store_currentTextState = $this->currentTextState;
if (!$this->numFonts){
$this->selectFont('./fonts/Helvetica');
}
// converts a number or a float to a string so it can get the width
285
$text = "$text";
// hmm, this is where it all starts to get tricky - use the font information
to
// calculate the width of each character, add them up and convert to
user units
$w=0;
$len=strlen($text);
$cf = $this->currentFont;
for ($i=0;$i<$len;$i++){
$f=1;
$directive = $this->PRVTcheckTextDirective($text,$i,$f);
if ($directive){
if ($f){
$this->setCurrentFont();
$cf = $this->currentFont;
}
$i=$i+$directive-1;
} else {
$char=ord($text[$i]);
if (isset($this->fonts[$cf]['differences'][$char])){
// then this character is being replaced by another
$name = $this->fonts[$cf]['differences'][$char];
if (isset($this->fonts[$cf]['C'][$name]['WX'])){
$w+=$this->fonts[$cf]['C'][$name]['WX'];
}
} else if (isset($this->fonts[$cf]['C'][$char]['WX'])){
$w+=$this->fonts[$cf]['C'][$char]['WX'];
}
}
}
286
$this->currentTextState = $store_currentTextState;
$this->setCurrentFont();
return $w*$size/1000;
}
/**
* do a part of the calculation for sorting out the justification of the text
*
* @access private
*/
function
PRVTadjustWrapText($text,$actual,$width,&$x,&$adjust,$justificatio
n){
switch ($justification){
case 'left':
return;
break;
case 'right':
$x+=$width-$actual;
break;
case 'center':
case 'centre':
$x+=($width-$actual)/2;
break;
case 'full':
// count the number of words
$words = explode(' ',$text);
$nspaces=count($words)-1;
if ($nspaces>0){
287
$adjust = ($width-$actual)/$nspaces;
} else {
$adjust=0;
}
break;
}
}
/**
* add text to the page, but ensure that it fits within a certain width
* if it does not fit then put in as much as possible, splitting at word
boundaries
* and return the remainder.
* justification and angle can also be specified for the text
*/
function
addTextWrap($x,$y,$width,$size,$text,$justification='left',$angle=0,$te
st=0){
// this will display the text, and if it goes beyond the width $width, will
backtrack to the
// previous space or hyphen, and return the remainder of the text.
// $justification can be set to 'left','right','center','centre','full'
// need to store the initial text state, as this will change during the
width calculation
// but will need to be re-set before printing, so that the chars work out
right
$store_currentTextState = $this->currentTextState;
if (!$this->numFonts){$this->selectFont('./fonts/Helvetica');}
288
if ($width<=0){
// error, pretend it printed ok, otherwise risking a loop
return '';
}
$w=0;
$break=0;
$breakWidth=0;
$len=strlen($text);
$cf = $this->currentFont;
$tw = $width/$size*1000;
for ($i=0;$i<$len;$i++){
$f=1;
$directive = $this->PRVTcheckTextDirective($text,$i,$f);
if ($directive){
if ($f){
$this->setCurrentFont();
$cf = $this->currentFont;
}
$i=$i+$directive-1;
} else {
$cOrd = ord($text[$i]);
if (isset($this->fonts[$cf]['differences'][$cOrd])){
// then this character is being replaced by another
$cOrd2 = $this->fonts[$cf]['differences'][$cOrd];
} else {
$cOrd2 = $cOrd;
}
if (isset($this->fonts[$cf]['C'][$cOrd2]['WX'])){
$w+=$this->fonts[$cf]['C'][$cOrd2]['WX'];
}
289
if ($w>$tw){
// then we need to truncate this line
if ($break>0){
// then we have somewhere that we can split :)
if ($text[$break]==' '){
$tmp = substr($text,0,$break);
} else {
$tmp = substr($text,0,$break+1);
}
$adjust=0;
$this-
>PRVTadjustWrapText($tmp,$breakWidth,$width,$x,$adjust,$justifica
tion);
// reset the text state
$this->currentTextState = $store_currentTextState;
$this->setCurrentFont();
if (!$test){
$this->addText($x,$y,$size,$tmp,$angle,$adjust);
}
return substr($text,$break+1);
} else {
// just split before the current character
$tmp = substr($text,0,$i);
$adjust=0;
$ctmp=ord($text[$i]);
if (isset($this->fonts[$cf]['differences'][$ctmp])){
$ctmp=$this->fonts[$cf]['differences'][$ctmp];
}
$tmpw=($w-$this->fonts[$cf]['C'][$ctmp]['WX'])*$size/1000;
290
$this-
>PRVTadjustWrapText($tmp,$tmpw,$width,$x,$adjust,$justification);
// reset the text state
$this->currentTextState = $store_currentTextState;
$this->setCurrentFont();
if (!$test){
$this->addText($x,$y,$size,$tmp,$angle,$adjust);
}
return substr($text,$i);
}
}
if ($text[$i]=='-'){
$break=$i;
$breakWidth = $w*$size/1000;
}
if ($text[$i]==' '){
$break=$i;
$ctmp=ord($text[$i]);
if (isset($this->fonts[$cf]['differences'][$ctmp])){
$ctmp=$this->fonts[$cf]['differences'][$ctmp];
}
$breakWidth = ($w-$this-
>fonts[$cf]['C'][$ctmp]['WX'])*$size/1000;
}
}
}
// then there was no need to break this line
if ($justification=='full'){
$justification='left';
}
$adjust=0;
291
$tmpw=$w*$size/1000;
$this-
>PRVTadjustWrapText($text,$tmpw,$width,$x,$adjust,$justification);
// reset the text state
$this->currentTextState = $store_currentTextState;
$this->setCurrentFont();
if (!$test){
$this->addText($x,$y,$size,$text,$angle,$adjust,$angle);
}
return '';
}
/**
* this will be called at a new page to return the state to what it was on
the
* end of the previous page, before the stack was closed down
* This is to get around not being able to have open 'q' across pages
*
*/
function saveState($pageEnd=0){
if ($pageEnd){
// this will be called at a new page to return the state to what it was on
the
// end of the previous page, before the stack was closed down
// This is to get around not being able to have open 'q' across pages
$opt = $this->stateStack[$pageEnd]; // ok to use this as stack starts
numbering at 1
$this->setColor($opt['col']['r'],$opt['col']['g'],$opt['col']['b'],1);
$this->setStrokeColor($opt['str']['r'],$opt['str']['g'],$opt['str']['b'],1);
$this->objects[$this->currentContents]['c'].="\n".$opt['lin'];
// $this->currentLineStyle = $opt['lin'];
292
} else {
$this->nStateStack++;
$this->stateStack[$this->nStateStack]=array(
'col'=>$this->currentColour
,'str'=>$this->currentStrokeColour
,'lin'=>$this->currentLineStyle
);
}
$this->objects[$this->currentContents]['c'].="\nq";
}
/**
* restore a previously saved state
*/
function restoreState($pageEnd=0){
if (!$pageEnd){
$n = $this->nStateStack;
$this->currentColour = $this->stateStack[$n]['col'];
$this->currentStrokeColour = $this->stateStack[$n]['str'];
$this->objects[$this->currentContents]['c'].="\n".$this-
>stateStack[$n]['lin'];
$this->currentLineStyle = $this->stateStack[$n]['lin'];
unset($this->stateStack[$n]);
$this->nStateStack--;
}
$this->objects[$this->currentContents]['c'].="\nQ";
}
/**
* make a loose object, the output will go into this object, until it is
closed, then will revert to
293
* the current one.
* this object will not appear until it is included within a page.
* the function will return the object number
*/
function openObject(){
$this->nStack++;
$this->stack[$this->nStack]=array('c'=>$this-
>currentContents,'p'=>$this->currentPage);
// add a new object of the content type, to hold the data flow
$this->numObj++;
$this->o_contents($this->numObj,'new');
$this->currentContents=$this->numObj;
$this->looseObjects[$this->numObj]=1;
return $this->numObj;
}
/**
* open an existing object for editing
*/
function reopenObject($id){
$this->nStack++;
$this->stack[$this->nStack]=array('c'=>$this-
>currentContents,'p'=>$this->currentPage);
$this->currentContents=$id;
// also if this object is the primary contents for a page, then set the
current page to its parent
if (isset($this->objects[$id]['onPage'])){
$this->currentPage = $this->objects[$id]['onPage'];
}
}
294
/**
* close an object
*/
function closeObject(){
// close the object, as long as there was one open in the first place,
which will be indicated by
// an objectId on the stack.
if ($this->nStack>0){
$this->currentContents=$this->stack[$this->nStack]['c'];
$this->currentPage=$this->stack[$this->nStack]['p'];
$this->nStack--;
// easier to probably not worry about removing the old entries, they
will be overwritten
// if there are new ones.
}
}
/**
* stop an object from appearing on pages from this point on
*/
function stopObject($id){
// if an object has been appearing on pages up to now, then stop it, this
page will
// be the last one that could contian it.
if (isset($this->addLooseObjects[$id])){
$this->addLooseObjects[$id]='';
}
}
/**
295
* after an object has been created, it wil only show if it has been added,
using this function.
*/
function addObject($id,$options='add'){
// add the specified object to the page
if (isset($this->looseObjects[$id]) && $this->currentContents!=$id){
// then it is a valid object, and it is not being added to itself
switch($options){
case 'all':
// then this object is to be added to this page (done in the next
block) and
// all future new pages.
$this->addLooseObjects[$id]='all';
case 'add':
if (isset($this->objects[$this->currentContents]['onPage'])){
// then the destination contents is the primary for the page
// (though this object is actually added to that page)
$this->o_page($this->objects[$this-
>currentContents]['onPage'],'content',$id);
}
break;
case 'even':
$this->addLooseObjects[$id]='even';
$pageObjectId=$this->objects[$this->currentContents]['onPage'];
if ($this->objects[$pageObjectId]['info']['pageNum']%2==0){
$this->addObject($id); // hacky huh :)
}
break;
case 'odd':
$this->addLooseObjects[$id]='odd';
$pageObjectId=$this->objects[$this->currentContents]['onPage'];
296
if ($this->objects[$pageObjectId]['info']['pageNum']%2==1){
$this->addObject($id); // hacky huh :)
}
break;
case 'next':
$this->addLooseObjects[$id]='all';
break;
case 'nexteven':
$this->addLooseObjects[$id]='even';
break;
case 'nextodd':
$this->addLooseObjects[$id]='odd';
break;
}
}
}
/**
* add content to the documents info object
*/
function addInfo($label,$value=0){
// this will only work if the label is one of the valid ones.
// modify this so that arrays can be passed as well.
// if $label is an array then assume that it is key=>value pairs
// else assume that they are both scalar, anything else will probably
error
if (is_array($label)){
foreach ($label as $l=>$v){
$this->o_info($this->infoObject,$l,$v);
}
} else {
297
$this->o_info($this->infoObject,$label,$value);
}
}
/**
* set the viewer preferences of the document, it is up to the browser to
obey these.
*/
function setPreferences($label,$value=0){
// this will only work if the label is one of the valid ones.
if (is_array($label)){
foreach ($label as $l=>$v){
$this->o_catalog($this-
>catalogId,'viewerPreferences',array($l=>$v));
}
} else {
$this->o_catalog($this-
>catalogId,'viewerPreferences',array($label=>$value));
}
}
/**
* extract an integer from a position in a byte stream
*
* @access private
*/
function PRVT_getBytes(&$data,$pos,$num){
// return the integer represented by $num bytes from $pos within $data
$ret=0;
for ($i=0;$i<$num;$i++){
$ret=$ret*256;
298
$ret+=ord($data[$pos+$i]);
}
return $ret;
}
/**
* add a PNG image into the document, from a file
* this should work with remote files
*/
function addPngFromFile($file,$x,$y,$w=0,$h=0){
// read in a png file, interpret it, then add to the system
$error=0;
$tmp = get_magic_quotes_runtime();
set_magic_quotes_runtime(0);
$fp = @fopen($file,'rb');
if ($fp){
$data='';
while(!feof($fp)){
$data .= fread($fp,1024);
}
fclose($fp);
} else {
$error = 1;
$errormsg = 'trouble opening file: '.$file;
}
set_magic_quotes_runtime($tmp);
if (!$error){
$header =
chr(137).chr(80).chr(78).chr(71).chr(13).chr(10).chr(26).chr(10);
if (substr($data,0,8)!=$header){
299
$error=1;
$errormsg = 'this file does not have a valid header';
}
}
if (!$error){
// set pointer
$p = 8;
$len = strlen($data);
// cycle through the file, identifying chunks
$haveHeader=0;
$info=array();
$idata='';
$pdata='';
while ($p<$len){
$chunkLen = $this->PRVT_getBytes($data,$p,4);
$chunkType = substr($data,$p+4,4);
// echo $chunkType.' - '.$chunkLen.'<br>';
switch($chunkType){
case 'IHDR':
// this is where all the file information comes from
$info['width']=$this->PRVT_getBytes($data,$p+8,4);
$info['height']=$this->PRVT_getBytes($data,$p+12,4);
$info['bitDepth']=ord($data[$p+16]);
$info['colorType']=ord($data[$p+17]);
$info['compressionMethod']=ord($data[$p+18]);
$info['filterMethod']=ord($data[$p+19]);
$info['interlaceMethod']=ord($data[$p+20]);
//print_r($info);
$haveHeader=1;
300
if ($info['compressionMethod']!=0){
$error=1;
$errormsg = 'unsupported compression method';
}
if ($info['filterMethod']!=0){
$error=1;
$errormsg = 'unsupported filter method';
}
break;
case 'PLTE':
$pdata.=substr($data,$p+8,$chunkLen);
break;
case 'IDAT':
$idata.=substr($data,$p+8,$chunkLen);
break;
case 'tRNS':
//this chunk can only occur once and it must occur after the PLTE
chunk and before IDAT chunk
//print "tRNS found, color type = ".$info['colorType']."<BR>";
$transparency = array();
if ($info['colorType'] == 3) { // indexed color, rbg
/* corresponding to entries in the plte chunk
Alpha for palette index 0: 1 byte
Alpha for palette index 1: 1 byte
...etc...
*/
// there will be one entry for each palette entry. up until the last
non-opaque entry.
// set up an array, stretching over all palette entries which will be
o (opaque) or 1 (transparent)
$transparency['type']='indexed';
301
$numPalette = strlen($pdata)/3;
$trans=0;
for ($i=$chunkLen;$i>=0;$i--){
if (ord($data[$p+8+$i])==0){
$trans=$i;
}
}
$transparency['data'] = $trans;
} elseif($info['colorType'] == 0) { // grayscale
/* corresponding to entries in the plte chunk
Gray: 2 bytes, range 0 .. (2^bitdepth)-1
*/
// $transparency['grayscale']=$this-
>PRVT_getBytes($data,$p+8,2); // g = grayscale
$transparency['type']='indexed';
$transparency['data'] = ord($data[$p+8+1]);
} elseif($info['colorType'] == 2) { // truecolor
/* corresponding to entries in the plte chunk
Red: 2 bytes, range 0 .. (2^bitdepth)-1
Green: 2 bytes, range 0 .. (2^bitdepth)-1
Blue: 2 bytes, range 0 .. (2^bitdepth)-1
*/
$transparency['r']=$this->PRVT_getBytes($data,$p+8,2); // r
from truecolor
$transparency['g']=$this->PRVT_getBytes($data,$p+10,2); // g
from truecolor
$transparency['b']=$this->PRVT_getBytes($data,$p+12,2); // b
from truecolor
302
} else {
//unsupported transparency type
}
// KS End new code
break;
default:
break;
}
$p += $chunkLen+12;
}
if(!$haveHeader){
$error = 1;
$errormsg = 'information header is missing';
}
if (isset($info['interlaceMethod']) && $info['interlaceMethod']){
$error = 1;
$errormsg = 'There appears to be no support for interlaced images in
pdf.';
}
}
if (!$error && $info['bitDepth'] > 8){
$error = 1;
$errormsg = 'only bit depth of 8 or less is supported';
}
if (!$error){
if ($info['colorType']!=2 && $info['colorType']!=0 &&
$info['colorType']!=3){
303
$error = 1;
$errormsg = 'transparancey alpha channel not supported,
transparency only supported for palette images.';
} else {
switch ($info['colorType']){
case 3:
$color = 'DeviceRGB';
$ncolor=1;
break;
case 2:
$color = 'DeviceRGB';
$ncolor=3;
break;
case 0:
$color = 'DeviceGray';
$ncolor=1;
break;
}
}
}
if ($error){
$this->addMessage('PNG error - ('.$file.') '.$errormsg);
return;
}
if ($w==0){
$w=$h/$info['height']*$info['width'];
}
if ($h==0){
$h=$w*$info['height']/$info['width'];
}
//print_r($info);
304
// so this image is ok... add it in.
$this->numImages++;
$im=$this->numImages;
$label='I'.$im;
$this->numObj++;
// $this->o_image($this-
>numObj,'new',array('label'=>$label,'data'=>$idata,'iw'=>$w,'ih'=>$h,'t
ype'=>'png','ic'=>$info['width']));
$options =
array('label'=>$label,'data'=>$idata,'bitsPerComponent'=>$info['bitDept
h'],'pdata'=>$pdata
,'iw'=>$info['width'],'ih'=>$info['height'],'type'=>'png','color'=>$color,'n
color'=>$ncolor);
if (isset($transparency)){
$options['transparency']=$transparency;
}
$this->o_image($this->numObj,'new',$options);
$this->objects[$this->currentContents]['c'].="\nq";
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$w)." 0
0 ".sprintf('%.3f',$h)." ".sprintf('%.3f',$x)." ".sprintf('%.3f',$y)." cm";
$this->objects[$this->currentContents]['c'].="\n/".$label.' Do';
$this->objects[$this->currentContents]['c'].="\nQ";
}
/**
* add a JPEG image into the document, from a file
*/
function addJpegFromFile($img,$x,$y,$w=0,$h=0){
305
// attempt to add a jpeg image straight from a file, using no GD
commands
// note that this function is unable to operate on a remote file.
if (!file_exists($img)){
return;
}
$tmp=getimagesize($img);
$imageWidth=$tmp[0];
$imageHeight=$tmp[1];
if (isset($tmp['channels'])){
$channels = $tmp['channels'];
} else {
$channels = 3;
}
if ($w<=0 && $h<=0){
$w=$imageWidth;
}
if ($w==0){
$w=$h/$imageHeight*$imageWidth;
}
if ($h==0){
$h=$w*$imageHeight/$imageWidth;
}
$fp=fopen($img,'rb');
$tmp = get_magic_quotes_runtime();
306
set_magic_quotes_runtime(0);
$data = fread($fp,filesize($img));
set_magic_quotes_runtime($tmp);
fclose($fp);
$this-
>addJpegImage_common($data,$x,$y,$w,$h,$imageWidth,$imageHeig
ht,$channels);
}
/**
* add an image into the document, from a GD object
* this function is not all that reliable, and I would probably encourage
people to use
* the file based functions
*/
function addImage(&$img,$x,$y,$w=0,$h=0,$quality=75){
// add a new image into the current location, as an external object
// add the image at $x,$y, and with width and height as defined by $w
& $h
// note that this will only work with full colour images and makes them
jpg images for display
// later versions could present lossless image formats if there is
interest.
// there seems to be some problem here in that images that have quality
set above 75 do not appear
// not too sure why this is, but in the meantime I have restricted this to
75.
307
if ($quality>75){
$quality=75;
}
// if the width or height are set to zero, then set the other one based on
keeping the image
// height/width ratio the same, if they are both zero, then give up :)
$imageWidth=imagesx($img);
$imageHeight=imagesy($img);
if ($w<=0 && $h<=0){
return;
}
if ($w==0){
$w=$h/$imageHeight*$imageWidth;
}
if ($h==0){
$h=$w*$imageHeight/$imageWidth;
}
// gotta get the data out of the img..
// so I write to a temp file, and then read it back.. soo ugly, my
apologies.
$tmpDir='/tmp';
$tmpName=tempnam($tmpDir,'img');
imagejpeg($img,$tmpName,$quality);
$fp=fopen($tmpName,'rb');
$tmp = get_magic_quotes_runtime();
set_magic_quotes_runtime(0);
308
$fp = @fopen($tmpName,'rb');
if ($fp){
$data='';
while(!feof($fp)){
$data .= fread($fp,1024);
}
fclose($fp);
} else {
$error = 1;
$errormsg = 'trouble opening file';
}
// $data = fread($fp,filesize($tmpName));
set_magic_quotes_runtime($tmp);
// fclose($fp);
unlink($tmpName);
$this-
>addJpegImage_common($data,$x,$y,$w,$h,$imageWidth,$imageHeig
ht);
}
/**
* common code used by the two JPEG adding functions
*
* @access private
*/
function
addJpegImage_common(&$data,$x,$y,$w=0,$h=0,$imageWidth,$imag
eHeight,$channels=3){
// note that this function is not to be called externally
// it is just the common code between the GD and the file options
$this->numImages++;
309
$im=$this->numImages;
$label='I'.$im;
$this->numObj++;
$this->o_image($this-
>numObj,'new',array('label'=>$label,'data'=>$data,'iw'=>$imageWidth,'
ih'=>$imageHeight,'channels'=>$channels));
$this->objects[$this->currentContents]['c'].="\nq";
$this->objects[$this->currentContents]['c'].="\n".sprintf('%.3f',$w)." 0
0 ".sprintf('%.3f',$h)." ".sprintf('%.3f',$x)." ".sprintf('%.3f',$y)." cm";
$this->objects[$this->currentContents]['c'].="\n/".$label.' Do';
$this->objects[$this->currentContents]['c'].="\nQ";
}
/**
* specify where the document should open when it first starts
*/
function openHere($style,$a=0,$b=0,$c=0){
// this function will open the document at a specified page, in a
specified style
// the values for style, and the required paramters are:
// 'XYZ' left, top, zoom
// 'Fit'
// 'FitH' top
// 'FitV' left
// 'FitR' left,bottom,right
// 'FitB'
// 'FitBH' top
// 'FitBV' left
$this->numObj++;
310
$this->o_destination($this->numObj,'new',array('page'=>$this-
>currentPage,'type'=>$style,'p1'=>$a,'p2'=>$b,'p3'=>$c));
$id = $this->catalogId;
$this->o_catalog($id,'openHere',$this->numObj);
}
/**
* create a labelled destination within the document
*/
function addDestination($label,$style,$a=0,$b=0,$c=0){
// associates the given label with the destination, it is done this way so
that a destination can be specified after
// it has been linked to
// styles are the same as the 'openHere' function
$this->numObj++;
$this->o_destination($this->numObj,'new',array('page'=>$this-
>currentPage,'type'=>$style,'p1'=>$a,'p2'=>$b,'p3'=>$c));
$id = $this->numObj;
// store the label->idf relationship, note that this means that labels can
be used only once
$this->destinations["$label"]=$id;
}
/**
* define font families, this is used to initialize the font families for the
default fonts
* and for the user to add new ones for their fonts. The default bahavious
can be overridden should
* that be desired.
*/
function setFontFamily($family,$options=''){
311
if (!is_array($options)){
if ($family=='init'){
// set the known family groups
// these font families will be used to enable bold and italic markers
to be included
// within text streams. html forms will be used... <b></b> <i></i>
$this->fontFamilies['Helvetica.afm']=array(
'b'=>'Helvetica-Bold.afm'
,'i'=>'Helvetica-Oblique.afm'
,'bi'=>'Helvetica-BoldOblique.afm'
,'ib'=>'Helvetica-BoldOblique.afm'
);
$this->fontFamilies['Courier.afm']=array(
'b'=>'Courier-Bold.afm'
,'i'=>'Courier-Oblique.afm'
,'bi'=>'Courier-BoldOblique.afm'
,'ib'=>'Courier-BoldOblique.afm'
);
$this->fontFamilies['Times-Roman.afm']=array(
'b'=>'Times-Bold.afm'
,'i'=>'Times-Italic.afm'
,'bi'=>'Times-BoldItalic.afm'
,'ib'=>'Times-BoldItalic.afm'
);
}
} else {
// the user is trying to set a font family
// note that this can also be used to set the base ones to something
else
if (strlen($family)){
$this->fontFamilies[$family] = $options;
312
}
}
}
/**
* used to add messages for use in debugging
*/
function addMessage($message){
$this->messages.=$message."\n";
}
/**
* a few functions which should allow the document to be treated
transactionally.
*/
function transaction($action){
switch ($action){
case 'start':
// store all the data away into the checkpoint variable
$data = get_object_vars($this);
$this->checkpoint = $data;
unset($data);
break;
case 'commit':
if (is_array($this->checkpoint) && isset($this-
>checkpoint['checkpoint'])){
$tmp = $this->checkpoint['checkpoint'];
$this->checkpoint = $tmp;
unset($tmp);
} else {
$this->checkpoint='';
313
}
break;
case 'rewind':
// do not destroy the current checkpoint, but move us back to the
state then, so that we can try again
if (is_array($this->checkpoint)){
// can only abort if were inside a checkpoint
$tmp = $this->checkpoint;
foreach ($tmp as $k=>$v){
if ($k != 'checkpoint'){
$this->$k=$v;
}
}
unset($tmp);
}
break;
case 'abort':
if (is_array($this->checkpoint)){
// can only abort if were inside a checkpoint
$tmp = $this->checkpoint;
foreach ($tmp as $k=>$v){
$this->$k=$v;
}
unset($tmp);
}
break;
}
}
} // end of class
?>
314
c. Laporan
<?php
require "../../config/koneksi.php";
include "../../config/fungsi_indotgl.php";
include "../../config/fungsi_combobox.php";
include "../../config/library.php";
echo "<h2>Cetak Laporan Hasil Diagnosa</h2><br/>
<form method=POST
action='main/main_laporan/pdf_diagnosa.php' target='_blank'>
<table>
<tr><td colspan=2><b>Laporan Per Periode</b></td></tr>
<tr><td>Dari Tanggal</td><td> : ";
combotgl(1,31,'tgl_mulai',$tgl_skrg);
combonamabln(1,12,'bln_mulai',$bln_sekarang);
combothn(2000,$thn_sekarang,'thn_mulai',$thn_sekarang);
echo "</td></tr>
<tr><td>s/d Tanggal</td><td> : ";
combotgl(1,31,'tgl_selesai',$tgl_skrg);
combonamabln(1,12,'bln_selesai',$bln_sekarang);
combothn(2000,$thn_sekarang,'thn_selesai',$thn_sekarang);
echo "</td></tr>
<tr><td colspan=2><input type=submit value=Proses></td></tr>
</table>
</form>";
?>
315
d. Pdf_diagnosa
<?php
include "class.ezpdf.php";
require "../../../../config/koneksi.php";
include "../../../../config/fungsi_indotgl.php";
include "../../../../config/fungsi_combobox.php";
include "../../../../config/library.php";
$pdf = new Cezpdf();
// Set margin dan font
$pdf->ezSetCmMargins(3, 3, 3, 3);
$pdf->selectFont('fonts/Courier.afm');
$all = $pdf->openObject();
// Tampilkan logo
$pdf->setStrokeColor(0, 0, 0, 1);
//$pdf->addJpegFromFile('logo.jpg',20,800,69);
// Teks di tengah atas untuk judul header
$pdf->addText(180, 820, 18,'<b>Laporan Hasil Diagnosa</b>');
$pdf->addText(200, 800, 14,'<b>Penyakit Demam Berdarah</b>');
// Garis atas untuk header
$pdf->line(10, 795, 578, 795);
// Garis bawah untuk footer
$pdf->line(10, 50, 578, 50);
// Teks kiri bawah
$pdf->addText(30,34,8,'Dicetak tgl:' . date( 'd-m-Y, H:i:s'));
316
$pdf->closeObject();
// Tampilkan object di semua halaman
$pdf->addObject($all, 'all');
// Baca input tanggal yang dikirimkan user
$mulai=$_POST[thn_mulai].'-'.$_POST[bln_mulai].'-
'.$_POST[tgl_mulai];
$selesai=$_POST[thn_selesai].'-'.$_POST[bln_selesai].'-
'.$_POST[tgl_selesai];
// Query untuk merelasikan kedua tabel di filter berdasarkan tanggal
$sql = mysql_query("SELECT diagnosa.kd_penyakit as
kd_penyakit,penyakit.nm_penyakit,DATE_FORMAT(tgl_diagnosa,
'%d-%m-%Y') as tanggal,
nama,jenis_kelamin,usia,alamat
FROM diagnosa, penyakit
WHERE (diagnosa.kd_penyakit=penyakit.kd_penyakit)
AND (diagnosa.tgl_diagnosa
BETWEEN '$mulai' AND '$selesai')");
$jml = mysql_num_rows($sql);
if ($jml > 0){
$i = 1;
while($r = mysql_fetch_array($sql)){
$data[$i]=array('<b>No</b>'=>$i,
'<b>Nama</b>'=>$r[nama],
'<b>Jenis Kelamin</b>'=>$r[jenis_kelamin],
317
'<b>Usia</b>'=>$r[usia],
'<b>Alamat</b>'=>$r[alamat],
'<b>Penyakit</b>'=>$r[nm_penyakit],
'<b>Tgl_Diagnosa</b>'=>$r[tanggal]);
$i++;
}
$pdf->ezTable($data, '', '', '');
// Penomoran halaman
$pdf->ezStartPageNumbers(320, 15, 8);
$pdf->ezStream();
}
else{
$m=$_POST[tgl_mulai].'-'.$_POST[bln_mulai].'-
'.$_POST[thn_mulai];
$s=$_POST[tgl_selesai].'-'.$_POST[bln_selesai].'-
'.$_POST[thn_selesai];
echo "Tidak ada Laporan/Hasil Diagnosa pada Tanggal $m s/d $s";
//echo '<script language="javascript">window.location =
"javascript:history.go(-1)"</script>';
}
?>
4.4.10 Main_penyakit
a. Add_penyakit
<?php
session_start();
?>
<link href="../../../../style/style.css" rel="stylesheet" type="text/css" />
318
<div class="add">
<fieldset>
<legend>Tambah Daftar Penyakit</legend>
<div ></div>
<?php
include "../../../../config/inc.library.php";
include "../../../../config/koneksi.php";
$dataKode = buatKode("penyakit", "H");
$dataNama = isset($_POST['txtNama']) ? $_POST['txtNama'] : '';
$dataPencegahan = isset($_POST['txtPencegahan']) ?
$_POST['txtPencegahan'] : '';
$dataPengobatan = isset($_POST['txtPengobatan']) ?
$_POST['txtPengobatan'] : '';
$dataPopulasi = isset($_POST['txtPopulasi']) ?
$_POST['txtPopulasi'] : '';
?>
<form action="?main=simpanpenyakit" method="post"
name="form1">
<table width="100%" cellpadding="2" cellspacing="1" class="table-
list">
<tr>
<th colspan="3">TAMBAH DATA PENYAKIT </th>
</tr>
<tr>
<td width="15%"><strong>Kode</strong></td>
<td width="1%"><strong>:</strong></td>
<td width="84%"><input name="textfield" value="<?php echo
$dataKode; ?>" size="10" maxlength="4"
readonly="readonly"/></td></tr>
<tr>
<td><strong>Nama Penyakit </strong></td>
319
<td><strong>:</strong></td>
<td><input name="txtNama" value="<?php echo $dataNama; ?>"
size="80" maxlength="100" /></td>
</tr>
<tr>
<td><strong>Pencegahan</strong></td>
<td><strong>:</strong></td>
<td><textarea name="txtPencegahan" cols="70"
rows="3"><?php echo $dataPencegahan; ?></textarea></td>
</tr>
<tr>
<td><strong>Pengobatan </strong></td>
<td><strong>:</strong></td>
<td><textarea name="txtPengobatan" cols="70" rows="3"><?php
echo $dataPengobatan; ?></textarea></td>
</tr>
<tr>
<td><strong>Nilai Believe</strong></td>
<td><strong>:</strong></td>
<td><input name="txtPopulasi" value="<?php echo
$dataPopulasi; ?>" size="20" maxlength="20" /></td>
</tr>
<tr><td> </td>
<td> </td>
<td><input type="submit" name="btnSimpan" value=" SIMPAN
"></td>
</tr>
</table>
</form>
</fieldset>
</div>
320
b. Edit_penyakit
<?php
session_start();
include "../../../../config/koneksi.php";
# MENGAMBIL DATA YANG DIEDIT, SESUAI KODE YANG
DIDAPAT DARI URL
$Kode = isset($_GET['Kode']) ? $_GET['Kode'] :
$_POST['txtKode'];
$mySql = "SELECT * FROM penyakit WHERE
kd_penyakit='$Kode'";
$myQry = mysql_query($mySql, $koneksidb) or die ("Query salah :
".mysql_error());
$myData = mysql_fetch_array($myQry);
# MASUKKAN DATA DARI FORM KE VARIABEL
TEMPORARY (SEMENTARA)
$dataKode = $myData['kd_penyakit'];
$dataNama = isset($_POST['txtNama']) ? $_POST['txtNama'] :
$myData['nm_penyakit'];
$dataPencegahan = isset($_POST['txtPencegahan']) ?
$_POST['txtPencegahan'] : $myData['pencegahan'];
$dataPengobatan = isset($_POST['txtPengobatan']) ?
$_POST['txtPengobatan'] : $myData['pengobatan'];
$dataPopulasi = isset($_POST['txtPopulasi']) ?
$_POST['txtPopulasi'] : $myData['np_populasi'];
?>
<form action="?main=updatepenyakit" method="post" name="form1"
enctype="multipart/form-data">
<table class="table-list" width="100%">
321
<tr>
<th colspan="3">UBAH DATA PENYAKIT </th>
</tr>
<tr>
<td width="15%"><strong>Kode</strong></td>
<td width="1%"><strong>:</strong></td>
<td width="84%"><input name="textfield" value="<?php echo
$dataKode; ?>" size="8" maxlength="4" readonly="readonly"/>
<input name="txtKode" type="hidden" value="<?php echo
$dataKode; ?>" /></td></tr>
<tr>
<td><strong>Nama Penyakit </strong></td>
<td><strong>:</strong></td>
<td><input name="txtNama" type="text" value="<?php echo
$dataNama; ?>" size="80" maxlength="100" />
<input name="txtLama" type="hidden" value="<?php echo
$myData['nm_penyakit']; ?>" /></td></tr>
<tr>
<td><strong>Pencegahan</strong></td>
<td><strong>:</strong></td>
<td><textarea name="txtPencegahan" cols="60"
rows="3"><?php echo $dataPencegahan; ?></textarea></td>
</tr>
<tr>
<td><strong>Pengobatan </strong></td>
<td><strong>:</strong></td>
<td><textarea name="txtPengobatan" cols="60" rows="3"><?php
echo $dataPengobatan; ?></textarea></td>
</tr>
<tr>
<td><strong>Nilai Believe</strong></td>
322
<td><strong>:</strong></td>
<td><input name="txtPopulasi" value="<?php echo
$dataPopulasi; ?>" size="20" maxlength="20" /></td>
</tr>
<tr><td> </td>
<td> </td>
<td><input type="submit" name="btnSimpan" value=" SIMPAN
"></td>
</tr>
</table>
</form>
</fieldset>
</div>
c. Penyakit
<script type="text/javascript">
$(document).ready(function(){
//Examples of how to assign the ColorBox
event to elements
$(".thickbox").colorbox({width:"50%",
height:"75%"});
});
</script>
<script type="text/javascript">
$(document).ready(function(){
//Examples of how to assign the ColorBox
event to elements
$(".colorbox").colorbox({width:"50%",
height:"75%"});
});
323
</script>
<?php
include "../../config/koneksi.php";
if (isset($_POST['Del'])) {
if ($_POST['cex'] == NULL) {
echo "<script>window.alert('Data yang akan dihapus belum di
pilih')
javascript:history.go(-1);</script>";
} else {
$a = join(",", $_POST['cex']);
//echo $a;
//exit;
$hapus= "DELETE FROM penyakit WHERE
kd_penyakit='$a'";
$hps = mysql_query($hapus, $koneksidb) or die ("Gagal
query".mysql_error());
//echo $hps;
//exit;
print "<script>alert('Data berhasil di dihapus');
javascript:history.go(-
1);</script>";
}
}else{
echo "
<div class=judul><h2>Daftar Penyakit Gigi :</h2></div>
<br/>
<form action='' method='post'>
<div style='float:right; padding:10px; width:300px; margin-top:5px;'>
324
<a class='thickbox'
href='main/main_penyakit/add_penyakit.php'>Tambah Daftar
Penyakit</a>
<input type='submit' name='Del' value='Hapus' onclick='return
confirmDelete();'>
</div><br/>
<table id=o width=100%><tbody>
<tr>
<th width='1%' class=th>no</th>
<th width='10%' class=th>Kode penyakit</th>
<th width='35%' class=th>nama penyakit</th>
<th width='35%' class=th>Pencegahan</th>
<th width='35%' class=th>Pengobatan</th>
<th width='25%' class=th>Nilai Believe</th>
<th width='1%' bgcolor='#8DAD9C'><div
align='center'><span class='style1'>Ubah</span></div></th>
<th width='1%' bgcolor='#8DAD9C'><div
align='center'><span class='style1'><input type='checkbox'
name='checkbox[]' class='checkall'></span></div></th>
</tr>";
$p = new Paging;
$batas = 15;
$posisi = $p->cariPosisi($batas);
$tampil=mysql_query("SELECT * FROM penyakit order by
kd_penyakit DESC LIMIT $posisi,$batas");
$i= 0;
$i = $posisi;
while ($r=mysql_fetch_array($tampil)){
if (($i % 2) > 0)
$bg = '#FFFFFF'; else
$bg = '#cccccc';
325
echo "<tr bgcolor=" . $bg . ">
<td class=td align=center>" . ++$i ."</td>
<td class=td>$r[kd_penyakit]</td>
<td class=td>$r[nm_penyakit]</td>
<td class=td>$r[pencegahan]</td>
<td class=td>$r[pengobatan]</td>
<td class=td>$r[np_populasi]</td> <td><div
align='center' style='background-color:none;'><a class='colorbox'
href=main/main_penyakit/edit_penyakit.php?Kode=" .
$r['kd_penyakit'] . " ><img src='../images/edit.png' border='0'
width='16' height='16' /></a></div></td>
<td><div align='center'><input type='checkbox' name='cex[]'
value='" . $r['kd_penyakit'] . "'></div></td>
</tr></tr>";
}
echo "</tbody></table></form>";
$sql_pagging = mysql_query("SELECT COUNT(*) AS jml FROM
penyakit");
$pagging = mysql_fetch_array($sql_pagging);
$jml = $pagging['jml'];
echo"
</br>
<div class='results'> <span>Jumlah Data : $jml</span><br/><br/>
";
$jmldata = mysql_num_rows(mysql_query("SELECT * from
penyakit"));
$jmlhalaman = $p->jumlahHalaman($jmldata, $batas);
326
$linkHalaman = $p->navHalaman($_GET['halaman'], $jmlhalaman);
echo" Halaman : $linkHalaman </div>";
}
?>
d. Proses_addpenyakit
<?php
include "../../config/koneksi.php";
# Tombol Simpan diklik
if(isset($_POST['btnSimpan'])){
# Baca Variabel Form
$txtNama = $_POST['txtNama'];
$txtPencegahan = $_POST['txtPencegahan'];
$txtPengobatan = $_POST['txtPengobatan'];
$txtPopulasi = $_POST['txtPopulasi'];
# Validasi form, jika kosong sampaikan pesan error
$pesanError = array();
if (trim($txtNama)=="") {
$pesanError[] = "Data <b>Nama Penyakit</b> tidak boleh
kosong !";
}
if (trim($txtPencegahan)=="") {
$pesanError[] = "Data <b>Pencegahan</b> tidak boleh
kosong !";
}
if (trim($txtPengobatan)=="") {
$pesanError[] = "Data <b>Pengobatan</b> tidak boleh
kosong !";
}
if (trim($txtPopulasi)=="") {
327
$pesanError[] = "Data <b>Populasi</b> tidak boleh kosong
!";
}
# JIKA ADA PESAN ERROR DARI VALIDASI
if (count($pesanError)>=1 ){
echo "<div class='mssgBox'>";
echo "<img src='../images/attention.png'> <br><hr>";
$noPesan=0;
foreach ($pesanError as $indeks=>$pesan_tampil) {
$noPesan++;
echo " $noPesan.
$pesan_tampil<br>";
}
echo "</div> <br>";
}
else {
# SIMPAN DATA KE DATABASE. // Jika tidak
menemukan error, simpan data ke database
// Membuat kode baru
$kodeBaru = buatKode("penyakit", "H");
$mySql = "INSERT INTO penyakit (kd_penyakit,
nm_penyakit, pencegahan, pengobatan, np_populasi)
VALUES ('$kodeBaru',
'$txtNama',
'$txtPencegahan',
'$txtPengobatan',
'$txtPopulasi')";
328
$myQry = mysql_query($mySql, $koneksidb) or die
("Gagal query".mysql_error());
if($myQry){
echo "<meta http-equiv='refresh' content='0;
url=?main=penyakit'>";
}
exit;
}
} // Penutup Tombol Simpan
?>
e. Proses_uppdatepenyakit
<?php
include "../../config/koneksi.php";
# Tombol Simpan diklik
if(isset($_POST['btnSimpan'])){
# Baca Variabel Form
$txtNama = $_POST['txtNama'];
$txtPencegahan = $_POST['txtPencegahan'];
$txtPengobatan = $_POST['txtPengobatan'];
$txtPopulasi = $_POST['txtPopulasi'];
# Validasi form, jika kosong sampaikan pesan error
$pesanError = array();
if (trim($txtNama)=="") {
$pesanError[] = "Data <b>Nama Penyakit</b> tidak boleh kosong
!";
}
if (trim($txtPencegahan)=="") {
$pesanError[] = "Data <b>Pencegahan</b> tidak boleh kosong !";
}
329
if (trim($txtPengobatan)=="") {
$pesanError[] = "Data <b>Pengobatan</b> tidak boleh kosong !";
}
if (trim($txtPopulasi)=="") {
$pesanError[] = "Data <b>Populasi</b> tidak boleh kosong !";
}
# JIKA ADA PESAN ERROR DARI VALIDASI
if (count($pesanError)>=1 ){
echo "<div class='mssgBox'>";
echo "<img src='../images/attention.png'> <br><hr>";
$noPesan=0;
foreach ($pesanError as $indeks=>$pesan_tampil) {
$noPesan++;
echo " $noPesan.
$pesan_tampil<br>";
}
echo "</div> <br>";
}
else {
# SIMPAN PERUBAHAN DATA, Jika jumlah error pesanError
tidak ada, simpan datanya
// Membaca Kode dari form
$Kode = $_POST['txtKode'];
$mySql = "UPDATE penyakit SET
nm_penyakit='$txtNama', pencegahan='$txtPencegahan',
pengobatan='$txtPengobatan', np_populasi='$txtPopulasi'
WHERE kd_penyakit ='$Kode'";
330
$myQry = mysql_query($mySql, $koneksidb) or die ("Gagal
query".mysql_error());
if($myQry){
echo "<meta http-equiv='refresh' content='0;
url=?main=penyakit'>";
}
exit;
}
} // Penutup Tombol Simpan
# MENGAMBIL DATA YANG DIEDIT, SESUAI KODE YANG
DIDAPAT DARI URL
$Kode = isset($_GET['Kode']) ? $_GET['Kode'] : $_POST['txtKode'];
$mySql = "SELECT * FROM penyakit WHERE
kd_penyakit='$Kode'";
$myQry = mysql_query($mySql, $koneksidb) or die ("Query salah :
".mysql_error());
$myData = mysql_fetch_array($myQry);
# MASUKKAN DATA DARI FORM KE VARIABEL TEMPORARY
(SEMENTARA)
$dataKode = $myData['kd_penyakit'];
$dataNama = isset($_POST['txtNama']) ? $_POST['txtNama'] :
$myData['nm_penyakit'];
$dataPencegahan = isset($_POST['txtPencegahan']) ?
$_POST['txtPencegahan'] : $myData['pencegahan'];
$dataPengobatan = isset($_POST['txtPengobatan']) ?
$_POST['txtPengobatan'] : $myData['pengobatan'];
$dataPopulasi = isset($_POST['txtPopulasi']) ?
$_POST['txtPopulasi'] : $myData['np_populasi'];