From 0f0296a02a67d812c999992560403db97a3143f7 Mon Sep 17 00:00:00 2001 From: Christian Paminger Date: Mon, 27 Nov 2006 08:46:23 +0000 Subject: [PATCH] --- .htaccess | 36 + admin/sync/sync_fas_exstd.php | 85 + admin/sync/sync_fas_lkt.php | 202 + admin/sync/sync_fas_lkt_fault.php | 56 + admin/sync/sync_fas_lva.php | 594 +++ admin/sync/sync_fas_std.php | 233 ++ admin/sync/sync_fas_std_fault.php | 48 + admin/sync/sync_feedback.php | 77 + admin/sync/sync_stpldev_stpl.php | 406 ++ admin/sync/sync_vilesci_stg.php | 594 +++ content/DragAndDrop.js | 360 ++ content/Ideen.php | 111 + content/dragboard.js | 57 + content/dragboard.js.php | 173 + content/einheiten.rdf.php | 65 + content/excel.php | 160 + content/fachbereich.rdf.php | 83 + content/fas.js.php | 144 + content/fas.xul.php | 170 + content/fas_bis_personal.php | 231 ++ content/fasoverlay.js.php | 300 ++ content/fasoverlay.xul.php | 238 ++ content/lehreinheitenDragnDrop.js.php | 237 ++ content/lehreinheitendetailoverlay.xul.php | 353 ++ content/lehreinheitenmitarbeiterdialog.js.php | 23 + .../lehreinheitenmitarbeiterdialog.xul.php | 94 + content/lehreinheitenneudialog.js.php | 30 + content/lehreinheitenneudialog.xul.php | 78 + content/lehreinheitenoverlay.js.php | 1127 ++++++ content/lehreinheitenoverlay.xul.php | 204 + content/lehrfach.rdf.php | 69 + content/lehrstunde.rdf.php | 130 + content/lehrveranstaltung.rdf.php | 214 + content/lfvt.css | 89 + content/lfvt.rdf.php | 135 + content/lfvtCUD.php | 67 + content/lfvtbinding.xml.php | 968 +++++ content/lfvtoverlay.js | 506 +++ content/lfvtoverlay.js.php | 512 +++ content/lfvtoverlay.xul.php | 142 + content/mitarbeiter.rdf.php | 75 + content/mitarbeiteradressendialog.js.php | 196 + content/mitarbeiteradressendialog.xul.php | 111 + .../mitarbeiterbankverbindungdialog.js.php | 194 + .../mitarbeiterbankverbindungdialog.xul.php | 101 + content/mitarbeiterdetailoverlay.xul.php | 630 +++ content/mitarbeiteremaildialog.js.php | 169 + content/mitarbeiteremaildialog.xul.php | 83 + content/mitarbeiterfunktiondialog.js.php | 285 ++ content/mitarbeiterfunktiondialog.xul.php | 214 + content/mitarbeiteroverlay.js.php | 1810 +++++++++ content/mitarbeiteroverlay.xul.php | 262 ++ content/mitarbeitertelefonnummerdialog.js.php | 159 + .../mitarbeitertelefonnummerdialog.xul.php | 84 + content/nextUNR.php | 35 + content/orte.rdf.php | 80 + content/orte2.rdf.php | 75 + content/orte_liste.rdf.php | 58 + content/phpRequest.js.php | 94 + content/raumtyp.rdf.php | 61 + content/stpl-details-overlay.xul.php | 162 + content/stpl-semester-overlay.js.php | 27 + content/stpl-semester-overlay.xul.php | 58 + content/stpl-week-overlay.js.php | 203 + content/stpl-week-overlay.xul.php | 191 + content/student-verbaende.rdf.php | 200 + content/studenten.js | 205 + content/studenten.rdf.php | 92 + content/studentenoverlay.xul.php | 166 + content/studiengang.rdf.php | 66 + content/studiensemester.rdf.php | 60 + content/tempus.js.php | 100 + content/tempus.xul.php | 158 + content/tempusoverlay.js.php | 207 + content/tempusoverlay.xul.php | 153 + content/timetable-week.xul.php | 462 +++ content/xxxstpl-lehrstunde.rdf.php | 101 + favicon.ico | Bin 0 -> 22486 bytes include/Authorization.class.php | 123 + include/Excel/BIFFwriter.php | 237 ++ include/Excel/File.php | 113 + include/Excel/Format.php | 1101 ++++++ include/Excel/OLE.php | 408 ++ include/Excel/PEAR.php | 1095 ++++++ include/Excel/PPS.php | 217 + include/Excel/Parser.php | 1688 ++++++++ include/Excel/Root.php | 518 +++ include/Excel/Validator.php | 229 ++ include/Excel/Workbook.php | 1523 +++++++ include/Excel/Worksheet.php | 3500 +++++++++++++++++ include/Excel/Writer.php | 103 + include/berechtigung.class.php | 321 ++ include/cis_functions.inc.php | 515 +++ include/ects_sync.class.php | 110 + include/einheit.class.php | 315 ++ include/fachbereich.class.php | 92 + include/fas/adresse.class.php | 355 ++ include/fas/ausbildungssemester.class.php | 182 + include/fas/bankverbindung.class.php | 340 ++ include/fas/benutzer.class.php | 386 ++ include/fas/email.class.php | 310 ++ include/fas/fachbereich.class.php | 127 + include/fas/functions.inc.php | 29 + include/fas/funktion.class.php | 691 ++++ include/fas/gruppe.class.php | 202 + include/fas/lehreinheit.class.php | 1588 ++++++++ include/fas/lehrform.class.php | 131 + include/fas/lehrfunktion.class.php | 124 + include/fas/lehrveranstaltung.class.php | 427 ++ include/fas/mitarbeiter.class.php | 742 ++++ include/fas/nation.class.php | 92 + include/fas/person.class.php | 615 +++ include/fas/raumtyp.class.php | 126 + include/fas/studiengang.class.php | 228 ++ include/fas/studiensemester.class.php | 163 + include/fas/telefonnummer.class.php | 296 ++ include/ferien.class.php | 88 + include/functions.inc.php | 155 + include/funktion.class.php | 279 ++ include/globals.inc.php | 22 + include/lehrfach.class.php | 206 + include/lehrform.class.php | 62 + include/lehrstunde.class.php | 457 +++ include/lehrveranstaltung.class.php | 392 ++ include/lfvt.class.php | 423 ++ include/lv_info.class.php | 324 ++ include/lv_verteilung.class.php | 359 ++ include/mailgrp.class.php | 84 + include/mitarbeiter.class.php | 362 ++ include/pdf.inc.php | 191 + include/pdf/FAQ.htm | 286 ++ include/pdf/doc/acceptpagebreak.htm | 70 + include/pdf/doc/addfont.htm | 62 + include/pdf/doc/addlink.htm | 28 + include/pdf/doc/addpage.htm | 42 + include/pdf/doc/aliasnbpages.htm | 47 + include/pdf/doc/cell.htm | 106 + include/pdf/doc/close.htm | 24 + include/pdf/doc/error.htm | 25 + include/pdf/doc/footer.htm | 39 + include/pdf/doc/fpdf.htm | 57 + include/pdf/doc/getstringwidth.htm | 23 + include/pdf/doc/getx.htm | 22 + include/pdf/doc/gety.htm | 22 + include/pdf/doc/header.htm | 41 + include/pdf/doc/image.htm | 88 + include/pdf/doc/index.htm | 57 + include/pdf/doc/line.htm | 38 + include/pdf/doc/link.htm | 46 + include/pdf/doc/ln.htm | 28 + include/pdf/doc/multicell.htm | 76 + include/pdf/doc/open.htm | 23 + include/pdf/doc/output.htm | 47 + include/pdf/doc/pageno.htm | 20 + include/pdf/doc/rect.htm | 48 + include/pdf/doc/setauthor.htm | 28 + include/pdf/doc/setautopagebreak.htm | 33 + include/pdf/doc/setcompression.htm | 31 + include/pdf/doc/setcreator.htm | 29 + include/pdf/doc/setdisplaymode.htm | 47 + include/pdf/doc/setdrawcolor.htm | 41 + include/pdf/doc/setfillcolor.htm | 40 + include/pdf/doc/setfont.htm | 103 + include/pdf/doc/setfontsize.htm | 25 + include/pdf/doc/setkeywords.htm | 28 + include/pdf/doc/setleftmargin.htm | 30 + include/pdf/doc/setlinewidth.htm | 29 + include/pdf/doc/setlink.htm | 34 + include/pdf/doc/setmargins.htm | 37 + include/pdf/doc/setrightmargin.htm | 28 + include/pdf/doc/setsubject.htm | 28 + include/pdf/doc/settextcolor.htm | 40 + include/pdf/doc/settitle.htm | 28 + include/pdf/doc/settopmargin.htm | 28 + include/pdf/doc/setx.htm | 29 + include/pdf/doc/setxy.htm | 31 + include/pdf/doc/sety.htm | 29 + include/pdf/doc/text.htm | 39 + include/pdf/doc/write.htm | 53 + include/pdf/font/courier.php | 7 + include/pdf/font/helvetica.php | 15 + include/pdf/font/helveticab.php | 15 + include/pdf/font/helveticabi.php | 15 + include/pdf/font/helveticai.php | 15 + include/pdf/font/makefont/cp1250.map | 251 ++ include/pdf/font/makefont/cp1251.map | 255 ++ include/pdf/font/makefont/cp1252.map | 251 ++ include/pdf/font/makefont/cp1253.map | 239 ++ include/pdf/font/makefont/cp1254.map | 249 ++ include/pdf/font/makefont/cp1255.map | 233 ++ include/pdf/font/makefont/cp1257.map | 244 ++ include/pdf/font/makefont/cp1258.map | 247 ++ include/pdf/font/makefont/cp874.map | 225 ++ include/pdf/font/makefont/iso-8859-1.map | 256 ++ include/pdf/font/makefont/iso-8859-11.map | 248 ++ include/pdf/font/makefont/iso-8859-15.map | 256 ++ include/pdf/font/makefont/iso-8859-16.map | 256 ++ include/pdf/font/makefont/iso-8859-2.map | 256 ++ include/pdf/font/makefont/iso-8859-4.map | 256 ++ include/pdf/font/makefont/iso-8859-5.map | 256 ++ include/pdf/font/makefont/iso-8859-7.map | 250 ++ include/pdf/font/makefont/iso-8859-9.map | 256 ++ include/pdf/font/makefont/koi8-r.map | 256 ++ include/pdf/font/makefont/koi8-u.map | 256 ++ include/pdf/font/makefont/makefont.php | 400 ++ include/pdf/font/symbol.php | 15 + include/pdf/font/times.php | 15 + include/pdf/font/timesb.php | 15 + include/pdf/font/timesbi.php | 15 + include/pdf/font/timesi.php | 15 + include/pdf/font/zapfdingbats.php | 15 + include/pdf/fpdf.css | 11 + include/pdf/fpdf.php | 1622 ++++++++ include/pdf/fpdf.php.ie | 1618 ++++++++ include/pdf/histo.htm | 103 + include/pdf/install.txt | 29 + include/pdf/tutorial/20k_c1.txt | 10 + include/pdf/tutorial/20k_c2.txt | 23 + include/pdf/tutorial/calligra.afm | 275 ++ include/pdf/tutorial/calligra.php | 24 + include/pdf/tutorial/calligra.ttf | Bin 0 -> 40120 bytes include/pdf/tutorial/calligra.z | Bin 0 -> 25604 bytes include/pdf/tutorial/countries.txt | 15 + include/pdf/tutorial/index.htm | 18 + include/pdf/tutorial/logo.png | Bin 0 -> 2373 bytes include/pdf/tutorial/logo_pb.png | Bin 0 -> 2656 bytes include/pdf/tutorial/makefont.php | 6 + include/pdf/tutorial/tuto1.htm | 92 + include/pdf/tutorial/tuto1.php | 10 + include/pdf/tutorial/tuto2.htm | 50 + include/pdf/tutorial/tuto2.php | 42 + include/pdf/tutorial/tuto3.htm | 43 + include/pdf/tutorial/tuto3.php | 84 + include/pdf/tutorial/tuto4.htm | 34 + include/pdf/tutorial/tuto4.php | 114 + include/pdf/tutorial/tuto5.htm | 43 + include/pdf/tutorial/tuto5.php | 102 + include/pdf/tutorial/tuto6.htm | 68 + include/pdf/tutorial/tuto6.php | 123 + include/pdf/tutorial/tuto7.htm | 316 ++ include/pdf/tutorial/tuto7.php | 10 + include/person.class.php | 194 + include/pgRS.class.php | 62 + include/raumtyp.class.php | 69 + include/reservierung.class.php | 354 ++ include/student.class.php | 345 ++ include/studiengang.class.php | 152 + include/studiensemester.class.php | 154 + include/stundenplan.class.php | 1567 ++++++++ include/test.php | 9 + include/zeitwunsch.class.php | 96 + index.cis.html | 23 + index.cis2.html | 22 + index.vilesci.html | 17 + locale/contents.rdf | 18 + locale/de-AT/contents.rdf | 18 + locale/de-AT/fas.dtd | 33 + locale/de-AT/tempus.dtd | 33 + locale/en-US/contents.rdf | 18 + locale/en-US/tempus.dtd | 7 + locale/tempus.dtd | 13 + phpinfo.php | 3 + rdf/einheiten.rdf.php | 65 + rdf/fachbereich.rdf.php | 83 + rdf/fas/adressen.rdf.php | 100 + rdf/fas/ausbildung.rdf.php | 90 + rdf/fas/ausbildungssemester.rdf.php | 61 + rdf/fas/ausmass.rdf.php | 61 + rdf/fas/bankverbindungen.rdf.php | 98 + rdf/fas/beschaeftigungsart1.rdf.php | 70 + rdf/fas/db_dml.rdf.php | 1156 ++++++ rdf/fas/email.rdf.php | 86 + rdf/fas/fachbereich.rdf.php | 54 + rdf/fas/funktion_id.rdf.php | 80 + rdf/fas/funktionen.rdf.php | 255 ++ rdf/fas/generate_kuerzel.rdf.php | 155 + rdf/fas/gruppen.rdf.php | 82 + rdf/fas/hauptberuf.rdf.php | 114 + rdf/fas/lehreinheiten.rdf.php | 177 + rdf/fas/lehrform.rdf.php | 53 + rdf/fas/lehrveranstaltungen.rdf.php | 95 + rdf/fas/mitarbeiter.rdf.php | 209 + rdf/fas/mitarbeiterlehreinheiten.rdf.php | 103 + .../mitarbeiterlehreinheitenauswahl.rdf.php | 105 + ...mitarbeiterlehreinheitenfunktionen.rdf.php | 44 + rdf/fas/nation.rdf.php | 56 + rdf/fas/qualifikation.rdf.php | 58 + rdf/fas/raumtyp.rdf.php | 51 + rdf/fas/student-verbaende.rdf.php | 203 + rdf/fas/studiengang.rdf.php | 62 + rdf/fas/studiensemester.rdf.php | 57 + rdf/fas/telefonnummern.rdf.php | 83 + rdf/fas/telefonnummerntyp.rdf.php | 51 + rdf/fas/verwendung.rdf.php | 90 + rdf/fas/wochenrythmus.rdf.php | 63 + rdf/index.html | 100 + rdf/lehrfach.rdf.php | 69 + rdf/lehrform.rdf.php | 55 + rdf/lehrstunde.rdf.php | 130 + rdf/lehrveranstaltung.rdf.php | 214 + rdf/lfvt.rdf.php | 135 + rdf/mitarbeiter.rdf.php | 75 + rdf/ort.rdf.php | 81 + rdf/orte.rdf.php | 80 + rdf/orte2.rdf.php | 75 + rdf/orte_liste.rdf.php | 58 + rdf/raumtyp.rdf.php | 61 + rdf/student-verbaende.rdf.php | 200 + rdf/student.rdf.php | 102 + rdf/studenten.rdf.php | 97 + rdf/studiengang.rdf.php | 66 + rdf/studiensemester.rdf.php | 60 + rdf/xxxstpl-lehrstunde.rdf.php | 101 + skin/cis.css | 273 ++ skin/fas.css | 43 + skin/images/1st_floor.gif | Bin 0 -> 27113 bytes skin/images/2nd_floor.gif | Bin 0 -> 29158 bytes skin/images/3rd_floor.gif | Bin 0 -> 30010 bytes skin/images/4th_floor.gif | Bin 0 -> 37994 bytes skin/images/5th_floor.gif | Bin 0 -> 43880 bytes skin/images/6th_floor.gif | Bin 0 -> 38990 bytes skin/images/DeleteIcon.png | Bin 0 -> 1278 bytes skin/images/ExcelIcon.png | Bin 0 -> 529 bytes skin/images/FAS.ico | Bin 0 -> 15086 bytes skin/images/Hauptmenue.png | Bin 0 -> 91688 bytes skin/images/NeuDokument.png | Bin 0 -> 175 bytes skin/images/OutlookImpDuplikate.png | Bin 0 -> 17193 bytes skin/images/OutlookImpImport.png | Bin 0 -> 20333 bytes skin/images/OutlookImpKalender.png | Bin 0 -> 22023 bytes skin/images/OutlookImpKomma.png | Bin 0 -> 19416 bytes skin/images/OutlookImpMenu.gif | Bin 0 -> 61524 bytes skin/images/OutlookImpSmbol.gif | Bin 0 -> 137867 bytes skin/images/Outlookimport.png | Bin 0 -> 208187 bytes skin/images/Saalplan_mit_Legende.png | Bin 0 -> 336300 bytes skin/images/TWLogo_klein.gif | Bin 0 -> 2874 bytes skin/images/TWLogo_klein.jpg | Bin 0 -> 7420 bytes skin/images/TWLogo_klein.png | Bin 0 -> 185381 bytes skin/images/TW_Logo_klein.jpg | Bin 0 -> 40320 bytes skin/images/Tempus.ico | Bin 0 -> 3638 bytes skin/images/TempusGruen.ico | Bin 0 -> 26694 bytes skin/images/background_linie.jpg | Bin 0 -> 399 bytes skin/images/background_main.jpg | Bin 0 -> 641 bytes skin/images/bg.gif | Bin 0 -> 369 bytes skin/images/bg_.gif | Bin 0 -> 871 bytes skin/images/bg_anwesenheit.gif | Bin 0 -> 5006 bytes skin/images/bg_cut.jpg | Bin 0 -> 9574 bytes skin/images/bgq.gif | Bin 0 -> 2750 bytes skin/images/blank.gif | Bin 0 -> 43 bytes skin/images/bugtracking-01.jpg | Bin 0 -> 21089 bytes skin/images/bugtracking-02.jpg | Bin 0 -> 29333 bytes skin/images/bugtracking-03.jpg | Bin 0 -> 48052 bytes skin/images/bugtracking-04.jpg | Bin 0 -> 22543 bytes skin/images/bugtracking-05.jpg | Bin 0 -> 35471 bytes skin/images/bugtracking-06.jpg | Bin 0 -> 36597 bytes skin/images/button_dl.jpg | Bin 0 -> 1765 bytes skin/images/button_fb.jpg | Bin 0 -> 1860 bytes skin/images/button_i.jpg | Bin 0 -> 1003 bytes skin/images/button_kt.jpg | Bin 0 -> 1775 bytes skin/images/button_lb.jpg | Bin 0 -> 1898 bytes skin/images/button_lv-info.jpg | Bin 0 -> 2007 bytes skin/images/button_lv.jpg | Bin 0 -> 1905 bytes skin/images/button_ng.jpg | Bin 0 -> 2101 bytes skin/images/button_semplan.jpg | Bin 0 -> 1847 bytes skin/images/button_termplan.jpg | Bin 0 -> 1898 bytes skin/images/button_test.jpg | Bin 0 -> 1857 bytes skin/images/button_ul.jpg | Bin 0 -> 1700 bytes skin/images/cdmenue01.JPG | Bin 0 -> 40017 bytes skin/images/crossline_l.gif | Bin 0 -> 86 bytes skin/images/crossline_r.gif | Bin 0 -> 131 bytes skin/images/csv-symbol.gif | Bin 0 -> 1334 bytes skin/images/csv.gif | Bin 0 -> 843 bytes skin/images/csv.ico | Bin 0 -> 4846 bytes skin/images/csv.png | Bin 0 -> 3777 bytes skin/images/dotpic.gif | Bin 0 -> 365 bytes skin/images/drucken.png | Bin 0 -> 1215 bytes skin/images/dummy.gif | Bin 0 -> 43 bytes skin/images/einstellungen01.JPG | Bin 0 -> 42405 bytes skin/images/empty_picture.jpg | Bin 0 -> 47935 bytes skin/images/entry.gif | Bin 0 -> 35 bytes skin/images/excel.gif | Bin 0 -> 158 bytes skin/images/false.gif | Bin 0 -> 120 bytes skin/images/fentry.gif | Bin 0 -> 35 bytes skin/images/file.gif | Bin 0 -> 196 bytes skin/images/flagge-aut.gif | Bin 0 -> 1785 bytes skin/images/flagge-eng.gif | Bin 0 -> 1285 bytes skin/images/folder.gif | Bin 0 -> 1167 bytes skin/images/folderup.gif | Bin 0 -> 169 bytes skin/images/gline.gif | Bin 0 -> 1004 bytes skin/images/green_point.gif | Bin 0 -> 896 bytes skin/images/haken.gif | Bin 0 -> 60 bytes skin/images/header_line.gif | Bin 0 -> 1004 bytes skin/images/hline.gif | Bin 0 -> 35 bytes skin/images/hline_tl.gif | Bin 0 -> 147 bytes skin/images/hlinie_tr.gif | Bin 0 -> 101 bytes skin/images/icon_delete.gif | Bin 0 -> 893 bytes skin/images/icon_voransicht.gif | Bin 0 -> 135 bytes skin/images/image_legend0.gif | Bin 0 -> 855 bytes skin/images/image_map.gif | Bin 0 -> 33919 bytes skin/images/image_overview.gif | Bin 0 -> 17823 bytes skin/images/ko.gif | Bin 0 -> 328 bytes skin/images/left.gif | Bin 0 -> 96 bytes skin/images/left.png | Bin 0 -> 1164 bytes skin/images/left_end_blue.jpg | Bin 0 -> 1403 bytes skin/images/left_end_green.jpg | Bin 0 -> 1203 bytes skin/images/login.gif | Bin 0 -> 345 bytes skin/images/logout.gif | Bin 0 -> 562 bytes skin/images/lvaMulti.png | Bin 0 -> 475 bytes skin/images/lvaMultiDel.png | Bin 0 -> 577 bytes skin/images/lvaSingle.png | Bin 0 -> 391 bytes skin/images/lvaSingleDel.png | Bin 0 -> 451 bytes skin/images/mailverteiler.jpg | Bin 0 -> 150463 bytes .../medienkasten_mikrofonempfaenger.JPG | Bin 0 -> 48790 bytes .../medienkasten_mikrofonempfaenger01.JPG | Bin 0 -> 50172 bytes skin/images/menu_bg.jpg | Bin 0 -> 4089 bytes skin/images/menu_item.gif | Bin 0 -> 61 bytes skin/images/moreleft.gif | Bin 0 -> 883 bytes skin/images/moreleft.png | Bin 0 -> 1181 bytes skin/images/moremoreleft.png | Bin 0 -> 1179 bytes skin/images/moremoreright.png | Bin 0 -> 1174 bytes skin/images/moreright.gif | Bin 0 -> 882 bytes skin/images/moreright.png | Bin 0 -> 1178 bytes skin/images/nopic.gif | Bin 0 -> 2772 bytes skin/images/ok.gif | Bin 0 -> 341 bytes skin/images/open.gif | Bin 0 -> 85 bytes skin/images/org-2004-17-A3.jpg | Bin 0 -> 544649 bytes skin/images/org-2005-03-A5.jpg | Bin 0 -> 518743 bytes skin/images/org-2005-03-A6.jpg | Bin 0 -> 471617 bytes skin/images/outlook.gif | Bin 0 -> 1079 bytes skin/images/outlook.ico | Bin 0 -> 8478 bytes skin/images/outlook.png | Bin 0 -> 1969 bytes skin/images/p.gif | Bin 0 -> 122 bytes skin/images/pc_steckfeld_audio.JPG | Bin 0 -> 13875 bytes skin/images/pdf.gif | Bin 0 -> 1350 bytes skin/images/pdf.ico | Bin 0 -> 5222 bytes skin/images/pdfpic.gif | Bin 0 -> 286 bytes skin/images/person.gif | Bin 0 -> 1151 bytes skin/images/picpic.gif | Bin 0 -> 324 bytes skin/images/pptpic.gif | Bin 0 -> 1066 bytes skin/images/qm.gif | Bin 0 -> 4123 bytes skin/images/red_point.gif | Bin 0 -> 895 bytes skin/images/refresh.png | Bin 0 -> 316 bytes skin/images/right.gif | Bin 0 -> 96 bytes skin/images/right.png | Bin 0 -> 1164 bytes skin/images/right_end_blue.jpg | Bin 0 -> 1362 bytes skin/images/right_end_green.jpg | Bin 0 -> 1161 bytes skin/images/room_background_blue.jpg | Bin 0 -> 496 bytes skin/images/room_background_green.jpg | Bin 0 -> 478 bytes skin/images/seperator.gif | Bin 0 -> 61 bytes skin/images/stdpl_main.jpg | Bin 0 -> 43446 bytes skin/images/stdplan_menue.gif | Bin 0 -> 45764 bytes skin/images/stdplan_menue_pfeile.gif | Bin 0 -> 42215 bytes skin/images/stdplan_ort_lektor.gif | Bin 0 -> 123513 bytes skin/images/stdplan_ort_lektor_pfeile.gif | Bin 0 -> 118363 bytes skin/images/stdplan_pers_student.gif | Bin 0 -> 107696 bytes skin/images/steckfeld01.JPG | Bin 0 -> 48289 bytes skin/images/steckfeld_audio.JPG | Bin 0 -> 42570 bytes skin/images/steckfeld_vga_laptop.JPG | Bin 0 -> 49885 bytes skin/images/steckfeld_vga_visualizer.JPG | Bin 0 -> 49760 bytes skin/images/sunbird.png | Bin 0 -> 5676 bytes skin/images/technikum_logo.gif | Bin 0 -> 3584 bytes skin/images/texpic.jpg | Bin 0 -> 585 bytes skin/images/ton.JPG | Bin 0 -> 40936 bytes skin/images/ton_mikrofon_ea.JPG | Bin 0 -> 43891 bytes skin/images/true.gif | Bin 0 -> 264 bytes skin/images/tw_logo.gif | Bin 0 -> 3584 bytes skin/images/tw_logo.jpg | Bin 0 -> 11132 bytes skin/images/tw_logo_01.jpg | Bin 0 -> 40320 bytes skin/images/tw_logo_02.jpg | Bin 0 -> 7861 bytes skin/images/upload.jpg | Bin 0 -> 75423 bytes skin/images/vcal_v1.png | Bin 0 -> 1356 bytes skin/images/vcal_v2.png | Bin 0 -> 1351 bytes skin/images/vcrmenue01.JPG | Bin 0 -> 42876 bytes skin/images/video_dvd01.JPG | Bin 0 -> 48761 bytes skin/images/video_dvd02.JPG | Bin 0 -> 48229 bytes skin/images/video_dvd03.JPG | Bin 0 -> 48534 bytes skin/images/visualizer_lampe.JPG | Bin 0 -> 63819 bytes skin/images/visualizer_light.JPG | Bin 0 -> 63451 bytes skin/images/visualizer_power.JPG | Bin 0 -> 63607 bytes skin/images/visualizer_zoom.JPG | Bin 0 -> 63702 bytes skin/images/vline.gif | Bin 0 -> 308 bytes skin/images/web_s_org-2004-17-A3.jpg | Bin 0 -> 62126 bytes skin/images/web_s_org-2005-03-A5.jpg | Bin 0 -> 55611 bytes skin/images/web_s_org-2005-03-A6.jpg | Bin 0 -> 55043 bytes skin/images/website.gif | Bin 0 -> 1190 bytes skin/images/website.ico | Bin 0 -> 25214 bytes skin/images/website.png | Bin 0 -> 4858 bytes skin/images/website3D.gif | Bin 0 -> 1190 bytes skin/images/winscp2.jpg | Bin 0 -> 51666 bytes skin/images/winscp2_dir_com.jpg | Bin 0 -> 74024 bytes skin/images/winscp2_dir_exp.jpg | Bin 0 -> 30533 bytes skin/images/winscp_browse.jpg | Bin 0 -> 45031 bytes skin/images/winscp_login.jpg | Bin 0 -> 34918 bytes skin/images/xlspic.gif | Bin 0 -> 252 bytes skin/images/xml.png | Bin 0 -> 3559 bytes skin/images/zippic.jpg | Bin 0 -> 3875 bytes skin/tempus.css | 48 + skin/vilesci.css | 307 ++ vilesci/.htaccess | 36 + vilesci/index.html | 15 + vilesci/kommunikation/kontakt.php | 127 + vilesci/kommunikation/mlists/index.html | 19 + .../mlists/lektor_mlists_create.php | 45 + vilesci/kommunikation/mlists/mlists_copy.php | 31 + .../kommunikation/mlists/mlists_create.php | 92 + vilesci/kommunikation/mlists/mlists_det.php | 99 + .../kommunikation/mlists/mlists_generate.php | 217 + vilesci/kommunikation/mlists/mlists_index.php | 105 + .../mlists/student_lists_copy.php | 32 + .../mlists/student_lists_create.php | 89 + .../kommunikation/studenten_liste_export.php | 43 + vilesci/left.php | 195 + vilesci/main.php | 21 + vilesci/personen/funktion.php | 74 + vilesci/personen/funktion_det.php | 255 ++ vilesci/personen/index.html | 23 + vilesci/personen/lektor_edit.php | 157 + vilesci/personen/lektor_edit_save.php | 29 + vilesci/personen/lektor_new.php | 41 + vilesci/personen/lektor_new_save.php | 23 + vilesci/personen/lektor_uebersicht.php | 105 + .../personen/lektor_uebersicht_Anktest.php | 85 + .../personen/lektor_uebersicht_ankertest.php | 79 + vilesci/personen/lektorzuteilung_edit.php | 144 + vilesci/personen/modulzuteilung_edit.php | 122 + vilesci/personen/search_go.php | 72 + vilesci/personen/student_edit.php | 203 + vilesci/personen/student_neu_save.php | 107 + vilesci/personen/studenten_uebersicht.php | 81 + vilesci/personen/studenten_uebersicht_det.php | 71 + vilesci/personen/zeitwunsch.php | 196 + vilesci/personen/zeitwunsch_save.php | 56 + vilesci/stundenplan/check/index.html | 12 + vilesci/stundenplan/check/res_check.php | 104 + .../stundenplan/check/res_check_delete.php | 30 + vilesci/stundenplan/check/res_check_det.php | 49 + vilesci/stundenplan/check/res_check_mail.php | 53 + vilesci/stundenplan/check/stdplan_check.php | 46 + .../check/stdplan_check_delete.php | 31 + .../stundenplan/check/stdplan_check_det.php | 46 + vilesci/stundenplan/einheit_det.php | 88 + vilesci/stundenplan/einheit_import.php | 63 + vilesci/stundenplan/einheit_menu.php | 219 ++ vilesci/stundenplan/export/index.html | 14 + vilesci/stundenplan/export/lektoren.php | 31 + vilesci/stundenplan/export/raum.php | 31 + vilesci/stundenplan/export/studenten.php | 31 + vilesci/stundenplan/export/zeitwunsch.php | 31 + vilesci/stundenplan/import/index.html | 23 + vilesci/stundenplan/import/stdplan_import.php | 57 + .../import/stdplan_import_check_ID.php | 169 + .../import/stdplan_import_sendmail.php | 103 + .../import/stdplan_import_takeover.php | 56 + .../import/stdplan_import_takeover_modul.php | 54 + .../stundenplan/import/wochendatum.inc.php | 46 + vilesci/stundenplan/lehrfach.php | 284 ++ vilesci/stundenplan/lehrfach/wartung.php | 232 ++ vilesci/stundenplan/lehrfach_verteilung.php | 214 + vilesci/stundenplan/lv_verteilung.php | 61 + vilesci/stundenplan/lv_verteilung/lv_edit.php | 340 ++ .../lv_verteilung/lv_verteilung.php | 249 ++ vilesci/stundenplan/modulplan_insert.php | 234 ++ vilesci/stundenplan/ort.php | 10 + vilesci/stundenplan/ort_edit_save.php | 39 + vilesci/stundenplan/stdplan_clean_check.php | 74 + vilesci/stundenplan/stdplan_clean_go.php | 54 + vilesci/stundenplan/stdplan_delete.php | 231 ++ vilesci/stundenplan/stdplan_insert.php | 347 ++ vilesci/stundenplan/stundenplan_info.html | 10 + vilesci/stundenplan/zeitwuensche.php | 108 + wap/index.php | 10 + 570 files changed, 69005 insertions(+) create mode 100644 .htaccess create mode 100644 admin/sync/sync_fas_exstd.php create mode 100644 admin/sync/sync_fas_lkt.php create mode 100644 admin/sync/sync_fas_lkt_fault.php create mode 100644 admin/sync/sync_fas_lva.php create mode 100644 admin/sync/sync_fas_std.php create mode 100644 admin/sync/sync_fas_std_fault.php create mode 100644 admin/sync/sync_feedback.php create mode 100644 admin/sync/sync_stpldev_stpl.php create mode 100644 admin/sync/sync_vilesci_stg.php create mode 100644 content/DragAndDrop.js create mode 100644 content/Ideen.php create mode 100644 content/dragboard.js create mode 100644 content/dragboard.js.php create mode 100644 content/einheiten.rdf.php create mode 100644 content/excel.php create mode 100644 content/fachbereich.rdf.php create mode 100644 content/fas.js.php create mode 100644 content/fas.xul.php create mode 100644 content/fas_bis_personal.php create mode 100644 content/fasoverlay.js.php create mode 100644 content/fasoverlay.xul.php create mode 100644 content/lehreinheitenDragnDrop.js.php create mode 100644 content/lehreinheitendetailoverlay.xul.php create mode 100644 content/lehreinheitenmitarbeiterdialog.js.php create mode 100644 content/lehreinheitenmitarbeiterdialog.xul.php create mode 100644 content/lehreinheitenneudialog.js.php create mode 100644 content/lehreinheitenneudialog.xul.php create mode 100644 content/lehreinheitenoverlay.js.php create mode 100644 content/lehreinheitenoverlay.xul.php create mode 100644 content/lehrfach.rdf.php create mode 100644 content/lehrstunde.rdf.php create mode 100644 content/lehrveranstaltung.rdf.php create mode 100644 content/lfvt.css create mode 100644 content/lfvt.rdf.php create mode 100644 content/lfvtCUD.php create mode 100644 content/lfvtbinding.xml.php create mode 100644 content/lfvtoverlay.js create mode 100644 content/lfvtoverlay.js.php create mode 100644 content/lfvtoverlay.xul.php create mode 100644 content/mitarbeiter.rdf.php create mode 100644 content/mitarbeiteradressendialog.js.php create mode 100644 content/mitarbeiteradressendialog.xul.php create mode 100644 content/mitarbeiterbankverbindungdialog.js.php create mode 100644 content/mitarbeiterbankverbindungdialog.xul.php create mode 100644 content/mitarbeiterdetailoverlay.xul.php create mode 100644 content/mitarbeiteremaildialog.js.php create mode 100644 content/mitarbeiteremaildialog.xul.php create mode 100644 content/mitarbeiterfunktiondialog.js.php create mode 100644 content/mitarbeiterfunktiondialog.xul.php create mode 100644 content/mitarbeiteroverlay.js.php create mode 100644 content/mitarbeiteroverlay.xul.php create mode 100644 content/mitarbeitertelefonnummerdialog.js.php create mode 100644 content/mitarbeitertelefonnummerdialog.xul.php create mode 100644 content/nextUNR.php create mode 100644 content/orte.rdf.php create mode 100644 content/orte2.rdf.php create mode 100644 content/orte_liste.rdf.php create mode 100644 content/phpRequest.js.php create mode 100644 content/raumtyp.rdf.php create mode 100644 content/stpl-details-overlay.xul.php create mode 100644 content/stpl-semester-overlay.js.php create mode 100644 content/stpl-semester-overlay.xul.php create mode 100644 content/stpl-week-overlay.js.php create mode 100644 content/stpl-week-overlay.xul.php create mode 100644 content/student-verbaende.rdf.php create mode 100644 content/studenten.js create mode 100644 content/studenten.rdf.php create mode 100644 content/studentenoverlay.xul.php create mode 100644 content/studiengang.rdf.php create mode 100644 content/studiensemester.rdf.php create mode 100644 content/tempus.js.php create mode 100644 content/tempus.xul.php create mode 100644 content/tempusoverlay.js.php create mode 100644 content/tempusoverlay.xul.php create mode 100644 content/timetable-week.xul.php create mode 100644 content/xxxstpl-lehrstunde.rdf.php create mode 100644 favicon.ico create mode 100644 include/Authorization.class.php create mode 100644 include/Excel/BIFFwriter.php create mode 100644 include/Excel/File.php create mode 100644 include/Excel/Format.php create mode 100644 include/Excel/OLE.php create mode 100644 include/Excel/PEAR.php create mode 100644 include/Excel/PPS.php create mode 100644 include/Excel/Parser.php create mode 100644 include/Excel/Root.php create mode 100644 include/Excel/Validator.php create mode 100644 include/Excel/Workbook.php create mode 100644 include/Excel/Worksheet.php create mode 100644 include/Excel/Writer.php create mode 100644 include/berechtigung.class.php create mode 100644 include/cis_functions.inc.php create mode 100644 include/ects_sync.class.php create mode 100644 include/einheit.class.php create mode 100644 include/fachbereich.class.php create mode 100644 include/fas/adresse.class.php create mode 100644 include/fas/ausbildungssemester.class.php create mode 100644 include/fas/bankverbindung.class.php create mode 100644 include/fas/benutzer.class.php create mode 100644 include/fas/email.class.php create mode 100644 include/fas/fachbereich.class.php create mode 100644 include/fas/functions.inc.php create mode 100644 include/fas/funktion.class.php create mode 100644 include/fas/gruppe.class.php create mode 100644 include/fas/lehreinheit.class.php create mode 100644 include/fas/lehrform.class.php create mode 100644 include/fas/lehrfunktion.class.php create mode 100644 include/fas/lehrveranstaltung.class.php create mode 100644 include/fas/mitarbeiter.class.php create mode 100644 include/fas/nation.class.php create mode 100644 include/fas/person.class.php create mode 100644 include/fas/raumtyp.class.php create mode 100644 include/fas/studiengang.class.php create mode 100644 include/fas/studiensemester.class.php create mode 100644 include/fas/telefonnummer.class.php create mode 100644 include/ferien.class.php create mode 100644 include/functions.inc.php create mode 100644 include/funktion.class.php create mode 100644 include/globals.inc.php create mode 100644 include/lehrfach.class.php create mode 100644 include/lehrform.class.php create mode 100644 include/lehrstunde.class.php create mode 100644 include/lehrveranstaltung.class.php create mode 100644 include/lfvt.class.php create mode 100644 include/lv_info.class.php create mode 100644 include/lv_verteilung.class.php create mode 100644 include/mailgrp.class.php create mode 100644 include/mitarbeiter.class.php create mode 100644 include/pdf.inc.php create mode 100644 include/pdf/FAQ.htm create mode 100644 include/pdf/doc/acceptpagebreak.htm create mode 100644 include/pdf/doc/addfont.htm create mode 100644 include/pdf/doc/addlink.htm create mode 100644 include/pdf/doc/addpage.htm create mode 100644 include/pdf/doc/aliasnbpages.htm create mode 100644 include/pdf/doc/cell.htm create mode 100644 include/pdf/doc/close.htm create mode 100644 include/pdf/doc/error.htm create mode 100644 include/pdf/doc/footer.htm create mode 100644 include/pdf/doc/fpdf.htm create mode 100644 include/pdf/doc/getstringwidth.htm create mode 100644 include/pdf/doc/getx.htm create mode 100644 include/pdf/doc/gety.htm create mode 100644 include/pdf/doc/header.htm create mode 100644 include/pdf/doc/image.htm create mode 100644 include/pdf/doc/index.htm create mode 100644 include/pdf/doc/line.htm create mode 100644 include/pdf/doc/link.htm create mode 100644 include/pdf/doc/ln.htm create mode 100644 include/pdf/doc/multicell.htm create mode 100644 include/pdf/doc/open.htm create mode 100644 include/pdf/doc/output.htm create mode 100644 include/pdf/doc/pageno.htm create mode 100644 include/pdf/doc/rect.htm create mode 100644 include/pdf/doc/setauthor.htm create mode 100644 include/pdf/doc/setautopagebreak.htm create mode 100644 include/pdf/doc/setcompression.htm create mode 100644 include/pdf/doc/setcreator.htm create mode 100644 include/pdf/doc/setdisplaymode.htm create mode 100644 include/pdf/doc/setdrawcolor.htm create mode 100644 include/pdf/doc/setfillcolor.htm create mode 100644 include/pdf/doc/setfont.htm create mode 100644 include/pdf/doc/setfontsize.htm create mode 100644 include/pdf/doc/setkeywords.htm create mode 100644 include/pdf/doc/setleftmargin.htm create mode 100644 include/pdf/doc/setlinewidth.htm create mode 100644 include/pdf/doc/setlink.htm create mode 100644 include/pdf/doc/setmargins.htm create mode 100644 include/pdf/doc/setrightmargin.htm create mode 100644 include/pdf/doc/setsubject.htm create mode 100644 include/pdf/doc/settextcolor.htm create mode 100644 include/pdf/doc/settitle.htm create mode 100644 include/pdf/doc/settopmargin.htm create mode 100644 include/pdf/doc/setx.htm create mode 100644 include/pdf/doc/setxy.htm create mode 100644 include/pdf/doc/sety.htm create mode 100644 include/pdf/doc/text.htm create mode 100644 include/pdf/doc/write.htm create mode 100644 include/pdf/font/courier.php create mode 100644 include/pdf/font/helvetica.php create mode 100644 include/pdf/font/helveticab.php create mode 100644 include/pdf/font/helveticabi.php create mode 100644 include/pdf/font/helveticai.php create mode 100644 include/pdf/font/makefont/cp1250.map create mode 100644 include/pdf/font/makefont/cp1251.map create mode 100644 include/pdf/font/makefont/cp1252.map create mode 100644 include/pdf/font/makefont/cp1253.map create mode 100644 include/pdf/font/makefont/cp1254.map create mode 100644 include/pdf/font/makefont/cp1255.map create mode 100644 include/pdf/font/makefont/cp1257.map create mode 100644 include/pdf/font/makefont/cp1258.map create mode 100644 include/pdf/font/makefont/cp874.map create mode 100644 include/pdf/font/makefont/iso-8859-1.map create mode 100644 include/pdf/font/makefont/iso-8859-11.map create mode 100644 include/pdf/font/makefont/iso-8859-15.map create mode 100644 include/pdf/font/makefont/iso-8859-16.map create mode 100644 include/pdf/font/makefont/iso-8859-2.map create mode 100644 include/pdf/font/makefont/iso-8859-4.map create mode 100644 include/pdf/font/makefont/iso-8859-5.map create mode 100644 include/pdf/font/makefont/iso-8859-7.map create mode 100644 include/pdf/font/makefont/iso-8859-9.map create mode 100644 include/pdf/font/makefont/koi8-r.map create mode 100644 include/pdf/font/makefont/koi8-u.map create mode 100644 include/pdf/font/makefont/makefont.php create mode 100644 include/pdf/font/symbol.php create mode 100644 include/pdf/font/times.php create mode 100644 include/pdf/font/timesb.php create mode 100644 include/pdf/font/timesbi.php create mode 100644 include/pdf/font/timesi.php create mode 100644 include/pdf/font/zapfdingbats.php create mode 100644 include/pdf/fpdf.css create mode 100644 include/pdf/fpdf.php create mode 100644 include/pdf/fpdf.php.ie create mode 100644 include/pdf/histo.htm create mode 100644 include/pdf/install.txt create mode 100644 include/pdf/tutorial/20k_c1.txt create mode 100644 include/pdf/tutorial/20k_c2.txt create mode 100644 include/pdf/tutorial/calligra.afm create mode 100644 include/pdf/tutorial/calligra.php create mode 100644 include/pdf/tutorial/calligra.ttf create mode 100644 include/pdf/tutorial/calligra.z create mode 100644 include/pdf/tutorial/countries.txt create mode 100644 include/pdf/tutorial/index.htm create mode 100644 include/pdf/tutorial/logo.png create mode 100644 include/pdf/tutorial/logo_pb.png create mode 100644 include/pdf/tutorial/makefont.php create mode 100644 include/pdf/tutorial/tuto1.htm create mode 100644 include/pdf/tutorial/tuto1.php create mode 100644 include/pdf/tutorial/tuto2.htm create mode 100644 include/pdf/tutorial/tuto2.php create mode 100644 include/pdf/tutorial/tuto3.htm create mode 100644 include/pdf/tutorial/tuto3.php create mode 100644 include/pdf/tutorial/tuto4.htm create mode 100644 include/pdf/tutorial/tuto4.php create mode 100644 include/pdf/tutorial/tuto5.htm create mode 100644 include/pdf/tutorial/tuto5.php create mode 100644 include/pdf/tutorial/tuto6.htm create mode 100644 include/pdf/tutorial/tuto6.php create mode 100644 include/pdf/tutorial/tuto7.htm create mode 100644 include/pdf/tutorial/tuto7.php create mode 100644 include/person.class.php create mode 100644 include/pgRS.class.php create mode 100644 include/raumtyp.class.php create mode 100644 include/reservierung.class.php create mode 100644 include/student.class.php create mode 100644 include/studiengang.class.php create mode 100644 include/studiensemester.class.php create mode 100644 include/stundenplan.class.php create mode 100644 include/test.php create mode 100644 include/zeitwunsch.class.php create mode 100644 index.cis.html create mode 100644 index.cis2.html create mode 100644 index.vilesci.html create mode 100644 locale/contents.rdf create mode 100644 locale/de-AT/contents.rdf create mode 100644 locale/de-AT/fas.dtd create mode 100644 locale/de-AT/tempus.dtd create mode 100644 locale/en-US/contents.rdf create mode 100644 locale/en-US/tempus.dtd create mode 100644 locale/tempus.dtd create mode 100644 phpinfo.php create mode 100644 rdf/einheiten.rdf.php create mode 100644 rdf/fachbereich.rdf.php create mode 100644 rdf/fas/adressen.rdf.php create mode 100644 rdf/fas/ausbildung.rdf.php create mode 100644 rdf/fas/ausbildungssemester.rdf.php create mode 100644 rdf/fas/ausmass.rdf.php create mode 100644 rdf/fas/bankverbindungen.rdf.php create mode 100644 rdf/fas/beschaeftigungsart1.rdf.php create mode 100644 rdf/fas/db_dml.rdf.php create mode 100644 rdf/fas/email.rdf.php create mode 100644 rdf/fas/fachbereich.rdf.php create mode 100644 rdf/fas/funktion_id.rdf.php create mode 100644 rdf/fas/funktionen.rdf.php create mode 100644 rdf/fas/generate_kuerzel.rdf.php create mode 100644 rdf/fas/gruppen.rdf.php create mode 100644 rdf/fas/hauptberuf.rdf.php create mode 100644 rdf/fas/lehreinheiten.rdf.php create mode 100644 rdf/fas/lehrform.rdf.php create mode 100644 rdf/fas/lehrveranstaltungen.rdf.php create mode 100644 rdf/fas/mitarbeiter.rdf.php create mode 100644 rdf/fas/mitarbeiterlehreinheiten.rdf.php create mode 100644 rdf/fas/mitarbeiterlehreinheitenauswahl.rdf.php create mode 100644 rdf/fas/mitarbeiterlehreinheitenfunktionen.rdf.php create mode 100644 rdf/fas/nation.rdf.php create mode 100644 rdf/fas/qualifikation.rdf.php create mode 100644 rdf/fas/raumtyp.rdf.php create mode 100644 rdf/fas/student-verbaende.rdf.php create mode 100644 rdf/fas/studiengang.rdf.php create mode 100644 rdf/fas/studiensemester.rdf.php create mode 100644 rdf/fas/telefonnummern.rdf.php create mode 100644 rdf/fas/telefonnummerntyp.rdf.php create mode 100644 rdf/fas/verwendung.rdf.php create mode 100644 rdf/fas/wochenrythmus.rdf.php create mode 100644 rdf/index.html create mode 100644 rdf/lehrfach.rdf.php create mode 100644 rdf/lehrform.rdf.php create mode 100644 rdf/lehrstunde.rdf.php create mode 100644 rdf/lehrveranstaltung.rdf.php create mode 100644 rdf/lfvt.rdf.php create mode 100644 rdf/mitarbeiter.rdf.php create mode 100644 rdf/ort.rdf.php create mode 100644 rdf/orte.rdf.php create mode 100644 rdf/orte2.rdf.php create mode 100644 rdf/orte_liste.rdf.php create mode 100644 rdf/raumtyp.rdf.php create mode 100644 rdf/student-verbaende.rdf.php create mode 100644 rdf/student.rdf.php create mode 100644 rdf/studenten.rdf.php create mode 100644 rdf/studiengang.rdf.php create mode 100644 rdf/studiensemester.rdf.php create mode 100644 rdf/xxxstpl-lehrstunde.rdf.php create mode 100644 skin/cis.css create mode 100644 skin/fas.css create mode 100644 skin/images/1st_floor.gif create mode 100644 skin/images/2nd_floor.gif create mode 100644 skin/images/3rd_floor.gif create mode 100644 skin/images/4th_floor.gif create mode 100644 skin/images/5th_floor.gif create mode 100644 skin/images/6th_floor.gif create mode 100644 skin/images/DeleteIcon.png create mode 100644 skin/images/ExcelIcon.png create mode 100644 skin/images/FAS.ico create mode 100644 skin/images/Hauptmenue.png create mode 100644 skin/images/NeuDokument.png create mode 100644 skin/images/OutlookImpDuplikate.png create mode 100644 skin/images/OutlookImpImport.png create mode 100644 skin/images/OutlookImpKalender.png create mode 100644 skin/images/OutlookImpKomma.png create mode 100644 skin/images/OutlookImpMenu.gif create mode 100644 skin/images/OutlookImpSmbol.gif create mode 100644 skin/images/Outlookimport.png create mode 100644 skin/images/Saalplan_mit_Legende.png create mode 100644 skin/images/TWLogo_klein.gif create mode 100644 skin/images/TWLogo_klein.jpg create mode 100644 skin/images/TWLogo_klein.png create mode 100644 skin/images/TW_Logo_klein.jpg create mode 100644 skin/images/Tempus.ico create mode 100644 skin/images/TempusGruen.ico create mode 100644 skin/images/background_linie.jpg create mode 100644 skin/images/background_main.jpg create mode 100644 skin/images/bg.gif create mode 100644 skin/images/bg_.gif create mode 100644 skin/images/bg_anwesenheit.gif create mode 100644 skin/images/bg_cut.jpg create mode 100644 skin/images/bgq.gif create mode 100644 skin/images/blank.gif create mode 100644 skin/images/bugtracking-01.jpg create mode 100644 skin/images/bugtracking-02.jpg create mode 100644 skin/images/bugtracking-03.jpg create mode 100644 skin/images/bugtracking-04.jpg create mode 100644 skin/images/bugtracking-05.jpg create mode 100644 skin/images/bugtracking-06.jpg create mode 100644 skin/images/button_dl.jpg create mode 100644 skin/images/button_fb.jpg create mode 100644 skin/images/button_i.jpg create mode 100644 skin/images/button_kt.jpg create mode 100644 skin/images/button_lb.jpg create mode 100644 skin/images/button_lv-info.jpg create mode 100644 skin/images/button_lv.jpg create mode 100644 skin/images/button_ng.jpg create mode 100644 skin/images/button_semplan.jpg create mode 100644 skin/images/button_termplan.jpg create mode 100644 skin/images/button_test.jpg create mode 100644 skin/images/button_ul.jpg create mode 100644 skin/images/cdmenue01.JPG create mode 100644 skin/images/crossline_l.gif create mode 100644 skin/images/crossline_r.gif create mode 100644 skin/images/csv-symbol.gif create mode 100644 skin/images/csv.gif create mode 100644 skin/images/csv.ico create mode 100644 skin/images/csv.png create mode 100644 skin/images/dotpic.gif create mode 100644 skin/images/drucken.png create mode 100644 skin/images/dummy.gif create mode 100644 skin/images/einstellungen01.JPG create mode 100644 skin/images/empty_picture.jpg create mode 100644 skin/images/entry.gif create mode 100644 skin/images/excel.gif create mode 100644 skin/images/false.gif create mode 100644 skin/images/fentry.gif create mode 100644 skin/images/file.gif create mode 100644 skin/images/flagge-aut.gif create mode 100644 skin/images/flagge-eng.gif create mode 100644 skin/images/folder.gif create mode 100644 skin/images/folderup.gif create mode 100644 skin/images/gline.gif create mode 100644 skin/images/green_point.gif create mode 100644 skin/images/haken.gif create mode 100644 skin/images/header_line.gif create mode 100644 skin/images/hline.gif create mode 100644 skin/images/hline_tl.gif create mode 100644 skin/images/hlinie_tr.gif create mode 100644 skin/images/icon_delete.gif create mode 100644 skin/images/icon_voransicht.gif create mode 100644 skin/images/image_legend0.gif create mode 100644 skin/images/image_map.gif create mode 100644 skin/images/image_overview.gif create mode 100644 skin/images/ko.gif create mode 100644 skin/images/left.gif create mode 100644 skin/images/left.png create mode 100644 skin/images/left_end_blue.jpg create mode 100644 skin/images/left_end_green.jpg create mode 100644 skin/images/login.gif create mode 100644 skin/images/logout.gif create mode 100644 skin/images/lvaMulti.png create mode 100644 skin/images/lvaMultiDel.png create mode 100644 skin/images/lvaSingle.png create mode 100644 skin/images/lvaSingleDel.png create mode 100644 skin/images/mailverteiler.jpg create mode 100644 skin/images/medienkasten_mikrofonempfaenger.JPG create mode 100644 skin/images/medienkasten_mikrofonempfaenger01.JPG create mode 100644 skin/images/menu_bg.jpg create mode 100644 skin/images/menu_item.gif create mode 100644 skin/images/moreleft.gif create mode 100644 skin/images/moreleft.png create mode 100644 skin/images/moremoreleft.png create mode 100644 skin/images/moremoreright.png create mode 100644 skin/images/moreright.gif create mode 100644 skin/images/moreright.png create mode 100644 skin/images/nopic.gif create mode 100644 skin/images/ok.gif create mode 100644 skin/images/open.gif create mode 100644 skin/images/org-2004-17-A3.jpg create mode 100644 skin/images/org-2005-03-A5.jpg create mode 100644 skin/images/org-2005-03-A6.jpg create mode 100644 skin/images/outlook.gif create mode 100644 skin/images/outlook.ico create mode 100644 skin/images/outlook.png create mode 100644 skin/images/p.gif create mode 100644 skin/images/pc_steckfeld_audio.JPG create mode 100644 skin/images/pdf.gif create mode 100644 skin/images/pdf.ico create mode 100644 skin/images/pdfpic.gif create mode 100644 skin/images/person.gif create mode 100644 skin/images/picpic.gif create mode 100644 skin/images/pptpic.gif create mode 100644 skin/images/qm.gif create mode 100644 skin/images/red_point.gif create mode 100644 skin/images/refresh.png create mode 100644 skin/images/right.gif create mode 100644 skin/images/right.png create mode 100644 skin/images/right_end_blue.jpg create mode 100644 skin/images/right_end_green.jpg create mode 100644 skin/images/room_background_blue.jpg create mode 100644 skin/images/room_background_green.jpg create mode 100644 skin/images/seperator.gif create mode 100644 skin/images/stdpl_main.jpg create mode 100644 skin/images/stdplan_menue.gif create mode 100644 skin/images/stdplan_menue_pfeile.gif create mode 100644 skin/images/stdplan_ort_lektor.gif create mode 100644 skin/images/stdplan_ort_lektor_pfeile.gif create mode 100644 skin/images/stdplan_pers_student.gif create mode 100644 skin/images/steckfeld01.JPG create mode 100644 skin/images/steckfeld_audio.JPG create mode 100644 skin/images/steckfeld_vga_laptop.JPG create mode 100644 skin/images/steckfeld_vga_visualizer.JPG create mode 100644 skin/images/sunbird.png create mode 100644 skin/images/technikum_logo.gif create mode 100644 skin/images/texpic.jpg create mode 100644 skin/images/ton.JPG create mode 100644 skin/images/ton_mikrofon_ea.JPG create mode 100644 skin/images/true.gif create mode 100644 skin/images/tw_logo.gif create mode 100644 skin/images/tw_logo.jpg create mode 100644 skin/images/tw_logo_01.jpg create mode 100644 skin/images/tw_logo_02.jpg create mode 100644 skin/images/upload.jpg create mode 100644 skin/images/vcal_v1.png create mode 100644 skin/images/vcal_v2.png create mode 100644 skin/images/vcrmenue01.JPG create mode 100644 skin/images/video_dvd01.JPG create mode 100644 skin/images/video_dvd02.JPG create mode 100644 skin/images/video_dvd03.JPG create mode 100644 skin/images/visualizer_lampe.JPG create mode 100644 skin/images/visualizer_light.JPG create mode 100644 skin/images/visualizer_power.JPG create mode 100644 skin/images/visualizer_zoom.JPG create mode 100644 skin/images/vline.gif create mode 100644 skin/images/web_s_org-2004-17-A3.jpg create mode 100644 skin/images/web_s_org-2005-03-A5.jpg create mode 100644 skin/images/web_s_org-2005-03-A6.jpg create mode 100644 skin/images/website.gif create mode 100644 skin/images/website.ico create mode 100644 skin/images/website.png create mode 100644 skin/images/website3D.gif create mode 100644 skin/images/winscp2.jpg create mode 100644 skin/images/winscp2_dir_com.jpg create mode 100644 skin/images/winscp2_dir_exp.jpg create mode 100644 skin/images/winscp_browse.jpg create mode 100644 skin/images/winscp_login.jpg create mode 100644 skin/images/xlspic.gif create mode 100644 skin/images/xml.png create mode 100644 skin/images/zippic.jpg create mode 100644 skin/tempus.css create mode 100644 skin/vilesci.css create mode 100644 vilesci/.htaccess create mode 100644 vilesci/index.html create mode 100644 vilesci/kommunikation/kontakt.php create mode 100644 vilesci/kommunikation/mlists/index.html create mode 100644 vilesci/kommunikation/mlists/lektor_mlists_create.php create mode 100644 vilesci/kommunikation/mlists/mlists_copy.php create mode 100644 vilesci/kommunikation/mlists/mlists_create.php create mode 100644 vilesci/kommunikation/mlists/mlists_det.php create mode 100644 vilesci/kommunikation/mlists/mlists_generate.php create mode 100644 vilesci/kommunikation/mlists/mlists_index.php create mode 100644 vilesci/kommunikation/mlists/student_lists_copy.php create mode 100644 vilesci/kommunikation/mlists/student_lists_create.php create mode 100644 vilesci/kommunikation/studenten_liste_export.php create mode 100644 vilesci/left.php create mode 100644 vilesci/main.php create mode 100644 vilesci/personen/funktion.php create mode 100644 vilesci/personen/funktion_det.php create mode 100644 vilesci/personen/index.html create mode 100644 vilesci/personen/lektor_edit.php create mode 100644 vilesci/personen/lektor_edit_save.php create mode 100644 vilesci/personen/lektor_new.php create mode 100644 vilesci/personen/lektor_new_save.php create mode 100644 vilesci/personen/lektor_uebersicht.php create mode 100644 vilesci/personen/lektor_uebersicht_Anktest.php create mode 100644 vilesci/personen/lektor_uebersicht_ankertest.php create mode 100644 vilesci/personen/lektorzuteilung_edit.php create mode 100644 vilesci/personen/modulzuteilung_edit.php create mode 100644 vilesci/personen/search_go.php create mode 100644 vilesci/personen/student_edit.php create mode 100644 vilesci/personen/student_neu_save.php create mode 100644 vilesci/personen/studenten_uebersicht.php create mode 100644 vilesci/personen/studenten_uebersicht_det.php create mode 100644 vilesci/personen/zeitwunsch.php create mode 100644 vilesci/personen/zeitwunsch_save.php create mode 100644 vilesci/stundenplan/check/index.html create mode 100644 vilesci/stundenplan/check/res_check.php create mode 100644 vilesci/stundenplan/check/res_check_delete.php create mode 100644 vilesci/stundenplan/check/res_check_det.php create mode 100644 vilesci/stundenplan/check/res_check_mail.php create mode 100644 vilesci/stundenplan/check/stdplan_check.php create mode 100644 vilesci/stundenplan/check/stdplan_check_delete.php create mode 100644 vilesci/stundenplan/check/stdplan_check_det.php create mode 100644 vilesci/stundenplan/einheit_det.php create mode 100644 vilesci/stundenplan/einheit_import.php create mode 100644 vilesci/stundenplan/einheit_menu.php create mode 100644 vilesci/stundenplan/export/index.html create mode 100644 vilesci/stundenplan/export/lektoren.php create mode 100644 vilesci/stundenplan/export/raum.php create mode 100644 vilesci/stundenplan/export/studenten.php create mode 100644 vilesci/stundenplan/export/zeitwunsch.php create mode 100644 vilesci/stundenplan/import/index.html create mode 100644 vilesci/stundenplan/import/stdplan_import.php create mode 100644 vilesci/stundenplan/import/stdplan_import_check_ID.php create mode 100644 vilesci/stundenplan/import/stdplan_import_sendmail.php create mode 100644 vilesci/stundenplan/import/stdplan_import_takeover.php create mode 100644 vilesci/stundenplan/import/stdplan_import_takeover_modul.php create mode 100644 vilesci/stundenplan/import/wochendatum.inc.php create mode 100644 vilesci/stundenplan/lehrfach.php create mode 100644 vilesci/stundenplan/lehrfach/wartung.php create mode 100644 vilesci/stundenplan/lehrfach_verteilung.php create mode 100644 vilesci/stundenplan/lv_verteilung.php create mode 100644 vilesci/stundenplan/lv_verteilung/lv_edit.php create mode 100644 vilesci/stundenplan/lv_verteilung/lv_verteilung.php create mode 100644 vilesci/stundenplan/modulplan_insert.php create mode 100644 vilesci/stundenplan/ort.php create mode 100644 vilesci/stundenplan/ort_edit_save.php create mode 100644 vilesci/stundenplan/stdplan_clean_check.php create mode 100644 vilesci/stundenplan/stdplan_clean_go.php create mode 100644 vilesci/stundenplan/stdplan_delete.php create mode 100644 vilesci/stundenplan/stdplan_insert.php create mode 100644 vilesci/stundenplan/stundenplan_info.html create mode 100644 vilesci/stundenplan/zeitwuensche.php create mode 100644 wap/index.php diff --git a/.htaccess b/.htaccess new file mode 100644 index 000000000..e87393a7c --- /dev/null +++ b/.htaccess @@ -0,0 +1,36 @@ +AuthName "Technikum-Wien" +AuthType Basic +AuthLDAPURL ldap://pdc1.technikum-wien.at/ou=People,dc=technikum-wien,dc=at?uid?one?objectClass=posixAccount +require group cn=fhadmin,ou=Group,dc=technikum-wien,dc=at +require user trob +require user wahl +require user drabek +require user elgner +require user schaaf +require user kofler +require user esberger +require user kollmitz +require user schmoe +require user trattner +require user naglr +require user patai +require user tw01e061 +require user docsek +require user teschl +require user oesi +require user adams +require user weisss +require user moserp +require user moehring +require user skritek +require user kroesl +require user ffe +require user kindlm +require user schmuderm +require user sagmeister +require user masik +require user kubicka +require user lehner +require user schwarzl +require user horauer +require user me diff --git a/admin/sync/sync_fas_exstd.php b/admin/sync/sync_fas_exstd.php new file mode 100644 index 000000000..014ad8e5f --- /dev/null +++ b/admin/sync/sync_fas_exstd.php @@ -0,0 +1,85 @@ +"; + $result=pg_exec($conn, $sql_query); + $vilesci_anz_std=pg_fetch_result($result,0,'anz'); + + // Start Studenten Synchro + $sql_query="SELECT DISTINCT uid FROM fas_view_vilesci_abbrecher WHERE uid IS NOT NULL AND uid NOT LIKE '' ORDER BY uid"; // LIMIT 5"; + //echo $sql_query."
"; + flush(); + $result=pg_exec($conn_fas, $sql_query); + $num_rows=pg_numrows($result); + $text="Dies ist eine automatische eMail!\r\r"; + $text.="Es wurde eine Synchronisation mit FAS durchgeführt.\r"; + $text.="Anzahl der Ex-Studenten vom FAS-Import: $num_rows \r"; + $text.="Anzahl der Studenten in VILESCI: $vilesci_anz_std \r\r"; + echo $text.'
'; + flush(); + $update_error=0; + $anz_update=0; + for ($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($result,$i); + $uid=str_replace(' ','',$row->uid); + // SQL vorbereiten (jeden Studenten vom FAS im vilesci suchen + $sql_query="SELECT uid,titel,vornamen,nachname, semester FROM tbl_person NATURAL JOIN tbl_student WHERE uid LIKE '$uid'"; + //echo $sql_query; + $res_std=pg_query($conn, $sql_query); + $num_rows_std=pg_numrows($res_std); + // neue Studenten + if ($num_rows_std>=1) + { + $row_std=pg_fetch_object($res_std); + if ($row_std->semester!=10) + { + $text.="Der Student $row_std->vornamen $row_std->nachname ($row_std->uid) wird verschoben.\r"; + $sql_query="UPDATE tbl_student SET semester=10, updateamum=now(), updatevon='auto' WHERE uid LIKE '$uid'"; + echo $sql_query.'
'; + if(!$res_update=pg_query($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $update_error++; + } + else + $anz_update++; + } + } + } + $text.="$update_error Fehler bei Student-Update!\r"; + $text.="$anz_update Studenten wurden ins 10te Semester verschoben.\r"; + $text.="\rEND OF SYNCHRONISATION\r"; + if (mail($adress,"FAS Synchro mit VILESCI (Ex-Studenten)",$text,"From: vilesci@technikum-wien.at")) + $sendmail=true; + else + $sendmail=false; +?> + + + + FAS-Synchro mit VILESCI (Ex-Studenten) + + + + +'; +else + echo "Mail konnte nicht verschickt werden!
"; +echo $text; + +?> + + diff --git a/admin/sync/sync_fas_lkt.php b/admin/sync/sync_fas_lkt.php new file mode 100644 index 000000000..5bdbf2437 --- /dev/null +++ b/admin/sync/sync_fas_lkt.php @@ -0,0 +1,202 @@ + "ae", + "ö" => "oe", + "ü" => "ue", + "Ä" => "ae", + "Ö" => "oe", + "Ü" => "ue", + "á" => "a", + "à" => "a", + "é" => "e", + "è" => "e", + "ó" => "o", + "ò" => "o", + "í" => "i", + "ì" => "i", + "ú" => "u", + "ù" => "u", + "ß" => "ss", + "´" => "", + "`" => "", + ); + $string = strtr($string, $trans); + return $string; + } + + $adress='fas_sync@technikum-wien.at'; + //mail($adress,"FAS Synchro mit VILESCI (Lektoren)","BEGIN OF SYNCHRONISATION","From: vilesci@technikum-wien.at"); + $conn=pg_connect(CONN_STRING); + $conn_fas=pg_connect(CONN_STRING_FAS); + + // Anzahl der Mitarbeiter in VILESCI + $sql_query="SELECT count(*) AS anz FROM tbl_mitarbeiter WHERE uid NOT LIKE '\\\\_%'"; + //echo $sql_query."
"; + $result=pg_exec($conn, $sql_query); + $vil_anz_mta=pg_fetch_result($result,0,'anz'); + + // Start Studenten Synchro + $sql_query="SELECT * FROM vw_vilesci_mitarbeiter_aktiv WHERE uid IS NOT NULL AND uid NOT LIKE ''"; // LIMIT 5"; + //echo $sql_query."
"; + $result=pg_exec($conn_fas, $sql_query); + $num_rows=pg_numrows($result); + $text="Dies ist eine automatische eMail!\r\r"; + $text.="Es wurde eine Synchronisation mit FAS durchgeführt.\r"; + $text.="Anzahl der Mitarbeiter vom FAS-Import: $num_rows \r"; + $text.="Anzahl der Mitarbeiter in der VILESCI: $vil_anz_mta \r\r"; + $plausi_error=0; + $update_error=0; + $insert_error=0; + $double_error=0; + $anz_update=0; + $anz_insert=0; + for ($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($result,$i); + $row->gebort=substr($row->gebort,0,30); + //$row->titel=substr($row->titel,0,15); + $uid=str_replace(' ','',$row->uid); + // Plausibilitaetscheck + if (strlen($row->titel)>64) + $text.="Der Mitarbeiter $row->titel $row->vornamen $row->nachname ($row->uid) hat einen zu langen Titel.\r"; + if (strlen($row->titel)<=64) + { + // SQL vorbereiten (jeden Mitarbeiter vom FAS in VILESCI suchen + $sql_query="SELECT uid,titel,vornamen,nachname,gebdatum,gebort,"; + $sql_query.="personalnummer"; + $sql_query.=" FROM tbl_person NATURAL JOIN tbl_mitarbeiter WHERE uid LIKE '$uid'"; + //echo $sql_query; + $res_std=pg_exec($conn, $sql_query); + $num_rows_std=pg_numrows($res_std); + + // neue Lektoren + if ($num_rows_std==0) + { + $text.="Der Lektor $row->vornamen $row->nachname ($row->uid) wird neu angelegt.\r"; + // person + $qry="INSERT INTO tbl_person(uid,titel,vornamen, nachname, gebdatum, gebort) ". + "VALUES('$uid','$row->titel','$row->vornamen','$row->nachname','$row->gebdatum','$row->gebort')"; + echo $qry.'
'; + if(!$res_insert=pg_exec($conn, $qry)) + { + $text.=$qry; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $insert_error++; + } + + //Alias erstellen + $vn = split('[- .,]',strtolower($row->vornamen)); + $vn = clean_string($vn[0]); + + $nn = split('[- .,]',strtolower($row->nachname)); + $nn = clean_string($nn[0]); + $alias = $vn.".".$nn; + $qry = "UPDATE tbl_person set alias='$alias' where uid='$uid'"; + if(!$res_insert=pg_exec($conn, $qry)) + { + $text.=$qry; + $text.="\rFehler: Alias existiert bereits: $alias"; + $insert_error++; + } + // lektor + $sql_query="INSERT INTO tbl_mitarbeiter (uid,personalnummer,kurzbz,lektor,telefonklappe,fixangestellt) ". + "VALUES('$row->uid','$row->persnr','$row->kurzbez',true,'$row->teltw',".($row->fixangestellt?'true':'false').")"; + echo $sql_query.'
'; + if(!$res_insert=pg_exec($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $insert_error++; + } + else + $anz_insert++; + } + // bestehende Lektoren + elseif ($num_rows_std==1) + { + $update=0; + $row_std=pg_fetch_object($res_std,0); + if ($row->gruppe==NULL) + $row->gruppe=1; + if ($row->titel!=$row_std->titel) + $update=1; + elseif ($row->vornamen!=$row_std->vornamen) + $update=2; + elseif ($row->nachname!=$row_std->nachname) + $update=3; + elseif ($row->gebdatum!=$row_std->gebdatum) + $update=4; + elseif ($row->gebort!=$row_std->gebort) + $update=5; + elseif ($row->persnr!=$row_std->personalnummer) + $update=6; + if ($update) + { + $text.="Der Lektor $row->vornamen $row->nachname ($row->uid) [$update] wird upgedatet.\r"; + // person + $sql_query="UPDATE tbl_person SET titel='$row->titel', vornamen='$row->vornamen', ". + " nachname='$row->nachname', gebdatum='$row->gebdatum', gebort='$row->gebort'". + " WHERE uid LIKE '$uid'"; + echo $sql_query.'
'; + if(!$res_update=pg_exec($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $update_error++; + } + + $sql_query="UPDATE tbl_mitarbeiter SET personalnummer='$row->persnr',fixangestellt=".($row->fixangestellt?'TRUE':'FALSE'); + $sql_query.=" WHERE uid LIKE '$uid'"; + echo $sql_query.'
'; // kurzbz='$row->kurzbez', + if(!$res_update=pg_exec($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $update_error++; + } + else + $anz_update++; + } + } + // Lektor kommt mehrmals vor ->Warnung + elseif ($num_rows_std>1) + { + $text.="\r!!! Der Lektor $row->vornamen $row->nachname ($row->uid) kommt mehrfach vor!\r"; + $double_error++; + } + } + else + $plausi_error++; + } + $text.="\r$plausi_error Fehler beim Plausibilitaetscheck!\r"; + $text.="$update_error Fehler bei Lektor-Update!\r"; + $text.="$insert_error Fehler bei Lektor-Insert!\r"; + $text.="$double_error Lektoren kommen in VileSci doppelt vor!\r\r"; + $text.="$anz_update Lektoren wurden upgedatet.\r"; + $text.="$anz_insert Lektoren wurden neu angelegt.\r\r"; + $text.="\rEND OF SYNCHRONISATION\r"; + if (mail($adress,"FAS Synchro mit VileSci (Lektoren)",$text,"From: vilesci@technikum-wien.at")) + $sendmail=true; + else + $sendmail=false; +?> + + + +FAS-Synchro mit VileSci (Lektoren) + + + +'; +else + echo "Mail konnte nicht verschickt werden!
"; +echo $text; + +?> + + diff --git a/admin/sync/sync_fas_lkt_fault.php b/admin/sync/sync_fas_lkt_fault.php new file mode 100644 index 000000000..1786ef507 --- /dev/null +++ b/admin/sync/sync_fas_lkt_fault.php @@ -0,0 +1,56 @@ +FAS-Synchro mit TEMPUS fehlende Lektoren'; + $text.=''; + + // Start Check + //Daten aus vilesci holen + $sql_query="SELECT tbl_person.*,tbl_mitarbeiter.personalnummer,tbl_mitarbeiter.kurzbz,tbl_mitarbeiter.fixangestellt FROM tbl_person join tbl_mitarbeiter using(uid) WHERE uid NOT LIKE '\\\\_%' ORDER BY nachname"; + //echo $sql_query."
"; + $result=pg_exec($conn, $sql_query); + $num_rows=pg_numrows($result); + // Daten aus dem FAS + $sql_query="SELECT * FROM fas_view_lektoren_vilesci"; + //echo $sql_query."
"; + $result_fas=pg_exec($conn_fas, $sql_query); + $fehlend=$num_rows-$num_rows_fas; + $num_rows_fas=pg_numrows($result_fas); + $text.="Dies ist eine automatische eMail!

"; + $text.="Es wurde eine Ueberpruefung der Daten in der FAS-View fuer Lektoren durchgeführt.
"; + $text.='Anzahl der fehlenden Daten: $fehlend

'; + $text.="Folgende Lektoren scheinen in der FAS-View nicht auf"; + $text.=''; + for ($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($result,$i); + $sql_query="SELECT uid FROM fas_view_lektoren_vilesci WHERE uid LIKE '$row->uid'"; + $result_fas=pg_exec($conn_fas, $sql_query); + if (pg_numrows($result_fas)!=1) + $text.='"; + } + $text.='
uidTitelVornamenNachname
$row->uid$row->titel$row->vornamen$row->nachname
'; + + echo $text; + + if (mail($adress,"FAS Synchro mit TEMPUS fehlende Lektoren",$text,$headers)) + echo 'Mail wurde verschickt an '.$adress.'!
'; + else + echo "Mail konnte nicht verschickt werden!
"; + +?> + + diff --git a/admin/sync/sync_fas_lva.php b/admin/sync/sync_fas_lva.php new file mode 100644 index 000000000..ed1ef081b --- /dev/null +++ b/admin/sync/sync_fas_lva.php @@ -0,0 +1,594 @@ +lvnr.' '.$row->bezeichnung; +} + +function getSemesterWhereClause() +{ + global $conn; + $qry="select * from tbl_studiensemester where ende>now()"; + $result=pg_exec($conn, $qry); + $where=''; + while ($row=pg_fetch_object($result)) + { + $where.= ((strlen($where)>0)?' or ':'')."studiensemester_kurzbz='".$row->studiensemester_kurzbz."' "; + } + if (strlen($where)>0) $where=" ($where) "; + return $where; +} + +function validate($row) +{ + global $error_log,$einheit,$missing_einheit,$missing_raumtyp,$missing_lehrform,$raumtyp,$lehrform; + $valid=true; + if ($row->raumtyp==null) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Raumtyp fehlt'; + $valid=false; + } + if ($row->semester>8 || $row->semester<1) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Semester bei '.$row->semester.$row->verband.$row->gruppe.' größer als 8'; + $valid=false; + } + if (!($row->verband==null || $row->verband=='' || $row->verband=='A' || $row->verband=='B' || $row->verband=='C' || $row->verband=='D')) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Verband bei '.$row->semester.$row->verband.$row->gruppe.' außerhalb des gültigen Bereichs (A bis D)'; + //print_r($row); + $valid=false; + } + if (!($row->gruppe==null || $row->gruppe=='' || $row->gruppe=='1' || $row->gruppe=='2' || $row->gruppe=='3' || $row->gruppe=='4')) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Gruppe bei '.$row->semester.$row->verband.$row->gruppe.' außerhalb des gültigen Bereichs (1 bis 4)'; + $valid=false; + } + if (!$row->stundenblockung>0) { + $error_log[$row->studiengang_kz][]=printLVA($row).': Stundenblockung ist nicht größer 0'; + $valid=false; + } + if (!$row->semesterstunden>0) { + $error_log[$row->studiengang_kz][]=printLVA($row).': Semesterstunden sind nicht größer 0'; + $valid=false; + } + if (!$row->wochenrythmus>0) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Wochenrythmus ist nicht größer 0'; + $valid=false; + } + if ($row->start_kw<=0 || $row->start_kw>53) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Start-KW außerhalb des gültigen Bereichs (1 bis 53)'; + $valid=false; + } + if (strlen($row->einheit_kurzbz)>0 && !isset($einheit[$row->einheit_kurzbz]) && !isset($missing_einheit[$row->einheit_kurzbz])) + { + $missing_einheit[$row->einheit_kurzbz]=1; + } + if (strlen($row->raumtyp)>0 && !isset($raumtyp[$row->raumtyp]) && !isset($missing_raumtyp[$row->raumtyp])) + { + $missing_raumtyp[$row->raumtyp]=1; + $valid=false; + } + if (strlen($row->raumtypalternativ)>0 && !isset($raumtyp[$row->raumtypalternativ]) && !isset($missing_raumtyp[$row->raumtypalternativ])) { + $missing_raumtyp[$row->raumtypalternativ]=1; + } + if (!ereg("^[A-Za-z]{1,5}[0-9]{0,1}$",$row->raumtyp)) + { + $error_log[$row->studiengang_kz][]=$row->raumtyp.': Raumtyp bei LVNR:'.$row->lvnr.' ist nicht plausibel.'; + $valid=false; + } + if (!ereg("^[A-Za-z]{1,5}[0-9]{0,1}$",$row->raumtypalternativ)) + { + $error_log[$row->studiengang_kz][]=$row->raumtypalternativ.': Raumtypalternative bei LVNR:'.$row->lvnr.' ist nicht plausibel.'; + $valid=false; + } + if (strlen($row->lehrform)>0 && !isset($lehrform[$row->lehrform]) && !isset($missing_lehrform[$row->lehrform])) { + $missing_lehrform[$row->lehrform]=1; + } + if (!ereg("^[A-Z]{1,5}[0-9]{0,1}$",$row->lehrfach_kurzbz)) + { + $error_log[$row->studiengang_kz][]=$row->lehrfach_kurzbz.'-'.$row->lehrform.'/'.$row->studiengang_kz.'-'.$row->semester.': Lehrfach-Kuerzel bei LVNR:'.$row->lvnr.' ist nicht plausibel.'; + $valid=false; + } + if (!ereg("^[A-Z]{1,3}$",$row->lehrform)) + { + $error_log[$row->studiengang_kz][]=$row->lehrfach_kurzbz.'-'.$row->lehrform.'/'.$row->studiengang_kz.'-'.$row->semester.': Lehrform bei LVNR:'.$row->lvnr.' ist nicht plausibel.'; + $valid=false; + } + return $valid; +} + +/** + * FAS-Lehrfach auf interne Lehrfach-Nr übersetzen + */ +function getLehrfachNr($kurzbz,$studiengang_kz,$semester,$lehrfach_bezeichnung, $fachbereich_id, $ects, $conn) +{ + global $lehrfach; + global $text; + + if (isset($lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr'])) + { + //echo 'Nummer:'.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr'].'Bez: '.$lehrfach_bezeichnung.'
'; + + // Nebenbei die Lehrfachbezeichnung kontrollieren + if ($lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_bezeichnung']!=$lehrfach_bezeichnung) + { + // Update + $qry="UPDATE tbl_lehrfach SET bezeichnung='$lehrfach_bezeichnung' WHERE lehrfach_nr=".$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr']; + if (!$result=pg_query($conn, $qry)) + echo $qry.' fehlgeschlagen!
'; + else + { + echo 'Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurde von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_bezeichnung'].' auf '.$lehrfach_bezeichnung.' geaendert!
'; + $text.='Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurde von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_bezeichnung'].' auf '.$lehrfach_bezeichnung.' geaendert!\n'; + $lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_bezeichnung']=$lehrfach_bezeichnung; + } + } + + // Nebenbei die ECTS Punkte kontrollieren + if ($lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['ects']!=$ects) + { + if ($ects!='') //ereg("[0-9]{1,4}[\.|,][0-9]{0,2}$",$ects) + { + // Update + $qry="UPDATE tbl_lehrfach SET ects='$ects' WHERE lehrfach_nr=".$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr']; + //echo $qry.'
'; + if (!$result=pg_query($conn, $qry)) + echo $qry.' fehlgeschlagen!
'; + else + { + echo ' Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurden die ECTS-Punkte von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['ects'].' auf '.$ects.' geaendert!
'; + $text.='Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurden die ECTS-Punkte von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['ects'].' auf '.$ects.' geaendert!\n'; + $lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['ects']=$ects; + } + } + else + { + echo 'Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' sind die ECTS-Punkte von '.$ects.' nicht Plausibel!
'; + $text.='Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' sind die ECTS-Punkte von '.$ects.' nicht Plausibel!\n'; + } + + } + + // Nebenbei die FachbereichID kontrollieren + if ($lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['fachbereich_id']!=$fachbereich_id) + { + // Update + $qry="UPDATE tbl_lehrfach SET fachbereich_id=$fachbereich_id WHERE lehrfach_nr=".$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr']; + if (!$result=@pg_query($conn, $qry)) + echo $qry.' fehlgeschlagen!
'; + else + { + echo 'Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurde die FachbereichID von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['fachbereich_id'].' auf '.$fachbereich_id.' geaendert!
'; + $text.='Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurde die FachbereichID von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['fachbereich_id'].' auf '.$fachbereich_id.' geaendert!\n'; + $lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['fachbereich_id']=$fachbereich_id; + } + } + return $lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr']; + } + //echo 'missing getLehrfachNr: '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.'
'; + return -1; +} + + +/************************* + * FAS-Synchronisation + */ + +// E-Mails der Studiengänge +$stg_mail=array(); +$qry="select studiengang_kz,email,kurzbz from tbl_studiengang"; +$result=pg_exec($conn, $qry); +while ($row=pg_fetch_object($result)) +{ + $stg_mail[$row->studiengang_kz] = $row->email; + $stg_kurzbz[$row->studiengang_kz]=$row->kurzbz; +} + +// Anzahl der LVA in VileSci +$sql_query="SELECT count(*) AS anz FROM tbl_lehrveranstaltung"; +//echo $sql_query."
"; +$result=pg_exec($conn, $sql_query); +$vil_anz_lva=pg_fetch_result($result,0,'anz'); + +// Lehrfächer holen und in Array speichern (Key ist kurzbz + '/' + lehform_kurzbz) +$sql_query="SELECT lehrfach_nr,kurzbz,studiengang_kz,semester, bezeichnung, fachbereich_id, ects FROM tbl_lehrfach"; +$result=pg_exec($conn, $sql_query); +while ($row=pg_fetch_object($result)) +{ + $lehrfach[$row->kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester]['lehrfach_nr'] = $row->lehrfach_nr; + $lehrfach[$row->kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester]['fachbereich_id'] = $row->fachbereich_id; + $lehrfach[$row->kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester]['lehrfach_bezeichnung'] = $row->bezeichnung; + $lehrfach[$row->kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester]['ects'] = $row->ects; +} +//print_r($lehrfach); +// Einheiten holen +$sql_query="SELECT einheit_kurzbz,bezeichnung FROM tbl_einheit"; +$result=pg_exec($conn, $sql_query); +while ($row=pg_fetch_object($result)) + $einheit[$row->einheit_kurzbz] = $row->bezeichnung; +// Raumtypen holen +$sql_query="SELECT raumtyp_kurzbz,beschreibung FROM tbl_raumtyp"; +$result=pg_exec($conn, $sql_query); +while ($row=pg_fetch_object($result)) + $raumtyp[$row->raumtyp_kurzbz] = $row->beschreibung; +// Lehformen holen +$sql_query="SELECT lehrform_kurzbz,bezeichnung FROM tbl_lehrform"; +$result=pg_exec($conn, $sql_query); +while ($row=pg_fetch_object($result)) + $lehrform[$row->lehrform_kurzbz] = $row->bezeichnung; +//print_r($lehrfach); +echo 'FAS-Datenbank wird abgefragt!
'; +flush(); + +// Start Lehrveranstaltungen Synchro +$sql_query="SELECT DISTINCT fas_id,trim(lvnr) AS lvnr,trim(unr)::int8 AS unr,einheit_kurzbz,lektor,trim(upper(lehrfach_kurzbz)) AS lehrfach_kurzbz, + trim(upper(lehrform)) AS lehrform, lehrfach_bezeichnung, + studiengang_kz,fachbereich_id,semester,verband,gruppe,raumtyp,raumtypalternativ, + round(semesterstunden) AS semesterstunden,stundenblockung,wochenrythmus,start_kw,anmerkung,studiensemester_kurzbz, ects + FROM fas_view_alle_lehreinheiten_vilesci ". + "where ".getSemesterWhereClause(); +//echo $sql_query."
"; +$result=pg_exec($conn_fas, $sql_query); +$num_rows=pg_numrows($result); +$text="Dies ist eine automatische eMail!\r\r"; +$text.="Es wurde eine Synchronisation mit FAS durchgeführt.\r"; +$text.="Anzahl der LVA vom FAS-Import: $num_rows \r"; +$text.="Anzahl der LVA in der VileSci: $vil_anz_lva \r\r"; +$plausi_error=0; +$update_error=0; +$insert_error=0; +$double_error=0; +$anz_update=0; +$anz_insert=0; +echo $num_rows.' Datensaetze
'; +for ($i=0;$i<$num_rows;$i++) +{ + if ($i%100==0) + { + echo '-'; + flush(); + } + $row=pg_fetch_object($result,$i); + // Kennzahl der Studiengangs bei ehemaligen bTec auf TW aendern. + if ($row->studiengang_kz==203) + $row->studiengang_kz=0; + // Lehrfach-Nr übersetzen (-1 wenn nicht vorhanden) + $row->lehrfach_nr=getLehrfachNr($row->lehrfach_kurzbz,$row->studiengang_kz,$row->semester, $row->lehrfach_bezeichnung, $row->fachbereich_id, $row->ects, $conn); + // Einheit vollstaendiger Name + if (count($row->einheit_kurzbz)>0) + $row->einheit_kurzbz=$stg_kurzbz[$row->studiengang_kz].'-'.$row->einheit_kurzbz; + + // Plausibilitaetscheck + //if ($row->gruppe==NULL) + // $row->gruppe='1'; + + // + if (!$row->stundenblockung>0) + $row->stundenblockung=1; + if (!$row->start_kw>0) + $row->start_kw=1; + if (!$row->wochenrythmus>0) + $row->wochenrythmus=1; + + if ($row->lehrfach_nr==-1) + { + //$error_log[$row->studiengang_kz][]=printLVA($row).': Lehrfach (Kurzbz='".$row->lehrfach_kurzbz."',Lehrform".$row->lehrform) existiert noch nicht. Stundenplanabteilung wurde benachrichtigt.'; + if (!isset($missing_lehrfaecher[$row->lehrfach_kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester])) $missing_lehrfaecher[$row->lehrfach_kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester]=1; + $valid=false; + } + + if (validate($row) && $row->lehrfach_nr>-1) + { + // SQL vorbereiten (jede LVA vom FAS im VileSci suchen) + $sql_query="SELECT * from tbl_lehrveranstaltung where fas_id=".$row->fas_id; + //echo $sql_query; + $res_lva=pg_query($conn, $sql_query); + $num_rows_lva=pg_numrows($res_lva); + + // neue LVA + if ($num_rows_lva==0) + { + $text.="Die LVA fas-id=$row->fas_id lvnr=$row->lvnr unr=$row->unr wird neu angelegt.\r"; + $sql_query="INSERT INTO tbl_lehrveranstaltung (lvnr,unr,einheit_kurzbz,lektor,lehrfach_nr,lehrform_kurzbz,"; + $sql_query.="studiengang_kz,fachbereich_id,semester,verband,gruppe,raumtyp,". + "raumtypalternativ,semesterstunden,stundenblockung,". + "wochenrythmus,start_kw,studiensemester_kurzbz,fas_id,anmerkung) ". + "VALUES('$row->lvnr'". + ",$row->unr,". + (strlen($row->einheit_kurzbz)>0?"'".$row->einheit_kurzbz."'":'NULL').",". + "'$row->lektor',". + "'$row->lehrfach_nr',". + "'$row->lehrform',". + "'$row->studiengang_kz',". + "$row->fachbereich_id,". + "$row->semester,"; + if ($row->verband==null) + $sql_query.='NULL,'; + else + $sql_query.="'$row->verband',"; + if ($row->gruppe==null) + $sql_query.='NULL,'; + else + $sql_query.="'$row->gruppe',"; + $sql_query.="'$row->raumtyp',". + "'$row->raumtypalternativ',". + "$row->semesterstunden,". + "$row->stundenblockung,". + "$row->wochenrythmus,". + "$row->start_kw,". + "'$row->studiensemester_kurzbz'," . + "$row->fas_id,'$row->anmerkung')"; + //echo $sql_query.'
'; + if(!$res_insert=@pg_exec($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\nFehler: ".pg_errormessage($conn)."\n"; + $insert_error++; + } + else + $anz_insert++; + } + // bestehende LVA + elseif ($num_rows_lva==1) + { + $update_sql=''; + $row_lva=pg_fetch_object($res_lva,0); + //var_dump($row_lva); + //if ($row->gruppe==NULL) + // $row->gruppe=1; + //echo '-'.$row->lvnr.'-'.$row_lva->lvnr.'-
'; + if ($row->lvnr!=$row_lva->lvnr) + $update_sql.="lvnr='".$row->lvnr."'"; + elseif ($row->unr!=$row_lva->unr) + $update_sql.="unr=".$row->unr; + elseif ($row->einheit_kurzbz!=$row_lva->einheit_kurzbz) + $update_sql.=(strlen($update_sql)>0?',':'').'einheit_kurzbz='.(strlen($row->einheit_kurzbz)>0?"'".$row->einheit_kurzbz."'":'NULL'); + elseif ($row->lektor!=$row_lva->lektor) + $update_sql.=(strlen($update_sql)>0?',':'')."lektor='".$row->lektor."'"; + elseif ($row->lehrfach_nr!=$row_lva->lehrfach_nr) + $update_sql.=(strlen($update_sql)>0?',':'')."lehrfach_nr=".$row->lehrfach_nr; + elseif ($row->lehrform!=$row_lva->lehrform_kurzbz) + $update_sql.=(strlen($update_sql)>0?',':'')."lehrform_kurzbz='".$row->lehrform."'"; + elseif ($row->studiengang_kz!=$row_lva->studiengang_kz) + $update_sql.=(strlen($update_sql)>0?',':'')."studiengang_kz=".$row->studiengang_kz; + elseif ($row->fachbereich_id!=$row_lva->fachbereich_id) + $update_sql.=(strlen($update_sql)>0?',':'')."fachbereich_id=".$row->fachbereich_id; + elseif ($row->semester!=$row_lva->semester) + $update_sql.=(strlen($update_sql)>0?',':'')."semester=".$row->semester; + elseif ($row->verband!=$row_lva->verband) + $update_sql.=(strlen($update_sql)>0?',':'')."verband=".(strlen($row->verband)>0?"'".$row->verband."'":'NULL'); + elseif ($row->gruppe!=$row_lva->gruppe) + $update_sql.=(strlen($update_sql)>0?',':'')."gruppe=".(strlen($row->gruppe)>0?"'".$row->gruppe."'":'NULL'); + elseif ($row->raumtyp!=$row_lva->raumtyp) + $update_sql.=(strlen($update_sql)>0?',':'')."raumtyp='".$row->raumtyp."'"; + elseif ($row->raumtypalternativ!=$row_lva->raumtypalternativ) + $update_sql.=(strlen($update_sql)>0?',':'')."raumtypalternativ='".$row->raumtypalternativ."'"; + elseif ($row->semesterstunden!=$row_lva->semesterstunden) + $update_sql.=(strlen($update_sql)>0?',':'')."semesterstunden=".$row->semesterstunden; + elseif ($row->stundenblockung!=$row_lva->stundenblockung) + $update_sql.=(strlen($update_sql)>0?',':'')."stundenblockung=".$row->stundenblockung; + elseif ($row->wochenrythmus!=$row_lva->wochenrythmus) + $update_sql.=(strlen($update_sql)>0?',':'')."wochenrythmus=".$row->wochenrythmus; + elseif ($row->start_kw!=$row_lva->start_kw) + $update_sql.=(strlen($update_sql)>0?',':'')."start_kw=".(strlen($row->start_kw)>0?$row->start_kw:'NULL'); + elseif ($row->studiensemester_kurzbz!=$row_lva->studiensemester_kurzbz) + $update_sql.=(strlen($update_sql)>0?',':'')."studiensemester_kurzbz='".$row->studiensemester_kurzbz."'"; + elseif ($row->anmerkung!=$row_lva->anmerkung) + $update_sql.=(strlen($update_sql)>0?',':'')."anmerkung='".$row->anmerkung."'"; + + if (strlen($update_sql)>0) + { + $text.="Die LVA fas-id=$row->fas_id lvnr=$row->lvnr unr=$row->unr wird upgedatet.\r"; + $sql_query="UPDATE tbl_lehrveranstaltung SET ". + $update_sql. + " where fas_id=".$row->fas_id; + + //echo $sql_query.'
'; + if(!$res_update=@pg_query($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $update_error++; + } + else + $anz_update++; + + // **************** + // Auch in tbl_stundenplandev updaten + $sql_query="SELECT * FROM tbl_stundenplandev WHERE + lehrveranstaltung_id=$row_lva->lehrveranstaltung_id AND datum>=now()"; + //echo $sql_query.'
'; + if(!$res_upd_stpl=@pg_query($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + } + else + { + if (!pg_query($conn,"BEGIN;")) + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $kollision=false; + while ($row_upd_stpl=pg_fetch_object($res_upd_stpl)) + { + // Lehrstunde auf Kollisionen checken + $lehrstunde=new lehrstunde($conn); + //echo '
STPL-ID:'.$row_upd_stpl->stundenplandev_id.'
'; + if (!$lehrstunde->load($row_upd_stpl->stundenplandev_id)) + echo $lehrstunde->errormsg; + $lehrstunde->lektor_uid=$row->lektor; + if (!$lehrstunde->kollision()) + { + if (!$lehrstunde->save('sync_fas_lva')) + echo $lehrstunde->errormsg; + } + else + { + $error_log[$row->studiengang_kz][]=$lehrstunde->errormsg; + $text.="\rKollision: ".$lehrstunde->errormsg."\r"; + $kollision=true; + echo "Kollision: ".$lehrstunde->errormsg."
"; + } + } + if ($kollision) + { + if (!pg_query($conn,"ROLLBACK;")) + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + } + else + if (!pg_query($conn,"COMMIT;")) + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + } + } + } + // LVA kommt mehrmals vor ->Warnung + elseif ($num_rows_lva>1) + { + $text.="\r!!! Die LVA fas_id=$row->fas_id kommt mehrfach vor!\r"; + $double_error++; + } + } + else + $plausi_error++; +} + + +// **************** +// Ueberfluessige Datensaetze loeschen +$whereClause=getSemesterWhereClause(); +$sql_query="DELETE FROM tbl_lehrveranstaltung WHERE fas_id NOT IN + (SELECT fas_id FROM vw_fas_lehrveranstaltung WHERE $whereClause) AND (fas_id!=0 OR fas_id IS NOT NULL) AND ($whereClause)"; +echo $sql_query.'
'; +if(!$res_delete=@pg_query($conn, $sql_query)) +{ + $text.='\n'.$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $text.="\rSolution: DELETE FROM tbl_stundenplandev WHERE lehrveranstaltung_id IN (SELECT lehrveranstaltung_id FROM tbl_lehrveranstaltung WHERE fas_id NOT IN (SELECT fas_id FROM vw_fas_lehrveranstaltung WHERE $whereClause) AND (fas_id!=0 OR fas_id IS NOT NULL) AND ($whereClause))\r"; +} +else +{ + $anz_delete=pg_numrows($res_delete); +} + +//Ausgabe Zusammenfassung +$text.="\n$anz_delete Lehrveranstaltungen wurden geloescht!\n"; +$text.="$plausi_error Fehler beim Plausibilitaetscheck!\n"; +$text.="$update_error Fehler bei LVA-Update!\n"; +$text.="$insert_error Fehler bei LVA-Insert!\n"; +$text.="$double_error LVA kommen in VileSci doppelt vor!\n\n"; +$text.="$anz_update LVA wurden upgedatet.\n"; +$text.="$anz_insert LVA wurden neu angelegt.\n\n"; +$text.="\nEND OF SYNCHRONISATION\n"; + +// Validation error hinzufügen +while(list($k,$v)=each($error_log)) +{ + $text.="\n\nStudiengang $k:\n"; + foreach($v as $txt) + $text.=" $txt\n"; +} +// fehlende lehrfächer +$text.="\n\nFehlende Lehrfächer: \n"; +while(list($k,$v)=each($missing_lehrfaecher)) +{ + $text.=" $k\n"; +} +// fehlende einheiten +$text.="\n\nFehlende Einheiten: \n"; +while(list($k,$v)=each($missing_einheit)) +{ + $text.=" $k\n"; +} +// fehlende raumtypen +$text.="\n\nFehlende Raumtypen: \n"; +while(list($k,$v)=each($missing_raumtyp)) +{ + $text.=" $k\n"; +} +// fehlende lehrformen +$text.="\n\nFehlende Lehrformen: \n"; +while(list($k,$v)=each($missing_lehrform)) +{ + $text.=" $k\n"; +} +if (mail($adress,"FAS Synchro mit VileSci (Lehrveranstaltungen)",$text,"From: vilesci@technikum-wien.at")) + $sendmail=true; +else + $sendmail=false; + +//print "debug: ";print_r($stg_mail); + +// Einzelnen Mails an Studiengänge verschicken +reset($error_log); +while(list($k,$v)=each($error_log)) +{ + echo "
Mail an Studiengang $k ".$stg_mail[$k].":
"; + $stg_text="Dies ist eine automatische Mail!\nFolgende Fehler sind bei der Synchronisation der Lehrveranstaltungen aufgetreten:\n\n"; + foreach($v as $txt) + $stg_text.="$txt\n"; + echo $stg_text.'
'; + // Studiengang + if (!mail($stg_mail[$k],"FAS Synchro mit VileSci (Lehrveranstaltungen) $k",$stg_text,"From: vilesci@technikum-wien.at")) + echo "Mail an '".$stg_mail[$k]."' konnte nicht verschickt werden!
"; + // Stundenplanstelle + echo "
Mail an Studiengang $k ($adress_stpl)
"; + if (!mail($adress_stpl,"FAS Synchro mit VileSci (Lehrveranstaltungen) $k",$stg_text,"From: vilesci@technikum-wien.at")) + echo 'Mail an "'.$adress_stpl.'" konnte nicht verschickt werden!
'; + +} + +// Doppelte IDs im FAS prüfen +$sql_query="SELECT count(*) AS anzahl, fas_id FROM fas_view_alle_lehreinheiten_vilesci + GROUP BY fas_id HAVING count(*)>1"; +//echo $sql_query."
"; +$result=pg_query($conn_fas, $sql_query); +$num_rows=pg_numrows($result); +$mail_text="Folgende $num_rows IDs kommen in der View fas_view_alle_lehreinheiten_vilesci (fas_id) mehrfach vor:\n\n"; +$mail_text_false=''; +if ($num_rows>0) + while ($row=pg_fetch_object($result)) + $mail_text_false.=$row->fas_id.'->'.$row->anzahl."x\n"; +$mail_text.=$mail_text_false."\n\nBitte überprüfen die Daten im FAS!!!"; +if ($mail_text_false!='') + if (!mail($adress_fas,"FAS Synchro mit VileSci (Lehrveranstaltungen)",$mail_text,"From: vilesci@technikum-wien.at")) + echo "Mail an '".$adress_fas."' konnte nicht verschickt werden!
"; + else + echo 'Mail wurde verschickt an '.$adress_fas.'!
'; +?> + + + +FAS-Synchro mit VileSci + + + +'; +else + echo "Mail konnte nicht verschickt werden!
"; +echo nl2br($text); + +?> + + diff --git a/admin/sync/sync_fas_std.php b/admin/sync/sync_fas_std.php new file mode 100644 index 000000000..6b0c2a635 --- /dev/null +++ b/admin/sync/sync_fas_std.php @@ -0,0 +1,233 @@ + "ae", + "ö" => "oe", + "ü" => "ue", + "Ä" => "ae", + "Ö" => "oe", + "Ü" => "ue", + "á" => "a", + "à" => "a", + "é" => "e", + "è" => "e", + "ó" => "o", + "ò" => "o", + "í" => "i", + "ì" => "i", + "ú" => "u", + "ù" => "u", + "ß" => "ss", + "´" => "", + "`" => "", + ); + $string = strtr($string, $trans); + return $string; + } + + //mail($adress,"FAS Synchro mit VileSci (Studenten)","BEGIN OF SYNCHRONISATION","From: vilesci@technikum-wien.at"); + $conn=pg_connect(CONN_STRING); + $conn_fas=pg_connect(CONN_STRING_FAS); + + // Anzahl der Studenten in VileSci + $sql_query="SELECT count(*) AS anz FROM tbl_student"; + //echo $sql_query."
"; + $result=pg_exec($conn, $sql_query); + $vilesci_anz_std=pg_fetch_result($result,0,'anz'); + + // Start Studenten Synchro + $sql_query="SELECT DISTINCT * FROM fas_view_student_vilesci WHERE semester >0 AND semester <9 AND"; + $sql_query.=" verband IS NOT NULL AND uid IS NOT NULL AND uid NOT LIKE ''"; // LIMIT 5"; + echo $sql_query."
"; + flush(); + $result=pg_exec($conn_fas, $sql_query); + $num_rows=pg_numrows($result); + $text="Dies ist eine automatische eMail!\r\r"; + $text.="Es wurde eine Synchronisation mit FAS durchgeführt.\r"; + $text.="Anzahl der Studenten vom FAS-Import: $num_rows \r"; + $text.="Anzahl der Studenten in VileSci: $vilesci_anz_std \r\r"; + echo $text.'
'; + flush(); + $plausi_error=0; + $update_error=0; + $insert_error=0; + $double_error=0; + $anz_update=0; + $anz_insert=0; + for ($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($result,$i); + $row->gebort=substr($row->gebort,0,30); + $row->titel=substr($row->titel,0,15); + $uid=str_replace(' ','',$row->uid); + // Plausibilitaetscheck + if ($row->gruppe==null) + $row->gruppe='1'; + if ($row->verband>='A' && $row->verband<='D' && $row->semester<=8 && $row->gruppe>'0' && $row->gruppe<='2') + { + // SQL vorbereiten (jeden Studenten vom FAS im VileSci suchen + $sql_query="SELECT uid,titel,vornamen,nachname,gebdatum,gebort,"; + $sql_query.="trim(both ' ' from matrikelnr) AS matrikelnr,"; + $sql_query.=" studiengang_kz,semester,verband,gruppe"; + $sql_query.=" FROM tbl_person NATURAL JOIN tbl_student WHERE uid LIKE '$uid'"; + // echo $sql_query; + $res_std=pg_exec($conn, $sql_query); + $num_rows_std=pg_numrows($res_std); + + // neue Studenten + if ($num_rows_std==0) + { + $text.="Der Student $row->vornamen $row->nachname ($row->uid) wird neu angelegt.\r"; + // tbl_person + $sql_query="INSERT INTO tbl_person(uid,titel,vornamen, nachname, gebdatum, gebort) ". + "VALUES('$row->uid','$row->titel','$row->vornamen','$row->nachname','$row->gebdatum','$row->gebort')"; + echo $sql_query.'
'; + flush(); + + //Alias erstellen + $vn = split('[- .,]',strtolower($row->vornamen)); + $vn = clean_string($vn[0]); + + $nn = split('[- .,]',strtolower($row->nachname)); + $nn = clean_string($nn[0]); + $alias = $vn.".".$nn; + $qry = "UPDATE tbl_person set alias='$alias' where uid='$row->uid'"; + if(!$res_insert=pg_exec($conn, $qry)) + { + $text.=$qry; + $text.="\rFehler: Alias existiert bereits: $alias"; + $insert_error++; + } + + // tbl_student + if(!$res_insert=pg_exec($conn, $sql_query)) + { + $text.=$qry; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $insert_error++; + } + $sql_query="INSERT INTO tbl_student (uid,matrikelnr, studiengang_kz, semester, verband, gruppe) ". + "VALUES('$row->uid','$row->perskz',$row->kennzahl,$row->semester,'$row->verband','$row->gruppe')"; + echo $sql_query.'
'; + if(!$res_insert=pg_exec($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $insert_error++; + } + else + $anz_insert++; + } + // bestehende Studenten + elseif ($num_rows_std==1) + { + $update=0; + $row_std=pg_fetch_object($res_std,0); + if ($row->gruppe==NULL) + $row->gruppe=1; + if ($row->titel!=$row_std->titel) + $update=1; + elseif ($row->vornamen!=$row_std->vornamen) + $update=2; + elseif ($row->nachname!=$row_std->nachname) + $update=3; + elseif ($row->gebdatum!=$row_std->gebdatum) + $update=4; + elseif ($row->gebort!=$row_std->gebort) + $update=5; + elseif ($row->perskz!=$row_std->matrikelnr) + $update=6; + elseif ($row->semester!=$row_std->semester) + $update=7; + elseif ($row->verband!=$row_std->verband) + $update=8; + elseif ($row->gruppe!=$row_std->gruppe) + $update=9; + elseif ($row->kennzahl!=$row_std->studiengang_kz) + $update=10; + if ($update) + { + $text.="Der Student $row->vornamen $row->nachname ($row->uid) wird upgedatet.\r"; + // person + $sql_query="UPDATE tbl_person SET titel='$row->titel', vornamen='$row->vornamen', ". + " nachname='$row->nachname', gebdatum='$row->gebdatum', gebort='$row->gebort'". + " WHERE uid LIKE '$uid'"; + echo $sql_query.'
'; + if(!$res_update=pg_exec($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $update_error++; + } + // student + $sql_query="UPDATE tbl_student SET matrikelnr='$row->perskz', semester=$row->semester"; + if ($row->verband==NULL) + $sql_query.=", verband=NULL"; + else + $sql_query.=", verband='$row->verband'"; + if ($row->gruppe==NULL) + $sql_query.=", gruppe=NULL"; + else + $sql_query.=", gruppe='$row->gruppe'"; + $sql_query.=", studiengang_kz=".$row->kennzahl; + $sql_query.=", updateamum=now(), updatevon='auto' WHERE uid LIKE '$uid'"; + echo $sql_query.'
'; + if(!$res_update=pg_exec($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $update_error++; + } + else + $anz_update++; + } + } + // Student kommt mehrmals vor ->Warnung + elseif ($num_rows_std>1) + { + $text.="\r!!! Der Student $row->vornamen $row->nachname ($row->uid) kommt mehrfach vor!\r"; + $double_error++; + } + } + else + { + $plausi_error++; + $text.="\r!!! Der Student $row->vornamen $row->nachname ($row->uid) STG:$row->kennzahl S:$row->semester V:$row->verband G:$row->gruppe hat nicht plausible Daten!"; + } + } + $text.="\r$plausi_error Fehler beim Plausibilitaetscheck!\r"; + $text.="$update_error Fehler bei Student-Update!\r"; + $text.="$insert_error Fehler bei Student-Insert!\r"; + $text.="$double_error Studenten kommen in VileSci doppelt vor!\r\r"; + $text.="$anz_update Studenten wurden upgedatet.\r"; + $text.="$anz_insert Studenten wurden neu angelegt.\r\r"; + $text.="\rEND OF SYNCHRONISATION\r"; + if (mail($adress,"FAS Synchro mit VileSci (Studenten)",$text,"From: vilesci@technikum-wien.at")) + $sendmail=true; + else + $sendmail=false; +?> + + + + FAS-Synchro mit VileSci (Studenten) + + + +'; +else + echo "Mail konnte nicht verschickt werden!
"; +echo $text; + +?> + + diff --git a/admin/sync/sync_fas_std_fault.php b/admin/sync/sync_fas_std_fault.php new file mode 100644 index 000000000..8f206a23c --- /dev/null +++ b/admin/sync/sync_fas_std_fault.php @@ -0,0 +1,48 @@ +FAS-Synchro mit TEMPUS fehlerhafte Studenten'; + $text.=''; + // Start Check + $sql_query="SELECT * FROM fas_view_student_vilesci WHERE uid NOT IN "; + $sql_query.="(SELECT uid FROM fas_view_student_vilesci WHERE semester >0 AND semester <8 AND"; + $sql_query.=" verband IS NOT NULL AND uid IS NOT NULL AND uid NOT LIKE '') ORDER BY kennzahl,nachname"; // LIMIT 5"; + //echo $sql_query."
"; + $result=pg_exec($conn_fas, $sql_query); + $num_rows=pg_numrows($result); + $num_fields=pg_numfields($result); + $text.="Dies ist eine automatische eMail!

"; + $text.="Es wurde eine Ueberpruefung der Daten in der FAS-View fuer Studenten durchgeführt.
"; + $text.="Anzahl der fehlerhaften Daten: $num_rows

"; + $text.="Folgende Studenten haben fehlerhafte Daten im FAS

"; + $text.=''; + $text.=''; + for ($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($result,$i); + $text.='"; + $text.=""; + } + $text.='
STG_KZuidTitelVornamenNachnameMatrikelnrSemesterVerbandGruppe
$row->kennzahl$row->uid$row->titel$row->vornamen$row->nachname$row->perskz$row->semester$row->verband$row->gruppe
'; + + echo $text; + + if (mail($adress,"FAS Synchro mit TEMPUS fehlerhafte Studenten",$text,$headers)) + echo 'Mail wurde verschickt an '.$adress.'!
'; + else + echo "Mail konnte nicht verschickt werden!
"; + +?> diff --git a/admin/sync/sync_feedback.php b/admin/sync/sync_feedback.php new file mode 100644 index 000000000..eeb64e80a --- /dev/null +++ b/admin/sync/sync_feedback.php @@ -0,0 +1,77 @@ +0) + return true; + return false; + } + + $qry = "SELECT * from lehre.tbl_feedback_lehrfach"; + $result = pg_exec($conn,$qry); + + echo "Uebernahme von tbl_feedback_lehrfach"; + flush(); + while($row=pg_fetch_object($result)) + { + $sql_qry = "Select * from tbl_lehrfach where studiengang_kz =$row->studiengang_kz AND semester=$row->semester AND lehrevz=$lehrfachzuteilung_kurzbz"; + + $lf_result=pg_exec($conn,$sql_qry); + if($lf_row=pg_fetch_object($conn,$qry)) + { + if(!isInTab($row->datum,$row->betreff,$row->text,$row->uid)) + { + $insert = "INSERT INTO tbl_feedback(datum,betreff,text,lfnr,uid) VALUES('$row->datum','$row->betreff','$row->text',$lf_row->lehrfach_nr,'$row->uid')"; + pg_exec($conn,$insert); + echo "+"; + flush(); + } + } + else + { + echo "Lehrfachaufloesung nicht moeglich"; //Oder Formular ausgeben + } + } + + $qry = "SELECT * from lehre.tbl_feedback_lehrfach"; + $result = pg_exec($conn,$qry); + + echo "Uebernahme von tbl_feedback_freifach"; + flush(); + while($row=pg_fetch_object($result)) + { + $sql_qry = "Select * from tbl_lehrfach where lehrevz=$lehrfachzuteilung_kurzbz AND studiengang_kz=0 AND semester is null"; + + $lf_result=pg_exec($conn,$sql_qry); + if($lf_row=pg_fetch_object($conn,$qry)) + { + $insert = "INSERT INTO tbl_feedback(datum,betreff,text,lfnr,uid) VALUES('$row->datum','$row->betreff','$row->text',$lf_row->lehrfach_nr,'$row->uid')"; + pg_exec($conn,$insert); + echo "+"; + flush(); + } + else + { + echo "Lehrfachaufloesung nicht moeglich"; //Oder Formular ausgeben + } + } + + + + +?> \ No newline at end of file diff --git a/admin/sync/sync_stpldev_stpl.php b/admin/sync/sync_stpldev_stpl.php new file mode 100644 index 000000000..4ee89ec08 --- /dev/null +++ b/admin/sync/sync_stpldev_stpl.php @@ -0,0 +1,406 @@ + + + + Stundenplan-Synchro (stpldev-stpl) + + +=now() ORDER BY start;"; +//echo $sql_query.'
'; +if (!$result=pg_query($conn, $sql_query)) +{ + echo $sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + $message_sync.=$sql_query.' fehlgeschlagen!
'.pg_last_error($conn); +} +else +{ + if ($row=pg_fetch_object($result)) + $datum_ende=$row->ende; + else + $message_sync.='Kein aktuelles Studiensemester gefunden! '.$sql_query.'
'; +} + + + +$message_begin='Dies ist eine automatische Mail!
Es haben sich folgende Aenderungen in Ihrem Stundenplan ergeben:
'; + + +/************************************************** + * Datensaetze holen die neu sind + */ +echo 'Neue Datensätze werden angelegt.
';flush(); +$sql_query="SELECT * FROM vw_stundenplandev WHERE datum>='$datum_begin' AND datum<='$datum_ende' AND + stundenplandev_id NOT IN + (SELECT stundenplan_id FROM tbl_stundenplan WHERE datum>='$datum_begin');"; +//echo $sql_query.'
'; +if (!$result=pg_query($conn, $sql_query)) +{ + echo $sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + $message_sync.=$sql_query.' fehlgeschlagen!
'.pg_last_error($conn); +} +else +{ + flush(); + while ($row=pg_fetch_object($result)) + { + $sql_query='INSERT INTO tbl_stundenplan + (stundenplan_id,unr,uid,datum,stunde,ort_kurzbz,lehrfach_nr,lehrform_kurzbz,studiengang_kz,semester,verband,gruppe, + einheit_kurzbz,titel,anmerkung,fix,updateamum,updatevon,lehrveranstaltung_id) VALUES'; + $sql_query.="($row->stundenplandev_id,$row->unr,'$row->uid','$row->datum',$row->stunde,'$row->ort_kurzbz', + $row->lehrfach_nr,'$row->lehrform',$row->studiengang_kz,$row->semester"; + if ($row->verband==null) + $sql_query.=',NULL'; + else + $sql_query.=",'$row->verband'"; + if ($row->gruppe==null) + $sql_query.=',NULL'; + else + $sql_query.=",'$row->gruppe'"; + if ($row->einheit_kurzbz==null) + $sql_query.=',NULL'; + else + $sql_query.=",'$row->einheit_kurzbz'"; + $sql_query.=",'$row->titel','$row->anmerkung'"; + if ($row->fix=='t') + $sql_query.=',TRUE'; + else + $sql_query.=',FALSE'; + $sql_query.=",'$row->updateamum','$row->updatevon'"; + if ($row->lehrveranstaltung_id==null) + $sql_query.=',NULL'; + else + $sql_query.=",$row->lehrveranstaltung_id"; + $sql_query.=');'; + //echo $sql_query; + if (!$result_insert=pg_query($conn, $sql_query)) + { + echo $sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + $message_sync.=$sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + $count_err++; + } + else + { + $count_ins++; + if ($count_ins%10==0) + { + echo '-'; + flush(); + } + // Mails vorbereiten + // Lektoren + if (substr($row->uid,0,1)!='_') + { + if (!isset($message[$row->uid]->isneu)); + { + $message[$row->uid]->isneu=true; + $message[$row->uid]->mailadress=$row->uid.'@technikum-wien.at'; + $message[$row->uid]->message=$message_begin.'
Neue Stunden:
+ '; + } + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + } + // Verband + $verband=$row->stg_kurzbz.$row->semester.$row->verband.$row->gruppe; + $verband=trim($verband); + $verband=strtolower($verband); + if (!isset($message[$verband]->isneu)); + { + $message[$verband]->isneu=true; + $message[$verband]->mailadress=$verband.'@technikum-wien.at'; + $message[$verband]->message=$message_begin.'
Neue Stunden:
+
OrtVerbandLektorDatum/StdLehrfach
'.$row->ort_kurzbz.''.$row->stg_kurzbz.'-'.$row->semester.$row->verband.$row->gruppe.' '.$row->einheit_kurzbz.''.$row->lektor.''.$row->datum.'/'.$row->stunde.''.$row->lehrfach.'-'.$row->lehrform.' ('.$row->lehrfach_bez.')
'; + } + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + } + } + foreach($message as $msg) + if($msg->isneu) + $msg->message.='
OrtVerbandLektorDatum/StdLehrfach
'.$row->ort_kurzbz.''.$row->stg_kurzbz.'-'.$row->semester.$row->verband.$row->gruppe.' '.$row->einheit_kurzbz.''.$row->lektor.''.$row->datum.'/'.$row->stunde.''.$row->lehrfach.'-'.$row->lehrform.' ('.$row->lehrfach_bez.')
'; +} + +/************************************************** +* Datensaetze holen die alt sind +*/ + +echo '
Alte Datensätze werden gelöscht.
';flush(); +$sql_query="SELECT * FROM vw_stundenplan WHERE stundenplan_id NOT IN + (SELECT stundenplandev_id FROM tbl_stundenplandev WHERE datum>='$datum_begin') + AND datum>='$datum_begin';"; +if (!$result=pg_query($conn, $sql_query)) +{ + echo $sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + $message_sync.=$sql_query.' fehlgeschlagen!
'.pg_last_error($conn); +} +while ($row=pg_fetch_object($result)) +{ + $sql_query='DELETE FROM tbl_stundenplan WHERE stundenplan_id='.$row->stundenplan_id; + //echo $sql_query.'
'; + if (!$result_delete=pg_query($conn, $sql_query)) + { + echo $sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + $message_sync.=$sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + $count_err++; + } + else + { + $count_del++; + if ($count_del%10==0) + { + echo '-'; + flush(); + } + // Mails vorbereiten + // Lektoren + if (substr($row->uid,0,1)!='_') + { + if (!isset($message[$row->uid]->isalt)); + { + $message[$row->uid]->isalt=true; + $message[$row->uid]->mailadress=$row->uid.'@technikum-wien.at'; + $message[$row->uid]->message.=$message_begin.'
Gelöeschte Stunden:
+ '; + } + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + } + // Verband + $verband=$row->stg_kurzbz.$row->semester.$row->verband.$row->gruppe; + $verband=trim($verband); + $verband=strtolower($verband); + if (!isset($message[$verband]->isalt)); + { + $message[$verband]->isalt=true; + $message[$verband]->mailadress=$verband.'@technikum-wien.at'; + $message[$verband]->message.=$message_begin.'
Geaenderte Stunden:
+
OrtVerbandLektorDatum/StdLehrfach
'.$row->ort_kurzbz.''.$row->stg_kurzbz.'-'.$row->semester.$row->verband.$row->gruppe.' '.$row->einheit_kurzbz.''.$row->lektor.''.$row->datum.'/'.$row->stunde.''.$row->lehrfach.'-'.$row->lehrform.' ('.$row->lehrfach_bez.')
'; + } + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + } + foreach($message as $msg) + if($msg->isalt) + $msg->message.='
OrtVerbandLektorDatum/StdLehrfach
'.$row->ort_kurzbz.''.$row->stg_kurzbz.'-'.$row->semester.$row->verband.$row->gruppe.' '.$row->einheit_kurzbz.''.$row->lektor.''.$row->datum.'/'.$row->stunde.''.$row->lehrfach.'-'.$row->lehrform.' ('.$row->lehrfach_bez.')
'; +} + + +/************************************************** + * Datensaetze holen die anders sind + */ + +echo '
Datensätze werden geändert.
';flush(); +$sql_query="SELECT vw_stundenplandev.*, vw_stundenplan.datum AS old_datum, vw_stundenplan.stunde AS old_stunde, + vw_stundenplan.ort_kurzbz AS old_ort_kurzbz, vw_stundenplan.lektor AS old_lektor + FROM vw_stundenplandev, vw_stundenplan + WHERE vw_stundenplan.stundenplan_id=vw_stundenplandev.stundenplandev_id AND ( + vw_stundenplandev.unr!=vw_stundenplan.unr OR + vw_stundenplandev.uid!=vw_stundenplan.uid OR + vw_stundenplandev.datum!=vw_stundenplan.datum OR + vw_stundenplandev.stunde!=vw_stundenplan.stunde OR + vw_stundenplandev.ort_kurzbz!=vw_stundenplan.ort_kurzbz OR + vw_stundenplandev.lehrfach_nr!=vw_stundenplan.lehrfach_nr OR + vw_stundenplandev.lehrform!=vw_stundenplan.lehrform OR + vw_stundenplandev.studiengang_kz!=vw_stundenplan.studiengang_kz OR + vw_stundenplandev.semester!=vw_stundenplan.semester OR + vw_stundenplandev.verband!=vw_stundenplan.verband OR + vw_stundenplandev.gruppe!=vw_stundenplan.gruppe OR + vw_stundenplandev.einheit_kurzbz!=vw_stundenplan.einheit_kurzbz OR + vw_stundenplandev.titel!=vw_stundenplan.titel OR + vw_stundenplandev.anmerkung!=vw_stundenplan.anmerkung OR + vw_stundenplandev.fix!=vw_stundenplan.fix OR + vw_stundenplandev.lehrveranstaltung_id!=vw_stundenplan.lehrveranstaltung_id ) + AND vw_stundenplandev.datum>='$datum_begin';"; +//echo $sql_query.'
'; +if (!$result=pg_query($conn, $sql_query)) +{ + echo $sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + $message_sync.=$sql_query.' fehlgeschlagen!
'.pg_last_error($conn); +} +while ($row=pg_fetch_object($result)) +{ + // Alten Eintrag aus tbl_stundenplan holen + $sql_query="SELECT * FROM tbl_stundenplandev WHERE stundenplandev_id=$row->stundenplandev_id;"; + if (!$result_old=pg_query($conn, $sql_query)) + { + echo $sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + $message_sync.=$sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + } + else + $row_old=pg_fetch_object($result_old); + + // Datensaetze aendern + $sql_query="UPDATE tbl_stundenplan SET + unr=$row->unr,uid='$row->uid',datum='$row->datum',stunde=$row->stunde, + ort_kurzbz='$row->ort_kurzbz',lehrfach_nr=$row->lehrfach_nr, lehrform_kurzbz='$row->lehrform', + studiengang_kz=$row->studiengang_kz,semester=$row->semester"; + if ($row->verband==null) + $sql_query.=',verband=NULL'; + else + $sql_query.=",verband='$row->verband'"; + if ($row->gruppe==null) + $sql_query.=',gruppe=NULL'; + else + $sql_query.=",gruppe='$row->gruppe'"; + if ($row->einheit_kurzbz==null) + $sql_query.=',einheit_kurzbz=NULL'; + else + $sql_query.=",einheit_kurzbz='$row->einheit_kurzbz'"; + $sql_query.=",titel='$row->titel',anmerkung='$row->anmerkung'"; + if ($row->fix=='t') + $sql_query.=',fix=TRUE'; + else + $sql_query.=',fix=FALSE'; + $sql_query.=",updateamum='$row->updateamum',updatevon='$row->updatevon'"; + if ($row->lehrveranstaltung_id==null) + $sql_query.=',lehrveranstaltung_id=NULL'; + else + $sql_query.=",lehrveranstaltung_id=$row->lehrveranstaltung_id"; + $sql_query.=" WHERE stundenplan_id=$row->stundenplandev_id;"; + echo $sql_query.'
'; + if (!$result_update=pg_query($conn, $sql_query)) + { + echo $sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + $message_sync.=$sql_query.' fehlgeschlagen!
'.pg_last_error($conn); + $count_err++; + } + else + { + $count_upd++; + if ($count_upd%10==0) + { + echo '-'; + flush(); + } + // Mails vorbereiten + // Lektoren + if (substr($row->uid,0,1)!='_') + { + if (!isset($message[$row->uid]->isset)); + { + $message[$row->uid]->isset=true; + $message[$row->uid]->mailadress=$row->uid.'@technikum-wien.at'; + $message[$row->uid]->message.=$message_begin.'
Geänderte Stunden:
+ '; + } + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + $message[$row->uid]->message.=''; + } + // Verband + $verband=$row->stg_kurzbz.$row->semester.$row->verband.$row->gruppe; + $verband=trim($verband); + $verband=strtolower($verband); + if (!isset($message[$verband]->isset)); + { + $message[$verband]->isset=true; + $message[$verband]->mailadress=$verband.'@technikum-wien.at'; + $message[$verband]->message.=$message_begin.'
Geänderte Stunden:
+
StatusOrtVerbandLektorDatum/StdLehrfach
Vorher: '.$row->old_ort_kurzbz.''.$row->stg_kurzbz.'-'.$row->semester.$row->verband.$row->gruppe.' '.$row->einheit_kurzbz.''.$row->old_lektor.''.$row->old_datum.'/'.$row->old_stunde.''.$row->lehrfach.'-'.$row->lehrform.' ('.$row->lehrfach_bez.')
Jetzt: '.$row->ort_kurzbz.''.$row->stg_kurzbz.'-'.$row->semester.$row->verband.$row->gruppe.' '.$row->einheit_kurzbz.''.$row->lektor.''.$row->datum.'/'.$row->stunde.''.$row->lehrfach.'-'.$row->lehrform.' ('.$row->lehrfach_bez.')
'; + } + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + $message[$verband]->message.=''; + } + foreach($message as $msg) + if($msg->isset) + $msg->message.='
StatusOrtVerbandLektorDatum/StdLehrfach
Vorher: '.$row->old_ort_kurzbz.''.$row->stg_kurzbz.'-'.$row->semester.$row->verband.$row->gruppe.' '.$row->einheit_kurzbz.''.$row->old_lektor.''.$row->old_datum.'/'.$row->old_stunde.''.$row->lehrfach.'-'.$row->lehrform.' ('.$row->lehrfach_bez.')
Jetzt: '.$row->ort_kurzbz.''.$row->stg_kurzbz.'-'.$row->semester.$row->verband.$row->gruppe.' '.$row->einheit_kurzbz.''.$row->lektor.''.$row->datum.'/'.$row->stunde.''.$row->lehrfach.'-'.$row->lehrform.' ('.$row->lehrfach_bez.')
'; +} + +/************************************************** + * Mails an Lektoren und Verbaende schicken + */ +if ($sendmail) + foreach ($message as $msg) + //if (mail('pam@technikum-wien.at',"Stundenplan update",$msg->message,$headers."From: stpl@technikum-wien.at")) + if (mail($msg->mailadress,"Stundenplan update",$msg->message,$headers."From: stpl@technikum-wien.at")) + { + echo 'Mail an '.$msg->mailadress.' wurde verschickt!
'; + $message_stpl.='Mail an '.$msg->mailadress.' wurde verschickt!
'; + } + else + { + echo 'Mail an '.$msg->mailadress.' konnte nicht verschickt werden!
'; + $message_sync.='Mail an '.$msg->mailadress.' konnte ***nicht*** verschickt werden!
'; + } +// Mail an Admin +$message_tmp=$count_upd.' Datensätze wurden geändert.
+ '.$count_ins.' Datensätze wurden hinzugefügt.
+ '.$count_del.' Datensätze wurden gelöscht.
+ '.$count_err.' Fehler sind dabei aufgetreten!

'; +echo '
'.$message_tmp; +$message_sync=''.$message_tmp.$message_sync.$message_stpl.''; +mail('pam@technikum-wien.at',"Stundenplan update",$message_sync,$headers."From: stpl@technikum-wien.at"); +$message_stpl=''.$message_tmp.$message_stpl.''; +mail('stpl@technikum-wien.at',"Stundenplan update",$message_stpl,$headers."From: stpl@technikum-wien.at"); +?> + + diff --git a/admin/sync/sync_vilesci_stg.php b/admin/sync/sync_vilesci_stg.php new file mode 100644 index 000000000..ed1ef081b --- /dev/null +++ b/admin/sync/sync_vilesci_stg.php @@ -0,0 +1,594 @@ +lvnr.' '.$row->bezeichnung; +} + +function getSemesterWhereClause() +{ + global $conn; + $qry="select * from tbl_studiensemester where ende>now()"; + $result=pg_exec($conn, $qry); + $where=''; + while ($row=pg_fetch_object($result)) + { + $where.= ((strlen($where)>0)?' or ':'')."studiensemester_kurzbz='".$row->studiensemester_kurzbz."' "; + } + if (strlen($where)>0) $where=" ($where) "; + return $where; +} + +function validate($row) +{ + global $error_log,$einheit,$missing_einheit,$missing_raumtyp,$missing_lehrform,$raumtyp,$lehrform; + $valid=true; + if ($row->raumtyp==null) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Raumtyp fehlt'; + $valid=false; + } + if ($row->semester>8 || $row->semester<1) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Semester bei '.$row->semester.$row->verband.$row->gruppe.' größer als 8'; + $valid=false; + } + if (!($row->verband==null || $row->verband=='' || $row->verband=='A' || $row->verband=='B' || $row->verband=='C' || $row->verband=='D')) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Verband bei '.$row->semester.$row->verband.$row->gruppe.' außerhalb des gültigen Bereichs (A bis D)'; + //print_r($row); + $valid=false; + } + if (!($row->gruppe==null || $row->gruppe=='' || $row->gruppe=='1' || $row->gruppe=='2' || $row->gruppe=='3' || $row->gruppe=='4')) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Gruppe bei '.$row->semester.$row->verband.$row->gruppe.' außerhalb des gültigen Bereichs (1 bis 4)'; + $valid=false; + } + if (!$row->stundenblockung>0) { + $error_log[$row->studiengang_kz][]=printLVA($row).': Stundenblockung ist nicht größer 0'; + $valid=false; + } + if (!$row->semesterstunden>0) { + $error_log[$row->studiengang_kz][]=printLVA($row).': Semesterstunden sind nicht größer 0'; + $valid=false; + } + if (!$row->wochenrythmus>0) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Wochenrythmus ist nicht größer 0'; + $valid=false; + } + if ($row->start_kw<=0 || $row->start_kw>53) + { + $error_log[$row->studiengang_kz][]=printLVA($row).': Start-KW außerhalb des gültigen Bereichs (1 bis 53)'; + $valid=false; + } + if (strlen($row->einheit_kurzbz)>0 && !isset($einheit[$row->einheit_kurzbz]) && !isset($missing_einheit[$row->einheit_kurzbz])) + { + $missing_einheit[$row->einheit_kurzbz]=1; + } + if (strlen($row->raumtyp)>0 && !isset($raumtyp[$row->raumtyp]) && !isset($missing_raumtyp[$row->raumtyp])) + { + $missing_raumtyp[$row->raumtyp]=1; + $valid=false; + } + if (strlen($row->raumtypalternativ)>0 && !isset($raumtyp[$row->raumtypalternativ]) && !isset($missing_raumtyp[$row->raumtypalternativ])) { + $missing_raumtyp[$row->raumtypalternativ]=1; + } + if (!ereg("^[A-Za-z]{1,5}[0-9]{0,1}$",$row->raumtyp)) + { + $error_log[$row->studiengang_kz][]=$row->raumtyp.': Raumtyp bei LVNR:'.$row->lvnr.' ist nicht plausibel.'; + $valid=false; + } + if (!ereg("^[A-Za-z]{1,5}[0-9]{0,1}$",$row->raumtypalternativ)) + { + $error_log[$row->studiengang_kz][]=$row->raumtypalternativ.': Raumtypalternative bei LVNR:'.$row->lvnr.' ist nicht plausibel.'; + $valid=false; + } + if (strlen($row->lehrform)>0 && !isset($lehrform[$row->lehrform]) && !isset($missing_lehrform[$row->lehrform])) { + $missing_lehrform[$row->lehrform]=1; + } + if (!ereg("^[A-Z]{1,5}[0-9]{0,1}$",$row->lehrfach_kurzbz)) + { + $error_log[$row->studiengang_kz][]=$row->lehrfach_kurzbz.'-'.$row->lehrform.'/'.$row->studiengang_kz.'-'.$row->semester.': Lehrfach-Kuerzel bei LVNR:'.$row->lvnr.' ist nicht plausibel.'; + $valid=false; + } + if (!ereg("^[A-Z]{1,3}$",$row->lehrform)) + { + $error_log[$row->studiengang_kz][]=$row->lehrfach_kurzbz.'-'.$row->lehrform.'/'.$row->studiengang_kz.'-'.$row->semester.': Lehrform bei LVNR:'.$row->lvnr.' ist nicht plausibel.'; + $valid=false; + } + return $valid; +} + +/** + * FAS-Lehrfach auf interne Lehrfach-Nr übersetzen + */ +function getLehrfachNr($kurzbz,$studiengang_kz,$semester,$lehrfach_bezeichnung, $fachbereich_id, $ects, $conn) +{ + global $lehrfach; + global $text; + + if (isset($lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr'])) + { + //echo 'Nummer:'.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr'].'Bez: '.$lehrfach_bezeichnung.'
'; + + // Nebenbei die Lehrfachbezeichnung kontrollieren + if ($lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_bezeichnung']!=$lehrfach_bezeichnung) + { + // Update + $qry="UPDATE tbl_lehrfach SET bezeichnung='$lehrfach_bezeichnung' WHERE lehrfach_nr=".$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr']; + if (!$result=pg_query($conn, $qry)) + echo $qry.' fehlgeschlagen!
'; + else + { + echo 'Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurde von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_bezeichnung'].' auf '.$lehrfach_bezeichnung.' geaendert!
'; + $text.='Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurde von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_bezeichnung'].' auf '.$lehrfach_bezeichnung.' geaendert!\n'; + $lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_bezeichnung']=$lehrfach_bezeichnung; + } + } + + // Nebenbei die ECTS Punkte kontrollieren + if ($lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['ects']!=$ects) + { + if ($ects!='') //ereg("[0-9]{1,4}[\.|,][0-9]{0,2}$",$ects) + { + // Update + $qry="UPDATE tbl_lehrfach SET ects='$ects' WHERE lehrfach_nr=".$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr']; + //echo $qry.'
'; + if (!$result=pg_query($conn, $qry)) + echo $qry.' fehlgeschlagen!
'; + else + { + echo ' Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurden die ECTS-Punkte von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['ects'].' auf '.$ects.' geaendert!
'; + $text.='Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurden die ECTS-Punkte von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['ects'].' auf '.$ects.' geaendert!\n'; + $lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['ects']=$ects; + } + } + else + { + echo 'Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' sind die ECTS-Punkte von '.$ects.' nicht Plausibel!
'; + $text.='Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' sind die ECTS-Punkte von '.$ects.' nicht Plausibel!\n'; + } + + } + + // Nebenbei die FachbereichID kontrollieren + if ($lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['fachbereich_id']!=$fachbereich_id) + { + // Update + $qry="UPDATE tbl_lehrfach SET fachbereich_id=$fachbereich_id WHERE lehrfach_nr=".$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr']; + if (!$result=@pg_query($conn, $qry)) + echo $qry.' fehlgeschlagen!
'; + else + { + echo 'Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurde die FachbereichID von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['fachbereich_id'].' auf '.$fachbereich_id.' geaendert!
'; + $text.='Bei Lehrfach '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.' wurde die FachbereichID von '.$lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['fachbereich_id'].' auf '.$fachbereich_id.' geaendert!\n'; + $lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['fachbereich_id']=$fachbereich_id; + } + } + return $lehrfach[$kurzbz.'/'.$studiengang_kz.'/'.$semester]['lehrfach_nr']; + } + //echo 'missing getLehrfachNr: '.$kurzbz.'/'.$studiengang_kz.'/'.$semester.'
'; + return -1; +} + + +/************************* + * FAS-Synchronisation + */ + +// E-Mails der Studiengänge +$stg_mail=array(); +$qry="select studiengang_kz,email,kurzbz from tbl_studiengang"; +$result=pg_exec($conn, $qry); +while ($row=pg_fetch_object($result)) +{ + $stg_mail[$row->studiengang_kz] = $row->email; + $stg_kurzbz[$row->studiengang_kz]=$row->kurzbz; +} + +// Anzahl der LVA in VileSci +$sql_query="SELECT count(*) AS anz FROM tbl_lehrveranstaltung"; +//echo $sql_query."
"; +$result=pg_exec($conn, $sql_query); +$vil_anz_lva=pg_fetch_result($result,0,'anz'); + +// Lehrfächer holen und in Array speichern (Key ist kurzbz + '/' + lehform_kurzbz) +$sql_query="SELECT lehrfach_nr,kurzbz,studiengang_kz,semester, bezeichnung, fachbereich_id, ects FROM tbl_lehrfach"; +$result=pg_exec($conn, $sql_query); +while ($row=pg_fetch_object($result)) +{ + $lehrfach[$row->kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester]['lehrfach_nr'] = $row->lehrfach_nr; + $lehrfach[$row->kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester]['fachbereich_id'] = $row->fachbereich_id; + $lehrfach[$row->kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester]['lehrfach_bezeichnung'] = $row->bezeichnung; + $lehrfach[$row->kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester]['ects'] = $row->ects; +} +//print_r($lehrfach); +// Einheiten holen +$sql_query="SELECT einheit_kurzbz,bezeichnung FROM tbl_einheit"; +$result=pg_exec($conn, $sql_query); +while ($row=pg_fetch_object($result)) + $einheit[$row->einheit_kurzbz] = $row->bezeichnung; +// Raumtypen holen +$sql_query="SELECT raumtyp_kurzbz,beschreibung FROM tbl_raumtyp"; +$result=pg_exec($conn, $sql_query); +while ($row=pg_fetch_object($result)) + $raumtyp[$row->raumtyp_kurzbz] = $row->beschreibung; +// Lehformen holen +$sql_query="SELECT lehrform_kurzbz,bezeichnung FROM tbl_lehrform"; +$result=pg_exec($conn, $sql_query); +while ($row=pg_fetch_object($result)) + $lehrform[$row->lehrform_kurzbz] = $row->bezeichnung; +//print_r($lehrfach); +echo 'FAS-Datenbank wird abgefragt!
'; +flush(); + +// Start Lehrveranstaltungen Synchro +$sql_query="SELECT DISTINCT fas_id,trim(lvnr) AS lvnr,trim(unr)::int8 AS unr,einheit_kurzbz,lektor,trim(upper(lehrfach_kurzbz)) AS lehrfach_kurzbz, + trim(upper(lehrform)) AS lehrform, lehrfach_bezeichnung, + studiengang_kz,fachbereich_id,semester,verband,gruppe,raumtyp,raumtypalternativ, + round(semesterstunden) AS semesterstunden,stundenblockung,wochenrythmus,start_kw,anmerkung,studiensemester_kurzbz, ects + FROM fas_view_alle_lehreinheiten_vilesci ". + "where ".getSemesterWhereClause(); +//echo $sql_query."
"; +$result=pg_exec($conn_fas, $sql_query); +$num_rows=pg_numrows($result); +$text="Dies ist eine automatische eMail!\r\r"; +$text.="Es wurde eine Synchronisation mit FAS durchgeführt.\r"; +$text.="Anzahl der LVA vom FAS-Import: $num_rows \r"; +$text.="Anzahl der LVA in der VileSci: $vil_anz_lva \r\r"; +$plausi_error=0; +$update_error=0; +$insert_error=0; +$double_error=0; +$anz_update=0; +$anz_insert=0; +echo $num_rows.' Datensaetze
'; +for ($i=0;$i<$num_rows;$i++) +{ + if ($i%100==0) + { + echo '-'; + flush(); + } + $row=pg_fetch_object($result,$i); + // Kennzahl der Studiengangs bei ehemaligen bTec auf TW aendern. + if ($row->studiengang_kz==203) + $row->studiengang_kz=0; + // Lehrfach-Nr übersetzen (-1 wenn nicht vorhanden) + $row->lehrfach_nr=getLehrfachNr($row->lehrfach_kurzbz,$row->studiengang_kz,$row->semester, $row->lehrfach_bezeichnung, $row->fachbereich_id, $row->ects, $conn); + // Einheit vollstaendiger Name + if (count($row->einheit_kurzbz)>0) + $row->einheit_kurzbz=$stg_kurzbz[$row->studiengang_kz].'-'.$row->einheit_kurzbz; + + // Plausibilitaetscheck + //if ($row->gruppe==NULL) + // $row->gruppe='1'; + + // + if (!$row->stundenblockung>0) + $row->stundenblockung=1; + if (!$row->start_kw>0) + $row->start_kw=1; + if (!$row->wochenrythmus>0) + $row->wochenrythmus=1; + + if ($row->lehrfach_nr==-1) + { + //$error_log[$row->studiengang_kz][]=printLVA($row).': Lehrfach (Kurzbz='".$row->lehrfach_kurzbz."',Lehrform".$row->lehrform) existiert noch nicht. Stundenplanabteilung wurde benachrichtigt.'; + if (!isset($missing_lehrfaecher[$row->lehrfach_kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester])) $missing_lehrfaecher[$row->lehrfach_kurzbz.'/'.$row->studiengang_kz.'/'.$row->semester]=1; + $valid=false; + } + + if (validate($row) && $row->lehrfach_nr>-1) + { + // SQL vorbereiten (jede LVA vom FAS im VileSci suchen) + $sql_query="SELECT * from tbl_lehrveranstaltung where fas_id=".$row->fas_id; + //echo $sql_query; + $res_lva=pg_query($conn, $sql_query); + $num_rows_lva=pg_numrows($res_lva); + + // neue LVA + if ($num_rows_lva==0) + { + $text.="Die LVA fas-id=$row->fas_id lvnr=$row->lvnr unr=$row->unr wird neu angelegt.\r"; + $sql_query="INSERT INTO tbl_lehrveranstaltung (lvnr,unr,einheit_kurzbz,lektor,lehrfach_nr,lehrform_kurzbz,"; + $sql_query.="studiengang_kz,fachbereich_id,semester,verband,gruppe,raumtyp,". + "raumtypalternativ,semesterstunden,stundenblockung,". + "wochenrythmus,start_kw,studiensemester_kurzbz,fas_id,anmerkung) ". + "VALUES('$row->lvnr'". + ",$row->unr,". + (strlen($row->einheit_kurzbz)>0?"'".$row->einheit_kurzbz."'":'NULL').",". + "'$row->lektor',". + "'$row->lehrfach_nr',". + "'$row->lehrform',". + "'$row->studiengang_kz',". + "$row->fachbereich_id,". + "$row->semester,"; + if ($row->verband==null) + $sql_query.='NULL,'; + else + $sql_query.="'$row->verband',"; + if ($row->gruppe==null) + $sql_query.='NULL,'; + else + $sql_query.="'$row->gruppe',"; + $sql_query.="'$row->raumtyp',". + "'$row->raumtypalternativ',". + "$row->semesterstunden,". + "$row->stundenblockung,". + "$row->wochenrythmus,". + "$row->start_kw,". + "'$row->studiensemester_kurzbz'," . + "$row->fas_id,'$row->anmerkung')"; + //echo $sql_query.'
'; + if(!$res_insert=@pg_exec($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\nFehler: ".pg_errormessage($conn)."\n"; + $insert_error++; + } + else + $anz_insert++; + } + // bestehende LVA + elseif ($num_rows_lva==1) + { + $update_sql=''; + $row_lva=pg_fetch_object($res_lva,0); + //var_dump($row_lva); + //if ($row->gruppe==NULL) + // $row->gruppe=1; + //echo '-'.$row->lvnr.'-'.$row_lva->lvnr.'-
'; + if ($row->lvnr!=$row_lva->lvnr) + $update_sql.="lvnr='".$row->lvnr."'"; + elseif ($row->unr!=$row_lva->unr) + $update_sql.="unr=".$row->unr; + elseif ($row->einheit_kurzbz!=$row_lva->einheit_kurzbz) + $update_sql.=(strlen($update_sql)>0?',':'').'einheit_kurzbz='.(strlen($row->einheit_kurzbz)>0?"'".$row->einheit_kurzbz."'":'NULL'); + elseif ($row->lektor!=$row_lva->lektor) + $update_sql.=(strlen($update_sql)>0?',':'')."lektor='".$row->lektor."'"; + elseif ($row->lehrfach_nr!=$row_lva->lehrfach_nr) + $update_sql.=(strlen($update_sql)>0?',':'')."lehrfach_nr=".$row->lehrfach_nr; + elseif ($row->lehrform!=$row_lva->lehrform_kurzbz) + $update_sql.=(strlen($update_sql)>0?',':'')."lehrform_kurzbz='".$row->lehrform."'"; + elseif ($row->studiengang_kz!=$row_lva->studiengang_kz) + $update_sql.=(strlen($update_sql)>0?',':'')."studiengang_kz=".$row->studiengang_kz; + elseif ($row->fachbereich_id!=$row_lva->fachbereich_id) + $update_sql.=(strlen($update_sql)>0?',':'')."fachbereich_id=".$row->fachbereich_id; + elseif ($row->semester!=$row_lva->semester) + $update_sql.=(strlen($update_sql)>0?',':'')."semester=".$row->semester; + elseif ($row->verband!=$row_lva->verband) + $update_sql.=(strlen($update_sql)>0?',':'')."verband=".(strlen($row->verband)>0?"'".$row->verband."'":'NULL'); + elseif ($row->gruppe!=$row_lva->gruppe) + $update_sql.=(strlen($update_sql)>0?',':'')."gruppe=".(strlen($row->gruppe)>0?"'".$row->gruppe."'":'NULL'); + elseif ($row->raumtyp!=$row_lva->raumtyp) + $update_sql.=(strlen($update_sql)>0?',':'')."raumtyp='".$row->raumtyp."'"; + elseif ($row->raumtypalternativ!=$row_lva->raumtypalternativ) + $update_sql.=(strlen($update_sql)>0?',':'')."raumtypalternativ='".$row->raumtypalternativ."'"; + elseif ($row->semesterstunden!=$row_lva->semesterstunden) + $update_sql.=(strlen($update_sql)>0?',':'')."semesterstunden=".$row->semesterstunden; + elseif ($row->stundenblockung!=$row_lva->stundenblockung) + $update_sql.=(strlen($update_sql)>0?',':'')."stundenblockung=".$row->stundenblockung; + elseif ($row->wochenrythmus!=$row_lva->wochenrythmus) + $update_sql.=(strlen($update_sql)>0?',':'')."wochenrythmus=".$row->wochenrythmus; + elseif ($row->start_kw!=$row_lva->start_kw) + $update_sql.=(strlen($update_sql)>0?',':'')."start_kw=".(strlen($row->start_kw)>0?$row->start_kw:'NULL'); + elseif ($row->studiensemester_kurzbz!=$row_lva->studiensemester_kurzbz) + $update_sql.=(strlen($update_sql)>0?',':'')."studiensemester_kurzbz='".$row->studiensemester_kurzbz."'"; + elseif ($row->anmerkung!=$row_lva->anmerkung) + $update_sql.=(strlen($update_sql)>0?',':'')."anmerkung='".$row->anmerkung."'"; + + if (strlen($update_sql)>0) + { + $text.="Die LVA fas-id=$row->fas_id lvnr=$row->lvnr unr=$row->unr wird upgedatet.\r"; + $sql_query="UPDATE tbl_lehrveranstaltung SET ". + $update_sql. + " where fas_id=".$row->fas_id; + + //echo $sql_query.'
'; + if(!$res_update=@pg_query($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $update_error++; + } + else + $anz_update++; + + // **************** + // Auch in tbl_stundenplandev updaten + $sql_query="SELECT * FROM tbl_stundenplandev WHERE + lehrveranstaltung_id=$row_lva->lehrveranstaltung_id AND datum>=now()"; + //echo $sql_query.'
'; + if(!$res_upd_stpl=@pg_query($conn, $sql_query)) + { + $text.=$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + } + else + { + if (!pg_query($conn,"BEGIN;")) + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $kollision=false; + while ($row_upd_stpl=pg_fetch_object($res_upd_stpl)) + { + // Lehrstunde auf Kollisionen checken + $lehrstunde=new lehrstunde($conn); + //echo '
STPL-ID:'.$row_upd_stpl->stundenplandev_id.'
'; + if (!$lehrstunde->load($row_upd_stpl->stundenplandev_id)) + echo $lehrstunde->errormsg; + $lehrstunde->lektor_uid=$row->lektor; + if (!$lehrstunde->kollision()) + { + if (!$lehrstunde->save('sync_fas_lva')) + echo $lehrstunde->errormsg; + } + else + { + $error_log[$row->studiengang_kz][]=$lehrstunde->errormsg; + $text.="\rKollision: ".$lehrstunde->errormsg."\r"; + $kollision=true; + echo "Kollision: ".$lehrstunde->errormsg."
"; + } + } + if ($kollision) + { + if (!pg_query($conn,"ROLLBACK;")) + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + } + else + if (!pg_query($conn,"COMMIT;")) + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + } + } + } + // LVA kommt mehrmals vor ->Warnung + elseif ($num_rows_lva>1) + { + $text.="\r!!! Die LVA fas_id=$row->fas_id kommt mehrfach vor!\r"; + $double_error++; + } + } + else + $plausi_error++; +} + + +// **************** +// Ueberfluessige Datensaetze loeschen +$whereClause=getSemesterWhereClause(); +$sql_query="DELETE FROM tbl_lehrveranstaltung WHERE fas_id NOT IN + (SELECT fas_id FROM vw_fas_lehrveranstaltung WHERE $whereClause) AND (fas_id!=0 OR fas_id IS NOT NULL) AND ($whereClause)"; +echo $sql_query.'
'; +if(!$res_delete=@pg_query($conn, $sql_query)) +{ + $text.='\n'.$sql_query; + $text.="\rFehler: ".pg_errormessage($conn)."\r"; + $text.="\rSolution: DELETE FROM tbl_stundenplandev WHERE lehrveranstaltung_id IN (SELECT lehrveranstaltung_id FROM tbl_lehrveranstaltung WHERE fas_id NOT IN (SELECT fas_id FROM vw_fas_lehrveranstaltung WHERE $whereClause) AND (fas_id!=0 OR fas_id IS NOT NULL) AND ($whereClause))\r"; +} +else +{ + $anz_delete=pg_numrows($res_delete); +} + +//Ausgabe Zusammenfassung +$text.="\n$anz_delete Lehrveranstaltungen wurden geloescht!\n"; +$text.="$plausi_error Fehler beim Plausibilitaetscheck!\n"; +$text.="$update_error Fehler bei LVA-Update!\n"; +$text.="$insert_error Fehler bei LVA-Insert!\n"; +$text.="$double_error LVA kommen in VileSci doppelt vor!\n\n"; +$text.="$anz_update LVA wurden upgedatet.\n"; +$text.="$anz_insert LVA wurden neu angelegt.\n\n"; +$text.="\nEND OF SYNCHRONISATION\n"; + +// Validation error hinzufügen +while(list($k,$v)=each($error_log)) +{ + $text.="\n\nStudiengang $k:\n"; + foreach($v as $txt) + $text.=" $txt\n"; +} +// fehlende lehrfächer +$text.="\n\nFehlende Lehrfächer: \n"; +while(list($k,$v)=each($missing_lehrfaecher)) +{ + $text.=" $k\n"; +} +// fehlende einheiten +$text.="\n\nFehlende Einheiten: \n"; +while(list($k,$v)=each($missing_einheit)) +{ + $text.=" $k\n"; +} +// fehlende raumtypen +$text.="\n\nFehlende Raumtypen: \n"; +while(list($k,$v)=each($missing_raumtyp)) +{ + $text.=" $k\n"; +} +// fehlende lehrformen +$text.="\n\nFehlende Lehrformen: \n"; +while(list($k,$v)=each($missing_lehrform)) +{ + $text.=" $k\n"; +} +if (mail($adress,"FAS Synchro mit VileSci (Lehrveranstaltungen)",$text,"From: vilesci@technikum-wien.at")) + $sendmail=true; +else + $sendmail=false; + +//print "debug: ";print_r($stg_mail); + +// Einzelnen Mails an Studiengänge verschicken +reset($error_log); +while(list($k,$v)=each($error_log)) +{ + echo "
Mail an Studiengang $k ".$stg_mail[$k].":
"; + $stg_text="Dies ist eine automatische Mail!\nFolgende Fehler sind bei der Synchronisation der Lehrveranstaltungen aufgetreten:\n\n"; + foreach($v as $txt) + $stg_text.="$txt\n"; + echo $stg_text.'
'; + // Studiengang + if (!mail($stg_mail[$k],"FAS Synchro mit VileSci (Lehrveranstaltungen) $k",$stg_text,"From: vilesci@technikum-wien.at")) + echo "Mail an '".$stg_mail[$k]."' konnte nicht verschickt werden!
"; + // Stundenplanstelle + echo "
Mail an Studiengang $k ($adress_stpl)
"; + if (!mail($adress_stpl,"FAS Synchro mit VileSci (Lehrveranstaltungen) $k",$stg_text,"From: vilesci@technikum-wien.at")) + echo 'Mail an "'.$adress_stpl.'" konnte nicht verschickt werden!
'; + +} + +// Doppelte IDs im FAS prüfen +$sql_query="SELECT count(*) AS anzahl, fas_id FROM fas_view_alle_lehreinheiten_vilesci + GROUP BY fas_id HAVING count(*)>1"; +//echo $sql_query."
"; +$result=pg_query($conn_fas, $sql_query); +$num_rows=pg_numrows($result); +$mail_text="Folgende $num_rows IDs kommen in der View fas_view_alle_lehreinheiten_vilesci (fas_id) mehrfach vor:\n\n"; +$mail_text_false=''; +if ($num_rows>0) + while ($row=pg_fetch_object($result)) + $mail_text_false.=$row->fas_id.'->'.$row->anzahl."x\n"; +$mail_text.=$mail_text_false."\n\nBitte überprüfen die Daten im FAS!!!"; +if ($mail_text_false!='') + if (!mail($adress_fas,"FAS Synchro mit VileSci (Lehrveranstaltungen)",$mail_text,"From: vilesci@technikum-wien.at")) + echo "Mail an '".$adress_fas."' konnte nicht verschickt werden!
"; + else + echo 'Mail wurde verschickt an '.$adress_fas.'!
'; +?> + + + +FAS-Synchro mit VileSci + + + +'; +else + echo "Mail konnte nicht verschickt werden!
"; +echo nl2br($text); + +?> + + diff --git a/content/DragAndDrop.js b/content/DragAndDrop.js new file mode 100644 index 000000000..2cf4fc3ca --- /dev/null +++ b/content/DragAndDrop.js @@ -0,0 +1,360 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ben Goodger (Original Author) + * Pierre Chanial + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the NPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +//////////////////////////////////////////////////////////////////////////// +// XXX - WARNING - DRAG AND DROP API CHANGE ALERT - XXX +// This file has been extensively modified in a checkin planned for Mozilla +// 0.8, and the API has been modified. DO NOT MODIFY THIS FILE without +// approval from ben@netscape.com, otherwise your changes will be lost. + +/** + * XXX - until load is supported in chrome, you also need to include + * these files: + * chrome://global/content/nsTransferable.js + **/ + + + +/** + * nsDragAndDrop - a convenience wrapper for nsTransferable, nsITransferable + * and nsIDragService/nsIDragSession. + * + * USAGE INFORMATION: see 'README-nsDragAndDrop.html' in the same source directory + * as this file (typically xpfe/global/resources/content) + */ + +var nsDragAndDrop = +{ + _mDS: null, + get mDragService() + { + if (!this._mDS) + { + const kDSContractID = "@mozilla.org/widget/dragservice;1"; + const kDSIID = Components.interfaces.nsIDragService; + this._mDS = Components.classes[kDSContractID].getService(kDSIID); + } + return this._mDS; + }, + + /** + * void startDrag (DOMEvent aEvent, Object aDragDropObserver) ; + * + * called when a drag on an element is started. + * + * @param DOMEvent aEvent + * the DOM event fired by the drag init + * @param Object aDragDropObserver + * javascript object of format described above that specifies + * the way in which the element responds to drag events. + **/ + startDrag: function (aEvent, aDragDropObserver) + { + try + { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch (e) { alert(e); } + if (!("onDragStart" in aDragDropObserver)) + return; + + const kDSIID = Components.interfaces.nsIDragService; + var dragAction = + { + action: kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_MOVE + kDSIID.DRAGDROP_ACTION_LINK + }; + + var transferData = + { + data: null + }; + try + { + aDragDropObserver.onDragStart(aEvent, transferData, dragAction); + } + catch (e) + { + return; // not a draggable item, bail! + } + + if (!transferData.data) + return; + transferData = transferData.data; + + var transArray = Components.classes["@mozilla.org/supports-array;1"] + .createInstance(Components.interfaces.nsISupportsArray); + + var region = null; + if (aEvent.originalTarget.localName == "treechildren") + { + // let's build the drag region + var tree = aEvent.originalTarget.parentNode; + try + { + region = Components.classes["@mozilla.org/gfx/region;1"].createInstance(Components.interfaces.nsIScriptableRegion); + region.init(); + var obo = tree.treeBoxObject; + var bo = obo.treeBody.boxObject; + var obosel= obo.selection; + var rowX = bo.x; + var rowY = bo.y; + var rowHeight = obo.rowHeight; + var rowWidth = bo.width; + + //add a rectangle for each visible selected row + for (var i = obo.getFirstVisibleRow(); i <= obo.getLastVisibleRow(); i ++) + { + if (obosel.isSelected(i)) + region.unionRect(rowX, rowY, rowWidth, rowHeight); + rowY = rowY + rowHeight; + } + + //and finally, clip the result to be sure we don't spill over... + region.intersectRect(bo.x, bo.y, bo.width, bo.height); + } + catch(ex) + { + dump("Error while building selection region: " + ex + "\n"); + region = null; + } + } + + var count = 0; + do + { + var trans = nsTransferable.set(transferData._XferID == "TransferData" + ? transferData : transferData.dataList[count++]); + transArray.AppendElement(trans.QueryInterface(Components.interfaces.nsISupports)); + } + while (transferData._XferID == "TransferDataSet" && count < transferData.dataList.length); + + try + { + this.mDragService.invokeDragSession(aEvent.target, transArray, region, dragAction.action); + } + catch(ex) + { + // this could be because the user pressed escape to + // cancel the drag. even if it's not, there's not much + // we can do, so be silent. + } + aEvent.preventBubble(); + }, + + /** + * void dragOver (DOMEvent aEvent, Object aDragDropObserver) ; + * + * called when a drag passes over this element + * + * @param DOMEvent aEvent + * the DOM event fired by passing over the element + * @param Object aDragDropObserver + * javascript object of format described above that specifies + * the way in which the element responds to drag events. + **/ + dragOver: function (aEvent, aDragDropObserver) + { + try + { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch (e) { alert(e); } + if (!("onDragOver" in aDragDropObserver)) + return; + if (!this.checkCanDrop(aEvent, aDragDropObserver)) + return; + var flavourSet = aDragDropObserver.getSupportedFlavours(); + for (var flavour in flavourSet.flavourTable) + { + if (this.mDragSession.isDataFlavorSupported(flavour)) + { + aDragDropObserver.onDragOver(aEvent, + flavourSet.flavourTable[flavour], + this.mDragSession); + aEvent.preventBubble(); + break; + } + } + }, + + mDragSession: null, + + /** + * void drop (DOMEvent aEvent, Object aDragDropObserver) ; + * + * called when the user drops on the element + * + * @param DOMEvent aEvent + * the DOM event fired by the drop + * @param Object aDragDropObserver + * javascript object of format described above that specifies + * the way in which the element responds to drag events. + **/ + drop: function (aEvent, aDragDropObserver) + { + try + { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch (e) { alert(e); } + + if (!("onDrop" in aDragDropObserver)) + return; + if (!this.checkCanDrop(aEvent, aDragDropObserver)) + return; + if (this.mDragSession.canDrop) { + var flavourSet = aDragDropObserver.getSupportedFlavours(); + var transferData = nsTransferable.get(flavourSet, this.getDragData, true); + // hand over to the client to respond to dropped data + var multiple = "canHandleMultipleItems" in aDragDropObserver && aDragDropObserver.canHandleMultipleItems; + var dropData = multiple ? transferData : transferData.first.first; + aDragDropObserver.onDrop(aEvent, dropData, this.mDragSession); + } + aEvent.preventBubble(); + }, + + /** + * void dragExit (DOMEvent aEvent, Object aDragDropObserver) ; + * + * called when a drag leaves this element + * + * @param DOMEvent aEvent + * the DOM event fired by leaving the element + * @param Object aDragDropObserver + * javascript object of format described above that specifies + * the way in which the element responds to drag events. + **/ + dragExit: function (aEvent, aDragDropObserver) + { + try + { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch (e) { alert(e); } + + if (!this.checkCanDrop(aEvent, aDragDropObserver)) + return; + if ("onDragExit" in aDragDropObserver) + aDragDropObserver.onDragExit(aEvent, this.mDragSession); + }, + + /** + * void dragEnter (DOMEvent aEvent, Object aDragDropObserver) ; + * + * called when a drag enters in this element + * + * @param DOMEvent aEvent + * the DOM event fired by entering in the element + * @param Object aDragDropObserver + * javascript object of format described above that specifies + * the way in which the element responds to drag events. + **/ + dragEnter: function (aEvent, aDragDropObserver) + { + try + { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch (e) { alert(e); } + + if (!this.checkCanDrop(aEvent, aDragDropObserver)) + return; + if ("onDragEnter" in aDragDropObserver) + aDragDropObserver.onDragEnter(aEvent, this.mDragSession); + }, + + /** + * nsISupportsArray getDragData (Object aFlavourList) + * + * Creates a nsISupportsArray of all droppable items for the given + * set of supported flavours. + * + * @param FlavourSet aFlavourSet + * formatted flavour list. + **/ + getDragData: function (aFlavourSet) + { + try + { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } + catch (e) + { + alert(e); + } + + var supportsArray = Components.classes["@mozilla.org/supports-array;1"] + .createInstance(Components.interfaces.nsISupportsArray); + + for (var i = 0; i < nsDragAndDrop.mDragSession.numDropItems; ++i) + { + var trans = nsTransferable.createTransferable(); + for (var j = 0; j < aFlavourSet.flavours.length; ++j) + trans.addDataFlavor(aFlavourSet.flavours[j].contentType); + nsDragAndDrop.mDragSession.getData(trans, i); + supportsArray.AppendElement(trans); + } + return supportsArray; + }, + + /** + * Boolean checkCanDrop (DOMEvent aEvent, Object aDragDropObserver) ; + * + * Sets the canDrop attribute for the drag session. + * returns false if there is no current drag session. + * + * @param DOMEvent aEvent + * the DOM event fired by the drop + * @param Object aDragDropObserver + * javascript object of format described above that specifies + * the way in which the element responds to drag events. + **/ + checkCanDrop: function (aEvent, aDragDropObserver) + { + try + { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch (e) { alert(e); } + + if (!this.mDragSession) + this.mDragSession = this.mDragService.getCurrentSession(); + if (!this.mDragSession) + return false; + this.mDragSession.canDrop = this.mDragSession.sourceNode != aEvent.target; + if ("canDrop" in aDragDropObserver) + this.mDragSession.canDrop &= aDragDropObserver.canDrop(aEvent, this.mDragSession); + return true; + } +}; + diff --git a/content/Ideen.php b/content/Ideen.php new file mode 100644 index 000000000..06b3a7488 --- /dev/null +++ b/content/Ideen.php @@ -0,0 +1,111 @@ +/************************************************************************** + * @brief Funktion draw_week_rdf Stundenplan im RDF-Format + * + * @param datum Datum eines Tages in der angeforderten Woche + * + * @return true oder false + * + */ + function draw_week_rdf() + { + // Stundentafel abfragen + $sql_query="SELECT * FROM tbl_stunde ORDER BY stunde"; + if(!$result_stunde=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + $num_rows_stunde=pg_numrows($result_stunde); + + //echo $this->datum; + + $rdf_url='http://www.technikum-wien.at/tempus/lehrstunde/'; + //RDF Kopf + echo ''; + + // Von Montag bis Samstag + for ($i=1; $i<7; $i++) + { + for ($k=0; $k<$num_rows_stunde; $k++) + { + $j=pg_result($result_stunde,$k,'"stunde"'); + if (isset($this->std_plan[$i][$j][0]->lehrfach)) + { + // Daten aufbereiten + $kollision=-1; + unset($a_unr); + foreach ($this->std_plan[$i][$j] as $lehrstunde) + $a_unr[]=$lehrstunde->unr; + + // Unterrichtsnummer (Kollision?) + $unr=array_unique($a_unr); + $kollision+=count($unr); + foreach ($a_unr as $unr) + foreach ($this->std_plan[$i][$j] as $lehrstunde) + if ($lehrstunde->unr==$unr) + { + // Ausgabe + $lvb=$lehrstunde->stg.'-'.$lehrstunde->sem; + if ($lehrstunde->ver!=null && $lehrstunde->ver!='0' && $lehrstunde->ver!='') + { + $lvb.=$lehrstunde->ver; + if ($lehrstunde->grp!=null && $lehrstunde->grp!='0' && $lehrstunde->grp!='') + $lvb.=$lehrstunde->grp; + } + echo ' + '.$lehrstunde->stundenplan_id.' + '.$lvb.' + '.$lehrstunde->stg_kz.' + '.$lehrstunde->stg.' + '.$lehrstunde->sem.' + '.$lehrstunde->ver.' + '.$lehrstunde->grp.' + '.$lehrstunde->einheit_kurzbz.' + '.$lehrstunde->datum.' + '.$lehrstunde->stunde.' + '.$i.' + + '.($kollision ? 'true':'false').' + + '; + } + } + } + } + + // Sequenz Von Montag bis Samstag + echo ''; + for ($i=1; $i<7; $i++) + { + for ($k=0; $k<$num_rows_stunde; $k++) + { + $j=pg_result($result_stunde,$k,'"stunde"'); + if (isset($this->std_plan[$i][$j][0]->lehrfach)) + { + // Daten aufbereiten + unset($a_unr); + foreach ($this->std_plan[$i][$j] as $lehrstunde) + $a_unr[]=$lehrstunde->unr; + + // Unterrichtsnummern + $unr=array_unique($a_unr); + foreach ($a_unr as $unr) + { + echo ' + + '; + foreach ($this->std_plan[$i][$j] as $lehrstunde) + if ($lehrstunde->unr==$unr) + { + // Ausgabe + echo ''; + } + echo ' + '; + } + } + } + } + echo ''; + echo ''; + } + \ No newline at end of file diff --git a/content/dragboard.js b/content/dragboard.js new file mode 100644 index 000000000..489514b3d --- /dev/null +++ b/content/dragboard.js @@ -0,0 +1,57 @@ +function lehrstunde(type,stg_kz,sem,ver,grp) +{ + this.type=type; + this.stg_kz=stg_kz; + this.sem=sem; + this.ver=ver; + this.grp=grp; +} + +var listObserver= +{ + onDragStart: function (evt,transferData,action) + { + var elemID=evt.target.getAttribute("elem"); + var paramList=evt.target.getAttribute("paramList"); + var transferObjekt=new lehrstunde(elemID,paramList,elemID,elemID,elemID); + transferData.data=new TransferData(); + //transferData.data.addDataForFlavour("text/unicode",transferObjekt); + transferData.data.addDataForFlavour("text/unicode",paramList); + } +}; + +var boardObserver= +{ + /*canHandleMultipleItems : function() + { + var canHandleMultipleItems=false; + },*/ + getSupportedFlavours : function () + { + var flavours = new FlavourSet(); + flavours.appendFlavour("text/unicode"); + return flavours; + }, + onDragOver: function (evt,flavour,session) + { + }, + onDrop: function (evt,dropdata,session) + { + if (dropdata.data!="") + { + var dragElement=document.getElementById(dropdata.data); + var contentFrame=document.getElementById('iframeTimeTableWeek'); + var stunde=evt.target.getAttribute("stunde"); + var datum=evt.target.getAttribute("datum"); + /*//var elem=document.createElement("label");*/ + /*evt.target.appendChild(elem); */ + var paramList=dragElement.getAttribute("paramList"); + /*elem.setAttribute("value",dropdata.data + paramList); */ + var url=location.href;//contentFrame.getAttribute('src'); + url+=paramList+"&new_stunde="+stunde+"&new_datum="+datum+'&aktion=stplverschieben'; + //contentFrame.setAttribute('src', url); + location.href=url; + } + } +}; + diff --git a/content/dragboard.js.php b/content/dragboard.js.php new file mode 100644 index 000000000..eee577a9b --- /dev/null +++ b/content/dragboard.js.php @@ -0,0 +1,173 @@ + +function lehrstunde(id,idList) +{ + this.id=id; + this.idList=idList; +} +var lehrstunden=new Array(); + +/***** Drag Observer fuer Lehrveranstaltungen *****/ +var lvaObserver= +{ + onDragStart: function (evt,transferData,action) + { + var idList=evt.target.getAttribute("idList"); + var aktion=evt.target.getAttribute("aktion"); + aktion+="_set"; + var paramList="?aktion="+aktion+"&lva_ids="+idList; + transferData.data=new TransferData(); + transferData.data.addDataForFlavour("application/tempus-lehrveranstaltung",paramList); + //alert("test"); + } +}; + +/***** Drag Observer fuer STPL-Verschiebung *****/ +var listObserver= +{ + onDragStart: function (evt,transferData,action) + { + var type=evt.target.getAttribute("stpltype"); + var dragdatum=evt.target.getAttribute("datum"); + var pers_uid=evt.target.getAttribute("pers_uid"); + var idList=evt.target.getAttribute("idList"); + var stg_kz=evt.target.getAttribute("stg_kz"); + var sem=evt.target.getAttribute("sem"); + var ver=evt.target.getAttribute("ver"); + var grp=evt.target.getAttribute("grp"); + var einheit=evt.target.getAttribute("einheit"); + var old_ort=evt.target.getAttribute("ort"); + var aktion=evt.target.getAttribute("aktion"); + aktion+="_set"; + var paramList="?dragtype="+type+"&dragdatum="+dragdatum+"&pers_uid="+pers_uid+"&stg_kz="+stg_kz+"&sem="+sem+"&ver="+ver+"&grp="+grp+"&einheit="+einheit+"&old_ort="+old_ort+idList+"&aktion="+aktion; + //var transferObjekt=new lehrstunde(type,dragdatum,pers_uid,stg_kz,sem,ver,grp,einheit,old_ort,idList); + transferData.data=new TransferData(); + transferData.data.addDataForFlavour("application/tempus-lehrstunde",paramList); + + var styleOrig=evt.target.getAttribute("styleOrig"); + evt.target.setAttribute("style",styleOrig+"color:red;font-style:italic;"); + } +}; + +/***** Board Observer fuer STPL- und LVA-Verschiebung *****/ +var boardObserver= +{ + /*canHandleMultipleItems : function() + { + var canHandleMultipleItems=false; + },*/ + getSupportedFlavours : function () + { + var flavours = new FlavourSet(); + flavours.appendFlavour("application/tempus-lehrveranstaltung"); + flavours.appendFlavour("application/tempus-lehrstunde"); + return flavours; + }, + onDragEnter: function (evt,flavour,session) + { + var styleNow=evt.target.getAttribute("style"); + if (evt.target.tagName=="label") + evt.target.setAttribute("style","background-color:#AAFFAA;"); + else + evt.target.setAttribute("style",styleNow+"border:1px dashed black;"); + + }, + onDragExit: function (evt,flavour,session) + { + var styleNow=evt.target.getAttribute("style"); + if (evt.target.tagName=="label") + evt.target.setAttribute("style",""); + else + evt.target.setAttribute("style",styleNow+"border:1px solid black;"); + }, + onDragOver: function(evt,flavour,session) + { + // Mehrfachauswahl von Lehrstunden mit CTRL bzw. ALT-Taste + if ((evt.ctrlKey || evt.altKey) && flavour.contentType=="application/tempus-lehrstunde" && evt.target.tagName=="button") + { + var idList=evt.target.getAttribute("idList"); + var id=evt.target.getAttribute("id"); + var styleOrig=evt.target.getAttribute("styleOrig"); + // Ist Element schon vorhanden und an welcher stelle im Array? + var gesetzt=null; + for (var i=0;i'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/einheit.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + + +// Einheiten holen +$einheitenDAO=new einheit($conn); +$einheiten=$einheitenDAO->getAll(); + + + +$rdf_url='http://www.technikum-wien.at/tempus/einheiten'; + +?> + + + + + + + + + + kurzbz ?> + stg_kz ?> + stg_kurzbz ?> + bezeichnung ?> + semester ?> + typ ?> + + + + + + + + \ No newline at end of file diff --git a/content/excel.php b/content/excel.php new file mode 100644 index 000000000..aee708e92 --- /dev/null +++ b/content/excel.php @@ -0,0 +1,160 @@ + + * date: 2006-04-22 +*/ + +//error_reporting(E_ALL); +//ini_set('display_errors','1'); + + +include('../vilesci/config.inc.php'); +include_once('../include/fas/functions.inc.php'); +include_once('../include/fas/person.class.php'); +include_once('../include/fas/mitarbeiter.class.php'); +include_once('../include/Excel/PEAR.php'); +include_once('../include/Excel/BIFFwriter.php'); +include_once('../include/Excel/Workbook.php'); +include_once('../include/Excel/Format.php'); +include_once('../include/Excel/Worksheet.php'); +include_once('../include/Excel/Parser.php'); +include_once('../include/Excel/OLE.php'); +include_once('../include/Excel/PPS.php'); +include_once('../include/Excel/Root.php'); +include_once('../include/Excel/File.php'); +include_once('../include/Excel/Writer.php'); + + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +//Parameter holen +if (isset($_GET['mitarbeiter_id'])) + $mitarbeiter_id = $_GET['mitarbeiter_id']; +else + $mitarbeiter_id=null; + +if (isset($_GET['fix'])) + $fix = $_GET['fix']; +else + $fix=null; + +if (isset($_GET['stgl'])) + $stgl = $_GET['stgl']; +else + $stgl=null; + +if (isset($_GET['fbl'])) + $fbl = $_GET['fbl']; +else + $fbl=null; + +if (isset($_GET['aktiv'])) + $aktiv = $_GET['aktiv']; +else + $aktiv=null; + +if (isset($_GET['karenziert'])) + $karenziert = $_GET['karenziert']; +else + $karenziert=null; + +if (isset($_GET['ausgeschieden'])) + $ausgeschieden = $_GET['ausgeschieden']; +else + $ausgeschieden=null; + +if (isset($_GET['zustelladresse'])) + $zustelladresse = $_GET['zustelladresse']; +else + $zustelladresse = null; + +//Spalten +$anzSpalten=0; +$varname='spalte'.(string)$anzSpalten; +while (isset($_GET[$varname])) +{ + $spalte[$anzSpalten]=$_GET[$varname]; + //echo $spalte[$anzSpalten]; + $anzSpalten++; + $varname='spalte'.(string)$anzSpalten; +} +$zustelladresse=true; + +// Mitarbeiter holen +$mitarbeiterDAO=new mitarbeiter($conn); +$mitarbeiterDAO->getMitarbeiter($mitarbeiter_id, $fix, $stgl, $fbl, $aktiv, $karenziert, $ausgeschieden, $zustelladresse,getStudiensemesterIdFromName($conn, $benutzer->variable->semester_aktuell)); + + /* + * Create Excel File with Content from Students Examples solved + */ + + // Creating a workbook + $workbook = new Spreadsheet_Excel_Writer(); + + // sending HTTP headers + $workbook->send("Mitarbeiter". "_" . date("d_m_Y") . ".xls"); + + // Creating a worksheet + $worksheet =& $workbook->addWorksheet("Mitarbeiter"); + + $format_bold =& $workbook->addFormat(); + $format_bold->setBold(); + + $format_title =& $workbook->addFormat(); + $format_title->setBold(); +// $format_title->setColor('yellow'); +// $format_title->setPattern(1); +// $format_title->setFgColor('blue'); + // let's merge + $format_title->setAlign('merge'); + + for ($i=0;$i<$anzSpalten;$i++) + $worksheet->write(0,$i,strtoupper(str_replace('_bezeichnung','',$spalte[$i])), $format_bold); + $worksheet->write(0,$i,"STRASSE", $format_bold); + $worksheet->write(0,$i+1,"PLZ", $format_bold); + $worksheet->write(0,$i+2,"ORT", $format_bold); + + // set width of columns + + //$worksheet->setColumn(1,4,20); // ersten 3 Spalten auf width=17 + //$worksheet->setColumn(0,0,22); + + $j=1; + $maxlength = array(); + for ($i=0;$i<$anzSpalten;$i++) + $maxlength[$i]=strlen(str_replace('_bezeichnung','',$spalte[$i])); + $maxlength[$i]=strlen('STRASSE'); + $maxlength[$i+1]=strlen('PLZ'); + $maxlength[$i+2]=strlen('ORT'); + + foreach ($mitarbeiterDAO->result as $mitarbeiter) + { + for ($i=0;$i<$anzSpalten;$i++) + { + if(strlen($mitarbeiter->$spalte[$i])>$maxlength[$i]) + $maxlength[$i] = strlen($mitarbeiter->$spalte[$i]); + $worksheet->write($j,$i, utf8_decode($mitarbeiter->$spalte[$i])); + } + if(strlen($mitarbeiter->zustelladresse_strasse)>$maxlength[$i]) + $maxlength[$i]=strlen($mitarbeiter->zustelladresse_strasse); + $worksheet->write($j,$i, utf8_decode($mitarbeiter->zustelladresse_strasse)); + if(strlen($mitarbeiter->zustelladresse_plz)>$maxlength[$i+1]) + $maxlength[$i+1]=strlen($mitarbeiter->zustelladresse_plz); + $worksheet->write($j,$i+1, utf8_decode($mitarbeiter->zustelladresse_plz)); + if(strlen($mitarbeiter->zustelladresse_ort)>$maxlength[$i+2]) + $maxlength[$i+2]=strlen($mitarbeiter->zustelladresse_ort); + $worksheet->write($j,$i+2, utf8_decode($mitarbeiter->zustelladresse_ort)); + $j++; + } + + for ($i=0;$i<$anzSpalten;$i++) + $worksheet->setColumn($i, $i, $maxlength[$i]+2); + $worksheet->setColumn($i, $i, $maxlength[$i]+2); + $worksheet->setColumn($i+1, $i+1, $maxlength[$i+1]+2); + $worksheet->setColumn($i+2, $i+2, $maxlength[$i+2]+2); + + $workbook->close(); + +?> diff --git a/content/fachbereich.rdf.php b/content/fachbereich.rdf.php new file mode 100644 index 000000000..79f692e9c --- /dev/null +++ b/content/fachbereich.rdf.php @@ -0,0 +1,83 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/fachbereich.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + + +// test + +$einheit_kurzbz=''; +$grp='1'; +//$ver='A'; +$sem=5; +$stg_kz=145; + + +/* +$einheit_kurzbz=''; +$grp=$_GET['grp']; +$ver=$_GET['ver']; +$sem=$_GET['sem']; +$stg_kz=$_GET['stg_kz']; */ + +// fachbereiche holen +$fachbereichDAO=new fachbereich($conn); +$fachbereiche=$fachbereichDAO->getAll(); + + + +$rdf_url='http://www.technikum-wien.at/tempus/fachbereich'; + +?> + + + + + + + + + id ?> + kurzbz ?> + bezeichnung ?> + farbe ?> + studiengang_kz ?> + studiengang_kurzbz ?> + + + + + + + \ No newline at end of file diff --git a/content/fas.js.php b/content/fas.js.php new file mode 100644 index 000000000..bd691c3b0 --- /dev/null +++ b/content/fas.js.php @@ -0,0 +1,144 @@ + + +/** + * Wenn einer der Tabs angeklickt wird wird der zugehoerige Tab + * im anderen Overlay auch geaendert + */ +function tabchange(select) +{ + if(select=='lehreinheiten') //Auswahl des Lehreinheiten Tabs + { + document.getElementById('tab-mitarbeiter').selected=false; + document.getElementById('tab-mitarbeiter1').selected=false; + document.getElementById('tab-lehreinheiten').selected=true; + document.getElementById('tab-verband').selected=true; + document.getElementById('tabpanels-main').selectedIndex=1; + document.getElementById('tabpanels-left').selectedIndex=1; + + } + else if(select=='mitarbeiter') //Auswahl des Mitarbeiter Tabs + { + document.getElementById('tab-lehreinheiten').selected=false; + document.getElementById('tab-verband').selected=false; + document.getElementById('tab-mitarbeiter').selected=true; + document.getElementById('tab-mitarbeiter1').selected=true; + document.getElementById('tabpanels-main').selectedIndex=0; + document.getElementById('tabpanels-left').selectedIndex=0; + } +} + +/** + * Beim schliessen des Fensters wird ueberprueft ob Daten geaendert und noch + * nicht gespeichert wurden. + */ +function closeWindow() +{ + //Wenn Daten geaendert wurden + if(treeMitarbeiterDetailChanged) + { + if(confirm("Wollen Sie die geänderten Daten speichern?")) + if(!saveMitarbeiter()) + { + //Falls beim Speichern ein Fehler auftritt bleibt das Fenster offen! + return false; + } + else + window.close(); + else + window.close(); + } + else + window.close(); +} + +/** + * Wenn das Fenster Fertig geladen ist + */ +function onLoad() +{ + //rebuild Listener setzen + document.getElementById('tree-liste-mitarbeiter').builder.addListener(treemenurebuildobserve); + + //Eingabefelder deaktivieren + SetMitarbeiterDetailAktiv(false); + + //studiengangsleiter als Default setzen + document.getElementById('tree-menu-mitarbeiter1').view.selection.select(6); +} + +/** + * Aenderung des Studiensemesters + */ +function studiensemesterChange() +{ + var items = document.getElementsByTagName('menuitem'); + var stsem=''; + //Markiertes Studiensemester holen + for(i in items) + { + if(items[i].id=='menu-properies-studiensemester-name' && items[i].getAttribute("checked")=='true') + stsem = items[i].label; + } + + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + // Request absetzen + var httpRequest = new XMLHttpRequest(); + var url = "rdf/fas/db_dml.rdf.php"; + + httpRequest.open("POST", url, false, '',''); + httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + + var param = "type=variablechange"; + param = param + "&stsem="+stsem; + + //Parameter schicken + httpRequest.send(param); + + // Bei status 4 ist sendung Ok + switch(httpRequest.readyState) + { + case 1,2,3: alert('Bad Ready State: '+httpRequest.status); + return false; + break; + + case 4: if(httpRequest.status !=200) + { + alert('The server respond with a bad status code: '+httpRequest.status); + return false; + } + else + { + var response = httpRequest.responseText; + } + break; + } + + // Returnwerte aus RDF abfragen + var dsource=parseRDFString(response, 'http://www.technikum-wien.at/dbdml'); + + var rdfService = Components.classes["@mozilla.org/rdf/rdf-service;1"]. + getService(Components.interfaces.nsIRDFService); + var subject = rdfService.GetResource("http://www.technikum-wien.at/dbdml/0"); + + var predicateNS = "http://www.technikum-wien.at/dbdml/rdf"; + + var dbdml_return = getTargetHelper(dsource, subject, rdfService.GetResource( predicateNS + "#return" )); + var dbdml_errormsg = getTargetHelper(dsource, subject, rdfService.GetResource( predicateNS + "#errormsg" )); + + if(dbdml_return=='true') + { + //Statusbar setzen + setStatusBarText("Studiensemester erfolgreich geändert"); + document.getElementById("tree-liste-funktionen").builder.refresh(); + document.getElementById("statusbarpanel-semester").label = stsem; + MitarbeiterDetailStudiensemester_id = dbdml_errormsg; + } + else + { + alert("Fehler beim Speichern der Daten: "+dbdml_errormsg); + } + return true; +} diff --git a/content/fas.xul.php b/content/fas.xul.php new file mode 100644 index 000000000..3bc6fc017 --- /dev/null +++ b/content/fas.xul.php @@ -0,0 +1,170 @@ +'; +include('../vilesci/config.inc.php'); +include('../include/functions.inc.php'); +include('../include/fas/benutzer.class.php'); + +// Testumgebung +//if (!isset($REMOTE_USER)) +// $REMOTE_USER='pam'; +//$uid=$REMOTE_USER; +$user = get_uid(); + +$error_msg=''; + +//Variablen laden +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$benutzer = new benutzer($conn); +if(!$benutzer->loadVariables($user)) + $error_msg = $benutzer->errormsg; + + +/*echo '';*/ +echo ''; +echo ''; +?> + + + + + + + \ No newline at end of file diff --git a/content/xxxstpl-lehrstunde.rdf.php b/content/xxxstpl-lehrstunde.rdf.php new file mode 100644 index 000000000..6bd82aa5c --- /dev/null +++ b/content/xxxstpl-lehrstunde.rdf.php @@ -0,0 +1,101 @@ +'; +//echo ''; +include('../vilesci/config.inc.php'); +include('../include/functions.inc.php'); +include('../include/lehrstunde.class.php'); +include('../include/stundenplan.class.php'); + +// Testumgebung +if (!isset($REMOTE_USER)) + $REMOTE_USER='pam'; + +$uid=$REMOTE_USER; + +// Variablen uebernehmen +if (isset($_GET[aktion])) + $aktion=$_GET[aktion]; +if (isset($_GET[new_stunde])) + $new_stunde=$_GET[new_stunde]; +if (isset($_GET[new_datum])) + $new_datum=$_GET[new_datum]; +if (isset($_GET[type])) + $type=$_GET[type]; +if (isset($_GET[ort_kurzbz])) + $ort_kurzbz=$_GET[ort_kurzbz]; +else + $ort_kurzbz='EDV6.08'; +$i=0; +$name_stpl_id='stundenplan_id'.$i; +while ($i<100 && isset($_GET[$name_stpl_id])) +{ + $stpl_id[]=$_GET[$name_stpl_id]; + //echo $stpl_id[$i]; + $name_stpl_id='stundenplan_id'.++$i; + +} + + +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; +$error_msg.=loadVariables($conn,$REMOTE_USER); + +// Authentifizierung +if ($uid=check_student($REMOTE_USER, $conn)) + $user='student'; +elseif ($uid=check_lektor($REMOTE_USER, $conn)) + $user='lektor'; +else + die("Cannot set usertype!"); + + // User bestimmen +if (!isset($type)) + $type=$user; +if (!isset($pers_uid)) + $pers_uid=$uid; + + // Datums Format +$erg_std=pg_query($conn, "SET datestyle TO ISO;") + or die(pg_last_error($conn)); + + +// Aktionen durchfuehren +if ($aktion=='stplverschieben') +{ + foreach ($stpl_id as $stundenplan_id) + { + $lehrstunde=new lehrstunde($conn); + $lehrstunde->load($stundenplan_id,$db_stpl_table); + $lehrstunde->datum=$new_datum; + $lehrstunde->stunde=$new_stunde; + $lehrstunde->save($db_stpl_table); + } +} +// Stundenplan abfragen +$stdplan=new stundenplan($type,$conn); +if (!isset($datum)) + $datum=mktime(); + +// Benutzergruppe +$stdplan->user=$user; +// aktueller Benutzer +$stdplan->user_uid=$uid; + +// Zusaetzliche Daten laden +if (! $stdplan->load_data($type,$pers_uid,$ort_kurzbz,$stg_kz,$sem,$ver,$grp,$einheit_kurzbz,$db_table) ) + die($stdplan->errormsg); +// Stundenplan einer Woche laden +if (! $stdplan->load_week($datum,$db_stpl_table)) + die($stdplan->errormsg); +// Kopfbereich drucken + +// Stundenplan der Woche in RDF drucken +$stdplan->draw_week_rdf(); +?> \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ab891453dc671bc7167cc0101030489d2747ac8e GIT binary patch literal 22486 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 + * date: + * title: Authorization.class.php + * manual: $auth = new Authorization($uid, $course_id, $semester, $lesson); + * + * Tries to login a user as a student, if fails, it tries + * to login as a teacher. + * returns 0 for student + * 1 for teacher + * -1 on error + * holt den firstname, lastname, uid und id des Benutzers + */ +class Authorization +{ + var $firstname; + var $lastname; + var $id; + var $uid; + var $stg_id; + var $semester; + var $verband; + var $gruppe; + var $isLector; + var $module; + var $lehrfach; + var $date; + var $session; + var $birthday; + + function Authorization($uid ="", $course_id = 0, $semester = 0, $lesson = "",$conn="") + { + $this->isLector = -1; + $this->module = 0; + + if ($uid == "oesi" || $uid == "kates") + { + $this->uid = $uid; + $this->stg_id = $course_id; + $this->lehrfach = $lesson; + $this->semester = $semester; + $this->isLector = 1; + return $this->isLector; + } + + // try to looon as a student + $sql = "SELECT * ". + "FROM tbl_student JOIN tbl_person USING (uid) WHERE + uid = '$uid' AND studiengang_kz = $course_id + AND semester >= $semester"; + + $rs = new pgRS($conn,$sql); + + if ($rs->num > 0) + { + $this->firstname = $rs->arr[0]["vornamen"]; + $this->lastname = $rs->arr[0]["nachname"]; + //$this->id = $rs->arr[0]["id"]; + $this->uid = $uid; + $this->stg_id = $rs->arr[0]["studiengang_kz"]; + $this->semester = $rs->arr[0]["semester"]; + $this->verband = $rs->arr[0]["verband"]; + $this->gruppe = $rs->arr[0]["gruppe"]; + $this->birthday = $rs->arr[0]["gebdatum"]; + $this->isLector = 0; + } + else + { + /* oesi 17-01-2005 + $sql = "SELECT * FROM lehre.tbl_lehrfachzuteilung JOIN tbl_person ON + (lektor_uid = uid) WHERE lektor_uid = '$uid' AND + lehrfachzuteilung_kurzbz = '$lesson' AND + semester = $semester AND studiengang_kz = $course_id LIMIT 1"; + */ + $sql = "SELECT * FROM tbl_lehrveranstaltung, tbl_lehrfach, tbl_person WHERE + tbl_lehrveranstaltung.lehrfach_nr=tbl_lehrfach.lehrfach_nr AND + tbl_person.uid=lektor AND lektor='$uid' AND + tbl_lehrfach.studiengang_kz=$course_id AND + tbl_lehrfach.semester=$semester AND lehrevz='$lesson' LIMIT 1"; + + $rs = new pgRS($conn,$sql); + if ($rs->num > 0) + { + $this->firstname = $rs->arr[0]["vornamen"]; + $this->lastname = $rs->arr[0]["nachname"]; + $this->birthday = $rs->arr[0]["gebdatum"]; + $this->uid = $uid; + $this->stg_id = $course_id; + $this->lehrfach = $lesson; + $this->semester = $semester; + $this->isLector = 1; + } + else + { + //$sql = "SELECT DISTINCT tbl_person.uid FROM public.tbl_person, lehre.tbl_lehrfachzuteilung WHERE tbl_person.uid='$uid' AND tbl_lehrfachzuteilung.lektor_uid=tbl_person.uid AND studiengang_kz='$course_id' UNION SELECT DISTINCT tbl_person.uid FROM public.tbl_person, public.tbl_personfunktion WHERE tbl_person.uid='$uid' AND tbl_personfunktion.uid=tbl_person.uid AND studiengang_kz='$course_id' LIMIT 1"; + $sql = "SELECT vornamen, nachname, gebdatum FROM public.tbl_person, tbl_lehrveranstaltung + WHERE tbl_person.uid='$uid' AND tbl_lehrveranstaltung.lektor=tbl_person.uid AND + studiengang_kz='$course_id' + UNION + SELECT vornamen, nachname, gebdatum FROM public.tbl_person, public.tbl_personfunktion + WHERE tbl_person.uid='$uid' AND tbl_personfunktion.uid=tbl_person.uid AND + studiengang_kz='$course_id' LIMIT 1"; + + $rs = new pgRS($conn,$sql); + + if ($rs->num > 0) + { + $this->firstname = $rs->arr[0]["vornamen"]; + $this->lastname = $rs->arr[0]["nachname"]; + $this->birthday = $rs->arr[0]["gebdatum"]; + $this->uid = $uid; + $this->stg_id = $course_id; + $this->lehrfach = $lesson; + $this->semester = $semester; + $this->isLector = 1; + } + } + } + return $this->isLector; + } +} +?> diff --git a/include/Excel/BIFFwriter.php b/include/Excel/BIFFwriter.php new file mode 100644 index 000000000..c8fbb1bd1 --- /dev/null +++ b/include/Excel/BIFFwriter.php @@ -0,0 +1,237 @@ + +* +* The majority of this is _NOT_ my code. I simply ported it from the +* PERL Spreadsheet::WriteExcel module. +* +* The author of the Spreadsheet::WriteExcel module is John McNamara +* +* +* I _DO_ maintain this code, and John McNamara has nothing to do with the +* porting of this code to PHP. Any questions directly related to this +* class library should be directed to me. +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@php.net +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +/** +* Class for writing Excel BIFF records. +* +* From "MICROSOFT EXCEL BINARY FILE FORMAT" by Mark O'Brien (Microsoft Corporation): +* +* BIFF (BInary File Format) is the file format in which Excel documents are +* saved on disk. A BIFF file is a complete description of an Excel document. +* BIFF files consist of sequences of variable-length records. There are many +* different types of BIFF records. For example, one record type describes a +* formula entered into a cell; one describes the size and location of a +* window into a document; another describes a picture format. +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer_BIFFwriter extends PEAR +{ + /** + * The BIFF/Excel version (5). + * @var integer + */ + var $_BIFF_version = 0x0500; + + /** + * The byte order of this architecture. 0 => little endian, 1 => big endian + * @var integer + */ + var $_byte_order; + + /** + * The string containing the data of the BIFF stream + * @var string + */ + var $_data; + + /** + * The size of the data in bytes. Should be the same as strlen($this->_data) + * @var integer + */ + var $_datasize; + + /** + * The maximun length for a BIFF record. See _addContinue() + * @var integer + * @see _addContinue() + */ + var $_limit; + + /** + * Constructor + * + * @access public + */ + function Spreadsheet_Excel_Writer_BIFFwriter() + { + $this->_byte_order = ''; + $this->_data = ''; + $this->_datasize = 0; + $this->_limit = 2080; + // Set the byte order + $this->_setByteOrder(); + } + + /** + * Determine the byte order and store it as class data to avoid + * recalculating it for each call to new(). + * + * @access private + */ + function _setByteOrder() + { + // Check if "pack" gives the required IEEE 64bit float + $teststr = pack("d", 1.2345); + $number = pack("C8", 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F); + if ($number == $teststr) { + $byte_order = 0; // Little Endian + } elseif ($number == strrev($teststr)){ + $byte_order = 1; // Big Endian + } else { + // Give up. I'll fix this in a later version. + return $this->raiseError("Required floating point format ". + "not supported on this platform."); + } + $this->_byte_order = $byte_order; + } + + /** + * General storage function + * + * @param string $data binary data to prepend + * @access private + */ + function _prepend($data) + { + if (strlen($data) > $this->_limit) { + $data = $this->_addContinue($data); + } + $this->_data = $data.$this->_data; + $this->_datasize += strlen($data); + } + + /** + * General storage function + * + * @param string $data binary data to append + * @access private + */ + function _append($data) + { + if (strlen($data) > $this->_limit) { + $data = $this->_addContinue($data); + } + $this->_data = $this->_data.$data; + $this->_datasize += strlen($data); + } + + /** + * Writes Excel BOF record to indicate the beginning of a stream or + * sub-stream in the BIFF file. + * + * @param integer $type Type of BIFF file to write: 0x0005 Workbook, + * 0x0010 Worksheet. + * @access private + */ + function _storeBof($type) + { + $record = 0x0809; // Record identifier + + // According to the SDK $build and $year should be set to zero. + // However, this throws a warning in Excel 5. So, use magic numbers. + if ($this->_BIFF_version == 0x0500) { + $length = 0x0008; + $unknown = ''; + $build = 0x096C; + $year = 0x07C9; + } elseif ($this->_BIFF_version == 0x0600) { + $length = 0x0010; + $unknown = pack("VV", 0x00000041, 0x00000006); //unknown last 8 bytes for BIFF8 + $build = 0x0DBB; + $year = 0x07CC; + } + $version = $this->_BIFF_version; + + $header = pack("vv", $record, $length); + $data = pack("vvvv", $version, $type, $build, $year); + $this->_prepend($header . $data . $unknown); + } + + /** + * Writes Excel EOF record to indicate the end of a BIFF stream. + * + * @access private + */ + function _storeEof() + { + $record = 0x000A; // Record identifier + $length = 0x0000; // Number of bytes to follow + $header = pack("vv", $record, $length); + $this->_append($header); + } + + /** + * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In + * Excel 97 the limit is 8228 bytes. Records that are longer than these limits + * must be split up into CONTINUE blocks. + * + * This function takes a long BIFF record and inserts CONTINUE records as + * necessary. + * + * @param string $data The original binary data to be written + * @return string A very convenient string of continue blocks + * @access private + */ + function _addContinue($data) + { + $limit = $this->_limit; + $record = 0x003C; // Record identifier + + // The first 2080/8224 bytes remain intact. However, we have to change + // the length field of the record. + $tmp = substr($data, 0, 2).pack("v", $limit-4).substr($data, 4, $limit - 4); + + $header = pack("vv", $record, $limit); // Headers for continue records + + // Retrieve chunks of 2080/8224 bytes +4 for the header. + $data_length = strlen($data); + for ($i = $limit; $i < ($data_length - $limit); $i += $limit) { + $tmp .= $header; + $tmp .= substr($data, $i, $limit); + } + + // Retrieve the last chunk of data + $header = pack("vv", $record, strlen($data) - $i); + $tmp .= $header; + $tmp .= substr($data, $i, strlen($data) - $i); + + return $tmp; + } +} +?> diff --git a/include/Excel/File.php b/include/Excel/File.php new file mode 100644 index 000000000..ec2c8376e --- /dev/null +++ b/include/Excel/File.php @@ -0,0 +1,113 @@ + | +// | Based on OLE::Storage_Lite by Kawai, Takanori | +// +----------------------------------------------------------------------+ +// +// $Id: File.php,v 1.8 2003/12/12 21:10:10 xnoguer Exp $ + + + +/** +* Class for creating File PPS's for OLE containers +* +* @author Xavier Noguer +* @category Structures +* @package OLE +*/ +class OLE_PPS_File extends OLE_PPS +{ + /** + * The temporary dir for storing the OLE file + * @var string + */ + var $_tmp_dir; + + /** + * The constructor + * + * @access public + * @param string $name The name of the file (in Unicode) + * @see OLE::Asc2Ucs() + */ + function OLE_PPS_File($name) + { + $this->_tmp_dir = ''; + $this->OLE_PPS( + null, + $name, + OLE_PPS_TYPE_FILE, + null, + null, + null, + null, + null, + '', + array()); + } + + /** + * Sets the temp dir used for storing the OLE file + * + * @access public + * @param string $dir The dir to be used as temp dir + * @return true if given dir is valid, false otherwise + */ + function setTempDir($dir) + { + if (is_dir($dir)) { + $this->_tmp_dir = $dir; + return true; + } + return false; + } + + /** + * Initialization method. Has to be called right after OLE_PPS_File(). + * + * @access public + * @return mixed true on success. PEAR_Error on failure + */ + function init() + { + $this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_File"); + $fh = @fopen($this->_tmp_filename, "w+b"); + if ($fh == false) { + return $this->raiseError("Can't create temporary file"); + } + $this->_PPS_FILE = $fh; + if ($this->_PPS_FILE) { + fseek($this->_PPS_FILE, 0); + } + } + + /** + * Append data to PPS + * + * @access public + * @param string $data The data to append + */ + function append($data) + { + if ($this->_PPS_FILE) { + fwrite($this->_PPS_FILE, $data); + } + else { + $this->_data .= $data; + } + } +} +?> diff --git a/include/Excel/Format.php b/include/Excel/Format.php new file mode 100644 index 000000000..7eca2c6f1 --- /dev/null +++ b/include/Excel/Format.php @@ -0,0 +1,1101 @@ + +* +* The majority of this is _NOT_ my code. I simply ported it from the +* PERL Spreadsheet::WriteExcel module. +* +* The author of the Spreadsheet::WriteExcel module is John McNamara +* +* +* I _DO_ maintain this code, and John McNamara has nothing to do with the +* porting of this code to PHP. Any questions directly related to this +* class library should be directed to me. +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +/** +* Class for generating Excel XF records (formats) +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer_Format extends PEAR +{ + /** + * The index given by the workbook when creating a new format. + * @var integer + */ + var $_xf_index; + + /** + * Index to the FONT record. + * @var integer + */ + var $font_index; + + /** + * The font name (ASCII). + * @var string + */ + var $_font_name; + + /** + * Height of font (1/20 of a point) + * @var integer + */ + var $_size; + + /** + * Bold style + * @var integer + */ + var $_bold; + + /** + * Bit specifiying if the font is italic. + * @var integer + */ + var $_italic; + + /** + * Index to the cell's color + * @var integer + */ + var $_color; + + /** + * The text underline property + * @var integer + */ + var $_underline; + + /** + * Bit specifiying if the font has strikeout. + * @var integer + */ + var $_font_strikeout; + + /** + * Bit specifiying if the font has outline. + * @var integer + */ + var $_font_outline; + + /** + * Bit specifiying if the font has shadow. + * @var integer + */ + var $_font_shadow; + + /** + * 2 bytes specifiying the script type for the font. + * @var integer + */ + var $_font_script; + + /** + * Byte specifiying the font family. + * @var integer + */ + var $_font_family; + + /** + * Byte specifiying the font charset. + * @var integer + */ + var $_font_charset; + + /** + * An index (2 bytes) to a FORMAT record (number format). + * @var integer + */ + var $_num_format; + + /** + * Bit specifying if formulas are hidden. + * @var integer + */ + var $_hidden; + + /** + * Bit specifying if the cell is locked. + * @var integer + */ + var $_locked; + + /** + * The three bits specifying the text horizontal alignment. + * @var integer + */ + var $_text_h_align; + + /** + * Bit specifying if the text is wrapped at the right border. + * @var integer + */ + var $_text_wrap; + + /** + * The three bits specifying the text vertical alignment. + * @var integer + */ + var $_text_v_align; + + /** + * 1 bit, apparently not used. + * @var integer + */ + var $_text_justlast; + + /** + * The two bits specifying the text rotation. + * @var integer + */ + var $_rotation; + + /** + * The cell's foreground color. + * @var integer + */ + var $_fg_color; + + /** + * The cell's background color. + * @var integer + */ + var $_bg_color; + + /** + * The cell's background fill pattern. + * @var integer + */ + var $_pattern; + + /** + * Style of the bottom border of the cell + * @var integer + */ + var $_bottom; + + /** + * Color of the bottom border of the cell. + * @var integer + */ + var $_bottom_color; + + /** + * Style of the top border of the cell + * @var integer + */ + var $_top; + + /** + * Color of the top border of the cell. + * @var integer + */ + var $_top_color; + + /** + * Style of the left border of the cell + * @var integer + */ + var $_left; + + /** + * Color of the left border of the cell. + * @var integer + */ + var $_left_color; + + /** + * Style of the right border of the cell + * @var integer + */ + var $_right; + + /** + * Color of the right border of the cell. + * @var integer + */ + var $_right_color; + + /** + * Constructor + * + * @access private + * @param integer $index the XF index for the format. + * @param array $properties array with properties to be set on initialization. + */ + function Spreadsheet_Excel_Writer_Format($BIFF_version, $index = 0, $properties = array()) + { + $this->_xf_index = $index; + $this->_BIFF_version = $BIFF_version; + $this->font_index = 0; + $this->_font_name = 'Arial'; + $this->_size = 10; + $this->_bold = 0x0190; + $this->_italic = 0; + $this->_color = 0x7FFF; + $this->_underline = 0; + $this->_font_strikeout = 0; + $this->_font_outline = 0; + $this->_font_shadow = 0; + $this->_font_script = 0; + $this->_font_family = 0; + $this->_font_charset = 0; + + $this->_num_format = 0; + + $this->_hidden = 0; + $this->_locked = 0; + + $this->_text_h_align = 0; + $this->_text_wrap = 0; + $this->_text_v_align = 2; + $this->_text_justlast = 0; + $this->_rotation = 0; + + $this->_fg_color = 0x40; + $this->_bg_color = 0x41; + + $this->_pattern = 0; + + $this->_bottom = 0; + $this->_top = 0; + $this->_left = 0; + $this->_right = 0; + $this->_diag = 0; + + $this->_bottom_color = 0x40; + $this->_top_color = 0x40; + $this->_left_color = 0x40; + $this->_right_color = 0x40; + $this->_diag_color = 0x40; + + // Set properties passed to Spreadsheet_Excel_Writer_Workbook::addFormat() + foreach ($properties as $property => $value) + { + if (method_exists($this, 'set'.ucwords($property))) { + $method_name = 'set'.ucwords($property); + $this->$method_name($value); + } + } + } + + + /** + * Generate an Excel BIFF XF record (style or cell). + * + * @param string $style The type of the XF record ('style' or 'cell'). + * @return string The XF record + */ + function getXf($style) + { + // Set the type of the XF record and some of the attributes. + if ($style == 'style') { + $style = 0xFFF5; + } else { + $style = $this->_locked; + $style |= $this->_hidden << 1; + } + + // Flags to indicate if attributes have been set. + $atr_num = ($this->_num_format != 0)?1:0; + $atr_fnt = ($this->font_index != 0)?1:0; + $atr_alc = ($this->_text_wrap)?1:0; + $atr_bdr = ($this->_bottom || + $this->_top || + $this->_left || + $this->_right)?1:0; + $atr_pat = (($this->_fg_color != 0x40) || + ($this->_bg_color != 0x41) || + $this->_pattern)?1:0; + $atr_prot = $this->_locked | $this->_hidden; + + // Zero the default border colour if the border has not been set. + if ($this->_bottom == 0) { + $this->_bottom_color = 0; + } + if ($this->_top == 0) { + $this->_top_color = 0; + } + if ($this->_right == 0) { + $this->_right_color = 0; + } + if ($this->_left == 0) { + $this->_left_color = 0; + } + if ($this->_diag == 0) { + $this->_diag_color = 0; + } + + $record = 0x00E0; // Record identifier + if ($this->_BIFF_version == 0x0500) { + $length = 0x0010; // Number of bytes to follow + } + if ($this->_BIFF_version == 0x0600) { + $length = 0x0014; + } + + $ifnt = $this->font_index; // Index to FONT record + $ifmt = $this->_num_format; // Index to FORMAT record + if ($this->_BIFF_version == 0x0500) { + $align = $this->_text_h_align; // Alignment + $align |= $this->_text_wrap << 3; + $align |= $this->_text_v_align << 4; + $align |= $this->_text_justlast << 7; + $align |= $this->_rotation << 8; + $align |= $atr_num << 10; + $align |= $atr_fnt << 11; + $align |= $atr_alc << 12; + $align |= $atr_bdr << 13; + $align |= $atr_pat << 14; + $align |= $atr_prot << 15; + + $icv = $this->_fg_color; // fg and bg pattern colors + $icv |= $this->_bg_color << 7; + + $fill = $this->_pattern; // Fill and border line style + $fill |= $this->_bottom << 6; + $fill |= $this->_bottom_color << 9; + + $border1 = $this->_top; // Border line style and color + $border1 |= $this->_left << 3; + $border1 |= $this->_right << 6; + $border1 |= $this->_top_color << 9; + + $border2 = $this->_left_color; // Border color + $border2 |= $this->_right_color << 7; + + $header = pack("vv", $record, $length); + $data = pack("vvvvvvvv", $ifnt, $ifmt, $style, $align, + $icv, $fill, + $border1, $border2); + } elseif ($this->_BIFF_version == 0x0600) { + $align = $this->_text_h_align; // Alignment + $align |= $this->_text_wrap << 3; + $align |= $this->_text_v_align << 4; + $align |= $this->_text_justlast << 7; + + $used_attrib = $atr_num << 2; + $used_attrib |= $atr_fnt << 3; + $used_attrib |= $atr_alc << 4; + $used_attrib |= $atr_bdr << 5; + $used_attrib |= $atr_pat << 6; + $used_attrib |= $atr_prot << 7; + + $icv = $this->_fg_color; // fg and bg pattern colors + $icv |= $this->_bg_color << 7; + + $border1 = $this->_left; // Border line style and color + $border1 |= $this->_right << 4; + $border1 |= $this->_top << 8; + $border1 |= $this->_bottom << 12; + $border1 |= $this->_left_color << 16; + $border1 |= $this->_right_color << 23; + $diag_tl_to_rb = 0; // FIXME: add method + $diag_tr_to_lb = 0; // FIXME: add method + $border1 |= $diag_tl_to_rb << 30; + $border1 |= $diag_tr_to_lb << 31; + + $border2 = $this->_top_color; // Border color + $border2 |= $this->_bottom_color << 7; + $border2 |= $this->_diag_color << 14; + $border2 |= $this->_diag << 21; + $border2 |= $this->_pattern << 26; + + $header = pack("vv", $record, $length); + + $rotation = 0x00; + $biff8_options = 0x00; + $data = pack("vvvC", $ifnt, $ifmt, $style, $align); + $data .= pack("CCC", $rotation, $biff8_options, $used_attrib); + $data .= pack("VVv", $border1, $border2, $icv); + } + + return($header . $data); + } + + /** + * Generate an Excel BIFF FONT record. + * + * @return string The FONT record + */ + function getFont() + { + $dyHeight = $this->_size * 20; // Height of font (1/20 of a point) + $icv = $this->_color; // Index to color palette + $bls = $this->_bold; // Bold style + $sss = $this->_font_script; // Superscript/subscript + $uls = $this->_underline; // Underline + $bFamily = $this->_font_family; // Font family + $bCharSet = $this->_font_charset; // Character set + $encoding = 0; // TODO: Unicode support + + $cch = strlen($this->_font_name); // Length of font name + $record = 0x31; // Record identifier + if ($this->_BIFF_version == 0x0500) { + $length = 0x0F + $cch; // Record length + } elseif ($this->_BIFF_version == 0x0600) { + $length = 0x10 + $cch; + } + $reserved = 0x00; // Reserved + $grbit = 0x00; // Font attributes + if ($this->_italic) { + $grbit |= 0x02; + } + if ($this->_font_strikeout) { + $grbit |= 0x08; + } + if ($this->_font_outline) { + $grbit |= 0x10; + } + if ($this->_font_shadow) { + $grbit |= 0x20; + } + + $header = pack("vv", $record, $length); + if ($this->_BIFF_version == 0x0500) { + $data = pack("vvvvvCCCCC", $dyHeight, $grbit, $icv, $bls, + $sss, $uls, $bFamily, + $bCharSet, $reserved, $cch); + } elseif ($this->_BIFF_version == 0x0600) { + $data = pack("vvvvvCCCCCC", $dyHeight, $grbit, $icv, $bls, + $sss, $uls, $bFamily, + $bCharSet, $reserved, $cch, $encoding); + } + return($header . $data . $this->_font_name); + } + + /** + * Returns a unique hash key for a font. + * Used by Spreadsheet_Excel_Writer_Workbook::_storeAllFonts() + * + * The elements that form the key are arranged to increase the probability of + * generating a unique key. Elements that hold a large range of numbers + * (eg. _color) are placed between two binary elements such as _italic + * + * @return string A key for this font + */ + function getFontKey() + { + $key = "$this->_font_name$this->_size"; + $key .= "$this->_font_script$this->_underline"; + $key .= "$this->_font_strikeout$this->_bold$this->_font_outline"; + $key .= "$this->_font_family$this->_font_charset"; + $key .= "$this->_font_shadow$this->_color$this->_italic"; + $key = str_replace(' ', '_', $key); + return ($key); + } + + /** + * Returns the index used by Spreadsheet_Excel_Writer_Worksheet::_XF() + * + * @return integer The index for the XF record + */ + function getXfIndex() + { + return($this->_xf_index); + } + + /** + * Used in conjunction with the set_xxx_color methods to convert a color + * string into a number. Color range is 0..63 but we will restrict it + * to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15. + * + * @access private + * @param string $name_color name of the color (i.e.: 'blue', 'red', etc..). Optional. + * @return integer The color index + */ + function _getColor($name_color = '') + { + $colors = array( + 'aqua' => 0x0F, + 'cyan' => 0x0F, + 'black' => 0x08, + 'blue' => 0x0C, + 'brown' => 0x10, + 'magenta' => 0x0E, + 'fuchsia' => 0x0E, + 'gray' => 0x17, + 'grey' => 0x17, + 'green' => 0x11, + 'lime' => 0x0B, + 'navy' => 0x12, + 'orange' => 0x35, + 'purple' => 0x14, + 'red' => 0x0A, + 'silver' => 0x16, + 'white' => 0x09, + 'yellow' => 0x0D + ); + + // Return the default color, 0x7FFF, if undef, + if ($name_color == '') { + return(0x7FFF); + } + + // or the color string converted to an integer, + if (isset($colors[$name_color])) { + return($colors[$name_color]); + } + + // or the default color if string is unrecognised, + if (preg_match("/\D/",$name_color)) { + return(0x7FFF); + } + + // or an index < 8 mapped into the correct range, + if ($name_color < 8) { + return($name_color + 8); + } + + // or the default color if arg is outside range, + if ($name_color > 63) { + return(0x7FFF); + } + + // or an integer in the valid range + return($name_color); + } + + /** + * Set cell alignment. + * + * @access public + * @param string $location alignment for the cell ('left', 'right', etc...). + */ + function setAlign($location) + { + if (preg_match("/\d/",$location)) { + return; // Ignore numbers + } + + $location = strtolower($location); + + if ($location == 'left') { + $this->_text_h_align = 1; + } + if ($location == 'centre') { + $this->_text_h_align = 2; + } + if ($location == 'center') { + $this->_text_h_align = 2; + } + if ($location == 'right') { + $this->_text_h_align = 3; + } + if ($location == 'fill') { + $this->_text_h_align = 4; + } + if ($location == 'justify') { + $this->_text_h_align = 5; + } + if ($location == 'merge') { + $this->_text_h_align = 6; + } + if ($location == 'equal_space') { // For T.K. + $this->_text_h_align = 7; + } + if ($location == 'top') { + $this->_text_v_align = 0; + } + if ($location == 'vcentre') { + $this->_text_v_align = 1; + } + if ($location == 'vcenter') { + $this->_text_v_align = 1; + } + if ($location == 'bottom') { + $this->_text_v_align = 2; + } + if ($location == 'vjustify') { + $this->_text_v_align = 3; + } + if ($location == 'vequal_space') { // For T.K. + $this->_text_v_align = 4; + } + } + + /** + * Set cell horizontal alignment. + * + * @access public + * @param string $location alignment for the cell ('left', 'right', etc...). + */ + function setHAlign($location) + { + if (preg_match("/\d/",$location)) { + return; // Ignore numbers + } + + $location = strtolower($location); + + if ($location == 'left') { + $this->_text_h_align = 1; + } + if ($location == 'centre') { + $this->_text_h_align = 2; + } + if ($location == 'center') { + $this->_text_h_align = 2; + } + if ($location == 'right') { + $this->_text_h_align = 3; + } + if ($location == 'fill') { + $this->_text_h_align = 4; + } + if ($location == 'justify') { + $this->_text_h_align = 5; + } + if ($location == 'merge') { + $this->_text_h_align = 6; + } + if ($location == 'equal_space') { // For T.K. + $this->_text_h_align = 7; + } + } + + /** + * Set cell vertical alignment. + * + * @access public + * @param string $location alignment for the cell ('top', 'vleft', 'vright', etc...). + */ + function setVAlign($location) + { + if (preg_match("/\d/",$location)) { + return; // Ignore numbers + } + + $location = strtolower($location); + + if ($location == 'top') { + $this->_text_v_align = 0; + } + if ($location == 'vcentre') { + $this->_text_v_align = 1; + } + if ($location == 'vcenter') { + $this->_text_v_align = 1; + } + if ($location == 'bottom') { + $this->_text_v_align = 2; + } + if ($location == 'vjustify') { + $this->_text_v_align = 3; + } + if ($location == 'vequal_space') { // For T.K. + $this->_text_v_align = 4; + } + } + + /** + * This is an alias for the unintuitive setAlign('merge') + * + * @access public + */ + function setMerge() + { + $this->setAlign('merge'); + } + + /** + * Sets the boldness of the text. + * Bold has a range 100..1000. + * 0 (400) is normal. 1 (700) is bold. + * + * @access public + * @param integer $weight Weight for the text, 0 maps to 400 (normal text), + 1 maps to 700 (bold text). Valid range is: 100-1000. + It's Optional, default is 1 (bold). + */ + function setBold($weight = 1) + { + if ($weight == 1) { + $weight = 0x2BC; // Bold text + } + if ($weight == 0) { + $weight = 0x190; // Normal text + } + if ($weight < 0x064) { + $weight = 0x190; // Lower bound + } + if ($weight > 0x3E8) { + $weight = 0x190; // Upper bound + } + $this->_bold = $weight; + } + + + /************************************ + * FUNCTIONS FOR SETTING CELLS BORDERS + */ + + /** + * Sets the width for the bottom border of the cell + * + * @access public + * @param integer $style style of the cell border. 1 => thin, 2 => thick. + */ + function setBottom($style) + { + $this->_bottom = $style; + } + + /** + * Sets the width for the top border of the cell + * + * @access public + * @param integer $style style of the cell top border. 1 => thin, 2 => thick. + */ + function setTop($style) + { + $this->_top = $style; + } + + /** + * Sets the width for the left border of the cell + * + * @access public + * @param integer $style style of the cell left border. 1 => thin, 2 => thick. + */ + function setLeft($style) + { + $this->_left = $style; + } + + /** + * Sets the width for the right border of the cell + * + * @access public + * @param integer $style style of the cell right border. 1 => thin, 2 => thick. + */ + function setRight($style) + { + $this->_right = $style; + } + + + /** + * Set cells borders to the same style + * + * @access public + * @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick. + */ + function setBorder($style) + { + $this->setBottom($style); + $this->setTop($style); + $this->setLeft($style); + $this->setRight($style); + } + + + /******************************************* + * FUNCTIONS FOR SETTING CELLS BORDERS COLORS + */ + + /** + * Sets all the cell's borders to the same color + * + * @access public + * @param mixed $color The color we are setting. Either a string (like 'blue'), + * or an integer (range is [8...63]). + */ + function setBorderColor($color) + { + $this->setBottomColor($color); + $this->setTopColor($color); + $this->setLeftColor($color); + $this->setRightColor($color); + } + + /** + * Sets the cell's bottom border color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + function setBottomColor($color) + { + $value = $this->_getColor($color); + $this->_bottom_color = $value; + } + + /** + * Sets the cell's top border color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + function setTopColor($color) + { + $value = $this->_getColor($color); + $this->_top_color = $value; + } + + /** + * Sets the cell's left border color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + function setLeftColor($color) + { + $value = $this->_getColor($color); + $this->_left_color = $value; + } + + /** + * Sets the cell's right border color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + function setRightColor($color) + { + $value = $this->_getColor($color); + $this->_right_color = $value; + } + + + /** + * Sets the cell's foreground color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + function setFgColor($color) + { + $value = $this->_getColor($color); + $this->_fg_color = $value; + if ($this->_pattern == 0) { // force color to be seen + $this->_pattern = 1; + } + } + + /** + * Sets the cell's background color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + function setBgColor($color) + { + $value = $this->_getColor($color); + $this->_bg_color = $value; + if ($this->_pattern == 0) { // force color to be seen + $this->_pattern = 1; + } + } + + /** + * Sets the cell's color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + function setColor($color) + { + $value = $this->_getColor($color); + $this->_color = $value; + } + + /** + * Sets the fill pattern attribute of a cell + * + * @access public + * @param integer $arg Optional. Defaults to 1. Meaningful values are: 0-18, + * 0 meaning no background. + */ + function setPattern($arg = 1) + { + $this->_pattern = $arg; + } + + /** + * Sets the underline of the text + * + * @access public + * @param integer $underline The value for underline. Possible values are: + * 1 => underline, 2 => double underline. + */ + function setUnderline($underline) + { + $this->_underline = $underline; + } + + /** + * Sets the font style as italic + * + * @access public + */ + function setItalic() + { + $this->_italic = 1; + } + + /** + * Sets the font size + * + * @access public + * @param integer $size The font size (in pixels I think). + */ + function setSize($size) + { + $this->_size = $size; + } + + /** + * Sets text wrapping + * + * @access public + */ + function setTextWrap() + { + $this->_text_wrap = 1; + } + + /** + * Sets the orientation of the text + * + * @access public + * @param integer $angle The rotation angle for the text (clockwise). Possible + values are: 0, 90, 270 and -1 for stacking top-to-bottom. + */ + function setTextRotation($angle) + { + switch ($angle) + { + case 0: + $this->_rotation = 0; + break; + case 90: + $this->_rotation = 3; + break; + case 270: + $this->_rotation = 2; + break; + case -1: + $this->_rotation = 1; + break; + default : + return $this->raiseError("Invalid value for angle.". + " Possible values are: 0, 90, 270 and -1 ". + "for stacking top-to-bottom."); + $this->_rotation = 0; + break; + } + } + + /** + * Sets the numeric format. + * It can be date, time, currency, etc... + * + * @access public + * @param integer $num_format The numeric format. + */ + function setNumFormat($num_format) + { + $this->_num_format = $num_format; + } + + /** + * Sets font as strikeout. + * + * @access public + */ + function setStrikeOut() + { + $this->_font_strikeout = 1; + } + + /** + * Sets outlining for a font. + * + * @access public + */ + function setOutLine() + { + $this->_font_outline = 1; + } + + /** + * Sets font as shadow. + * + * @access public + */ + function setShadow() + { + $this->_font_shadow = 1; + } + + /** + * Sets the script type of the text + * + * @access public + * @param integer $script The value for script type. Possible values are: + * 1 => superscript, 2 => subscript. + */ + function setScript($script) + { + $this->_font_script = $script; + } + + /** + * Locks a cell. + * + * @access public + */ + function setLocked() + { + $this->_locked = 1; + } + + /** + * Unlocks a cell. Useful for unprotecting particular cells of a protected sheet. + * + * @access public + */ + function setUnLocked() + { + $this->_locked = 0; + } + + /** + * Sets the font family name. + * + * @access public + * @param string $fontfamily The font family name. Possible values are: + * 'Times New Roman', 'Arial', 'Courier'. + */ + function setFontFamily($font_family) + { + $this->_font_name = $font_family; + } +} +?> diff --git a/include/Excel/OLE.php b/include/Excel/OLE.php new file mode 100644 index 000000000..40efcf1cf --- /dev/null +++ b/include/Excel/OLE.php @@ -0,0 +1,408 @@ + | +// | Based on OLE::Storage_Lite by Kawai, Takanori | +// +----------------------------------------------------------------------+ +// +// $Id: OLE.php,v 1.7 2003/08/21 15:15:40 xnoguer Exp $ + + +/** +* Constants for OLE package +*/ +define('OLE_PPS_TYPE_ROOT', 5); +define('OLE_PPS_TYPE_DIR', 1); +define('OLE_PPS_TYPE_FILE', 2); +define('OLE_DATA_SIZE_SMALL', 0x1000); +define('OLE_LONG_INT_SIZE', 4); +define('OLE_PPS_SIZE', 0x80); + + +/** +* OLE package base class. +* +* @author Xavier Noguer +* @category Structures +* @package OLE +*/ +class OLE extends PEAR +{ + /** + * The file handle for reading an OLE container + * @var resource + */ + var $_file_handle; + + /** + * Array of PPS's found on the OLE container + * @var array + */ + var $_list; + + /** + * Creates a new OLE object + * Remember to use ampersand when creating an OLE object ($my_ole =& new OLE();) + * @access public + */ + function OLE() + { + $this->_list = array(); + } + + /** + * Reads an OLE container from the contents of the file given. + * + * @acces public + * @param string $file + * @return mixed true on success, PEAR_Error on failure + */ + function read($file) + { + /* consider storing offsets as constants */ + $big_block_size_offset = 30; + $iBdbCnt_offset = 44; + $bd_start_offset = 68; + + $fh = @fopen($file, "r"); + if ($fh == false) { + return $this->raiseError("Can't open file $file"); + } + $this->_file_handle = $fh; + + /* begin reading OLE attributes */ + fseek($fh, 0); + $signature = fread($fh, 8); + if ("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" != $signature) { + return $this->raiseError("File doesn't seem to be an OLE container."); + } + fseek($fh, $big_block_size_offset); + $packed_array = unpack("v", fread($fh, 2)); + $big_block_size = pow(2, $packed_array['']); + + $packed_array = unpack("v", fread($fh, 2)); + $small_block_size = pow(2, $packed_array['']); + $i1stBdL = ($big_block_size - 0x4C) / OLE_LONG_INT_SIZE; + + fseek($fh, $iBdbCnt_offset); + $packed_array = unpack("V", fread($fh, 4)); + $iBdbCnt = $packed_array['']; + + $packed_array = unpack("V", fread($fh, 4)); + $pps_wk_start = $packed_array['']; + + fseek($fh, $bd_start_offset); + $packed_array = unpack("V", fread($fh, 4)); + $bd_start = $packed_array['']; + $packed_array = unpack("V", fread($fh, 4)); + $bd_count = $packed_array['']; + $packed_array = unpack("V", fread($fh, 4)); + $iAll = $packed_array['']; // this may be wrong + /* create OLE_PPS objects from */ + $ret = $this->_readPpsWks($pps_wk_start, $big_block_size); + if (PEAR::isError($ret)) { + return $ret; + } + return true; + } + + /** + * Destructor (using PEAR) + * Just closes the file handle on the OLE file. + * + * @access private + */ + function _OLE() + { + fclose($this->_file_handle); + } + + /** + * Gets information about all PPS's on the OLE container from the PPS WK's + * creates an OLE_PPS object for each one. + * + * @access private + * @param integer $pps_wk_start Position inside the OLE file where PPS WK's start + * @param integer $big_block_size Size of big blobks in the OLE file + * @return mixed true on success, PEAR_Error on failure + */ + function _readPpsWks($pps_wk_start, $big_block_size) + { + $pointer = ($pps_wk_start + 1) * $big_block_size; + while (1) + { + fseek($this->_file_handle, $pointer); + $pps_wk = fread($this->_file_handle, OLE_PPS_SIZE); + if (strlen($pps_wk) != OLE_PPS_SIZE) { + break; // Excel likes to add a trailing byte sometimes + //return $this->raiseError("PPS at $pointer seems too short: ".strlen($pps_wk)); + } + $name_length = unpack("c", substr($pps_wk, 64, 2)); // FIXME (2 bytes??) + $name_length = $name_length[''] - 2; + $name = substr($pps_wk, 0, $name_length); + $type = unpack("c", substr($pps_wk, 66, 1)); + if (($type[''] != OLE_PPS_TYPE_ROOT) and + ($type[''] != OLE_PPS_TYPE_DIR) and + ($type[''] != OLE_PPS_TYPE_FILE)) + { + return $this->raiseError("PPS at $pointer has unknown type: {$type['']}"); + } + $prev = unpack("V", substr($pps_wk, 68, 4)); + $next = unpack("V", substr($pps_wk, 72, 4)); + $dir = unpack("V", substr($pps_wk, 76, 4)); + // there is no magic number, it can take different values. + //$magic = unpack("V", strrev(substr($pps_wk, 92, 4))); + $time_1st = substr($pps_wk, 100, 8); + $time_2nd = substr($pps_wk, 108, 8); + $start_block = unpack("V", substr($pps_wk, 116, 4)); + $size = unpack("V", substr($pps_wk, 120, 4)); + // _data member will point to position in file!! + // OLE_PPS object is created with an empty children array!! + $this->_list[] = new OLE_PPS(null, '', $type[''], $prev[''], $next[''], + $dir[''], OLE::OLE2LocalDate($time_1st), + OLE::OLE2LocalDate($time_2nd), + ($start_block[''] + 1) * $big_block_size, array()); + // give it a size + $this->_list[count($this->_list) - 1]->Size = $size['']; + // check if the PPS tree (starting from root) is complete + if ($this->_ppsTreeComplete(0)) { + break; + } + $pointer += OLE_PPS_SIZE; + } + } + + /** + * It checks whether the PPS tree is complete (all PPS's read) + * starting with the given PPS (not necessarily root) + * + * @access private + * @param integer $index The index of the PPS from which we are checking + * @return boolean Whether the PPS tree for the given PPS is complete + */ + function _ppsTreeComplete($index) + { + if ($this->_list[$index]->NextPps != -1) { + if (!isset($this->_list[$this->_list[$index]->NextPps])) { + return false; + } + else { + return $this->_ppsTreeComplete($this->_list[$index]->NextPps); + } + } + if ($this->_list[$index]->DirPps != -1) { + if (!isset($this->_list[$this->_list[$index]->DirPps])) { + return false; + } + else { + return $this->_ppsTreeComplete($this->_list[$index]->DirPps); + } + } + return true; + } + + /** + * Checks whether a PPS is a File PPS or not. + * If there is no PPS for the index given, it will return false. + * + * @access public + * @param integer $index The index for the PPS + * @return bool true if it's a File PPS, false otherwise + */ + function isFile($index) + { + if (isset($this->_list[$index])) { + return ($this->_list[$index]->Type == OLE_PPS_TYPE_FILE); + } + return false; + } + + /** + * Checks whether a PPS is a Root PPS or not. + * If there is no PPS for the index given, it will return false. + * + * @access public + * @param integer $index The index for the PPS. + * @return bool true if it's a Root PPS, false otherwise + */ + function isRoot($index) + { + if (isset($this->_list[$index])) { + return ($this->_list[$index]->Type == OLE_PPS_TYPE_ROOT); + } + return false; + } + + /** + * Gives the total number of PPS's found in the OLE container. + * + * @access public + * @return integer The total number of PPS's found in the OLE container + */ + function ppsTotal() + { + return count($this->_list); + } + + /** + * Gets data from a PPS + * If there is no PPS for the index given, it will return an empty string. + * + * @access public + * @param integer $index The index for the PPS + * @param integer $position The position from which to start reading + * (relative to the PPS) + * @param integer $length The amount of bytes to read (at most) + * @return string The binary string containing the data requested + */ + function getData($index, $position, $length) + { + // if position is not valid return empty string + if (!isset($this->_list[$index]) or ($position >= $this->_list[$index]->Size) or ($position < 0)) { + return ''; + } + // Beware!!! _data member is actually a position + fseek($this->_file_handle, $this->_list[$index]->_data + $position); + return fread($this->_file_handle, $length); + } + + /** + * Gets the data length from a PPS + * If there is no PPS for the index given, it will return 0. + * + * @access public + * @param integer $index The index for the PPS + * @return integer The amount of bytes in data the PPS has + */ + function getDataLength($index) + { + if (isset($this->_list[$index])) { + return $this->_list[$index]->Size; + } + return 0; + } + + /** + * Utility function to transform ASCII text to Unicode + * + * @access public + * @static + * @param string $ascii The ASCII string to transform + * @return string The string in Unicode + */ + function Asc2Ucs($ascii) + { + $rawname = ''; + for ($i = 0; $i < strlen($ascii); $i++) { + $rawname .= $ascii{$i}."\x00"; + } + return $rawname; + } + + /** + * Utility function + * Returns a string for the OLE container with the date given + * + * @access public + * @static + * @param integer $date A timestamp + * @return string The string for the OLE container + */ + function LocalDate2OLE($date = null) + { + if (!isset($date)) { + return "\x00\x00\x00\x00\x00\x00\x00\x00"; + } + + // factor used for separating numbers into 4 bytes parts + $factor = pow(2,32); + + // days from 1-1-1601 until the beggining of UNIX era + $days = 134774; + // calculate seconds + $big_date = $days*24*3600 + gmmktime(date("H",$date),date("i",$date),date("s",$date), + date("m",$date),date("d",$date),date("Y",$date)); + // multiply just to make MS happy + $big_date *= 10000000; + + $high_part = floor($big_date/$factor); + // lower 4 bytes + $low_part = floor((($big_date/$factor) - $high_part)*$factor); + + // Make HEX string + $res = ''; + + for ($i=0; $i<4; $i++) + { + $hex = $low_part % 0x100; + $res .= pack('c', $hex); + $low_part /= 0x100; + } + for ($i=0; $i<4; $i++) + { + $hex = $high_part % 0x100; + $res .= pack('c', $hex); + $high_part /= 0x100; + } + return $res; + } + + /** + * Returns a timestamp from an OLE container's date + * + * @access public + * @static + * @param integer $string A binary string with the encoded date + * @return string The timestamp corresponding to the string + */ + function OLE2LocalDate($string) + { + if (strlen($string) != 8) { + return new PEAR_Error("Expecting 8 byte string"); + } + + // factor used for separating numbers into 4 bytes parts + $factor = pow(2,32); + $high_part = 0; + for ($i=0; $i<4; $i++) + { + $al = unpack('C', $string{(7 - $i)}); + $high_part += $al['']; + if ($i < 3) { + $high_part *= 0x100; + } + } + $low_part = 0; + for ($i=4; $i<8; $i++) + { + $al = unpack('C', $string{(7 - $i)}); + $low_part += $al['']; + if ($i < 7) { + $low_part *= 0x100; + } + } + $big_date = ($high_part*$factor) + $low_part; + // translate to seconds + $big_date /= 10000000; + + // days from 1-1-1601 until the beggining of UNIX era + $days = 134774; + + // translate to seconds from beggining of UNIX era + $big_date -= $days*24*3600; + return floor($big_date); + } +} +?> diff --git a/include/Excel/PEAR.php b/include/Excel/PEAR.php new file mode 100644 index 000000000..7e60a9e4e --- /dev/null +++ b/include/Excel/PEAR.php @@ -0,0 +1,1095 @@ + + * @author Stig Bakken + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: PEAR.php,v 1.97 2006/01/06 04:47:36 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/**#@+ + * ERROR constants + */ +define('PEAR_ERROR_RETURN', 1); +define('PEAR_ERROR_PRINT', 2); +define('PEAR_ERROR_TRIGGER', 4); +define('PEAR_ERROR_DIE', 8); +define('PEAR_ERROR_CALLBACK', 16); +/** + * WARNING: obsolete + * @deprecated + */ +define('PEAR_ERROR_EXCEPTION', 32); +/**#@-*/ +define('PEAR_ZE2', (function_exists('version_compare') && + version_compare(zend_version(), "2-dev", "ge"))); + +if (substr(PHP_OS, 0, 3) == 'WIN') { + define('OS_WINDOWS', true); + define('OS_UNIX', false); + define('PEAR_OS', 'Windows'); +} else { + define('OS_WINDOWS', false); + define('OS_UNIX', true); + define('PEAR_OS', 'Unix'); // blatant assumption +} + +// instant backwards compatibility +if (!defined('PATH_SEPARATOR')) { + if (OS_WINDOWS) { + define('PATH_SEPARATOR', ';'); + } else { + define('PATH_SEPARATOR', ':'); + } +} + +$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; +$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; +$GLOBALS['_PEAR_destructor_object_list'] = array(); +$GLOBALS['_PEAR_shutdown_funcs'] = array(); +$GLOBALS['_PEAR_error_handler_stack'] = array(); + +@ini_set('track_errors', true); + +/** + * Base class for other PEAR classes. Provides rudimentary + * emulation of destructors. + * + * If you want a destructor in your class, inherit PEAR and make a + * destructor method called _yourclassname (same name as the + * constructor, but with a "_" prefix). Also, in your constructor you + * have to call the PEAR constructor: $this->PEAR();. + * The destructor method will be called without parameters. Note that + * at in some SAPI implementations (such as Apache), any output during + * the request shutdown (in which destructors are called) seems to be + * discarded. If you need to get any debug information from your + * destructor, use error_log(), syslog() or something similar. + * + * IMPORTANT! To use the emulated destructors you need to create the + * objects by reference: $obj =& new PEAR_child; + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Greg Beaver + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.4.6 + * @link http://pear.php.net/package/PEAR + * @see PEAR_Error + * @since Class available since PHP 4.0.2 + * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear + */ +class PEAR +{ + // {{{ properties + + /** + * Whether to enable internal debug messages. + * + * @var bool + * @access private + */ + var $_debug = false; + + /** + * Default error mode for this object. + * + * @var int + * @access private + */ + var $_default_error_mode = null; + + /** + * Default error options used for this object when error mode + * is PEAR_ERROR_TRIGGER. + * + * @var int + * @access private + */ + var $_default_error_options = null; + + /** + * Default error handler (callback) for this object, if error mode is + * PEAR_ERROR_CALLBACK. + * + * @var string + * @access private + */ + var $_default_error_handler = ''; + + /** + * Which class to use for error objects. + * + * @var string + * @access private + */ + var $_error_class = 'PEAR_Error'; + + /** + * An array of expected errors. + * + * @var array + * @access private + */ + var $_expected_errors = array(); + + // }}} + + // {{{ constructor + + /** + * Constructor. Registers this object in + * $_PEAR_destructor_object_list for destructor emulation if a + * destructor object exists. + * + * @param string $error_class (optional) which class to use for + * error objects, defaults to PEAR_Error. + * @access public + * @return void + */ + function PEAR($error_class = null) + { + $classname = strtolower(get_class($this)); + if ($this->_debug) { + print "PEAR constructor called, class=$classname\n"; + } + if ($error_class !== null) { + $this->_error_class = $error_class; + } + while ($classname && strcasecmp($classname, "pear")) { + $destructor = "_$classname"; + if (method_exists($this, $destructor)) { + global $_PEAR_destructor_object_list; + $_PEAR_destructor_object_list[] = &$this; + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + break; + } else { + $classname = get_parent_class($classname); + } + } + } + + // }}} + // {{{ destructor + + /** + * Destructor (the emulated type of...). Does nothing right now, + * but is included for forward compatibility, so subclass + * destructors should always call it. + * + * See the note in the class desciption about output from + * destructors. + * + * @access public + * @return void + */ + function _PEAR() { + if ($this->_debug) { + printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); + } + } + + // }}} + // {{{ getStaticProperty() + + /** + * If you have a class that's mostly/entirely static, and you need static + * properties, you can use this method to simulate them. Eg. in your method(s) + * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); + * You MUST use a reference, or they will not persist! + * + * @access public + * @param string $class The calling classname, to prevent clashes + * @param string $var The variable to retrieve. + * @return mixed A reference to the variable. If not set it will be + * auto initialised to NULL. + */ + function &getStaticProperty($class, $var) + { + static $properties; + return $properties[$class][$var]; + } + + // }}} + // {{{ registerShutdownFunc() + + /** + * Use this function to register a shutdown method for static + * classes. + * + * @access public + * @param mixed $func The function name (or array of class/method) to call + * @param mixed $args The arguments to pass to the function + * @return void + */ + function registerShutdownFunc($func, $args = array()) + { + $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + } + + // }}} + // {{{ isError() + + /** + * Tell whether a value is a PEAR error. + * + * @param mixed $data the value to test + * @param int $code if $data is an error object, return true + * only if $code is a string and + * $obj->getMessage() == $code or + * $code is an integer and $obj->getCode() == $code + * @access public + * @return bool true if parameter is an error + */ + function isError($data, $code = null) + { + if (is_a($data, 'PEAR_Error')) { + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() == $code; + } else { + return $data->getCode() == $code; + } + } + return false; + } + + // }}} + // {{{ setErrorHandling() + + /** + * Sets how errors generated by this object should be handled. + * Can be invoked both in objects and statically. If called + * statically, setErrorHandling sets the default behaviour for all + * PEAR objects. If called in an object, setErrorHandling sets + * the default behaviour for that object. + * + * @param int $mode + * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. + * + * @param mixed $options + * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one + * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * + * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected + * to be the callback function or method. A callback + * function is a string with the name of the function, a + * callback method is an array of two elements: the element + * at index 0 is the object, and the element at index 1 is + * the name of the method to call in the object. + * + * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is + * a printf format string used when printing the error + * message. + * + * @access public + * @return void + * @see PEAR_ERROR_RETURN + * @see PEAR_ERROR_PRINT + * @see PEAR_ERROR_TRIGGER + * @see PEAR_ERROR_DIE + * @see PEAR_ERROR_CALLBACK + * @see PEAR_ERROR_EXCEPTION + * + * @since PHP 4.0.5 + */ + + function setErrorHandling($mode = null, $options = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $setmode = &$this->_default_error_mode; + $setoptions = &$this->_default_error_options; + } else { + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + } + + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + } + + // }}} + // {{{ expectError() + + /** + * This method is used to tell which errors you expect to get. + * Expected errors are always returned with error mode + * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, + * and this method pushes a new element onto it. The list of + * expected errors are in effect until they are popped off the + * stack with the popExpect() method. + * + * Note that this method can not be called statically + * + * @param mixed $code a single error code or an array of error codes to expect + * + * @return int the new depth of the "expected errors" stack + * @access public + */ + function expectError($code = '*') + { + if (is_array($code)) { + array_push($this->_expected_errors, $code); + } else { + array_push($this->_expected_errors, array($code)); + } + return sizeof($this->_expected_errors); + } + + // }}} + // {{{ popExpect() + + /** + * This method pops one element off the expected error codes + * stack. + * + * @return array the list of error codes that were popped + */ + function popExpect() + { + return array_pop($this->_expected_errors); + } + + // }}} + // {{{ _checkDelExpect() + + /** + * This method checks unsets an error code if available + * + * @param mixed error code + * @return bool true if the error code was unset, false otherwise + * @access private + * @since PHP 4.3.0 + */ + function _checkDelExpect($error_code) + { + $deleted = false; + + foreach ($this->_expected_errors AS $key => $error_array) { + if (in_array($error_code, $error_array)) { + unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); + $deleted = true; + } + + // clean up empty arrays + if (0 == count($this->_expected_errors[$key])) { + unset($this->_expected_errors[$key]); + } + } + return $deleted; + } + + // }}} + // {{{ delExpect() + + /** + * This method deletes all occurences of the specified element from + * the expected error codes stack. + * + * @param mixed $error_code error code that should be deleted + * @return mixed list of error codes that were deleted or error + * @access public + * @since PHP 4.3.0 + */ + function delExpect($error_code) + { + $deleted = false; + + if ((is_array($error_code) && (0 != count($error_code)))) { + // $error_code is a non-empty array here; + // we walk through it trying to unset all + // values + foreach($error_code as $key => $error) { + if ($this->_checkDelExpect($error)) { + $deleted = true; + } else { + $deleted = false; + } + } + return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } elseif (!empty($error_code)) { + // $error_code comes alone, trying to unset it + if ($this->_checkDelExpect($error_code)) { + return true; + } else { + return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } + } else { + // $error_code is empty + return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME + } + } + + // }}} + // {{{ raiseError() + + /** + * This method is a wrapper that returns an instance of the + * configured error class with this object's default error + * handling applied. If the $mode and $options parameters are not + * specified, the object's defaults are used. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. + * + * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter + * specifies the PHP-internal error level (one of + * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * If $mode is PEAR_ERROR_CALLBACK, this + * parameter specifies the callback function or + * method. In other error modes this parameter + * is ignored. + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @param string $error_class The returned error object will be + * instantiated from this class, if specified. + * + * @param bool $skipmsg If true, raiseError will only pass error codes, + * the error message parameter will be dropped. + * + * @access public + * @return object a PEAR error object + * @see PEAR::setErrorHandling + * @since PHP 4.0.5 + */ + function &raiseError($message = null, + $code = null, + $mode = null, + $options = null, + $userinfo = null, + $error_class = null, + $skipmsg = false) + { + // The error is yet a PEAR error object + if (is_object($message)) { + $code = $message->getCode(); + $userinfo = $message->getUserInfo(); + $error_class = $message->getType(); + $message->error_message_prefix = ''; + $message = $message->getMessage(); + } + + if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { + if ($exp[0] == "*" || + (is_int(reset($exp)) && in_array($code, $exp)) || + (is_string(reset($exp)) && in_array($message, $exp))) { + $mode = PEAR_ERROR_RETURN; + } + } + // No mode given, try global ones + if ($mode === null) { + // Class error handler + if (isset($this) && isset($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + // Global error handler + } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { + $mode = $GLOBALS['_PEAR_default_error_mode']; + $options = $GLOBALS['_PEAR_default_error_options']; + } + } + + if ($error_class !== null) { + $ec = $error_class; + } elseif (isset($this) && isset($this->_error_class)) { + $ec = $this->_error_class; + } else { + $ec = 'PEAR_Error'; + } + if ($skipmsg) { + $a = &new $ec($code, $mode, $options, $userinfo); + return $a; + } else { + $a = &new $ec($message, $code, $mode, $options, $userinfo); + return $a; + } + } + + // }}} + // {{{ throwError() + + /** + * Simpler form of raiseError with fewer options. In most cases + * message, code and userinfo are enough. + * + * @param string $message + * + */ + function &throwError($message = null, + $code = null, + $userinfo = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $a = &$this->raiseError($message, $code, null, null, $userinfo); + return $a; + } else { + $a = &PEAR::raiseError($message, $code, null, null, $userinfo); + return $a; + } + } + + // }}} + function staticPushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + $stack[] = array($def_mode, $def_options); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $def_mode = $mode; + $def_options = $options; + break; + + case PEAR_ERROR_CALLBACK: + $def_mode = $mode; + // class/object method callback + if (is_callable($options)) { + $def_options = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + $stack[] = array($mode, $options); + return true; + } + + function staticPopErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + return true; + } + + // {{{ pushErrorHandling() + + /** + * Push a new error handler on top of the error handler options stack. With this + * you can easily override the actual error handler for some code and restore + * it later with popErrorHandling. + * + * @param mixed $mode (same as setErrorHandling) + * @param mixed $options (same as setErrorHandling) + * + * @return bool Always true + * + * @see PEAR::setErrorHandling + */ + function pushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + if (isset($this) && is_a($this, 'PEAR')) { + $def_mode = &$this->_default_error_mode; + $def_options = &$this->_default_error_options; + } else { + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + } + $stack[] = array($def_mode, $def_options); + + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + $stack[] = array($mode, $options); + return true; + } + + // }}} + // {{{ popErrorHandling() + + /** + * Pop the last error handler used + * + * @return bool Always true + * + * @see PEAR::pushErrorHandling + */ + function popErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + return true; + } + + // }}} + // {{{ loadExtension() + + /** + * OS independant PHP extension load. Remember to take care + * on the correct extension name for case sensitive OSes. + * + * @param string $ext The extension name + * @return bool Success or not on the dl() call + */ + function loadExtension($ext) + { + if (!extension_loaded($ext)) { + // if either returns true dl() will produce a FATAL error, stop that + if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { + return false; + } + if (OS_WINDOWS) { + $suffix = '.dll'; + } elseif (PHP_OS == 'HP-UX') { + $suffix = '.sl'; + } elseif (PHP_OS == 'AIX') { + $suffix = '.a'; + } elseif (PHP_OS == 'OSX') { + $suffix = '.bundle'; + } else { + $suffix = '.so'; + } + return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); + } + return true; + } + + // }}} +} + +// {{{ _PEAR_call_destructors() + +function _PEAR_call_destructors() +{ + global $_PEAR_destructor_object_list; + if (is_array($_PEAR_destructor_object_list) && + sizeof($_PEAR_destructor_object_list)) + { + reset($_PEAR_destructor_object_list); + if (@PEAR::getStaticProperty('PEAR', 'destructlifo')) { + $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); + } + while (list($k, $objref) = each($_PEAR_destructor_object_list)) { + $classname = get_class($objref); + while ($classname) { + $destructor = "_$classname"; + if (method_exists($objref, $destructor)) { + $objref->$destructor(); + break; + } else { + $classname = get_parent_class($classname); + } + } + } + // Empty the object list to ensure that destructors are + // not called more than once. + $_PEAR_destructor_object_list = array(); + } + + // Now call the shutdown functions + if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { + foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { + call_user_func_array($value[0], $value[1]); + } + } +} + +// }}} +/** + * Standard PEAR error class for PHP 4 + * + * This class is supserseded by {@link PEAR_Exception} in PHP 5 + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Gregory Beaver + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.4.6 + * @link http://pear.php.net/manual/en/core.pear.pear-error.php + * @see PEAR::raiseError(), PEAR::throwError() + * @since Class available since PHP 4.0.2 + */ +class PEAR_Error +{ + // {{{ properties + + var $error_message_prefix = ''; + var $mode = PEAR_ERROR_RETURN; + var $level = E_USER_NOTICE; + var $code = -1; + var $message = ''; + var $userinfo = ''; + var $backtrace = null; + + // }}} + // {{{ constructor + + /** + * PEAR_Error constructor + * + * @param string $message message + * + * @param int $code (optional) error code + * + * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, + * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION + * + * @param mixed $options (optional) error level, _OR_ in the case of + * PEAR_ERROR_CALLBACK, the callback function or object/method + * tuple. + * + * @param string $userinfo (optional) additional user/debug info + * + * @access public + * + */ + function PEAR_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + if ($mode === null) { + $mode = PEAR_ERROR_RETURN; + } + $this->message = $message; + $this->code = $code; + $this->mode = $mode; + $this->userinfo = $userinfo; + if (function_exists("debug_backtrace")) { + if (@!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) { + $this->backtrace = debug_backtrace(); + } + } + if ($mode & PEAR_ERROR_CALLBACK) { + $this->level = E_USER_NOTICE; + $this->callback = $options; + } else { + if ($options === null) { + $options = E_USER_NOTICE; + } + $this->level = $options; + $this->callback = null; + } + if ($this->mode & PEAR_ERROR_PRINT) { + if (is_null($options) || is_int($options)) { + $format = "%s"; + } else { + $format = $options; + } + printf($format, $this->getMessage()); + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + trigger_error($this->getMessage(), $this->level); + } + if ($this->mode & PEAR_ERROR_DIE) { + $msg = $this->getMessage(); + if (is_null($options) || is_int($options)) { + $format = "%s"; + if (substr($msg, -1) != "\n") { + $msg .= "\n"; + } + } else { + $format = $options; + } + die(sprintf($format, $msg)); + } + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_callable($this->callback)) { + call_user_func($this->callback, $this); + } + } + if ($this->mode & PEAR_ERROR_EXCEPTION) { + trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); + eval('$e = new Exception($this->message, $this->code);throw($e);'); + } + } + + // }}} + // {{{ getMode() + + /** + * Get the error mode from an error object. + * + * @return int error mode + * @access public + */ + function getMode() { + return $this->mode; + } + + // }}} + // {{{ getCallback() + + /** + * Get the callback function/method from an error object. + * + * @return mixed callback function or object/method array + * @access public + */ + function getCallback() { + return $this->callback; + } + + // }}} + // {{{ getMessage() + + + /** + * Get the error message from an error object. + * + * @return string full error message + * @access public + */ + function getMessage() + { + return ($this->error_message_prefix . $this->message); + } + + + // }}} + // {{{ getCode() + + /** + * Get error code from an error object + * + * @return int error code + * @access public + */ + function getCode() + { + return $this->code; + } + + // }}} + // {{{ getType() + + /** + * Get the name of this error/exception. + * + * @return string error/exception name (type) + * @access public + */ + function getType() + { + return get_class($this); + } + + // }}} + // {{{ getUserInfo() + + /** + * Get additional user-supplied information. + * + * @return string user-supplied information + * @access public + */ + function getUserInfo() + { + return $this->userinfo; + } + + // }}} + // {{{ getDebugInfo() + + /** + * Get additional debug information supplied by the application. + * + * @return string debug information + * @access public + */ + function getDebugInfo() + { + return $this->getUserInfo(); + } + + // }}} + // {{{ getBacktrace() + + /** + * Get the call backtrace from where the error was generated. + * Supported with PHP 4.3.0 or newer. + * + * @param int $frame (optional) what frame to fetch + * @return array Backtrace, or NULL if not available. + * @access public + */ + function getBacktrace($frame = null) + { + if (defined('PEAR_IGNORE_BACKTRACE')) { + return null; + } + if ($frame === null) { + return $this->backtrace; + } + return $this->backtrace[$frame]; + } + + // }}} + // {{{ addUserInfo() + + function addUserInfo($info) + { + if (empty($this->userinfo)) { + $this->userinfo = $info; + } else { + $this->userinfo .= " ** $info"; + } + } + + // }}} + // {{{ toString() + + /** + * Make a string representation of this object. + * + * @return string a string with an object summary + * @access public + */ + function toString() { + $modes = array(); + $levels = array(E_USER_NOTICE => 'notice', + E_USER_WARNING => 'warning', + E_USER_ERROR => 'error'); + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_array($this->callback)) { + $callback = (is_object($this->callback[0]) ? + strtolower(get_class($this->callback[0])) : + $this->callback[0]) . '::' . + $this->callback[1]; + } else { + $callback = $this->callback; + } + return sprintf('[%s: message="%s" code=%d mode=callback '. + 'callback=%s prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + $callback, $this->error_message_prefix, + $this->userinfo); + } + if ($this->mode & PEAR_ERROR_PRINT) { + $modes[] = 'print'; + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + $modes[] = 'trigger'; + } + if ($this->mode & PEAR_ERROR_DIE) { + $modes[] = 'die'; + } + if ($this->mode & PEAR_ERROR_RETURN) { + $modes[] = 'return'; + } + return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. + 'prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + implode("|", $modes), $levels[$this->level], + $this->error_message_prefix, + $this->userinfo); + } + + // }}} +} + +/* + * Local Variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/include/Excel/PPS.php b/include/Excel/PPS.php new file mode 100644 index 000000000..38ddbf926 --- /dev/null +++ b/include/Excel/PPS.php @@ -0,0 +1,217 @@ + | +// | Based on OLE::Storage_Lite by Kawai, Takanori | +// +----------------------------------------------------------------------+ +// +// $Id: PPS.php,v 1.5 2003/12/14 18:12:28 xnoguer Exp $ + + + +/** +* Class for creating PPS's for OLE containers +* +* @author Xavier Noguer +* @category Structures +* @package OLE +*/ +class OLE_PPS extends PEAR +{ + /** + * The PPS index + * @var integer + */ + var $No; + + /** + * The PPS name (in Unicode) + * @var string + */ + var $Name; + + /** + * The PPS type. Dir, Root or File + * @var integer + */ + var $Type; + + /** + * The index of the previous PPS + * @var integer + */ + var $PrevPps; + + /** + * The index of the next PPS + * @var integer + */ + var $NextPps; + + /** + * The index of it's first child if this is a Dir or Root PPS + * @var integer + */ + var $DirPps; + + /** + * A timestamp + * @var integer + */ + var $Time1st; + + /** + * A timestamp + * @var integer + */ + var $Time2nd; + + /** + * Starting block (small or big) for this PPS's data inside the container + * @var integer + */ + var $_StartBlock; + + /** + * The size of the PPS's data (in bytes) + * @var integer + */ + var $Size; + + /** + * The PPS's data (only used if it's not using a temporary file) + * @var string + */ + var $_data; + + /** + * Array of child PPS's (only used by Root and Dir PPS's) + * @var array + */ + var $children = array(); + + /** + * The constructor + * + * @access public + * @param integer $No The PPS index + * @param string $name The PPS name (in Unicode) + * @param integer $type The PPS type. Dir, Root or File + * @param integer $prev The index of the previous PPS + * @param integer $next The index of the next PPS + * @param integer $dir The index of it's first child if this is a Dir or Root PPS + * @param integer $time_1st A timestamp + * @param integer $time_2nd A timestamp + * @param array $children Array containing children PPS for this PPS + */ + function OLE_PPS($No, $name, $type, $prev, $next, $dir, $time_1st, $time_2nd, $data, $children) + { + $this->No = $No; + $this->Name = $name; + $this->Type = $type; + $this->PrevPps = $prev; + $this->NextPps = $next; + $this->DirPps = $dir; + $this->Time1st = $time_1st; + $this->Time2nd = $time_2nd; + $this->_data = $data; + $this->children = $children; + if ($data != '') { + $this->Size = strlen($data); + } + else { + $this->Size = 0; + } + } + + /** + * Returns the amount of data saved for this PPS + * + * @access private + * @return integer The amount of data (in bytes) + */ + function _DataLen() + { + if (!isset($this->_data)) { + return 0; + } + if (isset($this->_PPS_FILE)) + { + fseek($this->_PPS_FILE, 0); + $stats = fstat($this->_PPS_FILE); + return $stats[7]; + } + else { + return strlen($this->_data); + } + } + + /** + * Returns a string with the PPS's WK (What is a WK?) + * + * @access private + * @return string The binary string + */ + function _getPpsWk() + { + $ret = $this->Name; + for ($i = 0; $i < (64 - strlen($this->Name)); $i++) { + $ret .= "\x00"; + } + $ret .= pack("v", strlen($this->Name) + 2) // 66 + . pack("c", $this->Type) // 67 + . pack("c", 0x00) //UK // 68 + . pack("V", $this->PrevPps) //Prev // 72 + . pack("V", $this->NextPps) //Next // 76 + . pack("V", $this->DirPps) //Dir // 80 + . "\x00\x09\x02\x00" // 84 + . "\x00\x00\x00\x00" // 88 + . "\xc0\x00\x00\x00" // 92 + . "\x00\x00\x00\x46" // 96 // Seems to be ok only for Root + . "\x00\x00\x00\x00" // 100 + . OLE::LocalDate2OLE($this->Time1st) // 108 + . OLE::LocalDate2OLE($this->Time2nd) // 116 + . pack("V", isset($this->_StartBlock)? + $this->_StartBlock:0) // 120 + . pack("V", $this->Size) // 124 + . pack("V", 0); // 128 + return $ret; + } + + /** + * Updates index and pointers to previous, next and children PPS's for this + * PPS. I don't think it'll work with Dir PPS's. + * + * @access private + * @param array &$pps_array Reference to the array of PPS's for the whole OLE + * container + * @return integer The index for this PPS + */ + function _savePpsSetPnt(&$pps_array) + { + $pps_array[count($pps_array)] = &$this; + $this->No = count($pps_array) - 1; + $this->PrevPps = 0xFFFFFFFF; + $this->NextPps = 0xFFFFFFFF; + if (count($this->children) > 0) { + $this->DirPps = $this->children[0]->_savePpsSetPnt($pps_array); + } + else { + $this->DirPps = 0xFFFFFFFF; + } + return $this->No; + } +} +?> diff --git a/include/Excel/Parser.php b/include/Excel/Parser.php new file mode 100644 index 000000000..eb300ce22 --- /dev/null +++ b/include/Excel/Parser.php @@ -0,0 +1,1688 @@ +" +*/ +define('SPREADSHEET_EXCEL_WRITER_GT', ">"); + +/** +* @const SPREADSHEET_EXCEL_WRITER_LT token identifier for character "<" +*/ +define('SPREADSHEET_EXCEL_WRITER_LT', "<"); + +/** +* @const SPREADSHEET_EXCEL_WRITER_LE token identifier for character "<=" +*/ +define('SPREADSHEET_EXCEL_WRITER_LE', "<="); + +/** +* @const SPREADSHEET_EXCEL_WRITER_GE token identifier for character ">=" +*/ +define('SPREADSHEET_EXCEL_WRITER_GE', ">="); + +/** +* @const SPREADSHEET_EXCEL_WRITER_EQ token identifier for character "=" +*/ +define('SPREADSHEET_EXCEL_WRITER_EQ', "="); + +/** +* @const SPREADSHEET_EXCEL_WRITER_NE token identifier for character "<>" +*/ +define('SPREADSHEET_EXCEL_WRITER_NE', "<>"); + + + +/** +* Class for parsing Excel formulas +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer_Parser extends PEAR +{ + /** + * The index of the character we are currently looking at + * @var integer + */ + var $_current_char; + + /** + * The token we are working on. + * @var string + */ + var $_current_token; + + /** + * The formula to parse + * @var string + */ + var $_formula; + + /** + * The character ahead of the current char + * @var string + */ + var $_lookahead; + + /** + * The parse tree to be generated + * @var string + */ + var $_parse_tree; + + /** + * The byte order. 1 => big endian, 0 => little endian. + * @var integer + */ + var $_byte_order; + + /** + * Array of external sheets + * @var array + */ + var $_ext_sheets; + + /** + * Array of sheet references in the form of REF structures + * @var array + */ + var $_references; + + /** + * The BIFF version for the workbook + * @var integer + */ + var $_BIFF_version; + + /** + * The class constructor + * + * @param integer $byte_order The byte order (Little endian or Big endian) of the architecture + (optional). 1 => big endian, 0 (default) little endian. + */ + function Spreadsheet_Excel_Writer_Parser($byte_order, $biff_version) + { + $this->_current_char = 0; + $this->_BIFF_version = $biff_version; + $this->_current_token = ''; // The token we are working on. + $this->_formula = ''; // The formula to parse. + $this->_lookahead = ''; // The character ahead of the current char. + $this->_parse_tree = ''; // The parse tree to be generated. + $this->_initializeHashes(); // Initialize the hashes: ptg's and function's ptg's + $this->_byte_order = $byte_order; // Little Endian or Big Endian + $this->_ext_sheets = array(); + $this->_references = array(); + } + + /** + * Initialize the ptg and function hashes. + * + * @access private + */ + function _initializeHashes() + { + // The Excel ptg indices + $this->ptg = array( + 'ptgExp' => 0x01, + 'ptgTbl' => 0x02, + 'ptgAdd' => 0x03, + 'ptgSub' => 0x04, + 'ptgMul' => 0x05, + 'ptgDiv' => 0x06, + 'ptgPower' => 0x07, + 'ptgConcat' => 0x08, + 'ptgLT' => 0x09, + 'ptgLE' => 0x0A, + 'ptgEQ' => 0x0B, + 'ptgGE' => 0x0C, + 'ptgGT' => 0x0D, + 'ptgNE' => 0x0E, + 'ptgIsect' => 0x0F, + 'ptgUnion' => 0x10, + 'ptgRange' => 0x11, + 'ptgUplus' => 0x12, + 'ptgUminus' => 0x13, + 'ptgPercent' => 0x14, + 'ptgParen' => 0x15, + 'ptgMissArg' => 0x16, + 'ptgStr' => 0x17, + 'ptgAttr' => 0x19, + 'ptgSheet' => 0x1A, + 'ptgEndSheet' => 0x1B, + 'ptgErr' => 0x1C, + 'ptgBool' => 0x1D, + 'ptgInt' => 0x1E, + 'ptgNum' => 0x1F, + 'ptgArray' => 0x20, + 'ptgFunc' => 0x21, + 'ptgFuncVar' => 0x22, + 'ptgName' => 0x23, + 'ptgRef' => 0x24, + 'ptgArea' => 0x25, + 'ptgMemArea' => 0x26, + 'ptgMemErr' => 0x27, + 'ptgMemNoMem' => 0x28, + 'ptgMemFunc' => 0x29, + 'ptgRefErr' => 0x2A, + 'ptgAreaErr' => 0x2B, + 'ptgRefN' => 0x2C, + 'ptgAreaN' => 0x2D, + 'ptgMemAreaN' => 0x2E, + 'ptgMemNoMemN' => 0x2F, + 'ptgNameX' => 0x39, + 'ptgRef3d' => 0x3A, + 'ptgArea3d' => 0x3B, + 'ptgRefErr3d' => 0x3C, + 'ptgAreaErr3d' => 0x3D, + 'ptgArrayV' => 0x40, + 'ptgFuncV' => 0x41, + 'ptgFuncVarV' => 0x42, + 'ptgNameV' => 0x43, + 'ptgRefV' => 0x44, + 'ptgAreaV' => 0x45, + 'ptgMemAreaV' => 0x46, + 'ptgMemErrV' => 0x47, + 'ptgMemNoMemV' => 0x48, + 'ptgMemFuncV' => 0x49, + 'ptgRefErrV' => 0x4A, + 'ptgAreaErrV' => 0x4B, + 'ptgRefNV' => 0x4C, + 'ptgAreaNV' => 0x4D, + 'ptgMemAreaNV' => 0x4E, + 'ptgMemNoMemN' => 0x4F, + 'ptgFuncCEV' => 0x58, + 'ptgNameXV' => 0x59, + 'ptgRef3dV' => 0x5A, + 'ptgArea3dV' => 0x5B, + 'ptgRefErr3dV' => 0x5C, + 'ptgAreaErr3d' => 0x5D, + 'ptgArrayA' => 0x60, + 'ptgFuncA' => 0x61, + 'ptgFuncVarA' => 0x62, + 'ptgNameA' => 0x63, + 'ptgRefA' => 0x64, + 'ptgAreaA' => 0x65, + 'ptgMemAreaA' => 0x66, + 'ptgMemErrA' => 0x67, + 'ptgMemNoMemA' => 0x68, + 'ptgMemFuncA' => 0x69, + 'ptgRefErrA' => 0x6A, + 'ptgAreaErrA' => 0x6B, + 'ptgRefNA' => 0x6C, + 'ptgAreaNA' => 0x6D, + 'ptgMemAreaNA' => 0x6E, + 'ptgMemNoMemN' => 0x6F, + 'ptgFuncCEA' => 0x78, + 'ptgNameXA' => 0x79, + 'ptgRef3dA' => 0x7A, + 'ptgArea3dA' => 0x7B, + 'ptgRefErr3dA' => 0x7C, + 'ptgAreaErr3d' => 0x7D + ); + + // Thanks to Michael Meeks and Gnumeric for the initial arg values. + // + // The following hash was generated by "function_locale.pl" in the distro. + // Refer to function_locale.pl for non-English function names. + // + // The array elements are as follow: + // ptg: The Excel function ptg code. + // args: The number of arguments that the function takes: + // >=0 is a fixed number of arguments. + // -1 is a variable number of arguments. + // class: The reference, value or array class of the function args. + // vol: The function is volatile. + // + $this->_functions = array( + // function ptg args class vol + 'COUNT' => array( 0, -1, 0, 0 ), + 'IF' => array( 1, -1, 1, 0 ), + 'ISNA' => array( 2, 1, 1, 0 ), + 'ISERROR' => array( 3, 1, 1, 0 ), + 'SUM' => array( 4, -1, 0, 0 ), + 'AVERAGE' => array( 5, -1, 0, 0 ), + 'MIN' => array( 6, -1, 0, 0 ), + 'MAX' => array( 7, -1, 0, 0 ), + 'ROW' => array( 8, -1, 0, 0 ), + 'COLUMN' => array( 9, -1, 0, 0 ), + 'NA' => array( 10, 0, 0, 0 ), + 'NPV' => array( 11, -1, 1, 0 ), + 'STDEV' => array( 12, -1, 0, 0 ), + 'DOLLAR' => array( 13, -1, 1, 0 ), + 'FIXED' => array( 14, -1, 1, 0 ), + 'SIN' => array( 15, 1, 1, 0 ), + 'COS' => array( 16, 1, 1, 0 ), + 'TAN' => array( 17, 1, 1, 0 ), + 'ATAN' => array( 18, 1, 1, 0 ), + 'PI' => array( 19, 0, 1, 0 ), + 'SQRT' => array( 20, 1, 1, 0 ), + 'EXP' => array( 21, 1, 1, 0 ), + 'LN' => array( 22, 1, 1, 0 ), + 'LOG10' => array( 23, 1, 1, 0 ), + 'ABS' => array( 24, 1, 1, 0 ), + 'INT' => array( 25, 1, 1, 0 ), + 'SIGN' => array( 26, 1, 1, 0 ), + 'ROUND' => array( 27, 2, 1, 0 ), + 'LOOKUP' => array( 28, -1, 0, 0 ), + 'INDEX' => array( 29, -1, 0, 1 ), + 'REPT' => array( 30, 2, 1, 0 ), + 'MID' => array( 31, 3, 1, 0 ), + 'LEN' => array( 32, 1, 1, 0 ), + 'VALUE' => array( 33, 1, 1, 0 ), + 'TRUE' => array( 34, 0, 1, 0 ), + 'FALSE' => array( 35, 0, 1, 0 ), + 'AND' => array( 36, -1, 0, 0 ), + 'OR' => array( 37, -1, 0, 0 ), + 'NOT' => array( 38, 1, 1, 0 ), + 'MOD' => array( 39, 2, 1, 0 ), + 'DCOUNT' => array( 40, 3, 0, 0 ), + 'DSUM' => array( 41, 3, 0, 0 ), + 'DAVERAGE' => array( 42, 3, 0, 0 ), + 'DMIN' => array( 43, 3, 0, 0 ), + 'DMAX' => array( 44, 3, 0, 0 ), + 'DSTDEV' => array( 45, 3, 0, 0 ), + 'VAR' => array( 46, -1, 0, 0 ), + 'DVAR' => array( 47, 3, 0, 0 ), + 'TEXT' => array( 48, 2, 1, 0 ), + 'LINEST' => array( 49, -1, 0, 0 ), + 'TREND' => array( 50, -1, 0, 0 ), + 'LOGEST' => array( 51, -1, 0, 0 ), + 'GROWTH' => array( 52, -1, 0, 0 ), + 'PV' => array( 56, -1, 1, 0 ), + 'FV' => array( 57, -1, 1, 0 ), + 'NPER' => array( 58, -1, 1, 0 ), + 'PMT' => array( 59, -1, 1, 0 ), + 'RATE' => array( 60, -1, 1, 0 ), + 'MIRR' => array( 61, 3, 0, 0 ), + 'IRR' => array( 62, -1, 0, 0 ), + 'RAND' => array( 63, 0, 1, 1 ), + 'MATCH' => array( 64, -1, 0, 0 ), + 'DATE' => array( 65, 3, 1, 0 ), + 'TIME' => array( 66, 3, 1, 0 ), + 'DAY' => array( 67, 1, 1, 0 ), + 'MONTH' => array( 68, 1, 1, 0 ), + 'YEAR' => array( 69, 1, 1, 0 ), + 'WEEKDAY' => array( 70, -1, 1, 0 ), + 'HOUR' => array( 71, 1, 1, 0 ), + 'MINUTE' => array( 72, 1, 1, 0 ), + 'SECOND' => array( 73, 1, 1, 0 ), + 'NOW' => array( 74, 0, 1, 1 ), + 'AREAS' => array( 75, 1, 0, 1 ), + 'ROWS' => array( 76, 1, 0, 1 ), + 'COLUMNS' => array( 77, 1, 0, 1 ), + 'OFFSET' => array( 78, -1, 0, 1 ), + 'SEARCH' => array( 82, -1, 1, 0 ), + 'TRANSPOSE' => array( 83, 1, 1, 0 ), + 'TYPE' => array( 86, 1, 1, 0 ), + 'ATAN2' => array( 97, 2, 1, 0 ), + 'ASIN' => array( 98, 1, 1, 0 ), + 'ACOS' => array( 99, 1, 1, 0 ), + 'CHOOSE' => array( 100, -1, 1, 0 ), + 'HLOOKUP' => array( 101, -1, 0, 0 ), + 'VLOOKUP' => array( 102, -1, 0, 0 ), + 'ISREF' => array( 105, 1, 0, 0 ), + 'LOG' => array( 109, -1, 1, 0 ), + 'CHAR' => array( 111, 1, 1, 0 ), + 'LOWER' => array( 112, 1, 1, 0 ), + 'UPPER' => array( 113, 1, 1, 0 ), + 'PROPER' => array( 114, 1, 1, 0 ), + 'LEFT' => array( 115, -1, 1, 0 ), + 'RIGHT' => array( 116, -1, 1, 0 ), + 'EXACT' => array( 117, 2, 1, 0 ), + 'TRIM' => array( 118, 1, 1, 0 ), + 'REPLACE' => array( 119, 4, 1, 0 ), + 'SUBSTITUTE' => array( 120, -1, 1, 0 ), + 'CODE' => array( 121, 1, 1, 0 ), + 'FIND' => array( 124, -1, 1, 0 ), + 'CELL' => array( 125, -1, 0, 1 ), + 'ISERR' => array( 126, 1, 1, 0 ), + 'ISTEXT' => array( 127, 1, 1, 0 ), + 'ISNUMBER' => array( 128, 1, 1, 0 ), + 'ISBLANK' => array( 129, 1, 1, 0 ), + 'T' => array( 130, 1, 0, 0 ), + 'N' => array( 131, 1, 0, 0 ), + 'DATEVALUE' => array( 140, 1, 1, 0 ), + 'TIMEVALUE' => array( 141, 1, 1, 0 ), + 'SLN' => array( 142, 3, 1, 0 ), + 'SYD' => array( 143, 4, 1, 0 ), + 'DDB' => array( 144, -1, 1, 0 ), + 'INDIRECT' => array( 148, -1, 1, 1 ), + 'CALL' => array( 150, -1, 1, 0 ), + 'CLEAN' => array( 162, 1, 1, 0 ), + 'MDETERM' => array( 163, 1, 2, 0 ), + 'MINVERSE' => array( 164, 1, 2, 0 ), + 'MMULT' => array( 165, 2, 2, 0 ), + 'IPMT' => array( 167, -1, 1, 0 ), + 'PPMT' => array( 168, -1, 1, 0 ), + 'COUNTA' => array( 169, -1, 0, 0 ), + 'PRODUCT' => array( 183, -1, 0, 0 ), + 'FACT' => array( 184, 1, 1, 0 ), + 'DPRODUCT' => array( 189, 3, 0, 0 ), + 'ISNONTEXT' => array( 190, 1, 1, 0 ), + 'STDEVP' => array( 193, -1, 0, 0 ), + 'VARP' => array( 194, -1, 0, 0 ), + 'DSTDEVP' => array( 195, 3, 0, 0 ), + 'DVARP' => array( 196, 3, 0, 0 ), + 'TRUNC' => array( 197, -1, 1, 0 ), + 'ISLOGICAL' => array( 198, 1, 1, 0 ), + 'DCOUNTA' => array( 199, 3, 0, 0 ), + 'ROUNDUP' => array( 212, 2, 1, 0 ), + 'ROUNDDOWN' => array( 213, 2, 1, 0 ), + 'RANK' => array( 216, -1, 0, 0 ), + 'ADDRESS' => array( 219, -1, 1, 0 ), + 'DAYS360' => array( 220, -1, 1, 0 ), + 'TODAY' => array( 221, 0, 1, 1 ), + 'VDB' => array( 222, -1, 1, 0 ), + 'MEDIAN' => array( 227, -1, 0, 0 ), + 'SUMPRODUCT' => array( 228, -1, 2, 0 ), + 'SINH' => array( 229, 1, 1, 0 ), + 'COSH' => array( 230, 1, 1, 0 ), + 'TANH' => array( 231, 1, 1, 0 ), + 'ASINH' => array( 232, 1, 1, 0 ), + 'ACOSH' => array( 233, 1, 1, 0 ), + 'ATANH' => array( 234, 1, 1, 0 ), + 'DGET' => array( 235, 3, 0, 0 ), + 'INFO' => array( 244, 1, 1, 1 ), + 'DB' => array( 247, -1, 1, 0 ), + 'FREQUENCY' => array( 252, 2, 0, 0 ), + 'ERROR.TYPE' => array( 261, 1, 1, 0 ), + 'REGISTER.ID' => array( 267, -1, 1, 0 ), + 'AVEDEV' => array( 269, -1, 0, 0 ), + 'BETADIST' => array( 270, -1, 1, 0 ), + 'GAMMALN' => array( 271, 1, 1, 0 ), + 'BETAINV' => array( 272, -1, 1, 0 ), + 'BINOMDIST' => array( 273, 4, 1, 0 ), + 'CHIDIST' => array( 274, 2, 1, 0 ), + 'CHIINV' => array( 275, 2, 1, 0 ), + 'COMBIN' => array( 276, 2, 1, 0 ), + 'CONFIDENCE' => array( 277, 3, 1, 0 ), + 'CRITBINOM' => array( 278, 3, 1, 0 ), + 'EVEN' => array( 279, 1, 1, 0 ), + 'EXPONDIST' => array( 280, 3, 1, 0 ), + 'FDIST' => array( 281, 3, 1, 0 ), + 'FINV' => array( 282, 3, 1, 0 ), + 'FISHER' => array( 283, 1, 1, 0 ), + 'FISHERINV' => array( 284, 1, 1, 0 ), + 'FLOOR' => array( 285, 2, 1, 0 ), + 'GAMMADIST' => array( 286, 4, 1, 0 ), + 'GAMMAINV' => array( 287, 3, 1, 0 ), + 'CEILING' => array( 288, 2, 1, 0 ), + 'HYPGEOMDIST' => array( 289, 4, 1, 0 ), + 'LOGNORMDIST' => array( 290, 3, 1, 0 ), + 'LOGINV' => array( 291, 3, 1, 0 ), + 'NEGBINOMDIST' => array( 292, 3, 1, 0 ), + 'NORMDIST' => array( 293, 4, 1, 0 ), + 'NORMSDIST' => array( 294, 1, 1, 0 ), + 'NORMINV' => array( 295, 3, 1, 0 ), + 'NORMSINV' => array( 296, 1, 1, 0 ), + 'STANDARDIZE' => array( 297, 3, 1, 0 ), + 'ODD' => array( 298, 1, 1, 0 ), + 'PERMUT' => array( 299, 2, 1, 0 ), + 'POISSON' => array( 300, 3, 1, 0 ), + 'TDIST' => array( 301, 3, 1, 0 ), + 'WEIBULL' => array( 302, 4, 1, 0 ), + 'SUMXMY2' => array( 303, 2, 2, 0 ), + 'SUMX2MY2' => array( 304, 2, 2, 0 ), + 'SUMX2PY2' => array( 305, 2, 2, 0 ), + 'CHITEST' => array( 306, 2, 2, 0 ), + 'CORREL' => array( 307, 2, 2, 0 ), + 'COVAR' => array( 308, 2, 2, 0 ), + 'FORECAST' => array( 309, 3, 2, 0 ), + 'FTEST' => array( 310, 2, 2, 0 ), + 'INTERCEPT' => array( 311, 2, 2, 0 ), + 'PEARSON' => array( 312, 2, 2, 0 ), + 'RSQ' => array( 313, 2, 2, 0 ), + 'STEYX' => array( 314, 2, 2, 0 ), + 'SLOPE' => array( 315, 2, 2, 0 ), + 'TTEST' => array( 316, 4, 2, 0 ), + 'PROB' => array( 317, -1, 2, 0 ), + 'DEVSQ' => array( 318, -1, 0, 0 ), + 'GEOMEAN' => array( 319, -1, 0, 0 ), + 'HARMEAN' => array( 320, -1, 0, 0 ), + 'SUMSQ' => array( 321, -1, 0, 0 ), + 'KURT' => array( 322, -1, 0, 0 ), + 'SKEW' => array( 323, -1, 0, 0 ), + 'ZTEST' => array( 324, -1, 0, 0 ), + 'LARGE' => array( 325, 2, 0, 0 ), + 'SMALL' => array( 326, 2, 0, 0 ), + 'QUARTILE' => array( 327, 2, 0, 0 ), + 'PERCENTILE' => array( 328, 2, 0, 0 ), + 'PERCENTRANK' => array( 329, -1, 0, 0 ), + 'MODE' => array( 330, -1, 2, 0 ), + 'TRIMMEAN' => array( 331, 2, 0, 0 ), + 'TINV' => array( 332, 2, 1, 0 ), + 'CONCATENATE' => array( 336, -1, 1, 0 ), + 'POWER' => array( 337, 2, 1, 0 ), + 'RADIANS' => array( 342, 1, 1, 0 ), + 'DEGREES' => array( 343, 1, 1, 0 ), + 'SUBTOTAL' => array( 344, -1, 0, 0 ), + 'SUMIF' => array( 345, -1, 0, 0 ), + 'COUNTIF' => array( 346, 2, 0, 0 ), + 'COUNTBLANK' => array( 347, 1, 0, 0 ), + 'ROMAN' => array( 354, -1, 1, 0 ) + ); + } + + /** + * Convert a token to the proper ptg value. + * + * @access private + * @param mixed $token The token to convert. + * @return mixed the converted token on success. PEAR_Error if the token + * is not recognized + */ + function _convert($token) + { + if (preg_match("/^\"[^\"]{0,255}\"$/", $token)) { + return $this->_convertString($token); + + } elseif (is_numeric($token)) { + return $this->_convertNumber($token); + + // match references like A1 or $A$1 + } elseif (preg_match('/^\$?([A-Ia-i]?[A-Za-z])\$?(\d+)$/',$token)) { + return $this->_convertRef2d($token); + + // match external references like Sheet1!A1 or Sheet1:Sheet2!A1 + } elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z](\d+)$/u",$token)) { + return $this->_convertRef3d($token); + + // match external references like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1 + } elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z](\d+)$/u",$token)) { + return $this->_convertRef3d($token); + + // match ranges like A1:B2 + } elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\:(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) { + return $this->_convertRange2d($token); + + // match ranges like A1..B2 + } elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) { + return $this->_convertRange2d($token); + + // match external ranges like Sheet1!A1 or Sheet1:Sheet2!A1:B2 + } elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/u",$token)) { + return $this->_convertRange3d($token); + + // match external ranges like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1:B2 + } elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/u",$token)) { + return $this->_convertRange3d($token); + + // operators (including parentheses) + } elseif (isset($this->ptg[$token])) { + return pack("C", $this->ptg[$token]); + + // commented so argument number can be processed correctly. See toReversePolish(). + /*elseif (preg_match("/[A-Z0-9\xc0-\xdc\.]+/",$token)) + { + return($this->_convertFunction($token,$this->_func_args)); + }*/ + + // if it's an argument, ignore the token (the argument remains) + } elseif ($token == 'arg') { + return ''; + } + // TODO: use real error codes + return $this->raiseError("Unknown token $token"); + } + + /** + * Convert a number token to ptgInt or ptgNum + * + * @access private + * @param mixed $num an integer or double for conversion to its ptg value + */ + function _convertNumber($num) + { + // Integer in the range 0..2**16-1 + if ((preg_match("/^\d+$/", $num)) and ($num <= 65535)) { + return pack("Cv", $this->ptg['ptgInt'], $num); + } else { // A float + if ($this->_byte_order) { // if it's Big Endian + $num = strrev($num); + } + return pack("Cd", $this->ptg['ptgNum'], $num); + } + } + + /** + * Convert a string token to ptgStr + * + * @access private + * @param string $string A string for conversion to its ptg value. + * @return mixed the converted token on success. PEAR_Error if the string + * is longer than 255 characters. + */ + function _convertString($string) + { + // chop away beggining and ending quotes + $string = substr($string, 1, strlen($string) - 2); + if (strlen($string) > 255) { + return $this->raiseError("String is too long"); + } + + if ($this->_BIFF_version == 0x0500) { + return pack("CC", $this->ptg['ptgStr'], strlen($string)).$string; + } elseif ($this->_BIFF_version == 0x0600) { + $encoding = 0; // TODO: Unicode support + return pack("CCC", $this->ptg['ptgStr'], strlen($string), $encoding).$string; + } + } + + /** + * Convert a function to a ptgFunc or ptgFuncVarV depending on the number of + * args that it takes. + * + * @access private + * @param string $token The name of the function for convertion to ptg value. + * @param integer $num_args The number of arguments the function receives. + * @return string The packed ptg for the function + */ + function _convertFunction($token, $num_args) + { + $args = $this->_functions[$token][1]; + $volatile = $this->_functions[$token][3]; + + // Fixed number of args eg. TIME($i,$j,$k). + if ($args >= 0) { + return pack("Cv", $this->ptg['ptgFuncV'], $this->_functions[$token][0]); + } + // Variable number of args eg. SUM($i,$j,$k, ..). + if ($args == -1) { + return pack("CCv", $this->ptg['ptgFuncVarV'], $num_args, $this->_functions[$token][0]); + } + } + + /** + * Convert an Excel range such as A1:D4 to a ptgRefV. + * + * @access private + * @param string $range An Excel range in the A1:A2 or A1..A2 format. + */ + function _convertRange2d($range) + { + $class = 2; // as far as I know, this is magick. + + // Split the range into 2 cell refs + if (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\:([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) { + list($cell1, $cell2) = split(':', $range); + } elseif (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\.\.([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) { + list($cell1, $cell2) = split('\.\.', $range); + + } else { + // TODO: use real error codes + return $this->raiseError("Unknown range separator", 0, PEAR_ERROR_DIE); + } + + // Convert the cell references + $cell_array1 = $this->_cellToPackedRowcol($cell1); + if (PEAR::isError($cell_array1)) { + return $cell_array1; + } + list($row1, $col1) = $cell_array1; + $cell_array2 = $this->_cellToPackedRowcol($cell2); + if (PEAR::isError($cell_array2)) { + return $cell_array2; + } + list($row2, $col2) = $cell_array2; + + // The ptg value depends on the class of the ptg. + if ($class == 0) { + $ptgArea = pack("C", $this->ptg['ptgArea']); + } elseif ($class == 1) { + $ptgArea = pack("C", $this->ptg['ptgAreaV']); + } elseif ($class == 2) { + $ptgArea = pack("C", $this->ptg['ptgAreaA']); + } else { + // TODO: use real error codes + return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE); + } + return $ptgArea . $row1 . $row2 . $col1. $col2; + } + + /** + * Convert an Excel 3d range such as "Sheet1!A1:D4" or "Sheet1:Sheet2!A1:D4" to + * a ptgArea3d. + * + * @access private + * @param string $token An Excel range in the Sheet1!A1:A2 format. + * @return mixed The packed ptgArea3d token on success, PEAR_Error on failure. + */ + function _convertRange3d($token) + { + $class = 2; // as far as I know, this is magick. + + // Split the ref at the ! symbol + list($ext_ref, $range) = split('!', $token); + + // Convert the external reference part (different for BIFF8) + if ($this->_BIFF_version == 0x0500) { + $ext_ref = $this->_packExtRef($ext_ref); + if (PEAR::isError($ext_ref)) { + return $ext_ref; + } + } elseif ($this->_BIFF_version == 0x0600) { + $ext_ref = $this->_getRefIndex($ext_ref); + if (PEAR::isError($ext_ref)) { + return $ext_ref; + } + } + + // Split the range into 2 cell refs + list($cell1, $cell2) = split(':', $range); + + // Convert the cell references + if (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/", $cell1)) { + $cell_array1 = $this->_cellToPackedRowcol($cell1); + if (PEAR::isError($cell_array1)) { + return $cell_array1; + } + list($row1, $col1) = $cell_array1; + $cell_array2 = $this->_cellToPackedRowcol($cell2); + if (PEAR::isError($cell_array2)) { + return $cell_array2; + } + list($row2, $col2) = $cell_array2; + } else { // It's a rows range (like 26:27) + $cells_array = $this->_rangeToPackedRange($cell1.':'.$cell2); + if (PEAR::isError($cells_array)) { + return $cells_array; + } + list($row1, $col1, $row2, $col2) = $cells_array; + } + + // The ptg value depends on the class of the ptg. + if ($class == 0) { + $ptgArea = pack("C", $this->ptg['ptgArea3d']); + } elseif ($class == 1) { + $ptgArea = pack("C", $this->ptg['ptgArea3dV']); + } elseif ($class == 2) { + $ptgArea = pack("C", $this->ptg['ptgArea3dA']); + } else { + return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE); + } + + return $ptgArea . $ext_ref . $row1 . $row2 . $col1. $col2; + } + + /** + * Convert an Excel reference such as A1, $B2, C$3 or $D$4 to a ptgRefV. + * + * @access private + * @param string $cell An Excel cell reference + * @return string The cell in packed() format with the corresponding ptg + */ + function _convertRef2d($cell) + { + $class = 2; // as far as I know, this is magick. + + // Convert the cell reference + $cell_array = $this->_cellToPackedRowcol($cell); + if (PEAR::isError($cell_array)) { + return $cell_array; + } + list($row, $col) = $cell_array; + + // The ptg value depends on the class of the ptg. + if ($class == 0) { + $ptgRef = pack("C", $this->ptg['ptgRef']); + } elseif ($class == 1) { + $ptgRef = pack("C", $this->ptg['ptgRefV']); + } elseif ($class == 2) { + $ptgRef = pack("C", $this->ptg['ptgRefA']); + } else { + // TODO: use real error codes + return $this->raiseError("Unknown class $class"); + } + return $ptgRef.$row.$col; + } + + /** + * Convert an Excel 3d reference such as "Sheet1!A1" or "Sheet1:Sheet2!A1" to a + * ptgRef3d. + * + * @access private + * @param string $cell An Excel cell reference + * @return mixed The packed ptgRef3d token on success, PEAR_Error on failure. + */ + function _convertRef3d($cell) + { + $class = 2; // as far as I know, this is magick. + + // Split the ref at the ! symbol + list($ext_ref, $cell) = split('!', $cell); + + // Convert the external reference part (different for BIFF8) + if ($this->_BIFF_version == 0x0500) { + $ext_ref = $this->_packExtRef($ext_ref); + if (PEAR::isError($ext_ref)) { + return $ext_ref; + } + } elseif ($this->_BIFF_version == 0x0600) { + $ext_ref = $this->_getRefIndex($ext_ref); + if (PEAR::isError($ext_ref)) { + return $ext_ref; + } + } + + // Convert the cell reference part + list($row, $col) = $this->_cellToPackedRowcol($cell); + + // The ptg value depends on the class of the ptg. + if ($class == 0) { + $ptgRef = pack("C", $this->ptg['ptgRef3d']); + } elseif ($class == 1) { + $ptgRef = pack("C", $this->ptg['ptgRef3dV']); + } elseif ($class == 2) { + $ptgRef = pack("C", $this->ptg['ptgRef3dA']); + } else { + return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE); + } + + return $ptgRef . $ext_ref. $row . $col; + } + + /** + * Convert the sheet name part of an external reference, for example "Sheet1" or + * "Sheet1:Sheet2", to a packed structure. + * + * @access private + * @param string $ext_ref The name of the external reference + * @return string The reference index in packed() format + */ + function _packExtRef($ext_ref) + { + $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any. + $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any. + + // Check if there is a sheet range eg., Sheet1:Sheet2. + if (preg_match("/:/", $ext_ref)) { + list($sheet_name1, $sheet_name2) = split(':', $ext_ref); + + $sheet1 = $this->_getSheetIndex($sheet_name1); + if ($sheet1 == -1) { + return $this->raiseError("Unknown sheet name $sheet_name1 in formula"); + } + $sheet2 = $this->_getSheetIndex($sheet_name2); + if ($sheet2 == -1) { + return $this->raiseError("Unknown sheet name $sheet_name2 in formula"); + } + + // Reverse max and min sheet numbers if necessary + if ($sheet1 > $sheet2) { + list($sheet1, $sheet2) = array($sheet2, $sheet1); + } + } else { // Single sheet name only. + $sheet1 = $this->_getSheetIndex($ext_ref); + if ($sheet1 == -1) { + return $this->raiseError("Unknown sheet name $ext_ref in formula"); + } + $sheet2 = $sheet1; + } + + // References are stored relative to 0xFFFF. + $offset = -1 - $sheet1; + + return pack('vdvv', $offset, 0x00, $sheet1, $sheet2); + } + + /** + * Look up the REF index that corresponds to an external sheet name + * (or range). If it doesn't exist yet add it to the workbook's references + * array. It assumes all sheet names given must exist. + * + * @access private + * @param string $ext_ref The name of the external reference + * @return mixed The reference index in packed() format on success, + * PEAR_Error on failure + */ + function _getRefIndex($ext_ref) + { + $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any. + $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any. + + // Check if there is a sheet range eg., Sheet1:Sheet2. + if (preg_match("/:/", $ext_ref)) { + list($sheet_name1, $sheet_name2) = split(':', $ext_ref); + + $sheet1 = $this->_getSheetIndex($sheet_name1); + if ($sheet1 == -1) { + return $this->raiseError("Unknown sheet name $sheet_name1 in formula"); + } + $sheet2 = $this->_getSheetIndex($sheet_name2); + if ($sheet2 == -1) { + return $this->raiseError("Unknown sheet name $sheet_name2 in formula"); + } + + // Reverse max and min sheet numbers if necessary + if ($sheet1 > $sheet2) { + list($sheet1, $sheet2) = array($sheet2, $sheet1); + } + } else { // Single sheet name only. + $sheet1 = $this->_getSheetIndex($ext_ref); + if ($sheet1 == -1) { + return $this->raiseError("Unknown sheet name $ext_ref in formula"); + } + $sheet2 = $sheet1; + } + + // assume all references belong to this document + $supbook_index = 0x00; + $ref = pack('vvv', $supbook_index, $sheet1, $sheet2); + $total_references = count($this->_references); + $index = -1; + for ($i = 0; $i < $total_references; $i++) { + if ($ref == $this->_references[$i]) { + $index = $i; + break; + } + } + // if REF was not found add it to references array + if ($index == -1) { + $this->_references[$total_references] = $ref; + $index = $total_references; + } + + return pack('v', $index); + } + + /** + * Look up the index that corresponds to an external sheet name. The hash of + * sheet names is updated by the addworksheet() method of the + * Spreadsheet_Excel_Writer_Workbook class. + * + * @access private + * @return integer The sheet index, -1 if the sheet was not found + */ + function _getSheetIndex($sheet_name) + { + if (!isset($this->_ext_sheets[$sheet_name])) { + return -1; + } else { + return $this->_ext_sheets[$sheet_name]; + } + } + + /** + * This method is used to update the array of sheet names. It is + * called by the addWorksheet() method of the + * Spreadsheet_Excel_Writer_Workbook class. + * + * @access public + * @see Spreadsheet_Excel_Writer_Workbook::addWorksheet() + * @param string $name The name of the worksheet being added + * @param integer $index The index of the worksheet being added + */ + function setExtSheet($name, $index) + { + $this->_ext_sheets[$name] = $index; + } + + /** + * pack() row and column into the required 3 or 4 byte format. + * + * @access private + * @param string $cell The Excel cell reference to be packed + * @return array Array containing the row and column in packed() format + */ + function _cellToPackedRowcol($cell) + { + $cell = strtoupper($cell); + list($row, $col, $row_rel, $col_rel) = $this->_cellToRowcol($cell); + if ($col >= 256) { + return $this->raiseError("Column in: $cell greater than 255"); + } + // FIXME: change for BIFF8 + if ($row >= 16384) { + return $this->raiseError("Row in: $cell greater than 16384 "); + } + + // Set the high bits to indicate if row or col are relative. + if ($this->_BIFF_version == 0x0500) { + $row |= $col_rel << 14; + $row |= $row_rel << 15; + $col = pack('C', $col); + } elseif ($this->_BIFF_version == 0x0600) { + $col |= $col_rel << 14; + $col |= $row_rel << 15; + $col = pack('v', $col); + } + $row = pack('v', $row); + + return array($row, $col); + } + + /** + * pack() row range into the required 3 or 4 byte format. + * Just using maximum col/rows, which is probably not the correct solution + * + * @access private + * @param string $range The Excel range to be packed + * @return array Array containing (row1,col1,row2,col2) in packed() format + */ + function _rangeToPackedRange($range) + { + preg_match('/(\$)?(\d+)\:(\$)?(\d+)/', $range, $match); + // return absolute rows if there is a $ in the ref + $row1_rel = empty($match[1]) ? 1 : 0; + $row1 = $match[2]; + $row2_rel = empty($match[3]) ? 1 : 0; + $row2 = $match[4]; + // Convert 1-index to zero-index + $row1--; + $row2--; + // Trick poor inocent Excel + $col1 = 0; + $col2 = 16383; // FIXME: maximum possible value for Excel 5 (change this!!!) + + // FIXME: this changes for BIFF8 + if (($row1 >= 16384) or ($row2 >= 16384)) { + return $this->raiseError("Row in: $range greater than 16384 "); + } + + // Set the high bits to indicate if rows are relative. + if ($this->_BIFF_version == 0x0500) { + $row1 |= $row1_rel << 14; // FIXME: probably a bug + $row2 |= $row2_rel << 15; + $col1 = pack('C', $col1); + $col2 = pack('C', $col2); + } elseif ($this->_BIFF_version == 0x0600) { + $col1 |= $row1_rel << 15; + $col2 |= $row2_rel << 15; + $col1 = pack('v', $col1); + $col2 = pack('v', $col2); + } + $row1 = pack('v', $row1); + $row2 = pack('v', $row2); + + return array($row1, $col1, $row2, $col2); + } + + /** + * Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero + * indexed row and column number. Also returns two (0,1) values to indicate + * whether the row or column are relative references. + * + * @access private + * @param string $cell The Excel cell reference in A1 format. + * @return array + */ + function _cellToRowcol($cell) + { + preg_match('/(\$)?([A-I]?[A-Z])(\$)?(\d+)/',$cell,$match); + // return absolute column if there is a $ in the ref + $col_rel = empty($match[1]) ? 1 : 0; + $col_ref = $match[2]; + $row_rel = empty($match[3]) ? 1 : 0; + $row = $match[4]; + + // Convert base26 column string to a number. + $expn = strlen($col_ref) - 1; + $col = 0; + $col_ref_length = strlen($col_ref); + for ($i = 0; $i < $col_ref_length; $i++) { + $col += (ord($col_ref{$i}) - ord('A') + 1) * pow(26, $expn); + $expn--; + } + + // Convert 1-index to zero-index + $row--; + $col--; + + return array($row, $col, $row_rel, $col_rel); + } + + /** + * Advance to the next valid token. + * + * @access private + */ + function _advance() + { + $i = $this->_current_char; + $formula_length = strlen($this->_formula); + // eat up white spaces + if ($i < $formula_length) { + while ($this->_formula{$i} == " ") { + $i++; + } + + if ($i < ($formula_length - 1)) { + $this->_lookahead = $this->_formula{$i+1}; + } + $token = ''; + } + + while ($i < $formula_length) { + $token .= $this->_formula{$i}; + if ($i < ($formula_length - 1)) { + $this->_lookahead = $this->_formula{$i+1}; + } else { + $this->_lookahead = ''; + } + + if ($this->_match($token) != '') { + //if ($i < strlen($this->_formula) - 1) { + // $this->_lookahead = $this->_formula{$i+1}; + //} + $this->_current_char = $i + 1; + $this->_current_token = $token; + return 1; + } + + if ($i < ($formula_length - 2)) { + $this->_lookahead = $this->_formula{$i+2}; + } else { // if we run out of characters _lookahead becomes empty + $this->_lookahead = ''; + } + $i++; + } + //die("Lexical error ".$this->_current_char); + } + + /** + * Checks if it's a valid token. + * + * @access private + * @param mixed $token The token to check. + * @return mixed The checked token or false on failure + */ + function _match($token) + { + switch($token) { + case SPREADSHEET_EXCEL_WRITER_ADD: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_SUB: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_MUL: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_DIV: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_OPEN: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_CLOSE: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_COMA: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_SEMICOLON: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_GT: + if ($this->_lookahead == '=') { // it's a GE token + break; + } + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_LT: + // it's a LE or a NE token + if (($this->_lookahead == '=') or ($this->_lookahead == '>')) { + break; + } + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_GE: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_LE: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_EQ: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_NE: + return $token; + break; + default: + // if it's a reference + if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$token) and + !ereg("[0-9]",$this->_lookahead) and + ($this->_lookahead != ':') and ($this->_lookahead != '.') and + ($this->_lookahead != '!')) + { + return $token; + } + // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1) + elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and + !ereg("[0-9]",$this->_lookahead) and + ($this->_lookahead != ':') and ($this->_lookahead != '.')) + { + return $token; + } + // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1) + elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and + !ereg("[0-9]",$this->_lookahead) and + ($this->_lookahead != ':') and ($this->_lookahead != '.')) + { + return $token; + } + // if it's a range (A1:A2) + elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and + !ereg("[0-9]",$this->_lookahead)) + { + return $token; + } + // if it's a range (A1..A2) + elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and + !ereg("[0-9]",$this->_lookahead)) + { + return $token; + } + // If it's an external range like Sheet1!A1 or Sheet1:Sheet2!A1:B2 + elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and + !ereg("[0-9]",$this->_lookahead)) + { + return $token; + } + // If it's an external range like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1:B2 + elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and + !ereg("[0-9]",$this->_lookahead)) + { + return $token; + } + // If it's a number (check that it's not a sheet name or range) + elseif (is_numeric($token) and + (!is_numeric($token.$this->_lookahead) or ($this->_lookahead == '')) and + ($this->_lookahead != '!') and ($this->_lookahead != ':')) + { + return $token; + } + // If it's a string (of maximum 255 characters) + elseif (ereg("^\"[^\"]{0,255}\"$",$token)) + { + return $token; + } + // if it's a function call + elseif (eregi("^[A-Z0-9\xc0-\xdc\.]+$",$token) and ($this->_lookahead == "(")) + { + return $token; + } + return ''; + } + } + + /** + * The parsing method. It parses a formula. + * + * @access public + * @param string $formula The formula to parse, without the initial equal + * sign (=). + * @return mixed true on success, PEAR_Error on failure + */ + function parse($formula) + { + $this->_current_char = 0; + $this->_formula = $formula; + $this->_lookahead = $formula{1}; + $this->_advance(); + $this->_parse_tree = $this->_condition(); + if (PEAR::isError($this->_parse_tree)) { + return $this->_parse_tree; + } + return true; + } + + /** + * It parses a condition. It assumes the following rule: + * Cond -> Expr [(">" | "<") Expr] + * + * @access private + * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure + */ + function _condition() + { + $result = $this->_expression(); + if (PEAR::isError($result)) { + return $result; + } + if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LT) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgLT', $result, $result2); + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GT) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgGT', $result, $result2); + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LE) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgLE', $result, $result2); + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GE) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgGE', $result, $result2); + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_EQ) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgEQ', $result, $result2); + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_NE) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgNE', $result, $result2); + } + return $result; + } + + /** + * It parses a expression. It assumes the following rule: + * Expr -> Term [("+" | "-") Term] + * -> "string" + * -> "-" Term + * + * @access private + * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure + */ + function _expression() + { + // If it's a string return a string node + if (ereg("^\"[^\"]{0,255}\"$", $this->_current_token)) { + $result = $this->_createTree($this->_current_token, '', ''); + $this->_advance(); + return $result; + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB) { + // catch "-" Term + $this->_advance(); + $result2 = $this->_expression(); + $result = $this->_createTree('ptgUminus', $result2, ''); + return $result; + } + $result = $this->_term(); + if (PEAR::isError($result)) { + return $result; + } + while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) or + ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB)) { + /**/ + if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) { + $this->_advance(); + $result2 = $this->_term(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgAdd', $result, $result2); + } else { + $this->_advance(); + $result2 = $this->_term(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgSub', $result, $result2); + } + } + return $result; + } + + /** + * This function just introduces a ptgParen element in the tree, so that Excel + * doesn't get confused when working with a parenthesized formula afterwards. + * + * @access private + * @see _fact() + * @return array The parsed ptg'd tree + */ + function _parenthesizedExpression() + { + $result = $this->_createTree('ptgParen', $this->_expression(), ''); + return $result; + } + + /** + * It parses a term. It assumes the following rule: + * Term -> Fact [("*" | "/") Fact] + * + * @access private + * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure + */ + function _term() + { + $result = $this->_fact(); + if (PEAR::isError($result)) { + return $result; + } + while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) or + ($this->_current_token == SPREADSHEET_EXCEL_WRITER_DIV)) { + /**/ + if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) { + $this->_advance(); + $result2 = $this->_fact(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgMul', $result, $result2); + } else { + $this->_advance(); + $result2 = $this->_fact(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgDiv', $result, $result2); + } + } + return $result; + } + + /** + * It parses a factor. It assumes the following rule: + * Fact -> ( Expr ) + * | CellRef + * | CellRange + * | Number + * | Function + * + * @access private + * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure + */ + function _fact() + { + if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_OPEN) { + $this->_advance(); // eat the "(" + $result = $this->_parenthesizedExpression(); + if ($this->_current_token != SPREADSHEET_EXCEL_WRITER_CLOSE) { + return $this->raiseError("')' token expected."); + } + $this->_advance(); // eat the ")" + return $result; + } + // if it's a reference + if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$this->_current_token)) + { + $result = $this->_createTree($this->_current_token, '', ''); + $this->_advance(); + return $result; + } + // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1) + elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z][0-9]+$/u",$this->_current_token)) + { + $result = $this->_createTree($this->_current_token, '', ''); + $this->_advance(); + return $result; + } + // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1) + elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z][0-9]+$/u",$this->_current_token)) + { + $result = $this->_createTree($this->_current_token, '', ''); + $this->_advance(); + return $result; + } + // if it's a range + elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token) or + preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token)) + { + $result = $this->_current_token; + $this->_advance(); + return $result; + } + // If it's an external range (Sheet1!A1 or Sheet1!A1:B2) + elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$this->_current_token)) + { + $result = $this->_current_token; + $this->_advance(); + return $result; + } + // If it's an external range ('Sheet1'!A1 or 'Sheet1'!A1:B2) + elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$this->_current_token)) + { + $result = $this->_current_token; + $this->_advance(); + return $result; + } + elseif (is_numeric($this->_current_token)) + { + $result = $this->_createTree($this->_current_token, '', ''); + $this->_advance(); + return $result; + } + // if it's a function call + elseif (eregi("^[A-Z0-9\xc0-\xdc\.]+$",$this->_current_token)) + { + $result = $this->_func(); + return $result; + } + return $this->raiseError("Syntax error: ".$this->_current_token. + ", lookahead: ".$this->_lookahead. + ", current char: ".$this->_current_char); + } + + /** + * It parses a function call. It assumes the following rule: + * Func -> ( Expr [,Expr]* ) + * + * @access private + * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure + */ + function _func() + { + $num_args = 0; // number of arguments received + $function = strtoupper($this->_current_token); + $result = ''; // initialize result + $this->_advance(); + $this->_advance(); // eat the "(" + while ($this->_current_token != ')') { + /**/ + if ($num_args > 0) { + if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_COMA or + $this->_current_token == SPREADSHEET_EXCEL_WRITER_SEMICOLON) + { + $this->_advance(); // eat the "," or ";" + } else { + return $this->raiseError("Syntax error: comma expected in ". + "function $function, arg #{$num_args}"); + } + $result2 = $this->_condition(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('arg', $result, $result2); + } else { // first argument + $result2 = $this->_condition(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('arg', '', $result2); + } + $num_args++; + } + if (!isset($this->_functions[$function])) { + return $this->raiseError("Function $function() doesn't exist"); + } + $args = $this->_functions[$function][1]; + // If fixed number of args eg. TIME($i,$j,$k). Check that the number of args is valid. + if (($args >= 0) and ($args != $num_args)) { + return $this->raiseError("Incorrect number of arguments in function $function() "); + } + + $result = $this->_createTree($function, $result, $num_args); + $this->_advance(); // eat the ")" + return $result; + } + + /** + * Creates a tree. In fact an array which may have one or two arrays (sub-trees) + * as elements. + * + * @access private + * @param mixed $value The value of this node. + * @param mixed $left The left array (sub-tree) or a final node. + * @param mixed $right The right array (sub-tree) or a final node. + * @return array A tree + */ + function _createTree($value, $left, $right) + { + return array('value' => $value, 'left' => $left, 'right' => $right); + } + + /** + * Builds a string containing the tree in reverse polish notation (What you + * would use in a HP calculator stack). + * The following tree: + * + * + + * / \ + * 2 3 + * + * produces: "23+" + * + * The following tree: + * + * + + * / \ + * 3 * + * / \ + * 6 A1 + * + * produces: "36A1*+" + * + * In fact all operands, functions, references, etc... are written as ptg's + * + * @access public + * @param array $tree The optional tree to convert. + * @return string The tree in reverse polish notation + */ + function toReversePolish($tree = array()) + { + $polish = ""; // the string we are going to return + if (empty($tree)) { // If it's the first call use _parse_tree + $tree = $this->_parse_tree; + } + if (is_array($tree['left'])) { + $converted_tree = $this->toReversePolish($tree['left']); + if (PEAR::isError($converted_tree)) { + return $converted_tree; + } + $polish .= $converted_tree; + } elseif ($tree['left'] != '') { // It's a final node + $converted_tree = $this->_convert($tree['left']); + if (PEAR::isError($converted_tree)) { + return $converted_tree; + } + $polish .= $converted_tree; + } + if (is_array($tree['right'])) { + $converted_tree = $this->toReversePolish($tree['right']); + if (PEAR::isError($converted_tree)) { + return $converted_tree; + } + $polish .= $converted_tree; + } elseif ($tree['right'] != '') { // It's a final node + $converted_tree = $this->_convert($tree['right']); + if (PEAR::isError($converted_tree)) { + return $converted_tree; + } + $polish .= $converted_tree; + } + // if it's a function convert it here (so we can set it's arguments) + if (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/",$tree['value']) and + !preg_match('/^([A-Ia-i]?[A-Za-z])(\d+)$/',$tree['value']) and + !preg_match("/^[A-Ia-i]?[A-Za-z](\d+)\.\.[A-Ia-i]?[A-Za-z](\d+)$/",$tree['value']) and + !is_numeric($tree['value']) and + !isset($this->ptg[$tree['value']])) + { + // left subtree for a function is always an array. + if ($tree['left'] != '') { + $left_tree = $this->toReversePolish($tree['left']); + } else { + $left_tree = ''; + } + if (PEAR::isError($left_tree)) { + return $left_tree; + } + // add it's left subtree and return. + return $left_tree.$this->_convertFunction($tree['value'], $tree['right']); + } else { + $converted_tree = $this->_convert($tree['value']); + if (PEAR::isError($converted_tree)) { + return $converted_tree; + } + } + $polish .= $converted_tree; + return $polish; + } +} +?> diff --git a/include/Excel/Root.php b/include/Excel/Root.php new file mode 100644 index 000000000..78936604d --- /dev/null +++ b/include/Excel/Root.php @@ -0,0 +1,518 @@ + | +// | Based on OLE::Storage_Lite by Kawai, Takanori | +// +----------------------------------------------------------------------+ +// +// $Id: Root.php,v 1.7 2003/12/12 21:10:10 xnoguer Exp $ + + + +/** +* Class for creating Root PPS's for OLE containers +* +* @author Xavier Noguer +* @category Structures +* @package OLE +*/ +class OLE_PPS_Root extends OLE_PPS +{ + /** + * The temporary dir for storing the OLE file + * @var string + */ + var $_tmp_dir; + + /** + * Constructor + * + * @access public + * @param integer $time_1st A timestamp + * @param integer $time_2nd A timestamp + */ + function OLE_PPS_Root($time_1st, $time_2nd, $raChild) + { + $this->_tmp_dir = ''; + $this->OLE_PPS( + null, + OLE::Asc2Ucs('Root Entry'), + OLE_PPS_TYPE_ROOT, + null, + null, + null, + $time_1st, + $time_2nd, + null, + $raChild); + } + + /** + * Sets the temp dir used for storing the OLE file + * + * @access public + * @param string $dir The dir to be used as temp dir + * @return true if given dir is valid, false otherwise + */ + function setTempDir($dir) + { + if (is_dir($dir)) { + $this->_tmp_dir = $dir; + return true; + } + return false; + } + + /** + * Method for saving the whole OLE container (including files). + * In fact, if called with an empty argument (or '-'), it saves to a + * temporary file and then outputs it's contents to stdout. + * + * @param string $filename The name of the file where to save the OLE container + * @access public + * @return mixed true on success, PEAR_Error on failure + */ + function save($filename) + { + // Initial Setting for saving + $this->_BIG_BLOCK_SIZE = pow(2, + ((isset($this->_BIG_BLOCK_SIZE))? $this->_adjust2($this->_BIG_BLOCK_SIZE) : 9)); + $this->_SMALL_BLOCK_SIZE= pow(2, + ((isset($this->_SMALL_BLOCK_SIZE))? $this->_adjust2($this->_SMALL_BLOCK_SIZE): 6)); + + // Open temp file if we are sending output to stdout + if (($filename == '-') or ($filename == '')) + { + $this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_Root"); + $this->_FILEH_ = @fopen($this->_tmp_filename,"w+b"); + if ($this->_FILEH_ == false) { + return $this->raiseError("Can't create temporary file."); + } + } + else + { + $this->_FILEH_ = @fopen($filename, "wb"); + if ($this->_FILEH_ == false) { + return $this->raiseError("Can't open $filename. It may be in use or protected."); + } + } + // Make an array of PPS's (for Save) + $aList = array(); + $this->_savePpsSetPnt($aList); + // calculate values for header + list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo); + // Save Header + $this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt); + + // Make Small Data string (write SBD) + $this->_data = $this->_makeSmallData($aList); + + // Write BB + $this->_saveBigData($iSBDcnt, $aList); + // Write PPS + $this->_savePps($aList); + // Write Big Block Depot and BDList and Adding Header informations + $this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt); + // Close File, send it to stdout if necessary + if(($filename == '-') or ($filename == '')) + { + fseek($this->_FILEH_, 0); + fpassthru($this->_FILEH_); + @fclose($this->_FILEH_); + // Delete the temporary file. + @unlink($this->_tmp_filename); + } + else { + @fclose($this->_FILEH_); + } + return true; + } + + /** + * Calculate some numbers + * + * @access private + * @param array $raList Reference to an array of PPS's + * @return array The array of numbers + */ + function _calcSize(&$raList) + { + // Calculate Basic Setting + list($iSBDcnt, $iBBcnt, $iPPScnt) = array(0,0,0); + $iSmallLen = 0; + $iSBcnt = 0; + for ($i = 0; $i < count($raList); $i++) { + if($raList[$i]->Type == OLE_PPS_TYPE_FILE) { + $raList[$i]->Size = $raList[$i]->_DataLen(); + if($raList[$i]->Size < OLE_DATA_SIZE_SMALL) { + $iSBcnt += floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE) + + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0); + } + else { + $iBBcnt += (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) + + (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0)); + } + } + } + $iSmallLen = $iSBcnt * $this->_SMALL_BLOCK_SIZE; + $iSlCnt = floor($this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE); + $iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt)? 1:0); + $iBBcnt += (floor($iSmallLen / $this->_BIG_BLOCK_SIZE) + + (( $iSmallLen % $this->_BIG_BLOCK_SIZE)? 1: 0)); + $iCnt = count($raList); + $iBdCnt = $this->_BIG_BLOCK_SIZE / OLE_PPS_SIZE; + $iPPScnt = (floor($iCnt/$iBdCnt) + (($iCnt % $iBdCnt)? 1: 0)); + + return array($iSBDcnt, $iBBcnt, $iPPScnt); + } + + /** + * Helper function for caculating a magic value for block sizes + * + * @access private + * @param integer $i2 The argument + * @see save() + * @return integer + */ + function _adjust2($i2) + { + $iWk = log($i2)/log(2); + return ($iWk > floor($iWk))? floor($iWk)+1:$iWk; + } + + /** + * Save OLE header + * + * @access private + * @param integer $iSBDcnt + * @param integer $iBBcnt + * @param integer $iPPScnt + */ + function _saveHeader($iSBDcnt, $iBBcnt, $iPPScnt) + { + $FILE = $this->_FILEH_; + + // Calculate Basic Setting + $iBlCnt = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE; + $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE; + + $iBdExL = 0; + $iAll = $iBBcnt + $iPPScnt + $iSBDcnt; + $iAllW = $iAll; + $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0); + $iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0); + + // Calculate BD count + if ($iBdCnt >$i1stBdL) + { + while (1) + { + $iBdExL++; + $iAllW++; + $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0); + $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0); + if ($iBdCnt <= ($iBdExL*$iBlCnt+ $i1stBdL)) { + break; + } + } + } + + // Save Header + fwrite($FILE, + "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" + . "\x00\x00\x00\x00" + . "\x00\x00\x00\x00" + . "\x00\x00\x00\x00" + . "\x00\x00\x00\x00" + . pack("v", 0x3b) + . pack("v", 0x03) + . pack("v", -2) + . pack("v", 9) + . pack("v", 6) + . pack("v", 0) + . "\x00\x00\x00\x00" + . "\x00\x00\x00\x00" + . pack("V", $iBdCnt) + . pack("V", $iBBcnt+$iSBDcnt) //ROOT START + . pack("V", 0) + . pack("V", 0x1000) + . pack("V", 0) //Small Block Depot + . pack("V", 1) + ); + // Extra BDList Start, Count + if ($iBdCnt < $i1stBdL) + { + fwrite($FILE, + pack("V", -2). // Extra BDList Start + pack("V", 0) // Extra BDList Count + ); + } + else + { + fwrite($FILE, pack("V", $iAll+$iBdCnt) . pack("V", $iBdExL)); + } + + // BDList + for ($i=0; $i<$i1stBdL and $i < $iBdCnt; $i++) { + fwrite($FILE, pack("V", $iAll+$i)); + } + if ($i < $i1stBdL) + { + for ($j = 0; $j < ($i1stBdL-$i); $j++) { + fwrite($FILE, (pack("V", -1))); + } + } + } + + /** + * Saving big data (PPS's with data bigger than OLE_DATA_SIZE_SMALL) + * + * @access private + * @param integer $iStBlk + * @param array &$raList Reference to array of PPS's + */ + function _saveBigData($iStBlk, &$raList) + { + $FILE = $this->_FILEH_; + + // cycle through PPS's + for ($i = 0; $i < count($raList); $i++) + { + if($raList[$i]->Type != OLE_PPS_TYPE_DIR) + { + $raList[$i]->Size = $raList[$i]->_DataLen(); + if(($raList[$i]->Size >= OLE_DATA_SIZE_SMALL) or + (($raList[$i]->Type == OLE_PPS_TYPE_ROOT) and isset($raList[$i]->_data))) + { + // Write Data + if(isset($raList[$i]->_PPS_FILE)) + { + $iLen = 0; + fseek($raList[$i]->_PPS_FILE, 0); // To The Top + while($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) + { + $iLen += strlen($sBuff); + fwrite($FILE, $sBuff); + } + } + else { + fwrite($FILE, $raList[$i]->_data); + } + + if ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE) + { + for ($j = 0; $j < ($this->_BIG_BLOCK_SIZE - ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)); $j++) { + fwrite($FILE, "\x00"); + } + } + // Set For PPS + $raList[$i]->_StartBlock = $iStBlk; + $iStBlk += + (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) + + (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0)); + } + // Close file for each PPS, and unlink it + if (isset($raList[$i]->_PPS_FILE)) + { + @fclose($raList[$i]->_PPS_FILE); + $raList[$i]->_PPS_FILE = null; + @unlink($raList[$i]->_tmp_filename); + } + } + } + } + + /** + * get small data (PPS's with data smaller than OLE_DATA_SIZE_SMALL) + * + * @access private + * @param array &$raList Reference to array of PPS's + */ + function _makeSmallData(&$raList) + { + $sRes = ''; + $FILE = $this->_FILEH_; + $iSmBlk = 0; + + for ($i = 0; $i < count($raList); $i++) + { + // Make SBD, small data string + if ($raList[$i]->Type == OLE_PPS_TYPE_FILE) + { + if ($raList[$i]->Size <= 0) { + continue; + } + if ($raList[$i]->Size < OLE_DATA_SIZE_SMALL) + { + $iSmbCnt = floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE) + + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0); + // Add to SBD + for ($j = 0; $j < ($iSmbCnt-1); $j++) { + fwrite($FILE, pack("V", $j+$iSmBlk+1)); + } + fwrite($FILE, pack("V", -2)); + + // Add to Data String(this will be written for RootEntry) + if ($raList[$i]->_PPS_FILE) + { + fseek($raList[$i]->_PPS_FILE, 0); // To The Top + while ($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) { + $sRes .= $sBuff; + } + } + else { + $sRes .= $raList[$i]->_data; + } + if($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE) + { + for ($j = 0; $j < ($this->_SMALL_BLOCK_SIZE - ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)); $j++) { + $sRes .= "\x00"; + } + } + // Set for PPS + $raList[$i]->_StartBlock = $iSmBlk; + $iSmBlk += $iSmbCnt; + } + } + } + $iSbCnt = floor($this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE); + if($iSmBlk % $iSbCnt) + { + for ($i = 0; $i < ($iSbCnt - ($iSmBlk % $iSbCnt)); $i++) { + fwrite($FILE, pack("V", -1)); + } + } + return $sRes; + } + + /** + * Saves all the PPS's WKs + * + * @access private + * @param array $raList Reference to an array with all PPS's + */ + function _savePps(&$raList) + { + // Save each PPS WK + for ($i = 0; $i < count($raList); $i++) { + fwrite($this->_FILEH_, $raList[$i]->_getPpsWk()); + } + // Adjust for Block + $iCnt = count($raList); + $iBCnt = $this->_BIG_BLOCK_SIZE / OLE_PPS_SIZE; + if ($iCnt % $iBCnt) + { + for ($i = 0; $i < (($iBCnt - ($iCnt % $iBCnt)) * OLE_PPS_SIZE); $i++) { + fwrite($this->_FILEH_, "\x00"); + } + } + } + + /** + * Saving Big Block Depot + * + * @access private + * @param integer $iSbdSize + * @param integer $iBsize + * @param integer $iPpsCnt + */ + function _saveBbd($iSbdSize, $iBsize, $iPpsCnt) + { + $FILE = $this->_FILEH_; + // Calculate Basic Setting + $iBbCnt = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE; + $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE; + + $iBdExL = 0; + $iAll = $iBsize + $iPpsCnt + $iSbdSize; + $iAllW = $iAll; + $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0); + $iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0); + // Calculate BD count + if ($iBdCnt >$i1stBdL) + { + while (1) + { + $iBdExL++; + $iAllW++; + $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0); + $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0); + if ($iBdCnt <= ($iBdExL*$iBbCnt+ $i1stBdL)) { + break; + } + } + } + + // Making BD + // Set for SBD + if ($iSbdSize > 0) + { + for ($i = 0; $i<($iSbdSize-1); $i++) { + fwrite($FILE, pack("V", $i+1)); + } + fwrite($FILE, pack("V", -2)); + } + // Set for B + for ($i = 0; $i<($iBsize-1); $i++) { + fwrite($FILE, pack("V", $i+$iSbdSize+1)); + } + fwrite($FILE, pack("V", -2)); + + // Set for PPS + for ($i = 0; $i<($iPpsCnt-1); $i++) { + fwrite($FILE, pack("V", $i+$iSbdSize+$iBsize+1)); + } + fwrite($FILE, pack("V", -2)); + // Set for BBD itself ( 0xFFFFFFFD : BBD) + for ($i=0; $i<$iBdCnt;$i++) { + fwrite($FILE, pack("V", 0xFFFFFFFD)); + } + // Set for ExtraBDList + for ($i=0; $i<$iBdExL;$i++) { + fwrite($FILE, pack("V", 0xFFFFFFFC)); + } + // Adjust for Block + if (($iAllW + $iBdCnt) % $iBbCnt) + { + for ($i = 0; $i < ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt)); $i++) { + fwrite($FILE, pack("V", -1)); + } + } + // Extra BDList + if ($iBdCnt > $i1stBdL) + { + $iN=0; + $iNb=0; + for ($i=$i1stBdL;$i<$iBdCnt; $i++, $iN++) + { + if ($iN>=($iBbCnt-1)) + { + $iN = 0; + $iNb++; + fwrite($FILE, pack("V", $iAll+$iBdCnt+$iNb)); + } + fwrite($FILE, pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i)); + } + if (($iBdCnt-$i1stBdL) % ($iBbCnt-1)) + { + for ($i = 0; $i < (($iBbCnt-1) - (($iBdCnt-$i1stBdL) % ($iBbCnt-1))); $i++) { + fwrite($FILE, pack("V", -1)); + } + } + fwrite($FILE, pack("V", -2)); + } + } +} +?> diff --git a/include/Excel/Validator.php b/include/Excel/Validator.php new file mode 100644 index 000000000..9a776c6c3 --- /dev/null +++ b/include/Excel/Validator.php @@ -0,0 +1,229 @@ + +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +// Possible operator types + +/* +FIXME: change prefixes +*/ +define("OP_BETWEEN", 0x00); +define("OP_NOTBETWEEN", 0x01); +define("OP_EQUAL", 0x02); +define("OP_NOTEQUAL", 0x03); +define("OP_GT", 0x04); +define("OP_LT", 0x05); +define("OP_GTE", 0x06); +define("OP_LTE", 0x07); + +/** +* Baseclass for generating Excel DV records (validations) +* +* @author Herman Kuiper +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ +class Spreadsheet_Excel_Writer_Validator +{ + var $_type; + var $_style; + var $_fixedList; + var $_blank; + var $_incell; + var $_showprompt; + var $_showerror; + var $_title_prompt; + var $_descr_prompt; + var $_title_error; + var $_descr_error; + var $_operator; + var $_formula1; + var $_formula2; + /** + * The parser from the workbook. Used to parse validation formulas also + * @var Spreadsheet_Excel_Writer_Parser + */ + var $_parser; + + function Spreadsheet_Excel_Writer_Validator(&$parser) + { + $this->_parser = $parser; + $this->_type = 0x01; // FIXME: add method for setting datatype + $this->_style = 0x00; + $this->_fixedList = false; + $this->_blank = false; + $this->_incell = false; + $this->_showprompt = false; + $this->_showerror = true; + $this->_title_prompt = "\x00"; + $this->_descr_prompt = "\x00"; + $this->_title_error = "\x00"; + $this->_descr_error = "\x00"; + $this->_operator = 0x00; // default is equal + $this->_formula1 = ''; + $this->_formula2 = ''; + } + + function setPrompt($promptTitle = "\x00", $promptDescription = "\x00", $showPrompt = true) + { + $this->_showprompt = $showPrompt; + $this->_title_prompt = $promptTitle; + $this->_descr_prompt = $promptDescription; + } + + function setError($errorTitle = "\x00", $errorDescription = "\x00", $showError = true) + { + $this->_showerror = $showError; + $this->_title_error = $errorTitle; + $this->_descr_error = $errorDescription; + } + + function allowBlank() + { + $this->_blank = true; + } + + function onInvalidStop() + { + $this->_style = 0x00; + } + + function onInvalidWarn() + { + $this->_style = 0x01; + } + + function onInvalidInfo() + { + $this->_style = 0x02; + } + + function setFormula1($formula) + { + // Parse the formula using the parser in Parser.php + $error = $this->_parser->parse($formula); + if (PEAR::isError($error)) { + return $this->_formula1; + } + + $this->_formula1 = $this->_parser->toReversePolish(); + if (PEAR::isError($this->_formula1)) { + return $this->_formula1; + } + return true; + } + + function setFormula2($formula) + { + // Parse the formula using the parser in Parser.php + $error = $this->_parser->parse($formula); + if (PEAR::isError($error)) { + return $this->_formula2; + } + + $this->_formula2 = $this->_parser->toReversePolish(); + if (PEAR::isError($this->_formula2)) { + return $this->_formula2; + } + return true; + } + + function _getOptions() + { + $options = $this->_type; + $options |= $this->_style << 3; + if ($this->_fixedList) { + $options |= 0x80; + } + if ($this->_blank) { + $options |= 0x100; + } + if (!$this->_incell) { + $options |= 0x200; + } + if ($this->_showprompt) { + $options |= 0x40000; + } + if ($this->_showerror) { + $options |= 0x80000; + } + $options |= $this->_operator << 20; + + return $options; + } + + function _getData() + { + $title_prompt_len = strlen($this->_title_prompt); + $descr_prompt_len = strlen($this->_descr_prompt); + $title_error_len = strlen($this->_title_error); + $descr_error_len = strlen($this->_descr_error); + + $formula1_size = strlen($this->_formula1); + $formula2_size = strlen($this->_formula2); + + $data = pack("V", $this->_getOptions()); + $data .= pack("vC", $title_prompt_len, 0x00) . $this->_title_prompt; + $data .= pack("vC", $title_error_len, 0x00) . $this->_title_error; + $data .= pack("vC", $descr_prompt_len, 0x00) . $this->_descr_prompt; + $data .= pack("vC", $descr_error_len, 0x00) . $this->_descr_error; + + $data .= pack("vv", $formula1_size, 0x0000) . $this->_formula1; + $data .= pack("vv", $formula2_size, 0x0000) . $this->_formula2; + + return $data; + } +} + +/*class Spreadsheet_Excel_Writer_Validation_List extends Spreadsheet_Excel_Writer_Validation +{ + function Spreadsheet_Excel_Writer_Validation_list() + { + parent::Spreadsheet_Excel_Writer_Validation(); + $this->_type = 0x03; + } + + function setList($source, $incell = true) + { + $this->_incell = $incell; + $this->_fixedList = true; + + $source = implode("\x00", $source); + $this->_formula1 = pack("CCC", 0x17, strlen($source), 0x0c) . $source; + } + + function setRow($row, $col1, $col2, $incell = true) + { + $this->_incell = $incell; + //$this->_formula1 = ...; + } + + function setCol($col, $row1, $row2, $incell = true) + { + $this->_incell = $incell; + //$this->_formula1 = ...; + } +}*/ + +?> diff --git a/include/Excel/Workbook.php b/include/Excel/Workbook.php new file mode 100644 index 000000000..2bcc369bc --- /dev/null +++ b/include/Excel/Workbook.php @@ -0,0 +1,1523 @@ + +* +* The majority of this is _NOT_ my code. I simply ported it from the +* PERL Spreadsheet::WriteExcel module. +* +* The author of the Spreadsheet::WriteExcel module is John McNamara +* +* +* I _DO_ maintain this code, and John McNamara has nothing to do with the +* porting of this code to PHP. Any questions directly related to this +* class library should be directed to me. +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + + +/** +* Class for generating Excel Spreadsheets +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwriter +{ + /** + * Filename for the Workbook + * @var string + */ + var $_filename; + + /** + * Formula parser + * @var object Parser + */ + var $_parser; + + /** + * Flag for 1904 date system (0 => base date is 1900, 1 => base date is 1904) + * @var integer + */ + var $_1904; + + /** + * The active worksheet of the workbook (0 indexed) + * @var integer + */ + var $_activesheet; + + /** + * 1st displayed worksheet in the workbook (0 indexed) + * @var integer + */ + var $_firstsheet; + + /** + * Number of workbook tabs selected + * @var integer + */ + var $_selected; + + /** + * Index for creating adding new formats to the workbook + * @var integer + */ + var $_xf_index; + + /** + * Flag for preventing close from being called twice. + * @var integer + * @see close() + */ + var $_fileclosed; + + /** + * The BIFF file size for the workbook. + * @var integer + * @see _calcSheetOffsets() + */ + var $_biffsize; + + /** + * The default sheetname for all sheets created. + * @var string + */ + var $_sheetname; + + /** + * The default XF format. + * @var object Format + */ + var $_tmp_format; + + /** + * Array containing references to all of this workbook's worksheets + * @var array + */ + var $_worksheets; + + /** + * Array of sheetnames for creating the EXTERNSHEET records + * @var array + */ + var $_sheetnames; + + /** + * Array containing references to all of this workbook's formats + * @var array + */ + var $_formats; + + /** + * Array containing the colour palette + * @var array + */ + var $_palette; + + /** + * The default format for URLs. + * @var object Format + */ + var $_url_format; + + /** + * The codepage indicates the text encoding used for strings + * @var integer + */ + var $_codepage; + + /** + * The country code used for localization + * @var integer + */ + var $_country_code; + + /** + * The temporary dir for storing the OLE file + * @var string + */ + var $_tmp_dir; + + /** + * number of bytes for sizeinfo of strings + * @var integer + */ + var $_string_sizeinfo_size; + + /** + * Class constructor + * + * @param string filename for storing the workbook. "-" for writing to stdout. + * @access public + */ + function Spreadsheet_Excel_Writer_Workbook($filename) + { + // It needs to call its parent's constructor explicitly + $this->Spreadsheet_Excel_Writer_BIFFwriter(); + + $this->_filename = $filename; + $this->_parser =& new Spreadsheet_Excel_Writer_Parser($this->_byte_order, $this->_BIFF_version); + $this->_1904 = 0; + $this->_activesheet = 0; + $this->_firstsheet = 0; + $this->_selected = 0; + $this->_xf_index = 16; // 15 style XF's and 1 cell XF. + $this->_fileclosed = 0; + $this->_biffsize = 0; + $this->_sheetname = 'Sheet'; + $this->_tmp_format =& new Spreadsheet_Excel_Writer_Format($this->_BIFF_version); + $this->_worksheets = array(); + $this->_sheetnames = array(); + $this->_formats = array(); + $this->_palette = array(); + $this->_codepage = 0x04E4; // FIXME: should change for BIFF8 + $this->_country_code = -1; + $this->_string_sizeinfo = 3; + + // Add the default format for hyperlinks + $this->_url_format =& $this->addFormat(array('color' => 'blue', 'underline' => 1)); + $this->_str_total = 0; + $this->_str_unique = 0; + $this->_str_table = array(); + $this->_setPaletteXl97(); + $this->_tmp_dir = ''; + } + + /** + * Calls finalization methods. + * This method should always be the last one to be called on every workbook + * + * @access public + * @return mixed true on success. PEAR_Error on failure + */ + function close() + { + if ($this->_fileclosed) { // Prevent close() from being called twice. + return true; + } + $res = $this->_storeWorkbook(); + if ($this->isError($res)) { + return $this->raiseError($res->getMessage()); + } + $this->_fileclosed = 1; + return true; + } + + /** + * An accessor for the _worksheets[] array + * Returns an array of the worksheet objects in a workbook + * It actually calls to worksheets() + * + * @access public + * @see worksheets() + * @return array + */ + function sheets() + { + return $this->worksheets(); + } + + /** + * An accessor for the _worksheets[] array. + * Returns an array of the worksheet objects in a workbook + * + * @access public + * @return array + */ + function worksheets() + { + return $this->_worksheets; + } + + /** + * Sets the BIFF version. + * This method exists just to access experimental functionality + * from BIFF8. It will be deprecated ! + * Only possible value is 8 (Excel 97/2000). + * For any other value it fails silently. + * + * @access public + * @param integer $version The BIFF version + */ + function setVersion($version) + { + if ($version == 8) { // only accept version 8 + $version = 0x0600; + $this->_BIFF_version = $version; + // change BIFFwriter limit for CONTINUE records + $this->_limit = 8228; + $this->_tmp_format->_BIFF_version = $version; + $this->_url_format->_BIFF_version = $version; + $this->_parser->_BIFF_version = $version; + + $total_worksheets = count($this->_worksheets); + // change version for all worksheets too + for ($i = 0; $i < $total_worksheets; $i++) { + $this->_worksheets[$i]->_BIFF_version = $version; + } + + $total_formats = count($this->_formats); + // change version for all formats too + for ($i = 0; $i < $total_formats; $i++) { + $this->_formats[$i]->_BIFF_version = $version; + } + } + } + + /** + * Set the country identifier for the workbook + * + * @access public + * @param integer $code Is the international calling country code for the + * chosen country. + */ + function setCountry($code) + { + $this->_country_code = $code; + } + + /** + * Add a new worksheet to the Excel workbook. + * If no name is given the name of the worksheet will be Sheeti$i, with + * $i in [1..]. + * + * @access public + * @param string $name the optional name of the worksheet + * @return mixed reference to a worksheet object on success, PEAR_Error + * on failure + */ + function &addWorksheet($name = '') + { + $index = count($this->_worksheets); + $sheetname = $this->_sheetname; + + if ($name == '') { + $name = $sheetname.($index+1); + } + + // Check that sheetname is <= 31 chars (Excel limit before BIFF8). + if ($this->_BIFF_version != 0x0600) + { + if (strlen($name) > 31) { + return $this->raiseError("Sheetname $name must be <= 31 chars"); + } + } + + // Check that the worksheet name doesn't already exist: a fatal Excel error. + $total_worksheets = count($this->_worksheets); + for ($i = 0; $i < $total_worksheets; $i++) { + if ($this->_worksheets[$i]->getName() == $name) { + return $this->raiseError("Worksheet '$name' already exists"); + } + } + + $worksheet = new Spreadsheet_Excel_Writer_Worksheet($this->_BIFF_version, + $name, $index, + $this->_activesheet, $this->_firstsheet, + $this->_str_total, $this->_str_unique, + $this->_str_table, $this->_url_format, + $this->_parser); + + $this->_worksheets[$index] = &$worksheet; // Store ref for iterator + $this->_sheetnames[$index] = $name; // Store EXTERNSHEET names + $this->_parser->setExtSheet($name, $index); // Register worksheet name with parser + return $worksheet; + } + + /** + * Add a new format to the Excel workbook. + * Also, pass any properties to the Format constructor. + * + * @access public + * @param array $properties array with properties for initializing the format. + * @return &Spreadsheet_Excel_Writer_Format reference to an Excel Format + */ + function &addFormat($properties = array()) + { + $format = new Spreadsheet_Excel_Writer_Format($this->_BIFF_version, $this->_xf_index, $properties); + $this->_xf_index += 1; + $this->_formats[] = &$format; + return $format; + } + + /** + * Create new validator. + * + * @access public + * @return &Spreadsheet_Excel_Writer_Validator reference to a Validator + */ + function &addValidator() + { + include_once 'Spreadsheet/Excel/Writer/Validator.php'; + /* FIXME: check for successful inclusion*/ + $valid = new Spreadsheet_Excel_Writer_Validator($this->_parser); + return $valid; + } + + /** + * Change the RGB components of the elements in the colour palette. + * + * @access public + * @param integer $index colour index + * @param integer $red red RGB value [0-255] + * @param integer $green green RGB value [0-255] + * @param integer $blue blue RGB value [0-255] + * @return integer The palette index for the custom color + */ + function setCustomColor($index, $red, $green, $blue) + { + // Match a HTML #xxyyzz style parameter + /*if (defined $_[1] and $_[1] =~ /^#(\w\w)(\w\w)(\w\w)/ ) { + @_ = ($_[0], hex $1, hex $2, hex $3); + }*/ + + // Check that the colour index is the right range + if ($index < 8 or $index > 64) { + // TODO: assign real error codes + return $this->raiseError("Color index $index outside range: 8 <= index <= 64"); + } + + // Check that the colour components are in the right range + if (($red < 0 or $red > 255) || + ($green < 0 or $green > 255) || + ($blue < 0 or $blue > 255)) + { + return $this->raiseError("Color component outside range: 0 <= color <= 255"); + } + + $index -= 8; // Adjust colour index (wingless dragonfly) + + // Set the RGB value + $this->_palette[$index] = array($red, $green, $blue, 0); + return($index + 8); + } + + /** + * Sets the colour palette to the Excel 97+ default. + * + * @access private + */ + function _setPaletteXl97() + { + $this->_palette = array( + array(0x00, 0x00, 0x00, 0x00), // 8 + array(0xff, 0xff, 0xff, 0x00), // 9 + array(0xff, 0x00, 0x00, 0x00), // 10 + array(0x00, 0xff, 0x00, 0x00), // 11 + array(0x00, 0x00, 0xff, 0x00), // 12 + array(0xff, 0xff, 0x00, 0x00), // 13 + array(0xff, 0x00, 0xff, 0x00), // 14 + array(0x00, 0xff, 0xff, 0x00), // 15 + array(0x80, 0x00, 0x00, 0x00), // 16 + array(0x00, 0x80, 0x00, 0x00), // 17 + array(0x00, 0x00, 0x80, 0x00), // 18 + array(0x80, 0x80, 0x00, 0x00), // 19 + array(0x80, 0x00, 0x80, 0x00), // 20 + array(0x00, 0x80, 0x80, 0x00), // 21 + array(0xc0, 0xc0, 0xc0, 0x00), // 22 + array(0x80, 0x80, 0x80, 0x00), // 23 + array(0x99, 0x99, 0xff, 0x00), // 24 + array(0x99, 0x33, 0x66, 0x00), // 25 + array(0xff, 0xff, 0xcc, 0x00), // 26 + array(0xcc, 0xff, 0xff, 0x00), // 27 + array(0x66, 0x00, 0x66, 0x00), // 28 + array(0xff, 0x80, 0x80, 0x00), // 29 + array(0x00, 0x66, 0xcc, 0x00), // 30 + array(0xcc, 0xcc, 0xff, 0x00), // 31 + array(0x00, 0x00, 0x80, 0x00), // 32 + array(0xff, 0x00, 0xff, 0x00), // 33 + array(0xff, 0xff, 0x00, 0x00), // 34 + array(0x00, 0xff, 0xff, 0x00), // 35 + array(0x80, 0x00, 0x80, 0x00), // 36 + array(0x80, 0x00, 0x00, 0x00), // 37 + array(0x00, 0x80, 0x80, 0x00), // 38 + array(0x00, 0x00, 0xff, 0x00), // 39 + array(0x00, 0xcc, 0xff, 0x00), // 40 + array(0xcc, 0xff, 0xff, 0x00), // 41 + array(0xcc, 0xff, 0xcc, 0x00), // 42 + array(0xff, 0xff, 0x99, 0x00), // 43 + array(0x99, 0xcc, 0xff, 0x00), // 44 + array(0xff, 0x99, 0xcc, 0x00), // 45 + array(0xcc, 0x99, 0xff, 0x00), // 46 + array(0xff, 0xcc, 0x99, 0x00), // 47 + array(0x33, 0x66, 0xff, 0x00), // 48 + array(0x33, 0xcc, 0xcc, 0x00), // 49 + array(0x99, 0xcc, 0x00, 0x00), // 50 + array(0xff, 0xcc, 0x00, 0x00), // 51 + array(0xff, 0x99, 0x00, 0x00), // 52 + array(0xff, 0x66, 0x00, 0x00), // 53 + array(0x66, 0x66, 0x99, 0x00), // 54 + array(0x96, 0x96, 0x96, 0x00), // 55 + array(0x00, 0x33, 0x66, 0x00), // 56 + array(0x33, 0x99, 0x66, 0x00), // 57 + array(0x00, 0x33, 0x00, 0x00), // 58 + array(0x33, 0x33, 0x00, 0x00), // 59 + array(0x99, 0x33, 0x00, 0x00), // 60 + array(0x99, 0x33, 0x66, 0x00), // 61 + array(0x33, 0x33, 0x99, 0x00), // 62 + array(0x33, 0x33, 0x33, 0x00), // 63 + ); + } + + /** + * Assemble worksheets into a workbook and send the BIFF data to an OLE + * storage. + * + * @access private + * @return mixed true on success. PEAR_Error on failure + */ + function _storeWorkbook() + { + // Ensure that at least one worksheet has been selected. + if ($this->_activesheet == 0) { + $this->_worksheets[0]->selected = 1; + } + + // Calculate the number of selected worksheet tabs and call the finalization + // methods for each worksheet + $total_worksheets = count($this->_worksheets); + for ($i = 0; $i < $total_worksheets; $i++) { + if ($this->_worksheets[$i]->selected) { + $this->_selected++; + } + $this->_worksheets[$i]->close($this->_sheetnames); + } + + // Add Workbook globals + $this->_storeBof(0x0005); + $this->_storeCodepage(); + if ($this->_BIFF_version == 0x0600) { + $this->_storeWindow1(); + } + if ($this->_BIFF_version == 0x0500) { + $this->_storeExterns(); // For print area and repeat rows + } + $this->_storeNames(); // For print area and repeat rows + if ($this->_BIFF_version == 0x0500) { + $this->_storeWindow1(); + } + $this->_storeDatemode(); + $this->_storeAllFonts(); + $this->_storeAllNumFormats(); + $this->_storeAllXfs(); + $this->_storeAllStyles(); + $this->_storePalette(); + $this->_calcSheetOffsets(); + + // Add BOUNDSHEET records + for ($i = 0; $i < $total_worksheets; $i++) { + $this->_storeBoundsheet($this->_worksheets[$i]->name,$this->_worksheets[$i]->offset); + } + + if ($this->_country_code != -1) { + $this->_storeCountry(); + } + + if ($this->_BIFF_version == 0x0600) { + //$this->_storeSupbookInternal(); + /* TODO: store external SUPBOOK records and XCT and CRN records + in case of external references for BIFF8 */ + //$this->_storeExternsheetBiff8(); + $this->_storeSharedStringsTable(); + } + + // End Workbook globals + $this->_storeEof(); + + // Store the workbook in an OLE container + $res = $this->_storeOLEFile(); + if ($this->isError($res)) { + return $this->raiseError($res->getMessage()); + } + return true; + } + + /** + * Sets the temp dir used for storing the OLE file + * + * @access public + * @param string $dir The dir to be used as temp dir + * @return true if given dir is valid, false otherwise + */ + function setTempDir($dir) + { + if (is_dir($dir)) { + $this->_tmp_dir = $dir; + return true; + } + return false; + } + + /** + * Store the workbook in an OLE container + * + * @access private + * @return mixed true on success. PEAR_Error on failure + */ + function _storeOLEFile() + { + $OLE = new OLE_PPS_File(OLE::Asc2Ucs('Book')); + if ($this->_tmp_dir != '') { + $OLE->setTempDir($this->_tmp_dir); + } + $res = $OLE->init(); + if ($this->isError($res)) { + return $this->raiseError("OLE Error: ".$res->getMessage()); + } + $OLE->append($this->_data); + + $total_worksheets = count($this->_worksheets); + for ($i = 0; $i < $total_worksheets; $i++) { + while ($tmp = $this->_worksheets[$i]->getData()) { + $OLE->append($tmp); + } + } + + $root = new OLE_PPS_Root(time(), time(), array($OLE)); + if ($this->_tmp_dir != '') { + $root->setTempDir($this->_tmp_dir); + } + + $res = $root->save($this->_filename); + if ($this->isError($res)) { + return $this->raiseError("OLE Error: ".$res->getMessage()); + } + return true; + } + + /** + * Calculate offsets for Worksheet BOF records. + * + * @access private + */ + function _calcSheetOffsets() + { + if ($this->_BIFF_version == 0x0600) { + $boundsheet_length = 12; // fixed length for a BOUNDSHEET record + } else { + $boundsheet_length = 11; + } + $EOF = 4; + $offset = $this->_datasize; + + if ($this->_BIFF_version == 0x0600) { + // add the length of the SST + /* TODO: check this works for a lot of strings (> 8224 bytes) */ + $offset += $this->_calculateSharedStringsSizes(); + if ($this->_country_code != -1) { + $offset += 8; // adding COUNTRY record + } + // add the lenght of SUPBOOK, EXTERNSHEET and NAME records + //$offset += 8; // FIXME: calculate real value when storing the records + } + $total_worksheets = count($this->_worksheets); + // add the length of the BOUNDSHEET records + for ($i = 0; $i < $total_worksheets; $i++) { + $offset += $boundsheet_length + strlen($this->_worksheets[$i]->name); + } + $offset += $EOF; + + for ($i = 0; $i < $total_worksheets; $i++) { + $this->_worksheets[$i]->offset = $offset; + $offset += $this->_worksheets[$i]->_datasize; + } + $this->_biffsize = $offset; + } + + /** + * Store the Excel FONT records. + * + * @access private + */ + function _storeAllFonts() + { + // tmp_format is added by the constructor. We use this to write the default XF's + $format = $this->_tmp_format; + $font = $format->getFont(); + + // Note: Fonts are 0-indexed. According to the SDK there is no index 4, + // so the following fonts are 0, 1, 2, 3, 5 + // + for ($i = 1; $i <= 5; $i++){ + $this->_append($font); + } + + // Iterate through the XF objects and write a FONT record if it isn't the + // same as the default FONT and if it hasn't already been used. + // + $fonts = array(); + $index = 6; // The first user defined FONT + + $key = $format->getFontKey(); // The default font from _tmp_format + $fonts[$key] = 0; // Index of the default font + + $total_formats = count($this->_formats); + for ($i = 0; $i < $total_formats; $i++) { + $key = $this->_formats[$i]->getFontKey(); + if (isset($fonts[$key])) { + // FONT has already been used + $this->_formats[$i]->font_index = $fonts[$key]; + } else { + // Add a new FONT record + $fonts[$key] = $index; + $this->_formats[$i]->font_index = $index; + $index++; + $font = $this->_formats[$i]->getFont(); + $this->_append($font); + } + } + } + + /** + * Store user defined numerical formats i.e. FORMAT records + * + * @access private + */ + function _storeAllNumFormats() + { + // Leaning num_format syndrome + $hash_num_formats = array(); + $num_formats = array(); + $index = 164; + + // Iterate through the XF objects and write a FORMAT record if it isn't a + // built-in format type and if the FORMAT string hasn't already been used. + $total_formats = count($this->_formats); + for ($i = 0; $i < $total_formats; $i++) { + $num_format = $this->_formats[$i]->_num_format; + + // Check if $num_format is an index to a built-in format. + // Also check for a string of zeros, which is a valid format string + // but would evaluate to zero. + // + if (!preg_match("/^0+\d/", $num_format)) { + if (preg_match("/^\d+$/", $num_format)) { // built-in format + continue; + } + } + + if (isset($hash_num_formats[$num_format])) { + // FORMAT has already been used + $this->_formats[$i]->_num_format = $hash_num_formats[$num_format]; + } else{ + // Add a new FORMAT + $hash_num_formats[$num_format] = $index; + $this->_formats[$i]->_num_format = $index; + array_push($num_formats,$num_format); + $index++; + } + } + + // Write the new FORMAT records starting from 0xA4 + $index = 164; + foreach ($num_formats as $num_format) { + $this->_storeNumFormat($num_format,$index); + $index++; + } + } + + /** + * Write all XF records. + * + * @access private + */ + function _storeAllXfs() + { + // _tmp_format is added by the constructor. We use this to write the default XF's + // The default font index is 0 + // + $format = $this->_tmp_format; + for ($i = 0; $i <= 14; $i++) { + $xf = $format->getXf('style'); // Style XF + $this->_append($xf); + } + + $xf = $format->getXf('cell'); // Cell XF + $this->_append($xf); + + // User defined XFs + $total_formats = count($this->_formats); + for ($i = 0; $i < $total_formats; $i++) { + $xf = $this->_formats[$i]->getXf('cell'); + $this->_append($xf); + } + } + + /** + * Write all STYLE records. + * + * @access private + */ + function _storeAllStyles() + { + $this->_storeStyle(); + } + + /** + * Write the EXTERNCOUNT and EXTERNSHEET records. These are used as indexes for + * the NAME records. + * + * @access private + */ + function _storeExterns() + { + // Create EXTERNCOUNT with number of worksheets + $this->_storeExterncount(count($this->_worksheets)); + + // Create EXTERNSHEET for each worksheet + foreach ($this->_sheetnames as $sheetname) { + $this->_storeExternsheet($sheetname); + } + } + + /** + * Write the NAME record to define the print area and the repeat rows and cols. + * + * @access private + */ + function _storeNames() + { + // Create the print area NAME records + $total_worksheets = count($this->_worksheets); + for ($i = 0; $i < $total_worksheets; $i++) { + // Write a Name record if the print area has been defined + if (isset($this->_worksheets[$i]->print_rowmin)) { + $this->_storeNameShort( + $this->_worksheets[$i]->index, + 0x06, // NAME type + $this->_worksheets[$i]->print_rowmin, + $this->_worksheets[$i]->print_rowmax, + $this->_worksheets[$i]->print_colmin, + $this->_worksheets[$i]->print_colmax + ); + } + } + + // Create the print title NAME records + $total_worksheets = count($this->_worksheets); + for ($i = 0; $i < $total_worksheets; $i++) { + $rowmin = $this->_worksheets[$i]->title_rowmin; + $rowmax = $this->_worksheets[$i]->title_rowmax; + $colmin = $this->_worksheets[$i]->title_colmin; + $colmax = $this->_worksheets[$i]->title_colmax; + + // Determine if row + col, row, col or nothing has been defined + // and write the appropriate record + // + if (isset($rowmin) && isset($colmin)) { + // Row and column titles have been defined. + // Row title has been defined. + $this->_storeNameLong( + $this->_worksheets[$i]->index, + 0x07, // NAME type + $rowmin, + $rowmax, + $colmin, + $colmax + ); + } elseif (isset($rowmin)) { + // Row title has been defined. + $this->_storeNameShort( + $this->_worksheets[$i]->index, + 0x07, // NAME type + $rowmin, + $rowmax, + 0x00, + 0xff + ); + } elseif (isset($colmin)) { + // Column title has been defined. + $this->_storeNameShort( + $this->_worksheets[$i]->index, + 0x07, // NAME type + 0x0000, + 0x3fff, + $colmin, + $colmax + ); + } else { + // Print title hasn't been defined. + } + } + } + + + + + /****************************************************************************** + * + * BIFF RECORDS + * + */ + + /** + * Stores the CODEPAGE biff record. + * + * @access private + */ + function _storeCodepage() + { + $record = 0x0042; // Record identifier + $length = 0x0002; // Number of bytes to follow + $cv = $this->_codepage; // The code page + + $header = pack('vv', $record, $length); + $data = pack('v', $cv); + + $this->_append($header . $data); + } + + /** + * Write Excel BIFF WINDOW1 record. + * + * @access private + */ + function _storeWindow1() + { + $record = 0x003D; // Record identifier + $length = 0x0012; // Number of bytes to follow + + $xWn = 0x0000; // Horizontal position of window + $yWn = 0x0000; // Vertical position of window + $dxWn = 0x25BC; // Width of window + $dyWn = 0x1572; // Height of window + + $grbit = 0x0038; // Option flags + $ctabsel = $this->_selected; // Number of workbook tabs selected + $wTabRatio = 0x0258; // Tab to scrollbar ratio + + $itabFirst = $this->_firstsheet; // 1st displayed worksheet + $itabCur = $this->_activesheet; // Active worksheet + + $header = pack("vv", $record, $length); + $data = pack("vvvvvvvvv", $xWn, $yWn, $dxWn, $dyWn, + $grbit, + $itabCur, $itabFirst, + $ctabsel, $wTabRatio); + $this->_append($header . $data); + } + + /** + * Writes Excel BIFF BOUNDSHEET record. + * FIXME: inconsistent with BIFF documentation + * + * @param string $sheetname Worksheet name + * @param integer $offset Location of worksheet BOF + * @access private + */ + function _storeBoundsheet($sheetname,$offset) + { + $record = 0x0085; // Record identifier + if ($this->_BIFF_version == 0x0600) { + $length = 0x08 + strlen($sheetname); // Number of bytes to follow + } else { + $length = 0x07 + strlen($sheetname); // Number of bytes to follow + } + + $grbit = 0x0000; // Visibility and sheet type + $cch = strlen($sheetname); // Length of sheet name + + $header = pack("vv", $record, $length); + if ($this->_BIFF_version == 0x0600) { + $data = pack("Vvv", $offset, $grbit, $cch); + } else { + $data = pack("VvC", $offset, $grbit, $cch); + } + $this->_append($header.$data.$sheetname); + } + + /** + * Write Internal SUPBOOK record + * + * @access private + */ + function _storeSupbookInternal() + { + $record = 0x01AE; // Record identifier + $length = 0x0004; // Bytes to follow + + $header = pack("vv", $record, $length); + $data = pack("vv", count($this->_worksheets), 0x0104); + $this->_append($header . $data); + } + + /** + * Writes the Excel BIFF EXTERNSHEET record. These references are used by + * formulas. + * + * @param string $sheetname Worksheet name + * @access private + */ + function _storeExternsheetBiff8() + { + $total_references = count($this->_parser->_references); + $record = 0x0017; // Record identifier + $length = 2 + 6 * $total_references; // Number of bytes to follow + + $supbook_index = 0; // FIXME: only using internal SUPBOOK record + $header = pack("vv", $record, $length); + $data = pack('v', $total_references); + for ($i = 0; $i < $total_references; $i++) { + $data .= $this->_parser->_references[$i]; + } + $this->_append($header . $data); + } + + /** + * Write Excel BIFF STYLE records. + * + * @access private + */ + function _storeStyle() + { + $record = 0x0293; // Record identifier + $length = 0x0004; // Bytes to follow + + $ixfe = 0x8000; // Index to style XF + $BuiltIn = 0x00; // Built-in style + $iLevel = 0xff; // Outline style level + + $header = pack("vv", $record, $length); + $data = pack("vCC", $ixfe, $BuiltIn, $iLevel); + $this->_append($header . $data); + } + + + /** + * Writes Excel FORMAT record for non "built-in" numerical formats. + * + * @param string $format Custom format string + * @param integer $ifmt Format index code + * @access private + */ + function _storeNumFormat($format, $ifmt) + { + $record = 0x041E; // Record identifier + + if ($this->_BIFF_version == 0x0600) { + $length = 5 + strlen($format); // Number of bytes to follow + $encoding = 0x0; + } elseif ($this->_BIFF_version == 0x0500) { + $length = 3 + strlen($format); // Number of bytes to follow + } + + $cch = strlen($format); // Length of format string + + $header = pack("vv", $record, $length); + if ($this->_BIFF_version == 0x0600) { + $data = pack("vvC", $ifmt, $cch, $encoding); + } elseif ($this->_BIFF_version == 0x0500) { + $data = pack("vC", $ifmt, $cch); + } + $this->_append($header . $data . $format); + } + + /** + * Write DATEMODE record to indicate the date system in use (1904 or 1900). + * + * @access private + */ + function _storeDatemode() + { + $record = 0x0022; // Record identifier + $length = 0x0002; // Bytes to follow + + $f1904 = $this->_1904; // Flag for 1904 date system + + $header = pack("vv", $record, $length); + $data = pack("v", $f1904); + $this->_append($header . $data); + } + + + /** + * Write BIFF record EXTERNCOUNT to indicate the number of external sheet + * references in the workbook. + * + * Excel only stores references to external sheets that are used in NAME. + * The workbook NAME record is required to define the print area and the repeat + * rows and columns. + * + * A similar method is used in Worksheet.php for a slightly different purpose. + * + * @param integer $cxals Number of external references + * @access private + */ + function _storeExterncount($cxals) + { + $record = 0x0016; // Record identifier + $length = 0x0002; // Number of bytes to follow + + $header = pack("vv", $record, $length); + $data = pack("v", $cxals); + $this->_append($header . $data); + } + + + /** + * Writes the Excel BIFF EXTERNSHEET record. These references are used by + * formulas. NAME record is required to define the print area and the repeat + * rows and columns. + * + * A similar method is used in Worksheet.php for a slightly different purpose. + * + * @param string $sheetname Worksheet name + * @access private + */ + function _storeExternsheet($sheetname) + { + $record = 0x0017; // Record identifier + $length = 0x02 + strlen($sheetname); // Number of bytes to follow + + $cch = strlen($sheetname); // Length of sheet name + $rgch = 0x03; // Filename encoding + + $header = pack("vv", $record, $length); + $data = pack("CC", $cch, $rgch); + $this->_append($header . $data . $sheetname); + } + + + /** + * Store the NAME record in the short format that is used for storing the print + * area, repeat rows only and repeat columns only. + * + * @param integer $index Sheet index + * @param integer $type Built-in name type + * @param integer $rowmin Start row + * @param integer $rowmax End row + * @param integer $colmin Start colum + * @param integer $colmax End column + * @access private + */ + function _storeNameShort($index, $type, $rowmin, $rowmax, $colmin, $colmax) + { + $record = 0x0018; // Record identifier + $length = 0x0024; // Number of bytes to follow + + $grbit = 0x0020; // Option flags + $chKey = 0x00; // Keyboard shortcut + $cch = 0x01; // Length of text name + $cce = 0x0015; // Length of text definition + $ixals = $index + 1; // Sheet index + $itab = $ixals; // Equal to ixals + $cchCustMenu = 0x00; // Length of cust menu text + $cchDescription = 0x00; // Length of description text + $cchHelptopic = 0x00; // Length of help topic text + $cchStatustext = 0x00; // Length of status bar text + $rgch = $type; // Built-in name type + + $unknown03 = 0x3b; + $unknown04 = 0xffff-$index; + $unknown05 = 0x0000; + $unknown06 = 0x0000; + $unknown07 = 0x1087; + $unknown08 = 0x8005; + + $header = pack("vv", $record, $length); + $data = pack("v", $grbit); + $data .= pack("C", $chKey); + $data .= pack("C", $cch); + $data .= pack("v", $cce); + $data .= pack("v", $ixals); + $data .= pack("v", $itab); + $data .= pack("C", $cchCustMenu); + $data .= pack("C", $cchDescription); + $data .= pack("C", $cchHelptopic); + $data .= pack("C", $cchStatustext); + $data .= pack("C", $rgch); + $data .= pack("C", $unknown03); + $data .= pack("v", $unknown04); + $data .= pack("v", $unknown05); + $data .= pack("v", $unknown06); + $data .= pack("v", $unknown07); + $data .= pack("v", $unknown08); + $data .= pack("v", $index); + $data .= pack("v", $index); + $data .= pack("v", $rowmin); + $data .= pack("v", $rowmax); + $data .= pack("C", $colmin); + $data .= pack("C", $colmax); + $this->_append($header . $data); + } + + + /** + * Store the NAME record in the long format that is used for storing the repeat + * rows and columns when both are specified. This shares a lot of code with + * _storeNameShort() but we use a separate method to keep the code clean. + * Code abstraction for reuse can be carried too far, and I should know. ;-) + * + * @param integer $index Sheet index + * @param integer $type Built-in name type + * @param integer $rowmin Start row + * @param integer $rowmax End row + * @param integer $colmin Start colum + * @param integer $colmax End column + * @access private + */ + function _storeNameLong($index, $type, $rowmin, $rowmax, $colmin, $colmax) + { + $record = 0x0018; // Record identifier + $length = 0x003d; // Number of bytes to follow + $grbit = 0x0020; // Option flags + $chKey = 0x00; // Keyboard shortcut + $cch = 0x01; // Length of text name + $cce = 0x002e; // Length of text definition + $ixals = $index + 1; // Sheet index + $itab = $ixals; // Equal to ixals + $cchCustMenu = 0x00; // Length of cust menu text + $cchDescription = 0x00; // Length of description text + $cchHelptopic = 0x00; // Length of help topic text + $cchStatustext = 0x00; // Length of status bar text + $rgch = $type; // Built-in name type + + $unknown01 = 0x29; + $unknown02 = 0x002b; + $unknown03 = 0x3b; + $unknown04 = 0xffff-$index; + $unknown05 = 0x0000; + $unknown06 = 0x0000; + $unknown07 = 0x1087; + $unknown08 = 0x8008; + + $header = pack("vv", $record, $length); + $data = pack("v", $grbit); + $data .= pack("C", $chKey); + $data .= pack("C", $cch); + $data .= pack("v", $cce); + $data .= pack("v", $ixals); + $data .= pack("v", $itab); + $data .= pack("C", $cchCustMenu); + $data .= pack("C", $cchDescription); + $data .= pack("C", $cchHelptopic); + $data .= pack("C", $cchStatustext); + $data .= pack("C", $rgch); + $data .= pack("C", $unknown01); + $data .= pack("v", $unknown02); + // Column definition + $data .= pack("C", $unknown03); + $data .= pack("v", $unknown04); + $data .= pack("v", $unknown05); + $data .= pack("v", $unknown06); + $data .= pack("v", $unknown07); + $data .= pack("v", $unknown08); + $data .= pack("v", $index); + $data .= pack("v", $index); + $data .= pack("v", 0x0000); + $data .= pack("v", 0x3fff); + $data .= pack("C", $colmin); + $data .= pack("C", $colmax); + // Row definition + $data .= pack("C", $unknown03); + $data .= pack("v", $unknown04); + $data .= pack("v", $unknown05); + $data .= pack("v", $unknown06); + $data .= pack("v", $unknown07); + $data .= pack("v", $unknown08); + $data .= pack("v", $index); + $data .= pack("v", $index); + $data .= pack("v", $rowmin); + $data .= pack("v", $rowmax); + $data .= pack("C", 0x00); + $data .= pack("C", 0xff); + // End of data + $data .= pack("C", 0x10); + $this->_append($header . $data); + } + + /** + * Stores the COUNTRY record for localization + * + * @access private + */ + function _storeCountry() + { + $record = 0x008C; // Record identifier + $length = 4; // Number of bytes to follow + + $header = pack('vv', $record, $length); + /* using the same country code always for simplicity */ + $data = pack('vv', $this->_country_code, $this->_country_code); + $this->_append($header . $data); + } + + /** + * Stores the PALETTE biff record. + * + * @access private + */ + function _storePalette() + { + $aref = $this->_palette; + + $record = 0x0092; // Record identifier + $length = 2 + 4 * count($aref); // Number of bytes to follow + $ccv = count($aref); // Number of RGB values to follow + $data = ''; // The RGB data + + // Pack the RGB data + foreach ($aref as $color) { + foreach ($color as $byte) { + $data .= pack("C",$byte); + } + } + + $header = pack("vvv", $record, $length, $ccv); + $this->_append($header . $data); + } + + /** + * Calculate + * Handling of the SST continue blocks is complicated by the need to include an + * additional continuation byte depending on whether the string is split between + * blocks or whether it starts at the beginning of the block. (There are also + * additional complications that will arise later when/if Rich Strings are + * supported). + * + * @access private + */ + function _calculateSharedStringsSizes() + { + /* Iterate through the strings to calculate the CONTINUE block sizes. + For simplicity we use the same size for the SST and CONTINUE records: + 8228 : Maximum Excel97 block size + -4 : Length of block header + -8 : Length of additional SST header information + = 8216 + */ + $continue_limit = 8216; + $block_length = 0; + $written = 0; + $this->_block_sizes = array(); + $continue = 0; + + foreach (array_keys($this->_str_table) as $string) { + $string_length = strlen($string); + + // Block length is the total length of the strings that will be + // written out in a single SST or CONTINUE block. + $block_length += $string_length; + + // We can write the string if it doesn't cross a CONTINUE boundary + if ($block_length < $continue_limit) { + $written += $string_length; + continue; + } + + // Deal with the cases where the next string to be written will exceed + // the CONTINUE boundary. If the string is very long it may need to be + // written in more than one CONTINUE record. + while ($block_length >= $continue_limit) { + + // We need to avoid the case where a string is continued in the first + // n bytes that contain the string header information. + $header_length = 3; // Min string + header size -1 + $space_remaining = $continue_limit - $written - $continue; + + + /* TODO: Unicode data should only be split on char (2 byte) + boundaries. Therefore, in some cases we need to reduce the + amount of available + */ + + if ($space_remaining > $header_length) { + // Write as much as possible of the string in the current block + $written += $space_remaining; + + // Reduce the current block length by the amount written + $block_length -= $continue_limit - $continue; + + // Store the max size for this block + $this->_block_sizes[] = $continue_limit; + + // If the current string was split then the next CONTINUE block + // should have the string continue flag (grbit) set unless the + // split string fits exactly into the remaining space. + if ($block_length > 0) { + $continue = 1; + } else { + $continue = 0; + } + } else { + // Store the max size for this block + $this->_block_sizes[] = $written + $continue; + + // Not enough space to start the string in the current block + $block_length -= $continue_limit - $space_remaining - $continue; + $continue = 0; + + } + + // If the string (or substr) is small enough we can write it in the + // new CONTINUE block. Else, go through the loop again to write it in + // one or more CONTINUE blocks + if ($block_length < $continue_limit) { + $written = $block_length; + } else { + $written = 0; + } + } + } + + // Store the max size for the last block unless it is empty + if ($written + $continue) { + $this->_block_sizes[] = $written + $continue; + } + + + /* Calculate the total length of the SST and associated CONTINUEs (if any). + The SST record will have a length even if it contains no strings. + This length is required to set the offsets in the BOUNDSHEET records since + they must be written before the SST records + */ + $total_offset = array_sum($this->_block_sizes); + // SST information + $total_offset += 8; + if (!empty($this->_block_sizes)) { + $total_offset += (count($this->_block_sizes)) * 4; // add CONTINUE headers + } + return $total_offset; + } + + /** + * Write all of the workbooks strings into an indexed array. + * See the comments in _calculate_shared_string_sizes() for more information. + * + * The Excel documentation says that the SST record should be followed by an + * EXTSST record. The EXTSST record is a hash table that is used to optimise + * access to SST. However, despite the documentation it doesn't seem to be + * required so we will ignore it. + * + * @access private + */ + function _storeSharedStringsTable() + { + $record = 0x00fc; // Record identifier + // sizes are upside down + $this->_block_sizes = array_reverse($this->_block_sizes); + $length = array_pop($this->_block_sizes) + 8; // First block size plus SST information + + // Write the SST block header information + $header = pack("vv", $record, $length); + $data = pack("VV", $this->_str_total, $this->_str_unique); + $this->_append($header . $data); + + + // Iterate through the strings to calculate the CONTINUE block sizes + $continue_limit = 8216; + $block_length = 0; + $written = 0; + $continue = 0; + + + /* TODO: not good for performance */ + foreach (array_keys($this->_str_table) as $string) { + + $string_length = strlen($string); + $encoding = 0; // assume there are no Unicode strings + $split_string = 0; + + // Block length is the total length of the strings that will be + // written out in a single SST or CONTINUE block. + // + $block_length += $string_length; + + + // We can write the string if it doesn't cross a CONTINUE boundary + if ($block_length < $continue_limit) { + $this->_append($string); + $written += $string_length; + continue; + } + + // Deal with the cases where the next string to be written will exceed + // the CONTINUE boundary. If the string is very long it may need to be + // written in more than one CONTINUE record. + // + while ($block_length >= $continue_limit) { + + // We need to avoid the case where a string is continued in the first + // n bytes that contain the string header information. + // + $header_length = 3; // Min string + header size -1 + $space_remaining = $continue_limit - $written - $continue; + + + // Unicode data should only be split on char (2 byte) boundaries. + // Therefore, in some cases we need to reduce the amount of available + + if ($space_remaining > $header_length) { + // Write as much as possible of the string in the current block + $tmp = substr($string, 0, $space_remaining); + $this->_append($tmp); + + // The remainder will be written in the next block(s) + $string = substr($string, $space_remaining); + + // Reduce the current block length by the amount written + $block_length -= $continue_limit - $continue; + + // If the current string was split then the next CONTINUE block + // should have the string continue flag (grbit) set unless the + // split string fits exactly into the remaining space. + // + if ($block_length > 0) { + $continue = 1; + } else { + $continue = 0; + } + } else { + // Not enough space to start the string in the current block + $block_length -= $continue_limit - $space_remaining - $continue; + $continue = 0; + } + + // Write the CONTINUE block header + if (!empty($this->_block_sizes)) { + $record = 0x003C; + $length = array_pop($this->_block_sizes); + $header = pack('vv', $record, $length); + if ($continue) { + $header .= pack('C', $encoding); + } + $this->_append($header); + } + + // If the string (or substr) is small enough we can write it in the + // new CONTINUE block. Else, go through the loop again to write it in + // one or more CONTINUE blocks + // + if ($block_length < $continue_limit) { + $this->_append($string); + $written = $block_length; + } else { + $written = 0; + } + } + } + } +} +?> diff --git a/include/Excel/Worksheet.php b/include/Excel/Worksheet.php new file mode 100644 index 000000000..0c61425c2 --- /dev/null +++ b/include/Excel/Worksheet.php @@ -0,0 +1,3500 @@ + +* +* The majority of this is _NOT_ my code. I simply ported it from the +* PERL Spreadsheet::WriteExcel module. +* +* The author of the Spreadsheet::WriteExcel module is John McNamara +* +* +* I _DO_ maintain this code, and John McNamara has nothing to do with the +* porting of this code to PHP. Any questions directly related to this +* class library should be directed to me. +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +/** +* Class for generating Excel Spreadsheets +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwriter +{ + /** + * Name of the Worksheet + * @var string + */ + var $name; + + /** + * Index for the Worksheet + * @var integer + */ + var $index; + + /** + * Reference to the (default) Format object for URLs + * @var object Format + */ + var $_url_format; + + /** + * Reference to the parser used for parsing formulas + * @var object Format + */ + var $_parser; + + /** + * Filehandle to the temporary file for storing data + * @var resource + */ + var $_filehandle; + + /** + * Boolean indicating if we are using a temporary file for storing data + * @var bool + */ + var $_using_tmpfile; + + /** + * Maximum number of rows for an Excel spreadsheet (BIFF5) + * @var integer + */ + var $_xls_rowmax; + + /** + * Maximum number of columns for an Excel spreadsheet (BIFF5) + * @var integer + */ + var $_xls_colmax; + + /** + * Maximum number of characters for a string (LABEL record in BIFF5) + * @var integer + */ + var $_xls_strmax; + + /** + * First row for the DIMENSIONS record + * @var integer + * @see _storeDimensions() + */ + var $_dim_rowmin; + + /** + * Last row for the DIMENSIONS record + * @var integer + * @see _storeDimensions() + */ + var $_dim_rowmax; + + /** + * First column for the DIMENSIONS record + * @var integer + * @see _storeDimensions() + */ + var $_dim_colmin; + + /** + * Last column for the DIMENSIONS record + * @var integer + * @see _storeDimensions() + */ + var $_dim_colmax; + + /** + * Array containing format information for columns + * @var array + */ + var $_colinfo; + + /** + * Array containing the selected area for the worksheet + * @var array + */ + var $_selection; + + /** + * Array containing the panes for the worksheet + * @var array + */ + var $_panes; + + /** + * The active pane for the worksheet + * @var integer + */ + var $_active_pane; + + /** + * Bit specifying if panes are frozen + * @var integer + */ + var $_frozen; + + /** + * Bit specifying if the worksheet is selected + * @var integer + */ + var $selected; + + /** + * The paper size (for printing) (DOCUMENT!!!) + * @var integer + */ + var $_paper_size; + + /** + * Bit specifying paper orientation (for printing). 0 => landscape, 1 => portrait + * @var integer + */ + var $_orientation; + + /** + * The page header caption + * @var string + */ + var $_header; + + /** + * The page footer caption + * @var string + */ + var $_footer; + + /** + * The horizontal centering value for the page + * @var integer + */ + var $_hcenter; + + /** + * The vertical centering value for the page + * @var integer + */ + var $_vcenter; + + /** + * The margin for the header + * @var float + */ + var $_margin_head; + + /** + * The margin for the footer + * @var float + */ + var $_margin_foot; + + /** + * The left margin for the worksheet in inches + * @var float + */ + var $_margin_left; + + /** + * The right margin for the worksheet in inches + * @var float + */ + var $_margin_right; + + /** + * The top margin for the worksheet in inches + * @var float + */ + var $_margin_top; + + /** + * The bottom margin for the worksheet in inches + * @var float + */ + var $_margin_bottom; + + /** + * First row to reapeat on each printed page + * @var integer + */ + var $title_rowmin; + + /** + * Last row to reapeat on each printed page + * @var integer + */ + var $title_rowmax; + + /** + * First column to reapeat on each printed page + * @var integer + */ + var $title_colmin; + + /** + * First row of the area to print + * @var integer + */ + var $print_rowmin; + + /** + * Last row to of the area to print + * @var integer + */ + var $print_rowmax; + + /** + * First column of the area to print + * @var integer + */ + var $print_colmin; + + /** + * Last column of the area to print + * @var integer + */ + var $print_colmax; + + /** + * Whether to use outline. + * @var integer + */ + var $_outline_on; + + /** + * Auto outline styles. + * @var bool + */ + var $_outline_style; + + /** + * Whether to have outline summary below. + * @var bool + */ + var $_outline_below; + + /** + * Whether to have outline summary at the right. + * @var bool + */ + var $_outline_right; + + /** + * Outline row level. + * @var integer + */ + var $_outline_row_level; + + /** + * Whether to fit to page when printing or not. + * @var bool + */ + var $_fit_page; + + /** + * Number of pages to fit wide + * @var integer + */ + var $_fit_width; + + /** + * Number of pages to fit high + * @var integer + */ + var $_fit_height; + + /** + * Reference to the total number of strings in the workbook + * @var integer + */ + var $_str_total; + + /** + * Reference to the number of unique strings in the workbook + * @var integer + */ + var $_str_unique; + + /** + * Reference to the array containing all the unique strings in the workbook + * @var array + */ + var $_str_table; + + /** + * Merged cell ranges + * @var array + */ + var $_merged_ranges; + + /** + * Charset encoding currently used when calling writeString() + * @var string + */ + var $_input_encoding; + + /** + * Constructor + * + * @param string $name The name of the new worksheet + * @param integer $index The index of the new worksheet + * @param mixed &$activesheet The current activesheet of the workbook we belong to + * @param mixed &$firstsheet The first worksheet in the workbook we belong to + * @param mixed &$url_format The default format for hyperlinks + * @param mixed &$parser The formula parser created for the Workbook + * @access private + */ + function Spreadsheet_Excel_Writer_Worksheet($BIFF_version, $name, + $index, &$activesheet, + &$firstsheet, &$str_total, + &$str_unique, &$str_table, + &$url_format, &$parser) + { + // It needs to call its parent's constructor explicitly + $this->Spreadsheet_Excel_Writer_BIFFwriter(); + $this->_BIFF_version = $BIFF_version; + $rowmax = 65536; // 16384 in Excel 5 + $colmax = 256; + + $this->name = $name; + $this->index = $index; + $this->activesheet = &$activesheet; + $this->firstsheet = &$firstsheet; + $this->_str_total = &$str_total; + $this->_str_unique = &$str_unique; + $this->_str_table = &$str_table; + $this->_url_format = &$url_format; + $this->_parser = &$parser; + + //$this->ext_sheets = array(); + $this->_filehandle = ''; + $this->_using_tmpfile = true; + //$this->fileclosed = 0; + //$this->offset = 0; + $this->_xls_rowmax = $rowmax; + $this->_xls_colmax = $colmax; + $this->_xls_strmax = 255; + $this->_dim_rowmin = $rowmax + 1; + $this->_dim_rowmax = 0; + $this->_dim_colmin = $colmax + 1; + $this->_dim_colmax = 0; + $this->_colinfo = array(); + $this->_selection = array(0,0,0,0); + $this->_panes = array(); + $this->_active_pane = 3; + $this->_frozen = 0; + $this->selected = 0; + + $this->_paper_size = 0x0; + $this->_orientation = 0x1; + $this->_header = ''; + $this->_footer = ''; + $this->_hcenter = 0; + $this->_vcenter = 0; + $this->_margin_head = 0.50; + $this->_margin_foot = 0.50; + $this->_margin_left = 0.75; + $this->_margin_right = 0.75; + $this->_margin_top = 1.00; + $this->_margin_bottom = 1.00; + + $this->title_rowmin = null; + $this->title_rowmax = null; + $this->title_colmin = null; + $this->title_colmax = null; + $this->print_rowmin = null; + $this->print_rowmax = null; + $this->print_colmin = null; + $this->print_colmax = null; + + $this->_print_gridlines = 1; + $this->_screen_gridlines = 1; + $this->_print_headers = 0; + + $this->_fit_page = 0; + $this->_fit_width = 0; + $this->_fit_height = 0; + + $this->_hbreaks = array(); + $this->_vbreaks = array(); + + $this->_protect = 0; + $this->_password = null; + + $this->col_sizes = array(); + $this->_row_sizes = array(); + + $this->_zoom = 100; + $this->_print_scale = 100; + + $this->_outline_row_level = 0; + $this->_outline_style = 0; + $this->_outline_below = 1; + $this->_outline_right = 1; + $this->_outline_on = 1; + + $this->_merged_ranges = array(); + + $this->_input_encoding = ''; + + $this->_dv = array(); + + $this->_initialize(); + } + + /** + * Open a tmp file to store the majority of the Worksheet data. If this fails, + * for example due to write permissions, store the data in memory. This can be + * slow for large files. + * + * @access private + */ + function _initialize() + { + // Open tmp file for storing Worksheet data + $fh = tmpfile(); + if ($fh) { + // Store filehandle + $this->_filehandle = $fh; + } else { + // If tmpfile() fails store data in memory + $this->_using_tmpfile = false; + } + } + + /** + * Add data to the beginning of the workbook (note the reverse order) + * and to the end of the workbook. + * + * @access public + * @see Spreadsheet_Excel_Writer_Workbook::storeWorkbook() + * @param array $sheetnames The array of sheetnames from the Workbook this + * worksheet belongs to + */ + function close($sheetnames) + { + $num_sheets = count($sheetnames); + + /*********************************************** + * Prepend in reverse order!! + */ + + // Prepend the sheet dimensions + $this->_storeDimensions(); + + // Prepend the sheet password + $this->_storePassword(); + + // Prepend the sheet protection + $this->_storeProtect(); + + // Prepend the page setup + $this->_storeSetup(); + + /* FIXME: margins are actually appended */ + // Prepend the bottom margin + $this->_storeMarginBottom(); + + // Prepend the top margin + $this->_storeMarginTop(); + + // Prepend the right margin + $this->_storeMarginRight(); + + // Prepend the left margin + $this->_storeMarginLeft(); + + // Prepend the page vertical centering + $this->_storeVcenter(); + + // Prepend the page horizontal centering + $this->_storeHcenter(); + + // Prepend the page footer + $this->_storeFooter(); + + // Prepend the page header + $this->_storeHeader(); + + // Prepend the vertical page breaks + $this->_storeVbreak(); + + // Prepend the horizontal page breaks + $this->_storeHbreak(); + + // Prepend WSBOOL + $this->_storeWsbool(); + + // Prepend GRIDSET + $this->_storeGridset(); + + // Prepend GUTS + if ($this->_BIFF_version == 0x0500) { + $this->_storeGuts(); + } + + // Prepend PRINTGRIDLINES + $this->_storePrintGridlines(); + + // Prepend PRINTHEADERS + $this->_storePrintHeaders(); + + // Prepend EXTERNSHEET references + if ($this->_BIFF_version == 0x0500) { + for ($i = $num_sheets; $i > 0; $i--) { + $sheetname = $sheetnames[$i-1]; + $this->_storeExternsheet($sheetname); + } + } + + // Prepend the EXTERNCOUNT of external references. + if ($this->_BIFF_version == 0x0500) { + $this->_storeExterncount($num_sheets); + } + + // Prepend the COLINFO records if they exist + if (!empty($this->_colinfo)) { + $colcount = count($this->_colinfo); + for ($i = 0; $i < $colcount; $i++) { + $this->_storeColinfo($this->_colinfo[$i]); + } + $this->_storeDefcol(); + } + + // Prepend the BOF record + $this->_storeBof(0x0010); + + /* + * End of prepend. Read upwards from here. + ***********************************************/ + + // Append + $this->_storeWindow2(); + $this->_storeZoom(); + if (!empty($this->_panes)) { + $this->_storePanes($this->_panes); + } + $this->_storeSelection($this->_selection); + $this->_storeMergedCells(); + /* TODO: add data validity */ + /*if ($this->_BIFF_version == 0x0600) { + $this->_storeDataValidity(); + }*/ + $this->_storeEof(); + } + + /** + * Retrieve the worksheet name. + * This is usefull when creating worksheets without a name. + * + * @access public + * @return string The worksheet's name + */ + function getName() + { + return $this->name; + } + + /** + * Retrieves data from memory in one chunk, or from disk in $buffer + * sized chunks. + * + * @return string The data + */ + function getData() + { + $buffer = 4096; + + // Return data stored in memory + if (isset($this->_data)) { + $tmp = $this->_data; + unset($this->_data); + $fh = $this->_filehandle; + if ($this->_using_tmpfile) { + fseek($fh, 0); + } + return $tmp; + } + // Return data stored on disk + if ($this->_using_tmpfile) { + if ($tmp = fread($this->_filehandle, $buffer)) { + return $tmp; + } + } + + // No data to return + return ''; + } + + /** + * Sets a merged cell range + * + * @access public + * @param integer $first_row First row of the area to merge + * @param integer $first_col First column of the area to merge + * @param integer $last_row Last row of the area to merge + * @param integer $last_col Last column of the area to merge + */ + function setMerge($first_row, $first_col, $last_row, $last_col) + { + if (($last_row < $first_row) || ($last_col < $first_col)) { + return; + } + // don't check rowmin, rowmax, etc... because we don't know when this + // is going to be called + $this->_merged_ranges[] = array($first_row, $first_col, $last_row, $last_col); + } + + /** + * Set this worksheet as a selected worksheet, + * i.e. the worksheet has its tab highlighted. + * + * @access public + */ + function select() + { + $this->selected = 1; + } + + /** + * Set this worksheet as the active worksheet, + * i.e. the worksheet that is displayed when the workbook is opened. + * Also set it as selected. + * + * @access public + */ + function activate() + { + $this->selected = 1; + $this->activesheet = $this->index; + } + + /** + * Set this worksheet as the first visible sheet. + * This is necessary when there are a large number of worksheets and the + * activated worksheet is not visible on the screen. + * + * @access public + */ + function setFirstSheet() + { + $this->firstsheet = $this->index; + } + + /** + * Set the worksheet protection flag + * to prevent accidental modification and to + * hide formulas if the locked and hidden format properties have been set. + * + * @access public + * @param string $password The password to use for protecting the sheet. + */ + function protect($password) + { + $this->_protect = 1; + $this->_password = $this->_encodePassword($password); + } + + /** + * Set the width of a single column or a range of columns. + * + * @access public + * @param integer $firstcol first column on the range + * @param integer $lastcol last column on the range + * @param integer $width width to set + * @param mixed $format The optional XF format to apply to the columns + * @param integer $hidden The optional hidden atribute + * @param integer $level The optional outline level + */ + function setColumn($firstcol, $lastcol, $width, $format = 0, $hidden = 0, $level = 0) + { + $this->_colinfo[] = array($firstcol, $lastcol, $width, &$format, $hidden, $level); + + // Set width to zero if column is hidden + $width = ($hidden) ? 0 : $width; + + for ($col = $firstcol; $col <= $lastcol; $col++) { + $this->col_sizes[$col] = $width; + } + } + + /** + * Set which cell or cells are selected in a worksheet + * + * @access public + * @param integer $first_row first row in the selected quadrant + * @param integer $first_column first column in the selected quadrant + * @param integer $last_row last row in the selected quadrant + * @param integer $last_column last column in the selected quadrant + */ + function setSelection($first_row,$first_column,$last_row,$last_column) + { + $this->_selection = array($first_row,$first_column,$last_row,$last_column); + } + + /** + * Set panes and mark them as frozen. + * + * @access public + * @param array $panes This is the only parameter received and is composed of the following: + * 0 => Vertical split position, + * 1 => Horizontal split position + * 2 => Top row visible + * 3 => Leftmost column visible + * 4 => Active pane + */ + function freezePanes($panes) + { + $this->_frozen = 1; + $this->_panes = $panes; + } + + /** + * Set panes and mark them as unfrozen. + * + * @access public + * @param array $panes This is the only parameter received and is composed of the following: + * 0 => Vertical split position, + * 1 => Horizontal split position + * 2 => Top row visible + * 3 => Leftmost column visible + * 4 => Active pane + */ + function thawPanes($panes) + { + $this->_frozen = 0; + $this->_panes = $panes; + } + + /** + * Set the page orientation as portrait. + * + * @access public + */ + function setPortrait() + { + $this->_orientation = 1; + } + + /** + * Set the page orientation as landscape. + * + * @access public + */ + function setLandscape() + { + $this->_orientation = 0; + } + + /** + * Set the paper type. Ex. 1 = US Letter, 9 = A4 + * + * @access public + * @param integer $size The type of paper size to use + */ + function setPaper($size = 0) + { + $this->_paper_size = $size; + } + + + /** + * Set the page header caption and optional margin. + * + * @access public + * @param string $string The header text + * @param float $margin optional head margin in inches. + */ + function setHeader($string,$margin = 0.50) + { + if (strlen($string) >= 255) { + //carp 'Header string must be less than 255 characters'; + return; + } + $this->_header = $string; + $this->_margin_head = $margin; + } + + /** + * Set the page footer caption and optional margin. + * + * @access public + * @param string $string The footer text + * @param float $margin optional foot margin in inches. + */ + function setFooter($string,$margin = 0.50) + { + if (strlen($string) >= 255) { + //carp 'Footer string must be less than 255 characters'; + return; + } + $this->_footer = $string; + $this->_margin_foot = $margin; + } + + /** + * Center the page horinzontally. + * + * @access public + * @param integer $center the optional value for centering. Defaults to 1 (center). + */ + function centerHorizontally($center = 1) + { + $this->_hcenter = $center; + } + + /** + * Center the page vertically. + * + * @access public + * @param integer $center the optional value for centering. Defaults to 1 (center). + */ + function centerVertically($center = 1) + { + $this->_vcenter = $center; + } + + /** + * Set all the page margins to the same value in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + function setMargins($margin) + { + $this->setMarginLeft($margin); + $this->setMarginRight($margin); + $this->setMarginTop($margin); + $this->setMarginBottom($margin); + } + + /** + * Set the left and right margins to the same value in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + function setMargins_LR($margin) + { + $this->setMarginLeft($margin); + $this->setMarginRight($margin); + } + + /** + * Set the top and bottom margins to the same value in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + function setMargins_TB($margin) + { + $this->setMarginTop($margin); + $this->setMarginBottom($margin); + } + + /** + * Set the left margin in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + function setMarginLeft($margin = 0.75) + { + $this->_margin_left = $margin; + } + + /** + * Set the right margin in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + function setMarginRight($margin = 0.75) + { + $this->_margin_right = $margin; + } + + /** + * Set the top margin in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + function setMarginTop($margin = 1.00) + { + $this->_margin_top = $margin; + } + + /** + * Set the bottom margin in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + function setMarginBottom($margin = 1.00) + { + $this->_margin_bottom = $margin; + } + + /** + * Set the rows to repeat at the top of each printed page. + * + * @access public + * @param integer $first_row First row to repeat + * @param integer $last_row Last row to repeat. Optional. + */ + function repeatRows($first_row, $last_row = null) + { + $this->title_rowmin = $first_row; + if (isset($last_row)) { //Second row is optional + $this->title_rowmax = $last_row; + } else { + $this->title_rowmax = $first_row; + } + } + + /** + * Set the columns to repeat at the left hand side of each printed page. + * + * @access public + * @param integer $first_col First column to repeat + * @param integer $last_col Last column to repeat. Optional. + */ + function repeatColumns($first_col, $last_col = null) + { + $this->title_colmin = $first_col; + if (isset($last_col)) { // Second col is optional + $this->title_colmax = $last_col; + } else { + $this->title_colmax = $first_col; + } + } + + /** + * Set the area of each worksheet that will be printed. + * + * @access public + * @param integer $first_row First row of the area to print + * @param integer $first_col First column of the area to print + * @param integer $last_row Last row of the area to print + * @param integer $last_col Last column of the area to print + */ + function printArea($first_row, $first_col, $last_row, $last_col) + { + $this->print_rowmin = $first_row; + $this->print_colmin = $first_col; + $this->print_rowmax = $last_row; + $this->print_colmax = $last_col; + } + + + /** + * Set the option to hide gridlines on the printed page. + * + * @access public + */ + function hideGridlines() + { + $this->_print_gridlines = 0; + } + + /** + * Set the option to hide gridlines on the worksheet (as seen on the screen). + * + * @access public + */ + function hideScreenGridlines() + { + $this->_screen_gridlines = 0; + } + + /** + * Set the option to print the row and column headers on the printed page. + * + * @access public + * @param integer $print Whether to print the headers or not. Defaults to 1 (print). + */ + function printRowColHeaders($print = 1) + { + $this->_print_headers = $print; + } + + /** + * Set the vertical and horizontal number of pages that will define the maximum area printed. + * It doesn't seem to work with OpenOffice. + * + * @access public + * @param integer $width Maximun width of printed area in pages + * @param integer $height Maximun heigth of printed area in pages + * @see setPrintScale() + */ + function fitToPages($width, $height) + { + $this->_fit_page = 1; + $this->_fit_width = $width; + $this->_fit_height = $height; + } + + /** + * Store the horizontal page breaks on a worksheet (for printing). + * The breaks represent the row after which the break is inserted. + * + * @access public + * @param array $breaks Array containing the horizontal page breaks + */ + function setHPagebreaks($breaks) + { + foreach ($breaks as $break) { + array_push($this->_hbreaks, $break); + } + } + + /** + * Store the vertical page breaks on a worksheet (for printing). + * The breaks represent the column after which the break is inserted. + * + * @access public + * @param array $breaks Array containing the vertical page breaks + */ + function setVPagebreaks($breaks) + { + foreach ($breaks as $break) { + array_push($this->_vbreaks, $break); + } + } + + + /** + * Set the worksheet zoom factor. + * + * @access public + * @param integer $scale The zoom factor + */ + function setZoom($scale = 100) + { + // Confine the scale to Excel's range + if ($scale < 10 || $scale > 400) { + $this->raiseError("Zoom factor $scale outside range: 10 <= zoom <= 400"); + $scale = 100; + } + + $this->_zoom = floor($scale); + } + + /** + * Set the scale factor for the printed page. + * It turns off the "fit to page" option + * + * @access public + * @param integer $scale The optional scale factor. Defaults to 100 + */ + function setPrintScale($scale = 100) + { + // Confine the scale to Excel's range + if ($scale < 10 || $scale > 400) { + $this->raiseError("Print scale $scale outside range: 10 <= zoom <= 400"); + $scale = 100; + } + + // Turn off "fit to page" option + $this->_fit_page = 0; + + $this->_print_scale = floor($scale); + } + + /** + * Map to the appropriate write method acording to the token recieved. + * + * @access public + * @param integer $row The row of the cell we are writing to + * @param integer $col The column of the cell we are writing to + * @param mixed $token What we are writing + * @param mixed $format The optional format to apply to the cell + */ + function write($row, $col, $token, $format = 0) + { + // Check for a cell reference in A1 notation and substitute row and column + /*if ($_[0] =~ /^\D/) { + @_ = $this->_substituteCellref(@_); + }*/ + + if (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/", $token)) { + // Match number + return $this->writeNumber($row, $col, $token, $format); + } elseif (preg_match("/^[fh]tt?p:\/\//", $token)) { + // Match http or ftp URL + return $this->writeUrl($row, $col, $token, '', $format); + } elseif (preg_match("/^mailto:/", $token)) { + // Match mailto: + return $this->writeUrl($row, $col, $token, '', $format); + } elseif (preg_match("/^(?:in|ex)ternal:/", $token)) { + // Match internal or external sheet link + return $this->writeUrl($row, $col, $token, '', $format); + } elseif (preg_match("/^=/", $token)) { + // Match formula + return $this->writeFormula($row, $col, $token, $format); + } elseif (preg_match("/^@/", $token)) { + // Match formula + return $this->writeFormula($row, $col, $token, $format); + } elseif ($token == '') { + // Match blank + return $this->writeBlank($row, $col, $format); + } else { + // Default: match string + return $this->writeString($row, $col, $token, $format); + } + } + + /** + * Write an array of values as a row + * + * @access public + * @param integer $row The row we are writing to + * @param integer $col The first col (leftmost col) we are writing to + * @param array $val The array of values to write + * @param mixed $format The optional format to apply to the cell + * @return mixed PEAR_Error on failure + */ + + function writeRow($row, $col, $val, $format = 0) + { + $retval = ''; + if (is_array($val)) { + foreach ($val as $v) { + if (is_array($v)) { + $this->writeCol($row, $col, $v, $format); + } else { + $this->write($row, $col, $v, $format); + } + $col++; + } + } else { + $retval = new PEAR_Error('$val needs to be an array'); + } + return($retval); + } + + /** + * Write an array of values as a column + * + * @access public + * @param integer $row The first row (uppermost row) we are writing to + * @param integer $col The col we are writing to + * @param array $val The array of values to write + * @param mixed $format The optional format to apply to the cell + * @return mixed PEAR_Error on failure + */ + + function writeCol($row, $col, $val, $format=0) + { + $retval = ''; + if (is_array($val)) { + foreach ($val as $v) { + $this->write($row, $col, $v, $format); + $row++; + } + } else { + $retval = new PEAR_Error('$val needs to be an array'); + } + return($retval); + } + + /** + * Returns an index to the XF record in the workbook + * + * @access private + * @param mixed &$format The optional XF format + * @return integer The XF record index + */ + function _XF(&$format) + { + if ($format != 0) { + return($format->getXfIndex()); + } else { + return(0x0F); + } + } + + + /****************************************************************************** + ******************************************************************************* + * + * Internal methods + */ + + + /** + * Store Worksheet data in memory using the parent's class append() or to a + * temporary file, the default. + * + * @access private + * @param string $data The binary data to append + */ + function _append($data) + { + if ($this->_using_tmpfile) { + // Add CONTINUE records if necessary + if (strlen($data) > $this->_limit) { + $data = $this->_addContinue($data); + } + fwrite($this->_filehandle, $data); + $this->_datasize += strlen($data); + } else { + parent::_append($data); + } + } + + /** + * Substitute an Excel cell reference in A1 notation for zero based row and + * column values in an argument list. + * + * Ex: ("A4", "Hello") is converted to (3, 0, "Hello"). + * + * @access private + * @param string $cell The cell reference. Or range of cells. + * @return array + */ + function _substituteCellref($cell) + { + $cell = strtoupper($cell); + + // Convert a column range: 'A:A' or 'B:G' + if (preg_match("/([A-I]?[A-Z]):([A-I]?[A-Z])/", $cell, $match)) { + list($no_use, $col1) = $this->_cellToRowcol($match[1] .'1'); // Add a dummy row + list($no_use, $col2) = $this->_cellToRowcol($match[2] .'1'); // Add a dummy row + return(array($col1, $col2)); + } + + // Convert a cell range: 'A1:B7' + if (preg_match("/\$?([A-I]?[A-Z]\$?\d+):\$?([A-I]?[A-Z]\$?\d+)/", $cell, $match)) { + list($row1, $col1) = $this->_cellToRowcol($match[1]); + list($row2, $col2) = $this->_cellToRowcol($match[2]); + return(array($row1, $col1, $row2, $col2)); + } + + // Convert a cell reference: 'A1' or 'AD2000' + if (preg_match("/\$?([A-I]?[A-Z]\$?\d+)/", $cell)) { + list($row1, $col1) = $this->_cellToRowcol($match[1]); + return(array($row1, $col1)); + } + + // TODO use real error codes + $this->raiseError("Unknown cell reference $cell", 0, PEAR_ERROR_DIE); + } + + /** + * Convert an Excel cell reference in A1 notation to a zero based row and column + * reference; converts C1 to (0, 2). + * + * @access private + * @param string $cell The cell reference. + * @return array containing (row, column) + */ + function _cellToRowcol($cell) + { + preg_match("/\$?([A-I]?[A-Z])\$?(\d+)/",$cell,$match); + $col = $match[1]; + $row = $match[2]; + + // Convert base26 column string to number + $chars = split('', $col); + $expn = 0; + $col = 0; + + while ($chars) { + $char = array_pop($chars); // LS char first + $col += (ord($char) -ord('A') +1) * pow(26,$expn); + $expn++; + } + + // Convert 1-index to zero-index + $row--; + $col--; + + return(array($row, $col)); + } + + /** + * Based on the algorithm provided by Daniel Rentz of OpenOffice. + * + * @access private + * @param string $plaintext The password to be encoded in plaintext. + * @return string The encoded password + */ + function _encodePassword($plaintext) + { + $password = 0x0000; + $i = 1; // char position + + // split the plain text password in its component characters + $chars = preg_split('//', $plaintext, -1, PREG_SPLIT_NO_EMPTY); + foreach ($chars as $char) { + $value = ord($char) << $i; // shifted ASCII value + $rotated_bits = $value >> 15; // rotated bits beyond bit 15 + $value &= 0x7fff; // first 15 bits + $password ^= ($value | $rotated_bits); + $i++; + } + + $password ^= strlen($plaintext); + $password ^= 0xCE4B; + + return($password); + } + + /** + * This method sets the properties for outlining and grouping. The defaults + * correspond to Excel's defaults. + * + * @param bool $visible + * @param bool $symbols_below + * @param bool $symbols_right + * @param bool $auto_style + */ + function setOutline($visible = true, $symbols_below = true, $symbols_right = true, $auto_style = false) + { + $this->_outline_on = $visible; + $this->_outline_below = $symbols_below; + $this->_outline_right = $symbols_right; + $this->_outline_style = $auto_style; + + // Ensure this is a boolean vale for Window2 + if ($this->_outline_on) { + $this->_outline_on = 1; + } + } + + /****************************************************************************** + ******************************************************************************* + * + * BIFF RECORDS + */ + + + /** + * Write a double to the specified row and column (zero indexed). + * An integer can be written as a double. Excel will display an + * integer. $format is optional. + * + * Returns 0 : normal termination + * -2 : row or column out of range + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param float $num The number to write + * @param mixed $format The optional XF format + * @return integer + */ + function writeNumber($row, $col, $num, $format = 0) + { + $record = 0x0203; // Record identifier + $length = 0x000E; // Number of bytes to follow + + $xf = $this->_XF($format); // The cell format + + // Check that row and col are valid and store max and min values + if ($row >= $this->_xls_rowmax) { + return(-2); + } + if ($col >= $this->_xls_colmax) { + return(-2); + } + if ($row < $this->_dim_rowmin) { + $this->_dim_rowmin = $row; + } + if ($row > $this->_dim_rowmax) { + $this->_dim_rowmax = $row; + } + if ($col < $this->_dim_colmin) { + $this->_dim_colmin = $col; + } + if ($col > $this->_dim_colmax) { + $this->_dim_colmax = $col; + } + + $header = pack("vv", $record, $length); + $data = pack("vvv", $row, $col, $xf); + $xl_double = pack("d", $num); + if ($this->_byte_order) { // if it's Big Endian + $xl_double = strrev($xl_double); + } + + $this->_append($header.$data.$xl_double); + return(0); + } + + /** + * Write a string to the specified row and column (zero indexed). + * NOTE: there is an Excel 5 defined limit of 255 characters. + * $format is optional. + * Returns 0 : normal termination + * -2 : row or column out of range + * -3 : long string truncated to 255 chars + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param string $str The string to write + * @param mixed $format The XF format for the cell + * @return integer + */ + function writeString($row, $col, $str, $format = 0) + { + if ($this->_BIFF_version == 0x0600) { + return $this->writeStringBIFF8($row, $col, $str, $format); + } + $strlen = strlen($str); + $record = 0x0204; // Record identifier + $length = 0x0008 + $strlen; // Bytes to follow + $xf = $this->_XF($format); // The cell format + + $str_error = 0; + + // Check that row and col are valid and store max and min values + if ($row >= $this->_xls_rowmax) { + return(-2); + } + if ($col >= $this->_xls_colmax) { + return(-2); + } + if ($row < $this->_dim_rowmin) { + $this->_dim_rowmin = $row; + } + if ($row > $this->_dim_rowmax) { + $this->_dim_rowmax = $row; + } + if ($col < $this->_dim_colmin) { + $this->_dim_colmin = $col; + } + if ($col > $this->_dim_colmax) { + $this->_dim_colmax = $col; + } + + if ($strlen > $this->_xls_strmax) { // LABEL must be < 255 chars + $str = substr($str, 0, $this->_xls_strmax); + $length = 0x0008 + $this->_xls_strmax; + $strlen = $this->_xls_strmax; + $str_error = -3; + } + + $header = pack("vv", $record, $length); + $data = pack("vvvv", $row, $col, $xf, $strlen); + $this->_append($header . $data . $str); + return($str_error); + } + + /** + * Sets Input Encoding for writing strings + * + * @access public + * @param string $encoding The encoding. Ex: 'UTF-16LE', 'utf-8', 'ISO-859-7' + */ + function setInputEncoding($encoding) + { + if ($encoding != 'UTF-16LE' && !function_exists('iconv')) { + $this->raiseError("Using an input encoding other than UTF-16LE requires PHP support for iconv"); + } + $this->_input_encoding = $encoding; + } + + /** + * Write a string to the specified row and column (zero indexed). + * This is the BIFF8 version (no 255 chars limit). + * $format is optional. + * Returns 0 : normal termination + * -2 : row or column out of range + * -3 : long string truncated to 255 chars + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param string $str The string to write + * @param mixed $format The XF format for the cell + * @return integer + */ + function writeStringBIFF8($row, $col, $str, $format = 0) + { + if ($this->_input_encoding == 'UTF-16LE') + { + $strlen = function_exists('mb_strlen') ? mb_strlen($str, 'UTF-16LE') : (strlen($str) / 2); + $encoding = 0x1; + } + elseif ($this->_input_encoding != '') + { + $str = iconv($this->_input_encoding, 'UTF-16LE', $str); + $strlen = function_exists('mb_strlen') ? mb_strlen($str, 'UTF-16LE') : (strlen($str) / 2); + $encoding = 0x1; + } + else + { + $strlen = strlen($str); + $encoding = 0x0; + } + $record = 0x00FD; // Record identifier + $length = 0x000A; // Bytes to follow + $xf = $this->_XF($format); // The cell format + + $str_error = 0; + + // Check that row and col are valid and store max and min values + if ($this->_checkRowCol($row, $col) == false) { + return -2; + } + + $str = pack('vC', $strlen, $encoding).$str; + + /* check if string is already present */ + if (!isset($this->_str_table[$str])) { + $this->_str_table[$str] = $this->_str_unique++; + } + $this->_str_total++; + + $header = pack('vv', $record, $length); + $data = pack('vvvV', $row, $col, $xf, $this->_str_table[$str]); + $this->_append($header.$data); + return $str_error; + } + + /** + * Check row and col before writing to a cell, and update the sheet's + * dimensions accordingly + * + * @access private + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @return boolean true for success, false if row and/or col are grester + * then maximums allowed. + */ + function _checkRowCol($row, $col) + { + if ($row >= $this->_xls_rowmax) { + return false; + } + if ($col >= $this->_xls_colmax) { + return false; + } + if ($row < $this->_dim_rowmin) { + $this->_dim_rowmin = $row; + } + if ($row > $this->_dim_rowmax) { + $this->_dim_rowmax = $row; + } + if ($col < $this->_dim_colmin) { + $this->_dim_colmin = $col; + } + if ($col > $this->_dim_colmax) { + $this->_dim_colmax = $col; + } + return true; + } + + /** + * Writes a note associated with the cell given by the row and column. + * NOTE records don't have a length limit. + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param string $note The note to write + */ + function writeNote($row, $col, $note) + { + $note_length = strlen($note); + $record = 0x001C; // Record identifier + $max_length = 2048; // Maximun length for a NOTE record + //$length = 0x0006 + $note_length; // Bytes to follow + + // Check that row and col are valid and store max and min values + if ($row >= $this->_xls_rowmax) { + return(-2); + } + if ($col >= $this->_xls_colmax) { + return(-2); + } + if ($row < $this->_dim_rowmin) { + $this->_dim_rowmin = $row; + } + if ($row > $this->_dim_rowmax) { + $this->_dim_rowmax = $row; + } + if ($col < $this->_dim_colmin) { + $this->_dim_colmin = $col; + } + if ($col > $this->_dim_colmax) { + $this->_dim_colmax = $col; + } + + // Length for this record is no more than 2048 + 6 + $length = 0x0006 + min($note_length, 2048); + $header = pack("vv", $record, $length); + $data = pack("vvv", $row, $col, $note_length); + $this->_append($header . $data . substr($note, 0, 2048)); + + for ($i = $max_length; $i < $note_length; $i += $max_length) { + $chunk = substr($note, $i, $max_length); + $length = 0x0006 + strlen($chunk); + $header = pack("vv", $record, $length); + $data = pack("vvv", -1, 0, strlen($chunk)); + $this->_append($header.$data.$chunk); + } + return(0); + } + + /** + * Write a blank cell to the specified row and column (zero indexed). + * A blank cell is used to specify formatting without adding a string + * or a number. + * + * A blank cell without a format serves no purpose. Therefore, we don't write + * a BLANK record unless a format is specified. + * + * Returns 0 : normal termination (including no format) + * -1 : insufficient number of arguments + * -2 : row or column out of range + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param mixed $format The XF format + */ + function writeBlank($row, $col, $format) + { + // Don't write a blank cell unless it has a format + if ($format == 0) { + return(0); + } + + $record = 0x0201; // Record identifier + $length = 0x0006; // Number of bytes to follow + $xf = $this->_XF($format); // The cell format + + // Check that row and col are valid and store max and min values + if ($row >= $this->_xls_rowmax) { + return(-2); + } + if ($col >= $this->_xls_colmax) { + return(-2); + } + if ($row < $this->_dim_rowmin) { + $this->_dim_rowmin = $row; + } + if ($row > $this->_dim_rowmax) { + $this->_dim_rowmax = $row; + } + if ($col < $this->_dim_colmin) { + $this->_dim_colmin = $col; + } + if ($col > $this->_dim_colmax) { + $this->_dim_colmax = $col; + } + + $header = pack("vv", $record, $length); + $data = pack("vvv", $row, $col, $xf); + $this->_append($header . $data); + return 0; + } + + /** + * Write a formula to the specified row and column (zero indexed). + * The textual representation of the formula is passed to the parser in + * Parser.php which returns a packed binary string. + * + * Returns 0 : normal termination + * -1 : formula errors (bad formula) + * -2 : row or column out of range + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param string $formula The formula text string + * @param mixed $format The optional XF format + * @return integer + */ + function writeFormula($row, $col, $formula, $format = 0) + { + $record = 0x0006; // Record identifier + + // Excel normally stores the last calculated value of the formula in $num. + // Clearly we are not in a position to calculate this a priori. Instead + // we set $num to zero and set the option flags in $grbit to ensure + // automatic calculation of the formula when the file is opened. + // + $xf = $this->_XF($format); // The cell format + $num = 0x00; // Current value of formula + $grbit = 0x03; // Option flags + $unknown = 0x0000; // Must be zero + + + // Check that row and col are valid and store max and min values + if ($this->_checkRowCol($row, $col) == false) { + return -2; + } + + // Strip the '=' or '@' sign at the beginning of the formula string + if (preg_match("/^=/", $formula)) { + $formula = preg_replace("/(^=)/", "", $formula); + } elseif (preg_match("/^@/", $formula)) { + $formula = preg_replace("/(^@)/", "", $formula); + } else { + // Error handling + $this->writeString($row, $col, 'Unrecognised character for formula'); + return -1; + } + + // Parse the formula using the parser in Parser.php + $error = $this->_parser->parse($formula); + if ($this->isError($error)) { + $this->writeString($row, $col, $error->getMessage()); + return -1; + } + + $formula = $this->_parser->toReversePolish(); + if ($this->isError($formula)) { + $this->writeString($row, $col, $formula->getMessage()); + return -1; + } + + $formlen = strlen($formula); // Length of the binary string + $length = 0x16 + $formlen; // Length of the record data + + $header = pack("vv", $record, $length); + $data = pack("vvvdvVv", $row, $col, $xf, $num, + $grbit, $unknown, $formlen); + + $this->_append($header . $data . $formula); + return 0; + } + + /** + * Write a hyperlink. + * This is comprised of two elements: the visible label and + * the invisible link. The visible label is the same as the link unless an + * alternative string is specified. The label is written using the + * writeString() method. Therefore the 255 characters string limit applies. + * $string and $format are optional. + * + * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external + * directory url. + * + * Returns 0 : normal termination + * -2 : row or column out of range + * -3 : long string truncated to 255 chars + * + * @access public + * @param integer $row Row + * @param integer $col Column + * @param string $url URL string + * @param string $string Alternative label + * @param mixed $format The cell format + * @return integer + */ + function writeUrl($row, $col, $url, $string = '', $format = 0) + { + // Add start row and col to arg list + return($this->_writeUrlRange($row, $col, $row, $col, $url, $string, $format)); + } + + /** + * This is the more general form of writeUrl(). It allows a hyperlink to be + * written to a range of cells. This function also decides the type of hyperlink + * to be written. These are either, Web (http, ftp, mailto), Internal + * (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1'). + * + * @access private + * @see writeUrl() + * @param integer $row1 Start row + * @param integer $col1 Start column + * @param integer $row2 End row + * @param integer $col2 End column + * @param string $url URL string + * @param string $string Alternative label + * @param mixed $format The cell format + * @return integer + */ + + function _writeUrlRange($row1, $col1, $row2, $col2, $url, $string = '', $format = 0) + { + + // Check for internal/external sheet links or default to web link + if (preg_match('[^internal:]', $url)) { + return($this->_writeUrlInternal($row1, $col1, $row2, $col2, $url, $string, $format)); + } + if (preg_match('[^external:]', $url)) { + return($this->_writeUrlExternal($row1, $col1, $row2, $col2, $url, $string, $format)); + } + return($this->_writeUrlWeb($row1, $col1, $row2, $col2, $url, $string, $format)); + } + + + /** + * Used to write http, ftp and mailto hyperlinks. + * The link type ($options) is 0x03 is the same as absolute dir ref without + * sheet. However it is differentiated by the $unknown2 data stream. + * + * @access private + * @see writeUrl() + * @param integer $row1 Start row + * @param integer $col1 Start column + * @param integer $row2 End row + * @param integer $col2 End column + * @param string $url URL string + * @param string $str Alternative label + * @param mixed $format The cell format + * @return integer + */ + function _writeUrlWeb($row1, $col1, $row2, $col2, $url, $str, $format = 0) + { + $record = 0x01B8; // Record identifier + $length = 0x00000; // Bytes to follow + + if ($format == 0) { + $format = $this->_url_format; + } + + // Write the visible label using the writeString() method. + if ($str == '') { + $str = $url; + } + $str_error = $this->writeString($row1, $col1, $str, $format); + if (($str_error == -2) || ($str_error == -3)) { + return $str_error; + } + + // Pack the undocumented parts of the hyperlink stream + $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000"); + $unknown2 = pack("H*", "E0C9EA79F9BACE118C8200AA004BA90B"); + + // Pack the option flags + $options = pack("V", 0x03); + + // Convert URL to a null terminated wchar string + $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY)); + $url = $url . "\0\0\0"; + + // Pack the length of the URL + $url_len = pack("V", strlen($url)); + + // Calculate the data length + $length = 0x34 + strlen($url); + + // Pack the header data + $header = pack("vv", $record, $length); + $data = pack("vvvv", $row1, $row2, $col1, $col2); + + // Write the packed data + $this->_append($header . $data . + $unknown1 . $options . + $unknown2 . $url_len . $url); + return($str_error); + } + + /** + * Used to write internal reference hyperlinks such as "Sheet1!A1". + * + * @access private + * @see writeUrl() + * @param integer $row1 Start row + * @param integer $col1 Start column + * @param integer $row2 End row + * @param integer $col2 End column + * @param string $url URL string + * @param string $str Alternative label + * @param mixed $format The cell format + * @return integer + */ + function _writeUrlInternal($row1, $col1, $row2, $col2, $url, $str, $format = 0) + { + $record = 0x01B8; // Record identifier + $length = 0x00000; // Bytes to follow + + if ($format == 0) { + $format = $this->_url_format; + } + + // Strip URL type + $url = preg_replace('/^internal:/', '', $url); + + // Write the visible label + if ($str == '') { + $str = $url; + } + $str_error = $this->writeString($row1, $col1, $str, $format); + if (($str_error == -2) || ($str_error == -3)) { + return $str_error; + } + + // Pack the undocumented parts of the hyperlink stream + $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000"); + + // Pack the option flags + $options = pack("V", 0x08); + + // Convert the URL type and to a null terminated wchar string + $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY)); + $url = $url . "\0\0\0"; + + // Pack the length of the URL as chars (not wchars) + $url_len = pack("V", floor(strlen($url)/2)); + + // Calculate the data length + $length = 0x24 + strlen($url); + + // Pack the header data + $header = pack("vv", $record, $length); + $data = pack("vvvv", $row1, $row2, $col1, $col2); + + // Write the packed data + $this->_append($header . $data . + $unknown1 . $options . + $url_len . $url); + return($str_error); + } + + /** + * Write links to external directory names such as 'c:\foo.xls', + * c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'. + * + * Note: Excel writes some relative links with the $dir_long string. We ignore + * these cases for the sake of simpler code. + * + * @access private + * @see writeUrl() + * @param integer $row1 Start row + * @param integer $col1 Start column + * @param integer $row2 End row + * @param integer $col2 End column + * @param string $url URL string + * @param string $str Alternative label + * @param mixed $format The cell format + * @return integer + */ + function _writeUrlExternal($row1, $col1, $row2, $col2, $url, $str, $format = 0) + { + // Network drives are different. We will handle them separately + // MS/Novell network drives and shares start with \\ + if (preg_match('[^external:\\\\]', $url)) { + return; //($this->_writeUrlExternal_net($row1, $col1, $row2, $col2, $url, $str, $format)); + } + + $record = 0x01B8; // Record identifier + $length = 0x00000; // Bytes to follow + + if ($format == 0) { + $format = $this->_url_format; + } + + // Strip URL type and change Unix dir separator to Dos style (if needed) + // + $url = preg_replace('/^external:/', '', $url); + $url = preg_replace('/\//', "\\", $url); + + // Write the visible label + if ($str == '') { + $str = preg_replace('/\#/', ' - ', $url); + } + $str_error = $this->writeString($row1, $col1, $str, $format); + if (($str_error == -2) or ($str_error == -3)) { + return $str_error; + } + + // Determine if the link is relative or absolute: + // relative if link contains no dir separator, "somefile.xls" + // relative if link starts with up-dir, "..\..\somefile.xls" + // otherwise, absolute + + $absolute = 0x02; // Bit mask + if (!preg_match("/\\\/", $url)) { + $absolute = 0x00; + } + if (preg_match("/^\.\.\\\/", $url)) { + $absolute = 0x00; + } + $link_type = 0x01 | $absolute; + + // Determine if the link contains a sheet reference and change some of the + // parameters accordingly. + // Split the dir name and sheet name (if it exists) + /*if (preg_match("/\#/", $url)) { + list($dir_long, $sheet) = split("\#", $url); + } else { + $dir_long = $url; + } + + if (isset($sheet)) { + $link_type |= 0x08; + $sheet_len = pack("V", strlen($sheet) + 0x01); + $sheet = join("\0", split('', $sheet)); + $sheet .= "\0\0\0"; + } else { + $sheet_len = ''; + $sheet = ''; + }*/ + $dir_long = $url; + if (preg_match("/\#/", $url)) { + $link_type |= 0x08; + } + + + + // Pack the link type + $link_type = pack("V", $link_type); + + // Calculate the up-level dir count e.g.. (..\..\..\ == 3) + $up_count = preg_match_all("/\.\.\\\/", $dir_long, $useless); + $up_count = pack("v", $up_count); + + // Store the short dos dir name (null terminated) + $dir_short = preg_replace("/\.\.\\\/", '', $dir_long) . "\0"; + + // Store the long dir name as a wchar string (non-null terminated) + //$dir_long = join("\0", split('', $dir_long)); + $dir_long = $dir_long . "\0"; + + // Pack the lengths of the dir strings + $dir_short_len = pack("V", strlen($dir_short) ); + $dir_long_len = pack("V", strlen($dir_long) ); + $stream_len = pack("V", 0);//strlen($dir_long) + 0x06); + + // Pack the undocumented parts of the hyperlink stream + $unknown1 = pack("H*",'D0C9EA79F9BACE118C8200AA004BA90B02000000' ); + $unknown2 = pack("H*",'0303000000000000C000000000000046' ); + $unknown3 = pack("H*",'FFFFADDE000000000000000000000000000000000000000'); + $unknown4 = pack("v", 0x03 ); + + // Pack the main data stream + $data = pack("vvvv", $row1, $row2, $col1, $col2) . + $unknown1 . + $link_type . + $unknown2 . + $up_count . + $dir_short_len. + $dir_short . + $unknown3 . + $stream_len ;/*. + $dir_long_len . + $unknown4 . + $dir_long . + $sheet_len . + $sheet ;*/ + + // Pack the header data + $length = strlen($data); + $header = pack("vv", $record, $length); + + // Write the packed data + $this->_append($header. $data); + return($str_error); + } + + + /** + * This method is used to set the height and format for a row. + * + * @access public + * @param integer $row The row to set + * @param integer $height Height we are giving to the row. + * Use null to set XF without setting height + * @param mixed $format XF format we are giving to the row + * @param bool $hidden The optional hidden attribute + * @param integer $level The optional outline level for row, in range [0,7] + */ + function setRow($row, $height, $format = 0, $hidden = false, $level = 0) + { + $record = 0x0208; // Record identifier + $length = 0x0010; // Number of bytes to follow + + $colMic = 0x0000; // First defined column + $colMac = 0x0000; // Last defined column + $irwMac = 0x0000; // Used by Excel to optimise loading + $reserved = 0x0000; // Reserved + $grbit = 0x0000; // Option flags + $ixfe = $this->_XF($format); // XF index + + // set _row_sizes so _sizeRow() can use it + $this->_row_sizes[$row] = $height; + + // Use setRow($row, null, $XF) to set XF format without setting height + if ($height != null) { + $miyRw = $height * 20; // row height + } else { + $miyRw = 0xff; // default row height is 256 + } + + $level = max(0, min($level, 7)); // level should be between 0 and 7 + $this->_outline_row_level = max($level, $this->_outline_row_level); + + + // Set the options flags. fUnsynced is used to show that the font and row + // heights are not compatible. This is usually the case for WriteExcel. + // The collapsed flag 0x10 doesn't seem to be used to indicate that a row + // is collapsed. Instead it is used to indicate that the previous row is + // collapsed. The zero height flag, 0x20, is used to collapse a row. + + $grbit |= $level; + if ($hidden) { + $grbit |= 0x0020; + } + $grbit |= 0x0040; // fUnsynced + if ($format) { + $grbit |= 0x0080; + } + $grbit |= 0x0100; + + $header = pack("vv", $record, $length); + $data = pack("vvvvvvvv", $row, $colMic, $colMac, $miyRw, + $irwMac,$reserved, $grbit, $ixfe); + $this->_append($header.$data); + } + + /** + * Writes Excel DIMENSIONS to define the area in which there is data. + * + * @access private + */ + function _storeDimensions() + { + $record = 0x0200; // Record identifier + $row_min = $this->_dim_rowmin; // First row + $row_max = $this->_dim_rowmax + 1; // Last row plus 1 + $col_min = $this->_dim_colmin; // First column + $col_max = $this->_dim_colmax + 1; // Last column plus 1 + $reserved = 0x0000; // Reserved by Excel + + if ($this->_BIFF_version == 0x0500) { + $length = 0x000A; // Number of bytes to follow + $data = pack("vvvvv", $row_min, $row_max, + $col_min, $col_max, $reserved); + } elseif ($this->_BIFF_version == 0x0600) { + $length = 0x000E; + $data = pack("VVvvv", $row_min, $row_max, + $col_min, $col_max, $reserved); + } + $header = pack("vv", $record, $length); + $this->_prepend($header.$data); + } + + /** + * Write BIFF record Window2. + * + * @access private + */ + function _storeWindow2() + { + $record = 0x023E; // Record identifier + if ($this->_BIFF_version == 0x0500) { + $length = 0x000A; // Number of bytes to follow + } elseif ($this->_BIFF_version == 0x0600) { + $length = 0x0012; + } + + $grbit = 0x00B6; // Option flags + $rwTop = 0x0000; // Top row visible in window + $colLeft = 0x0000; // Leftmost column visible in window + + + // The options flags that comprise $grbit + $fDspFmla = 0; // 0 - bit + $fDspGrid = $this->_screen_gridlines; // 1 + $fDspRwCol = 1; // 2 + $fFrozen = $this->_frozen; // 3 + $fDspZeros = 1; // 4 + $fDefaultHdr = 1; // 5 + $fArabic = 0; // 6 + $fDspGuts = $this->_outline_on; // 7 + $fFrozenNoSplit = 0; // 0 - bit + $fSelected = $this->selected; // 1 + $fPaged = 1; // 2 + + $grbit = $fDspFmla; + $grbit |= $fDspGrid << 1; + $grbit |= $fDspRwCol << 2; + $grbit |= $fFrozen << 3; + $grbit |= $fDspZeros << 4; + $grbit |= $fDefaultHdr << 5; + $grbit |= $fArabic << 6; + $grbit |= $fDspGuts << 7; + $grbit |= $fFrozenNoSplit << 8; + $grbit |= $fSelected << 9; + $grbit |= $fPaged << 10; + + $header = pack("vv", $record, $length); + $data = pack("vvv", $grbit, $rwTop, $colLeft); + // FIXME !!! + if ($this->_BIFF_version == 0x0500) { + $rgbHdr = 0x00000000; // Row/column heading and gridline color + $data .= pack("V", $rgbHdr); + } elseif ($this->_BIFF_version == 0x0600) { + $rgbHdr = 0x0040; // Row/column heading and gridline color index + $zoom_factor_page_break = 0x0000; + $zoom_factor_normal = 0x0000; + $data .= pack("vvvvV", $rgbHdr, 0x0000, $zoom_factor_page_break, $zoom_factor_normal, 0x00000000); + } + $this->_append($header.$data); + } + + /** + * Write BIFF record DEFCOLWIDTH if COLINFO records are in use. + * + * @access private + */ + function _storeDefcol() + { + $record = 0x0055; // Record identifier + $length = 0x0002; // Number of bytes to follow + $colwidth = 0x0008; // Default column width + + $header = pack("vv", $record, $length); + $data = pack("v", $colwidth); + $this->_prepend($header . $data); + } + + /** + * Write BIFF record COLINFO to define column widths + * + * Note: The SDK says the record length is 0x0B but Excel writes a 0x0C + * length record. + * + * @access private + * @param array $col_array This is the only parameter received and is composed of the following: + * 0 => First formatted column, + * 1 => Last formatted column, + * 2 => Col width (8.43 is Excel default), + * 3 => The optional XF format of the column, + * 4 => Option flags. + * 5 => Optional outline level + */ + function _storeColinfo($col_array) + { + if (isset($col_array[0])) { + $colFirst = $col_array[0]; + } + if (isset($col_array[1])) { + $colLast = $col_array[1]; + } + if (isset($col_array[2])) { + $coldx = $col_array[2]; + } else { + $coldx = 8.43; + } + if (isset($col_array[3])) { + $format = $col_array[3]; + } else { + $format = 0; + } + if (isset($col_array[4])) { + $grbit = $col_array[4]; + } else { + $grbit = 0; + } + if (isset($col_array[5])) { + $level = $col_array[5]; + } else { + $level = 0; + } + $record = 0x007D; // Record identifier + $length = 0x000B; // Number of bytes to follow + + $coldx += 0.72; // Fudge. Excel subtracts 0.72 !? + $coldx *= 256; // Convert to units of 1/256 of a char + + $ixfe = $this->_XF($format); + $reserved = 0x00; // Reserved + + $level = max(0, min($level, 7)); + $grbit |= $level << 8; + + $header = pack("vv", $record, $length); + $data = pack("vvvvvC", $colFirst, $colLast, $coldx, + $ixfe, $grbit, $reserved); + $this->_prepend($header.$data); + } + + /** + * Write BIFF record SELECTION. + * + * @access private + * @param array $array array containing ($rwFirst,$colFirst,$rwLast,$colLast) + * @see setSelection() + */ + function _storeSelection($array) + { + list($rwFirst,$colFirst,$rwLast,$colLast) = $array; + $record = 0x001D; // Record identifier + $length = 0x000F; // Number of bytes to follow + + $pnn = $this->_active_pane; // Pane position + $rwAct = $rwFirst; // Active row + $colAct = $colFirst; // Active column + $irefAct = 0; // Active cell ref + $cref = 1; // Number of refs + + if (!isset($rwLast)) { + $rwLast = $rwFirst; // Last row in reference + } + if (!isset($colLast)) { + $colLast = $colFirst; // Last col in reference + } + + // Swap last row/col for first row/col as necessary + if ($rwFirst > $rwLast) { + list($rwFirst, $rwLast) = array($rwLast, $rwFirst); + } + + if ($colFirst > $colLast) { + list($colFirst, $colLast) = array($colLast, $colFirst); + } + + $header = pack("vv", $record, $length); + $data = pack("CvvvvvvCC", $pnn, $rwAct, $colAct, + $irefAct, $cref, + $rwFirst, $rwLast, + $colFirst, $colLast); + $this->_append($header . $data); + } + + /** + * Store the MERGEDCELLS record for all ranges of merged cells + * + * @access private + */ + function _storeMergedCells() + { + // if there are no merged cell ranges set, return + if (count($this->_merged_ranges) == 0) { + return; + } + $record = 0x00E5; + $length = 2 + count($this->_merged_ranges) * 8; + + $header = pack('vv', $record, $length); + $data = pack('v', count($this->_merged_ranges)); + foreach ($this->_merged_ranges as $range) { + $data .= pack('vvvv', $range[0], $range[2], $range[1], $range[3]); + } + $this->_append($header . $data); + } + + /** + * Write BIFF record EXTERNCOUNT to indicate the number of external sheet + * references in a worksheet. + * + * Excel only stores references to external sheets that are used in formulas. + * For simplicity we store references to all the sheets in the workbook + * regardless of whether they are used or not. This reduces the overall + * complexity and eliminates the need for a two way dialogue between the formula + * parser the worksheet objects. + * + * @access private + * @param integer $count The number of external sheet references in this worksheet + */ + function _storeExterncount($count) + { + $record = 0x0016; // Record identifier + $length = 0x0002; // Number of bytes to follow + + $header = pack("vv", $record, $length); + $data = pack("v", $count); + $this->_prepend($header . $data); + } + + /** + * Writes the Excel BIFF EXTERNSHEET record. These references are used by + * formulas. A formula references a sheet name via an index. Since we store a + * reference to all of the external worksheets the EXTERNSHEET index is the same + * as the worksheet index. + * + * @access private + * @param string $sheetname The name of a external worksheet + */ + function _storeExternsheet($sheetname) + { + $record = 0x0017; // Record identifier + + // References to the current sheet are encoded differently to references to + // external sheets. + // + if ($this->name == $sheetname) { + $sheetname = ''; + $length = 0x02; // The following 2 bytes + $cch = 1; // The following byte + $rgch = 0x02; // Self reference + } else { + $length = 0x02 + strlen($sheetname); + $cch = strlen($sheetname); + $rgch = 0x03; // Reference to a sheet in the current workbook + } + + $header = pack("vv", $record, $length); + $data = pack("CC", $cch, $rgch); + $this->_prepend($header . $data . $sheetname); + } + + /** + * Writes the Excel BIFF PANE record. + * The panes can either be frozen or thawed (unfrozen). + * Frozen panes are specified in terms of an integer number of rows and columns. + * Thawed panes are specified in terms of Excel's units for rows and columns. + * + * @access private + * @param array $panes This is the only parameter received and is composed of the following: + * 0 => Vertical split position, + * 1 => Horizontal split position + * 2 => Top row visible + * 3 => Leftmost column visible + * 4 => Active pane + */ + function _storePanes($panes) + { + $y = $panes[0]; + $x = $panes[1]; + $rwTop = $panes[2]; + $colLeft = $panes[3]; + if (count($panes) > 4) { // if Active pane was received + $pnnAct = $panes[4]; + } else { + $pnnAct = null; + } + $record = 0x0041; // Record identifier + $length = 0x000A; // Number of bytes to follow + + // Code specific to frozen or thawed panes. + if ($this->_frozen) { + // Set default values for $rwTop and $colLeft + if (!isset($rwTop)) { + $rwTop = $y; + } + if (!isset($colLeft)) { + $colLeft = $x; + } + } else { + // Set default values for $rwTop and $colLeft + if (!isset($rwTop)) { + $rwTop = 0; + } + if (!isset($colLeft)) { + $colLeft = 0; + } + + // Convert Excel's row and column units to the internal units. + // The default row height is 12.75 + // The default column width is 8.43 + // The following slope and intersection values were interpolated. + // + $y = 20*$y + 255; + $x = 113.879*$x + 390; + } + + + // Determine which pane should be active. There is also the undocumented + // option to override this should it be necessary: may be removed later. + // + if (!isset($pnnAct)) { + if ($x != 0 && $y != 0) { + $pnnAct = 0; // Bottom right + } + if ($x != 0 && $y == 0) { + $pnnAct = 1; // Top right + } + if ($x == 0 && $y != 0) { + $pnnAct = 2; // Bottom left + } + if ($x == 0 && $y == 0) { + $pnnAct = 3; // Top left + } + } + + $this->_active_pane = $pnnAct; // Used in _storeSelection + + $header = pack("vv", $record, $length); + $data = pack("vvvvv", $x, $y, $rwTop, $colLeft, $pnnAct); + $this->_append($header . $data); + } + + /** + * Store the page setup SETUP BIFF record. + * + * @access private + */ + function _storeSetup() + { + $record = 0x00A1; // Record identifier + $length = 0x0022; // Number of bytes to follow + + $iPaperSize = $this->_paper_size; // Paper size + $iScale = $this->_print_scale; // Print scaling factor + $iPageStart = 0x01; // Starting page number + $iFitWidth = $this->_fit_width; // Fit to number of pages wide + $iFitHeight = $this->_fit_height; // Fit to number of pages high + $grbit = 0x00; // Option flags + $iRes = 0x0258; // Print resolution + $iVRes = 0x0258; // Vertical print resolution + $numHdr = $this->_margin_head; // Header Margin + $numFtr = $this->_margin_foot; // Footer Margin + $iCopies = 0x01; // Number of copies + + $fLeftToRight = 0x0; // Print over then down + $fLandscape = $this->_orientation; // Page orientation + $fNoPls = 0x0; // Setup not read from printer + $fNoColor = 0x0; // Print black and white + $fDraft = 0x0; // Print draft quality + $fNotes = 0x0; // Print notes + $fNoOrient = 0x0; // Orientation not set + $fUsePage = 0x0; // Use custom starting page + + $grbit = $fLeftToRight; + $grbit |= $fLandscape << 1; + $grbit |= $fNoPls << 2; + $grbit |= $fNoColor << 3; + $grbit |= $fDraft << 4; + $grbit |= $fNotes << 5; + $grbit |= $fNoOrient << 6; + $grbit |= $fUsePage << 7; + + $numHdr = pack("d", $numHdr); + $numFtr = pack("d", $numFtr); + if ($this->_byte_order) { // if it's Big Endian + $numHdr = strrev($numHdr); + $numFtr = strrev($numFtr); + } + + $header = pack("vv", $record, $length); + $data1 = pack("vvvvvvvv", $iPaperSize, + $iScale, + $iPageStart, + $iFitWidth, + $iFitHeight, + $grbit, + $iRes, + $iVRes); + $data2 = $numHdr.$numFtr; + $data3 = pack("v", $iCopies); + $this->_prepend($header . $data1 . $data2 . $data3); + } + + /** + * Store the header caption BIFF record. + * + * @access private + */ + function _storeHeader() + { + $record = 0x0014; // Record identifier + + $str = $this->_header; // header string + $cch = strlen($str); // Length of header string + if ($this->_BIFF_version == 0x0600) { + $encoding = 0x0; // TODO: Unicode support + $length = 3 + $cch; // Bytes to follow + } else { + $length = 1 + $cch; // Bytes to follow + } + + $header = pack("vv", $record, $length); + if ($this->_BIFF_version == 0x0600) { + $data = pack("vC", $cch, $encoding); + } else { + $data = pack("C", $cch); + } + + $this->_prepend($header.$data.$str); + } + + /** + * Store the footer caption BIFF record. + * + * @access private + */ + function _storeFooter() + { + $record = 0x0015; // Record identifier + + $str = $this->_footer; // Footer string + $cch = strlen($str); // Length of footer string + if ($this->_BIFF_version == 0x0600) { + $encoding = 0x0; // TODO: Unicode support + $length = 3 + $cch; // Bytes to follow + } else { + $length = 1 + $cch; + } + + $header = pack("vv", $record, $length); + if ($this->_BIFF_version == 0x0600) { + $data = pack("vC", $cch, $encoding); + } else { + $data = pack("C", $cch); + } + + $this->_prepend($header . $data . $str); + } + + /** + * Store the horizontal centering HCENTER BIFF record. + * + * @access private + */ + function _storeHcenter() + { + $record = 0x0083; // Record identifier + $length = 0x0002; // Bytes to follow + + $fHCenter = $this->_hcenter; // Horizontal centering + + $header = pack("vv", $record, $length); + $data = pack("v", $fHCenter); + + $this->_prepend($header.$data); + } + + /** + * Store the vertical centering VCENTER BIFF record. + * + * @access private + */ + function _storeVcenter() + { + $record = 0x0084; // Record identifier + $length = 0x0002; // Bytes to follow + + $fVCenter = $this->_vcenter; // Horizontal centering + + $header = pack("vv", $record, $length); + $data = pack("v", $fVCenter); + $this->_prepend($header . $data); + } + + /** + * Store the LEFTMARGIN BIFF record. + * + * @access private + */ + function _storeMarginLeft() + { + $record = 0x0026; // Record identifier + $length = 0x0008; // Bytes to follow + + $margin = $this->_margin_left; // Margin in inches + + $header = pack("vv", $record, $length); + $data = pack("d", $margin); + if ($this->_byte_order) { // if it's Big Endian + $data = strrev($data); + } + + $this->_prepend($header . $data); + } + + /** + * Store the RIGHTMARGIN BIFF record. + * + * @access private + */ + function _storeMarginRight() + { + $record = 0x0027; // Record identifier + $length = 0x0008; // Bytes to follow + + $margin = $this->_margin_right; // Margin in inches + + $header = pack("vv", $record, $length); + $data = pack("d", $margin); + if ($this->_byte_order) { // if it's Big Endian + $data = strrev($data); + } + + $this->_prepend($header . $data); + } + + /** + * Store the TOPMARGIN BIFF record. + * + * @access private + */ + function _storeMarginTop() + { + $record = 0x0028; // Record identifier + $length = 0x0008; // Bytes to follow + + $margin = $this->_margin_top; // Margin in inches + + $header = pack("vv", $record, $length); + $data = pack("d", $margin); + if ($this->_byte_order) { // if it's Big Endian + $data = strrev($data); + } + + $this->_prepend($header . $data); + } + + /** + * Store the BOTTOMMARGIN BIFF record. + * + * @access private + */ + function _storeMarginBottom() + { + $record = 0x0029; // Record identifier + $length = 0x0008; // Bytes to follow + + $margin = $this->_margin_bottom; // Margin in inches + + $header = pack("vv", $record, $length); + $data = pack("d", $margin); + if ($this->_byte_order) { // if it's Big Endian + $data = strrev($data); + } + + $this->_prepend($header . $data); + } + + /** + * Merges the area given by its arguments. + * This is an Excel97/2000 method. It is required to perform more complicated + * merging than the normal setAlign('merge'). + * + * @access public + * @param integer $first_row First row of the area to merge + * @param integer $first_col First column of the area to merge + * @param integer $last_row Last row of the area to merge + * @param integer $last_col Last column of the area to merge + */ + function mergeCells($first_row, $first_col, $last_row, $last_col) + { + $record = 0x00E5; // Record identifier + $length = 0x000A; // Bytes to follow + $cref = 1; // Number of refs + + // Swap last row/col for first row/col as necessary + if ($first_row > $last_row) { + list($first_row, $last_row) = array($last_row, $first_row); + } + + if ($first_col > $last_col) { + list($first_col, $last_col) = array($last_col, $first_col); + } + + $header = pack("vv", $record, $length); + $data = pack("vvvvv", $cref, $first_row, $last_row, + $first_col, $last_col); + + $this->_append($header.$data); + } + + /** + * Write the PRINTHEADERS BIFF record. + * + * @access private + */ + function _storePrintHeaders() + { + $record = 0x002a; // Record identifier + $length = 0x0002; // Bytes to follow + + $fPrintRwCol = $this->_print_headers; // Boolean flag + + $header = pack("vv", $record, $length); + $data = pack("v", $fPrintRwCol); + $this->_prepend($header . $data); + } + + /** + * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the + * GRIDSET record. + * + * @access private + */ + function _storePrintGridlines() + { + $record = 0x002b; // Record identifier + $length = 0x0002; // Bytes to follow + + $fPrintGrid = $this->_print_gridlines; // Boolean flag + + $header = pack("vv", $record, $length); + $data = pack("v", $fPrintGrid); + $this->_prepend($header . $data); + } + + /** + * Write the GRIDSET BIFF record. Must be used in conjunction with the + * PRINTGRIDLINES record. + * + * @access private + */ + function _storeGridset() + { + $record = 0x0082; // Record identifier + $length = 0x0002; // Bytes to follow + + $fGridSet = !($this->_print_gridlines); // Boolean flag + + $header = pack("vv", $record, $length); + $data = pack("v", $fGridSet); + $this->_prepend($header . $data); + } + + /** + * Write the GUTS BIFF record. This is used to configure the gutter margins + * where Excel outline symbols are displayed. The visibility of the gutters is + * controlled by a flag in WSBOOL. + * + * @see _storeWsbool() + * @access private + */ + function _storeGuts() + { + $record = 0x0080; // Record identifier + $length = 0x0008; // Bytes to follow + + $dxRwGut = 0x0000; // Size of row gutter + $dxColGut = 0x0000; // Size of col gutter + + $row_level = $this->_outline_row_level; + $col_level = 0; + + // Calculate the maximum column outline level. The equivalent calculation + // for the row outline level is carried out in setRow(). + $colcount = count($this->_colinfo); + for ($i = 0; $i < $colcount; $i++) { + // Skip cols without outline level info. + if (count($col_level) >= 6) { + $col_level = max($this->_colinfo[$i][5], $col_level); + } + } + + // Set the limits for the outline levels (0 <= x <= 7). + $col_level = max(0, min($col_level, 7)); + + // The displayed level is one greater than the max outline levels + if ($row_level) { + $row_level++; + } + if ($col_level) { + $col_level++; + } + + $header = pack("vv", $record, $length); + $data = pack("vvvv", $dxRwGut, $dxColGut, $row_level, $col_level); + + $this->_prepend($header.$data); + } + + + /** + * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction + * with the SETUP record. + * + * @access private + */ + function _storeWsbool() + { + $record = 0x0081; // Record identifier + $length = 0x0002; // Bytes to follow + $grbit = 0x0000; + + // The only option that is of interest is the flag for fit to page. So we + // set all the options in one go. + // + /*if ($this->_fit_page) { + $grbit = 0x05c1; + } else { + $grbit = 0x04c1; + }*/ + // Set the option flags + $grbit |= 0x0001; // Auto page breaks visible + if ($this->_outline_style) { + $grbit |= 0x0020; // Auto outline styles + } + if ($this->_outline_below) { + $grbit |= 0x0040; // Outline summary below + } + if ($this->_outline_right) { + $grbit |= 0x0080; // Outline summary right + } + if ($this->_fit_page) { + $grbit |= 0x0100; // Page setup fit to page + } + if ($this->_outline_on) { + $grbit |= 0x0400; // Outline symbols displayed + } + + $header = pack("vv", $record, $length); + $data = pack("v", $grbit); + $this->_prepend($header . $data); + } + + /** + * Write the HORIZONTALPAGEBREAKS BIFF record. + * + * @access private + */ + function _storeHbreak() + { + // Return if the user hasn't specified pagebreaks + if (empty($this->_hbreaks)) { + return; + } + + // Sort and filter array of page breaks + $breaks = $this->_hbreaks; + sort($breaks, SORT_NUMERIC); + if ($breaks[0] == 0) { // don't use first break if it's 0 + array_shift($breaks); + } + + $record = 0x001b; // Record identifier + $cbrk = count($breaks); // Number of page breaks + if ($this->_BIFF_version == 0x0600) { + $length = 2 + 6*$cbrk; // Bytes to follow + } else { + $length = 2 + 2*$cbrk; // Bytes to follow + } + + $header = pack("vv", $record, $length); + $data = pack("v", $cbrk); + + // Append each page break + foreach ($breaks as $break) { + if ($this->_BIFF_version == 0x0600) { + $data .= pack("vvv", $break, 0x0000, 0x00ff); + } else { + $data .= pack("v", $break); + } + } + + $this->_prepend($header.$data); + } + + + /** + * Write the VERTICALPAGEBREAKS BIFF record. + * + * @access private + */ + function _storeVbreak() + { + // Return if the user hasn't specified pagebreaks + if (empty($this->_vbreaks)) { + return; + } + + // 1000 vertical pagebreaks appears to be an internal Excel 5 limit. + // It is slightly higher in Excel 97/200, approx. 1026 + $breaks = array_slice($this->_vbreaks,0,1000); + + // Sort and filter array of page breaks + sort($breaks, SORT_NUMERIC); + if ($breaks[0] == 0) { // don't use first break if it's 0 + array_shift($breaks); + } + + $record = 0x001a; // Record identifier + $cbrk = count($breaks); // Number of page breaks + if ($this->_BIFF_version == 0x0600) { + $length = 2 + 6*$cbrk; // Bytes to follow + } else { + $length = 2 + 2*$cbrk; // Bytes to follow + } + + $header = pack("vv", $record, $length); + $data = pack("v", $cbrk); + + // Append each page break + foreach ($breaks as $break) { + if ($this->_BIFF_version == 0x0600) { + $data .= pack("vvv", $break, 0x0000, 0xffff); + } else { + $data .= pack("v", $break); + } + } + + $this->_prepend($header . $data); + } + + /** + * Set the Biff PROTECT record to indicate that the worksheet is protected. + * + * @access private + */ + function _storeProtect() + { + // Exit unless sheet protection has been specified + if ($this->_protect == 0) { + return; + } + + $record = 0x0012; // Record identifier + $length = 0x0002; // Bytes to follow + + $fLock = $this->_protect; // Worksheet is protected + + $header = pack("vv", $record, $length); + $data = pack("v", $fLock); + + $this->_prepend($header.$data); + } + + /** + * Write the worksheet PASSWORD record. + * + * @access private + */ + function _storePassword() + { + // Exit unless sheet protection and password have been specified + if (($this->_protect == 0) || (!isset($this->_password))) { + return; + } + + $record = 0x0013; // Record identifier + $length = 0x0002; // Bytes to follow + + $wPassword = $this->_password; // Encoded password + + $header = pack("vv", $record, $length); + $data = pack("v", $wPassword); + + $this->_prepend($header . $data); + } + + + /** + * Insert a 24bit bitmap image in a worksheet. + * + * @access public + * @param integer $row The row we are going to insert the bitmap into + * @param integer $col The column we are going to insert the bitmap into + * @param string $bitmap The bitmap filename + * @param integer $x The horizontal position (offset) of the image inside the cell. + * @param integer $y The vertical position (offset) of the image inside the cell. + * @param integer $scale_x The horizontal scale + * @param integer $scale_y The vertical scale + */ + function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1) + { + $bitmap_array = $this->_processBitmap($bitmap); + if ($this->isError($bitmap_array)) { + $this->writeString($row, $col, $bitmap_array->getMessage()); + return; + } + list($width, $height, $size, $data) = $bitmap_array; //$this->_processBitmap($bitmap); + + // Scale the frame of the image. + $width *= $scale_x; + $height *= $scale_y; + + // Calculate the vertices of the image and write the OBJ record + $this->_positionImage($col, $row, $x, $y, $width, $height); + + // Write the IMDATA record to store the bitmap data + $record = 0x007f; + $length = 8 + $size; + $cf = 0x09; + $env = 0x01; + $lcb = $size; + + $header = pack("vvvvV", $record, $length, $cf, $env, $lcb); + $this->_append($header.$data); + } + + /** + * Calculate the vertices that define the position of the image as required by + * the OBJ record. + * + * +------------+------------+ + * | A | B | + * +-----+------------+------------+ + * | |(x1,y1) | | + * | 1 |(A1)._______|______ | + * | | | | | + * | | | | | + * +-----+----| BITMAP |-----+ + * | | | | | + * | 2 | |______________. | + * | | | (B2)| + * | | | (x2,y2)| + * +---- +------------+------------+ + * + * Example of a bitmap that covers some of the area from cell A1 to cell B2. + * + * Based on the width and height of the bitmap we need to calculate 8 vars: + * $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2. + * The width and height of the cells are also variable and have to be taken into + * account. + * The values of $col_start and $row_start are passed in from the calling + * function. The values of $col_end and $row_end are calculated by subtracting + * the width and height of the bitmap from the width and height of the + * underlying cells. + * The vertices are expressed as a percentage of the underlying cell width as + * follows (rhs values are in pixels): + * + * x1 = X / W *1024 + * y1 = Y / H *256 + * x2 = (X-1) / W *1024 + * y2 = (Y-1) / H *256 + * + * Where: X is distance from the left side of the underlying cell + * Y is distance from the top of the underlying cell + * W is the width of the cell + * H is the height of the cell + * + * @access private + * @note the SDK incorrectly states that the height should be expressed as a + * percentage of 1024. + * @param integer $col_start Col containing upper left corner of object + * @param integer $row_start Row containing top left corner of object + * @param integer $x1 Distance to left side of object + * @param integer $y1 Distance to top of object + * @param integer $width Width of image frame + * @param integer $height Height of image frame + */ + function _positionImage($col_start, $row_start, $x1, $y1, $width, $height) + { + // Initialise end cell to the same as the start cell + $col_end = $col_start; // Col containing lower right corner of object + $row_end = $row_start; // Row containing bottom right corner of object + + // Zero the specified offset if greater than the cell dimensions + if ($x1 >= $this->_sizeCol($col_start)) { + $x1 = 0; + } + if ($y1 >= $this->_sizeRow($row_start)) { + $y1 = 0; + } + + $width = $width + $x1 -1; + $height = $height + $y1 -1; + + // Subtract the underlying cell widths to find the end cell of the image + while ($width >= $this->_sizeCol($col_end)) { + $width -= $this->_sizeCol($col_end); + $col_end++; + } + + // Subtract the underlying cell heights to find the end cell of the image + while ($height >= $this->_sizeRow($row_end)) { + $height -= $this->_sizeRow($row_end); + $row_end++; + } + + // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell + // with zero eight or width. + // + if ($this->_sizeCol($col_start) == 0) { + return; + } + if ($this->_sizeCol($col_end) == 0) { + return; + } + if ($this->_sizeRow($row_start) == 0) { + return; + } + if ($this->_sizeRow($row_end) == 0) { + return; + } + + // Convert the pixel values to the percentage value expected by Excel + $x1 = $x1 / $this->_sizeCol($col_start) * 1024; + $y1 = $y1 / $this->_sizeRow($row_start) * 256; + $x2 = $width / $this->_sizeCol($col_end) * 1024; // Distance to right side of object + $y2 = $height / $this->_sizeRow($row_end) * 256; // Distance to bottom of object + + $this->_storeObjPicture($col_start, $x1, + $row_start, $y1, + $col_end, $x2, + $row_end, $y2); + } + + /** + * Convert the width of a cell from user's units to pixels. By interpolation + * the relationship is: y = 7x +5. If the width hasn't been set by the user we + * use the default value. If the col is hidden we use a value of zero. + * + * @access private + * @param integer $col The column + * @return integer The width in pixels + */ + function _sizeCol($col) + { + // Look up the cell value to see if it has been changed + if (isset($this->col_sizes[$col])) { + if ($this->col_sizes[$col] == 0) { + return(0); + } else { + return(floor(7 * $this->col_sizes[$col] + 5)); + } + } else { + return(64); + } + } + + /** + * Convert the height of a cell from user's units to pixels. By interpolation + * the relationship is: y = 4/3x. If the height hasn't been set by the user we + * use the default value. If the row is hidden we use a value of zero. (Not + * possible to hide row yet). + * + * @access private + * @param integer $row The row + * @return integer The width in pixels + */ + function _sizeRow($row) + { + // Look up the cell value to see if it has been changed + if (isset($this->_row_sizes[$row])) { + if ($this->_row_sizes[$row] == 0) { + return(0); + } else { + return(floor(4/3 * $this->_row_sizes[$row])); + } + } else { + return(17); + } + } + + /** + * Store the OBJ record that precedes an IMDATA record. This could be generalise + * to support other Excel objects. + * + * @access private + * @param integer $colL Column containing upper left corner of object + * @param integer $dxL Distance from left side of cell + * @param integer $rwT Row containing top left corner of object + * @param integer $dyT Distance from top of cell + * @param integer $colR Column containing lower right corner of object + * @param integer $dxR Distance from right of cell + * @param integer $rwB Row containing bottom right corner of object + * @param integer $dyB Distance from bottom of cell + */ + function _storeObjPicture($colL,$dxL,$rwT,$dyT,$colR,$dxR,$rwB,$dyB) + { + $record = 0x005d; // Record identifier + $length = 0x003c; // Bytes to follow + + $cObj = 0x0001; // Count of objects in file (set to 1) + $OT = 0x0008; // Object type. 8 = Picture + $id = 0x0001; // Object ID + $grbit = 0x0614; // Option flags + + $cbMacro = 0x0000; // Length of FMLA structure + $Reserved1 = 0x0000; // Reserved + $Reserved2 = 0x0000; // Reserved + + $icvBack = 0x09; // Background colour + $icvFore = 0x09; // Foreground colour + $fls = 0x00; // Fill pattern + $fAuto = 0x00; // Automatic fill + $icv = 0x08; // Line colour + $lns = 0xff; // Line style + $lnw = 0x01; // Line weight + $fAutoB = 0x00; // Automatic border + $frs = 0x0000; // Frame style + $cf = 0x0009; // Image format, 9 = bitmap + $Reserved3 = 0x0000; // Reserved + $cbPictFmla = 0x0000; // Length of FMLA structure + $Reserved4 = 0x0000; // Reserved + $grbit2 = 0x0001; // Option flags + $Reserved5 = 0x0000; // Reserved + + + $header = pack("vv", $record, $length); + $data = pack("V", $cObj); + $data .= pack("v", $OT); + $data .= pack("v", $id); + $data .= pack("v", $grbit); + $data .= pack("v", $colL); + $data .= pack("v", $dxL); + $data .= pack("v", $rwT); + $data .= pack("v", $dyT); + $data .= pack("v", $colR); + $data .= pack("v", $dxR); + $data .= pack("v", $rwB); + $data .= pack("v", $dyB); + $data .= pack("v", $cbMacro); + $data .= pack("V", $Reserved1); + $data .= pack("v", $Reserved2); + $data .= pack("C", $icvBack); + $data .= pack("C", $icvFore); + $data .= pack("C", $fls); + $data .= pack("C", $fAuto); + $data .= pack("C", $icv); + $data .= pack("C", $lns); + $data .= pack("C", $lnw); + $data .= pack("C", $fAutoB); + $data .= pack("v", $frs); + $data .= pack("V", $cf); + $data .= pack("v", $Reserved3); + $data .= pack("v", $cbPictFmla); + $data .= pack("v", $Reserved4); + $data .= pack("v", $grbit2); + $data .= pack("V", $Reserved5); + + $this->_append($header . $data); + } + + /** + * Convert a 24 bit bitmap into the modified internal format used by Windows. + * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the + * MSDN library. + * + * @access private + * @param string $bitmap The bitmap to process + * @return array Array with data and properties of the bitmap + */ + function _processBitmap($bitmap) + { + // Open file. + $bmp_fd = @fopen($bitmap,"rb"); + if (!$bmp_fd) { + $this->raiseError("Couldn't import $bitmap"); + } + + // Slurp the file into a string. + $data = fread($bmp_fd, filesize($bitmap)); + + // Check that the file is big enough to be a bitmap. + if (strlen($data) <= 0x36) { + $this->raiseError("$bitmap doesn't contain enough data.\n"); + } + + // The first 2 bytes are used to identify the bitmap. + $identity = unpack("A2ident", $data); + if ($identity['ident'] != "BM") { + $this->raiseError("$bitmap doesn't appear to be a valid bitmap image.\n"); + } + + // Remove bitmap data: ID. + $data = substr($data, 2); + + // Read and remove the bitmap size. This is more reliable than reading + // the data size at offset 0x22. + // + $size_array = unpack("Vsa", substr($data, 0, 4)); + $size = $size_array['sa']; + $data = substr($data, 4); + $size -= 0x36; // Subtract size of bitmap header. + $size += 0x0C; // Add size of BIFF header. + + // Remove bitmap data: reserved, offset, header length. + $data = substr($data, 12); + + // Read and remove the bitmap width and height. Verify the sizes. + $width_and_height = unpack("V2", substr($data, 0, 8)); + $width = $width_and_height[1]; + $height = $width_and_height[2]; + $data = substr($data, 8); + if ($width > 0xFFFF) { + $this->raiseError("$bitmap: largest image width supported is 65k.\n"); + } + if ($height > 0xFFFF) { + $this->raiseError("$bitmap: largest image height supported is 65k.\n"); + } + + // Read and remove the bitmap planes and bpp data. Verify them. + $planes_and_bitcount = unpack("v2", substr($data, 0, 4)); + $data = substr($data, 4); + if ($planes_and_bitcount[2] != 24) { // Bitcount + $this->raiseError("$bitmap isn't a 24bit true color bitmap.\n"); + } + if ($planes_and_bitcount[1] != 1) { + $this->raiseError("$bitmap: only 1 plane supported in bitmap image.\n"); + } + + // Read and remove the bitmap compression. Verify compression. + $compression = unpack("Vcomp", substr($data, 0, 4)); + $data = substr($data, 4); + + //$compression = 0; + if ($compression['comp'] != 0) { + $this->raiseError("$bitmap: compression not supported in bitmap image.\n"); + } + + // Remove bitmap data: data size, hres, vres, colours, imp. colours. + $data = substr($data, 20); + + // Add the BITMAPCOREHEADER data + $header = pack("Vvvvv", 0x000c, $width, $height, 0x01, 0x18); + $data = $header . $data; + + return (array($width, $height, $size, $data)); + } + + /** + * Store the window zoom factor. This should be a reduced fraction but for + * simplicity we will store all fractions with a numerator of 100. + * + * @access private + */ + function _storeZoom() + { + // If scale is 100 we don't need to write a record + if ($this->_zoom == 100) { + return; + } + + $record = 0x00A0; // Record identifier + $length = 0x0004; // Bytes to follow + + $header = pack("vv", $record, $length); + $data = pack("vv", $this->_zoom, 100); + $this->_append($header . $data); + } + + /** + * FIXME: add comments + */ + function setValidation($row1, $col1, $row2, $col2, &$validator) + { + $this->_dv[] = $validator->_getData() . + pack("vvvvv", 1, $row1, $row2, $col1, $col2); + } + + /** + * Store the DVAL and DV records. + * + * @access private + */ + function _storeDataValidity() + { + $record = 0x01b2; // Record identifier + $length = 0x0012; // Bytes to follow + + $grbit = 0x0002; // Prompt box at cell, no cached validity data at DV records + $horPos = 0x00000000; // Horizontal position of prompt box, if fixed position + $verPos = 0x00000000; // Vertical position of prompt box, if fixed position + $objId = 0xffffffff; // Object identifier of drop down arrow object, or -1 if not visible + + $header = pack('vv', $record, $length); + $data = pack('vVVVV', $grbit, $horPos, $verPos, $objId, + count($this->_dv)); + $this->_append($header.$data); + + $record = 0x01be; // Record identifier + foreach ($this->_dv as $dv) { + $length = strlen($dv); // Bytes to follow + $header = pack("vv", $record, $length); + $this->_append($header . $dv); + } + } +} +?> diff --git a/include/Excel/Writer.php b/include/Excel/Writer.php new file mode 100644 index 000000000..4ae1e04d2 --- /dev/null +++ b/include/Excel/Writer.php @@ -0,0 +1,103 @@ + +* +* PERL Spreadsheet::WriteExcel module. +* +* The author of the Spreadsheet::WriteExcel module is John McNamara +* +* +* I _DO_ maintain this code, and John McNamara has nothing to do with the +* porting of this code to PHP. Any questions directly related to this +* class library should be directed to me. +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + + +/** +* Class for writing Excel Spreadsheets. This class should change COMPLETELY. +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer extends Spreadsheet_Excel_Writer_Workbook +{ + /** + * The constructor. It just creates a Workbook + * + * @param string $filename The optional filename for the Workbook. + * @return Spreadsheet_Excel_Writer_Workbook The Workbook created + */ + function Spreadsheet_Excel_Writer($filename = '') + { + $this->_filename = $filename; + $this->Spreadsheet_Excel_Writer_Workbook($filename); + } + + /** + * Send HTTP headers for the Excel file. + * + * @param string $filename The filename to use for HTTP headers + * @access public + */ + function send($filename) + { + header("Content-type: application/vnd.ms-excel"); + header("Content-Disposition: attachment; filename=\"$filename\""); + header("Expires: 0"); + header("Cache-Control: must-revalidate, post-check=0,pre-check=0"); + header("Pragma: public"); + } + + /** + * Utility function for writing formulas + * Converts a cell's coordinates to the A1 format. + * + * @access public + * @static + * @param integer $row Row for the cell to convert (0-indexed). + * @param integer $col Column for the cell to convert (0-indexed). + * @return string The cell identifier in A1 format + */ + function rowcolToCell($row, $col) + { + if ($col > 255) { //maximum column value exceeded + return new PEAR_Error("Maximum column value exceeded: $col"); + } + + $int = (int)($col / 26); + $frac = $col % 26; + $chr1 = ''; + + if ($int > 0) { + $chr1 = chr(ord('A') + $int - 1); + } + + $chr2 = chr(ord('A') + $frac); + $row++; + + return $chr1 . $chr2 . $row; + } +} +?> diff --git a/include/berechtigung.class.php b/include/berechtigung.class.php new file mode 100644 index 000000000..0be0e732d --- /dev/null +++ b/include/berechtigung.class.php @@ -0,0 +1,321 @@ +conn=$conn; + $this->new=true; + } + + + /** + * Ladet die Attribute der Berechtigung aus der Datenbank. Bei Fehler ist der + * Rueckgabewert 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true=ok, false=fehler + */ + function load($id) + { + // Berechtigung holen + $sql_query="SELECT * FROM tbl_userberechtigung WHERE userberechtigung_id=$id"; + //echo $sql_query; + if(!($erg=pg_exec($this->conn, $sql_query))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + if($num_rows!=1) + { + $this->errormsg="Zuwenige oder zuviele Ergebnisse (Anzahl: $num_rows)!"; + return false; + } + $row=pg_fetch_object($erg,0); + + $this->userberechtigung_id=$row->userberechtigung_id; + $this->studiengang_kz=$row->studiengang_kz; + $this->fachbereich_id=$row->fachbereich_id; + $this->berechtigung_kurzbz=$row->berechtigung_kurzbz; + $this->uid=$row->uid; + $this->studiensemester_kurzbz=$row->studiensemester_kurzbz; + $this->start=$row->start; + $this->ende=$row->ende; + $this->art=$row->art; + $this->new=false; + return true; + } + + /** + * @return boolean true=ok, false=fehler + */ + function save() + { + // Connection holen + if (is_null($conn=$this->getConnection())) + { + return false; + } + // Daten zur Person speichern + + if (!person::save()) { + $this->errormsg.="Daten zur LVA konnten nicht gespeichert werden."; + return false; + } + if ($this->new) { + $qry="INSERT INTO tbl_lehrveranstaltung(lvnr,unr,einheit_kurzbz,". + "lektor,lehrfach_nr,studiengang_kz,fachbereich_id,semester,verband,". + "gruppe,raumtyp,raumtypalternativ,semesterstunden,stundenblockung,". + "wochenrythmus,start_kw,anmerkung)". + "values(". + "'".$this->lvnr."',". + "'".$this->unr."',". + "'".$this->einheit_kurzbz."',". + "'".$this->lektor."',". + (strlen($this->lehrfach_nr)>0?$this->lehrfach_nr:NULL).",". + (strlen($this->studiengang_kz)>0?$this->studiengang_kz:NULL).",". + (strlen($this->fachbereich_id)>0?$this->fachbereich_id:NULL).",". + (strlen($this->semester)>0?$this->semester:NULL).",". + "'".$this->verband."',". + "'".$this->gruppe."',". + (strlen($this->raumtyp)>0?"'".$this->raumtyp."'":NULL).",". + (strlen($this->raumtypalternativ)>0?"'".$this->raumtypalternativ."'":NULL).",". + (strlen($this->semesterstunden)>0?$this->semesterstunden:NULL).",". + (strlen($this->stundenblockung)>0?$this->stundenblockung:NULL).",". + (strlen($this->wochenrythmus)>0?$this->wochenrythmus:NULL).",". + (strlen($this->start_kw)>0?$this->start_kw:NULL).",". + (strlen($this->anmerkung)>0?"'".$this->anmerkung."'":NULL).",". + ")"; + } else + { + $qry="UPDATE tbl_lehrveranstaltung ". + "SET lvnr='".$this->lvnr."',". + "unr='".$this->unr."',". + "einheit_kurzbz='".$this->einheit_kurzbz."',". + "lektor='".$this->lehrfach_nr."',". + "lehrfach_nr=".(strlen($this->lehrfach_nr)>0?$this->lehrfach_nr:NULL).",". + "studiengang_kz=".(strlen($this->studiengang_kz)>0?$this->studiengang_kz:NULL).",". + "fachbereich_id=".(strlen($this->fachbereich_id)>0?$this->fachbereich_id:NULL).",". + "semester=".(strlen($this->semester)>0?$this->semester:NULL).",". + "verband='".$this->verband."',". + "gruppe='".$this->gruppe."',". + "raumtyp=".(strlen($this->raumtyp)>0?"'".$this->raumtyp."'":NULL).",". + "raumtypalternativ=".(strlen($this->raumtypalternativ)>0?"'".$this->raumtypalternativ."'":NULL).",". + "semesterstunden=".(strlen($this->semesterstunden)>0?$this->semesterstunden:NULL).",". + "stundenblockung=".(strlen($this->stundenblockung)>0?$this->stundenblockung:NULL).",". + "wochenrythmus=".(strlen($this->wochenrythmus)>0?$this->wochenrythmus:NULL).",". + "start_kw=".(strlen($this->start_kw)>0?$this->start_kw:NULL).",". + "anmerkung=".(strlen($this->anmerkung)>0?"'".$this->anmerkung."'":NULL). + " WHERE lehrveranstaltung_id='".$this->lehrveranstaltung_id."'"; + } + //echo "
".$qry; + if(!@pg_query($conn, $qry)) + { + $this->errormsg=pg_errormessage($conn); + return false; + } + return true; + } + + + /** + * Rueckgabewert ist ein Array mit den Ergebnissen. Bei Fehler false und die + * Fehlermeldung liegt in errormsg. + * Wenn der Parameter stg_kz NULL ist tritt einheit_kurzbzb in Kraft. + * @param string $uid UserID + * @return variabel Array mit LVA; false bei Fehler + */ + function getBerechtigungen($uid) + { + // Berechtigungen holen + $sql_query="SELECT * FROM tbl_userberechtigung WHERE uid='$uid' AND (startnow() OR ende IS NULL)"; + //echo $sql_query; + if(!$erg=@pg_query($this->conn, $sql_query)) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + //$num_rows=pg_numrows($erg); + while($row=pg_fetch_object($erg)) + { + $b=new berechtigung($this->conn); + $b->userberechtigung_id=$row->userberechtigung_id; + $b->studiengang_kz=$row->studiengang_kz; + $b->fachbereich_id=$row->fachbereich_id; + $b->berechtigung_kurzbz=$row->berechtigung_kurzbz; + $b->uid=$row->uid; + $b->studiensemester_kurzbz=$row->studiensemester_kurzbz; + $b->start=$row->start; + if ($row->start!=null) + $b->starttimestamp=mktime(0,0,0,substr($row->start,5,2),substr($row->start,8),substr($row->start,0,4)); + else + $b->starttimestamp=null; + $b->ende=$row->ende; + if ($row->ende!=null) + $b->endetimestamp=mktime(23,59,59,substr($row->ende,5,2),substr($row->ende,8),substr($row->ende,0,4)); + else + $b->endetimestamp=null; + $b->art=$row->art; + $this->berechtigungen[]=$b; + } + return true; + } + + function isBerechtigt($berechtigung,$studiengang_kz=null,$art=null, $fachbereich_id=null) + { + $timestamp=time(); + foreach ($this->berechtigungen as $b) + { + //Fachbereichsberechtigung + if($fachbereich_id!=null) + { + //Wenn Fachbereichs oder Adminberechtigung + if(($berechtigung == $b->berechtigung_kurzbz || $b->berechtigung_kurzbz == 'admin') && ($b->fachbereich_id==$fachbereich_id || $b->fachbereich_id=='0')) + { + if ($b->starttimestamp!=null && $b->endetimestamp!=null) + { + if ($timestamp>$b->starttimestamp && $timestamp<$b->endetimestamp) + return true; + } + else + return true; + } + } + + //Wenn Berechtigung fuer Bestimmte Klasse vorhanden ist + if($berechtigung == $b->berechtigung_kurzbz && $studiengang_kz==null && $art==null && $fachbereich_id==null) + if ($b->starttimestamp!=null && $b->endetimestamp!=null) + { + if ($timestamp>$b->starttimestamp && $timestamp<$b->endetimestamp) + return true; + } + else + return true; + //Wenn Berechtigung fuer Bestimmten Studiengang vorhanden ist + if ($berechtigung==$b->berechtigung_kurzbz + && ($studiengang_kz==$b->studiengang_kz || $b->studiengang_kz==0) && $art==null && $b->fachbereich_id==null) + if ($b->starttimestamp!=null && $b->endetimestamp!=null) + { + if ($timestamp>$b->starttimestamp && $timestamp<$b->endetimestamp) + return true; + } + else + return true; + //Wenn Berechtigung mit Studiengang und der richtigen BerechtigungsArt (suid) vorhanden ist + if ($berechtigung==$b->berechtigung_kurzbz + && ($studiengang_kz==$b->studiengang_kz || $b->studiengang_kz==0) + && strstr($b->art,$art)) + if ($b->starttimestamp!=null && $b->endetimestamp!=null) + { + if ($timestamp>$b->starttimestamp && $timestamp<$b->endetimestamp) + return true; + } + else + return true; + } + return false; + } + + /** + * Gibt Array mit Kennzahlen der Studiengaenge sortiert zurueck. + * Optional wird auf Berechtigung eingeschraenkt. + * Wenn Berechtigung ueber alle Studiengaenge steht im ersten Feld 0. + */ + function getStgKz($berechtigung=null) + { + $studiengang_kz=array(); + $timestamp=time(); + + foreach ($this->berechtigungen as $b) + if ($berechtigung==$b->berechtigung_kurzbz || $berechtigung==null) + if($b->fachbereich_id==null) + $studiengang_kz[]=$b->studiengang_kz; + $studiengang_kz=array_unique($studiengang_kz); + sort($studiengang_kz); + return $studiengang_kz; + } + + function getFbKz($berechtigung=null) + { + $fachbereichs_kz=array(); + $timestamp=time(); + + foreach($this->berechtigungen as $b) + { + if(($berechtigung==$b->berechtigung_kurzbz || $berechtigung==null) + && (($timestamp>$b->starttimestamp && $timestamp<$b->endetimestamp) || ($b->starttimestamp==null && $b->endetimestamp==null))) + { + if($b->fachbereich_id!='' && !in_array($b->fachbereich_id,$fachbereichs_kz)) + $fachbereichs_kz[] = $b->fachbereich_id; + } + } + sort($fachbereichs_kz); + return $fachbereichs_kz; + } +} +?> \ No newline at end of file diff --git a/include/cis_functions.inc.php b/include/cis_functions.inc.php new file mode 100644 index 000000000..beb74e1d7 --- /dev/null +++ b/include/cis_functions.inc.php @@ -0,0 +1,515 @@ +stg_id; + $term_id = $auth->semester; + + $sql = "SELECT distinct verband, gruppe FROM tbl_student WHERE (studiengang_kz = $course_id) AND (semester = $term_id) ORDER BY verband,gruppe"; + $rs = new pgRS($sql); + $count_verband = $rs->num; + $verbands = $rs->arr; + for ($rt = $count_verband-1; $rt >= 0; $rt--) { + $verband = $verbands[$rt]["verband"] . $verbands[$rt]["gruppe"]; + if ($verbands[$rt]["verband"] == $auth->verband && + $verbands[$rt]["gruppe"] == $auth->gruppe) + return pow(2,$rt); + } + return 0; + } // eof function get_active_status + + //get_lf_bezeichnung holt die Studiengang Bezeichnung und die Lehrfach + // bezeichnung für das aktuelle Lehrfach. + function get_lf_bezeichnung($course_id, $term_id, $lesson) + { + $sql = "SELECT lf.bezeichnung, kurzbzlang FROM lehre.tbl_lehrfachzuteilung lf + JOIN tbl_studiengang USING(studiengang_kz) WHERE lf.studiengang_kz = $course_id + AND lf.lehrfachzuteilung_kurzbz = '$lesson' AND lf.semester = $term_id LIMIT 1"; + $rs = new pgRS($sql); + $ret[0] = $rs->arr[0]["kurzbzlang"]; + $ret[1] = $rs->arr[0]["bezeichnung"]; + + return $ret; + } + + // Die Freigabe für die Verbände für den Studienbrief berechnen + // Um die Freigeschaltenen Studienbriefe zu berechnen. + function sum($points = array()) { + $p = 0; + for ($i = 0; $i < count($points); $i++) + { + $p+= $points[$i]; + } + return $p; + } /* eof sum() */ + + // erstellen des aktuellen studienjahres + function get_studienjahr($i = -1) { + if ($i != -1) { + $stj = date("Y")+$i; + $stj .= "/"; + $stj .= sprintf("%02d", date("y")+$i+1); + } else if ( date("n") >= 7) + $stj = date("Y") . "/" . date("y", mktime(0,0,0,1,1,date("Y")+1)); + else + $stj = date("Y")-1 . "/" . date("y"); + return $stj; + } + + function get_needed_term_id($term_id = 0, $stj = "") { + if ($stj == "") + $stj = get_studienjahr(); + $needed_term_id = $term_id + ((date("Y") - substr($stj,0,4))*2); + + if ((date("n") >= 8 || date("n") < 3)) + if ($term_id%2==0) + $needed_term_id--; + else + $needed_term_id++; + + if ((date("n") < 8 || date("n") >= 3)) + if ($term_id%2!= 0) + $needed_term_id--; + return $needed_term_id; + } + + + // berechnet die notwendige Semester_ID zum Anzeigen der + // Studenten im Kreuzerltool + function get_needed_term_id2($term_id = 0, $stj = "") { + // im WS sollen noch Studenten vom letzten SS sichtbar sein + if ((date("n") >= 8 || date("n") < 2)) { + if ($term_id%2==0) + $term_id++; + } + // im SS sollen noch die Studenten vom WS sichtbar sein + else { + if ($term_id%2==1) { + $term_id++; + } + } + return $term_id; + } + + + // zurückrechnen auf die studenten im jetzigen semester + // studienpunkte sind nur für die eigene person sichtbar + function get_old_studienjahr() { + if (date("n") >= 7 && $term_id%2 == 1) { + $studienjahr = date("Y") - intval(($auth->semester - $term_id)/2); + } + else if (date("n") >= 7 && $term_id%2 == 0) { + $studienjahr = date("Y") - intval(($auth->semester - $term_id)/2)-1; + } + else if (date("n") < 7 && $term_id%2 == 1) { + $studienjahr = date("Y") - intval(($auth->semester - $term_id)/2); + } + else { + $studienjahr = date("Y") - intval(($auth->semester - $term_id)/2); + } + + $studienjahr .= "/" . date("y", mktime(0,0,0,1,1,$studienjahr+1)); + } + // write out the menu for kreuzerltool (campus/lehre/effort + function write_menu($menu, $course_id, $lesson, $term_id, $module = "", $stj = 0) { + if ($stj == 0) + $stj = get_studienjahr(); + print " +
+ + + +
+ + + + + + + + + + + + + + + + + +
+
  • Kreuzerlliste Statistik
  • +
    +
  • Anwesenheits- + und
       Übersichtstabelle
  • +
  • Kreuzerllisten anlegen
       und verwalten
  • +
  • Studentenpunkte
        verwalten
  •  
      + $menuStudienjahr:
     
    + +
    + +EOF; + } + + + + /** + * @params inputString - the String to be formatted + * @return the formatted String + */ + function format($inputString) { + $inputString = stripslashes($inputString); + return str_replace("\n", "
    ",$inputString); + } + + + function get_lectors($course_id, $term_id, $short) { + if ($course_id && $term_id && $short) { + $sql = "SELECT DISTINCT on (bezeichnung,nachname) bezeichnung, studiengang_kz, semester, vornamen, nachname, email, uid FROM lehre.tbl_lehrfachzuteilung JOIN tbl_person ON uid = lektor_uid WHERE studiengang_kz='$course_id' AND semester='$term_id' AND lehrfachzuteilung_kurzbz = '$short' AND tbl_person.aktiv=TRUE ORDER BY bezeichnung, nachname"; + //$sql_query = "SELECT DISTINCT ON(uid), vornamen, nachname, + // titel FROM lehre.tbl_lehrfachzuteilung, tbl_person, + //tbl_mitarbeiter WHERE tbl_person.uid = + //lehre.tbl_lehrfachzuteilung.lektor_uid AND + //lehre.tbl_lehrfachzuteilung.studiengang_kz='$course_id' + //AND lehre.tbl_lehrfachzuteilung.semester='$term_id' + //AND LOWER(lehre.tbl_lehrfachzuteilung.lehrfachzuteilung_kurzbz)='$short' + //AND lehre.tbl_lehrfachzuteilung.aktiv = true + //ORDER BY nachname"; + + $result_lectors = new pgRS($sql); + } + $num_rows_lectors = $result_lectors->num; + $row_email = array(); + $row_vornamen = array(); + $row_nachname = array(); + $row_titel = array(); + for($i = 0; $i < $num_rows_lectors; $i++) + { + $row_email[] = $result_lectors->arr[$i]["emailtw"]; + $row_vornamen[] = $result_lectors->arr[$i]["vornamen"]; + $row_nachname[] = $result_lectors->arr[$i]["nachname"]; + $row_titel[] = $result_lectors->arr[$i]["titel"]; + + } + $ret = ""; + for ($i = 0; $i < count($row_email); $i++) + { + $ret .= "$row_titel[$i] $row_vornamen[$i] $row_nachname[$i]"; + if ($i < count($row_email)-1) + $ret .= ", "; + } + return $ret; + } + + function get_person($bezeichnung, $course_id) { + $sql = "SELECT titel, vornamen, nachname, bezeichnung FROM tbl_funktion, public.tbl_person JOIN tbl_personfunktion ON (tbl_personfunktion.uid = tbl_person.uid) WHERE tbl_personfunktion.funktion_kurzbz = tbl_funktion.funktion_kurzbz AND bezeichnung='$bezeichnung' AND tbl_personfunktion.studiengang_kz='$course_id'"; + $rs = new pgRS($sql); + $arr = $rs->arr[0]; + $ret = $arr["titel"]." " . $arr["vornamen"]." " . $arr["nachname"]; + return $ret; + } + function create_version($user, $info_data) { + $id = 0; + $info_id = 0; + $version_id = 0; + + $ects_points = $info_data["ects_credits"]; + $learning_language = $info_data["sprache"]; + $wochenstunden = $info_data["hours"]; + $course_id = $info_data["course_id"]; + $term_id = $info_data["term_id"]; + $short = $info_data["short"]; + $studienjahr = $info_data["studienjahr"]; + $fachbereich = $info_data["fachbereich"]; + $fachbereichsleiter = $info_data["fachbereichsleiter"]; + $fachbereichskoordinator = $info_data["fachbereichskoordinator"]; + $lehrender = $info_data["lehrender"]; + + $sql = "INSERT INTO lv_infos (ects_credits, + sprache, hours, studienjahr, fachbereich, + fachbereichsleiter, fachbereichskoordinator, lehrender) VALUES + ($ects_points, $learning_language, + $wochenstunden, '$studienjahr', + '$fachbereich', '$fachbereichsleiter', + '$fachbereichskoordinator', '$lehrender')"; + $rs = new myRS($sql); + $info_id = $rs->iid; + if ($info_id) { + $sql = "SELECT max(version) as version FROM lv_versions + WHERE studiengang_kz = $course_id AND + short = '$short' AND term_id = $term_id"; + $rs = new myRS($sql); + $max_version = $rs->arr[0]["version"]; + $sql ="INSERT INTO lv_versions (studiengang_kz, term_id, + short, lector_uid, version, + status, info_id, date_created, date_modified) + VALUES ($course_id, $term_id, '$short', + '$user', " . ($max_version +1).", 0,$info_id," .time() .", " . time().")"; + $rs = new myRS($sql); + $version_id = $rs->iid; + } + return array($version_id, $info_id); + } // eof create_version + + function get_version($version_id) { + $sql = "SELECT * FROM lv_versions v, lv_infos i + WHERE v.id = $version_id AND v.info_id = i.id"; + $rs = new myRS($sql); + return array( + $rs->arr[0]["ects_credits"]/10, + $rs->arr[0]["sprache"], + $rs->arr[0]["hours"]/10, + $rs->arr[0]["info_id"], + $rs->arr[0]["content_de_id"], + $rs->arr[0]["content_en_id"], + $rs->arr[0]["date_created"], + $rs->arr[0]["date_modified"], + $rs->arr[0]["studienjahr"], + $rs->arr[0]["fachbereich"], + $rs->arr[0]["fachbereichsleiter"], + $rs->arr[0]["fachbereichskoordinator"], + $rs->arr[0]["lehrender"], + $rs->arr[0]["studiengang_kz"], + $rs->arr[0]["term_id"], + $rs->arr[0]["short"] + ); + + } // eof get_version + + + // updates the record with info_id in lv_infos + function update_version($user, $info_data) { + $id = 0; + $version_id = 0; + $ects_points = $info_data["ects_credits"]; + $learning_language = $info_data["sprache"]; + $wochenstunden = $info_data["hours"]; + $info_id = $info_data["info_id"]; + $studienjahr = $info_data["studienjahr"]; + $fachbereich = $info_data["fachbereich"]; + $fachbereichsleiter = $info_data["fachbereichsleiter"]; + $fachbereichskoordinator = $info_data["fachbereichskoordinator"]; + $lehrender = $info_data["lehrender"]; + $version_id = $info_data["version_id"]; + + $sql = "UPDATE lv_infos SET ects_credits = $ects_points, + sprache = $learning_language, + hours = $wochenstunden, + studienjahr = '$studienjahr', + fachbereich = '$fachbereich', + fachbereichsleiter = '$fachbereichsleiter', + fachbereichskoordinator = '$fachbereichskoordinator', + lehrender = '$lehrender' + WHERE id = $info_id"; + $rs = new myRS($sql); + $sql = "UPDATE lv_versions SET date_modified = " .time() . + " WHERE id = $version_id"; + $rs = new myRS($sql); + } // eof update_version + + + // saves a version to be displayed in LV infos freigeben + function save_version($version_id) { + $sql = "UPDATE lv_versions SET status = 1 WHERE id = $version_id"; + $rs = new myRS($sql); + } + + // inserts a record into lv_content_$lang and + // update lv_versions.content_$lang_id + function create_content($lang, $version_id, $info_data) { + $arr_values = array_values($info_data); + $keys = join(", ", array_keys($info_data)); + + for ($i = 0; $i < count($arr_values)-1;$i++) { + $values .= "'" . $arr_values[$i] . "', "; + } + $values .= "'" . $arr_values[count($arr_values)-1] ."'"; + $sql = "INSERT INTO lv_content_$lang ($keys) VALUES ($values)"; + $rs = new myRS($sql); + $content_id = $rs->iid; + + $sql = "UPDATE lv_versions SET content_" . $lang . "_id = + $content_id WHERE id = $version_id"; + $rs = new myRS($sql); + + return $content_id; + } // eof create_content + + // update_content updates the table lv_content_$lang + function update_content($lang, $id, $info_data) { + $sql = "UPDATE lv_content_$lang SET "; + + $keys = array_keys($info_data); + $values = array_values($info_data); + + for ($i = 0; $i < count($values); $i++) { + $sql .= $keys[$i] ." = '" . $values[$i] . "'"; + if ($i < count($values)-1) $sql .= ", "; + } + $sql .= " WHERE id = $id"; + $rs = new myRS($sql); + } // eof update_content + function get_content($lang, $content_id, $fields) { + $sql = "SELECT " . join (", ", $fields) . " FROM + lv_content_$lang WHERE id = $content_id"; + $rs = new myRS($sql); + return $rs->arr[0]; + } // eof get_content + + function write_log($lektor_uid, $action) { + $sql = "INSERT INTO lv_log (lektor_uid, action, datum)" . + " VALUES ('$lektor_uid', '$action', " . time() .")"; + $rs = new myRS($sql); + return 1; + } + + +/***************************************************************************** +* function write_ects_menu($menu = 0, $course_id, $term_id, $short, $lang) { +* +* if ($menu == 1) $menu_name = "LV-Infos anzeigen"; +* +* print << + + + + + + + + + + + + + + + + + +
     
  • LV-Infos - anzeigen + +
  • LV-Infos - erstellen / bearbeiten + +
  • LV-Infos - freigeben
  • LV-Infos - Feedback
  •     
    + + +EOF; + + if ($menu_name) { + print << + + + + + + + +*
    + $menu_name + +Lehrfach: '; + if ($menu != 2) { + if ($lang == "" || $lang!="en") { +* echo "[Deutsch]"; +* } else { +* echo "[Deutsch]"; +* } +* if ($lang == "en") { +* echo "[English]"; +* } else { +* echo "[English]"; +* } +* } // eof menu=2 +* echo '
    +* '; +* } +* echo ' +*  '; +* } +***************************************************************************/ + + + // write a menu for a quicker navigation in the ects - course contents program + function write_ects_quick_menu($course_id, $term_id, $short, $p, $version_id = 0, $info_id = 0, $content_de_id = 0, $content_en_id = 0) { + if ($p > 0) { + print ''; + ?> + +'; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
    Schnellnavigation
    +'; + static $headlines = array("", "Allgemeine Infos", "Inhalte DE", "Prüfung DE", "Inhalte EN", "Prüfung EN", "Beenden"); + for ($i = 1; $i < count($headlines); $i++) { + echo " + $i "; + if ($i==$p) echo ""; + echo $headlines[$i]; + if ($i==$p) echo ""; + echo "
    "; + } + } + } + + + + // this function returns the dictionary entry for the keyword in the + // given language + function dict($lang = "de", $key = "") { + static $dictionary = array ( + "back" => array("de" => "Zurück", "en" => "Back"), + "LVInfos" => array("de" => "LV - Informationen", "en" => "Course Description"), + "allCourses" => array("de" => "Alle Studiengänge", "en" => "All Courses"), + "availCourses" => array("de" => "Vorhandene Lehrfächer in ", "en" => "Available Courses in "), + "term" => array("de" => "Semester", "en" => "term"), + "noinfo" => array("de" => "Keine Informationenen verfügbar", "en" => "No course information available") + + ); + + return $dictionary[$key][$lang]; + } +?> diff --git a/include/ects_sync.class.php b/include/ects_sync.class.php new file mode 100644 index 000000000..f59427f95 --- /dev/null +++ b/include/ects_sync.class.php @@ -0,0 +1,110 @@ +connection=$conn; + } + + /******************************************************************** + * @brief Überprüft ob der Fachbereich existiert + * + * @param $fachb Fachbereichsbezeichnung + ********************************************************************/ + function check_fachbereich($fachb) + { + $sql_query = "SELECT * FROM tbl_fachbereich where bezeichnung='$fachb' OR kurzbz='$fachb'"; + + $result = pg_exec($this->connection, $sql_query); + + if($row=pg_fetch_object($result)) + $this->erg = $row->fachbereich_id; + else + return false; + + return true; + } + + /******************************************************************** + * @brief Überprüft ob der Studiengang existiert + * + * @param $stg Studiengangs Kurzzeichen + ********************************************************************/ + function check_studiengang($stg) + { + $sql_query = "SELECT * FROM tbl_studiengang where studiengang_kz = $stg"; + + $result = pg_exec($this->connection, $sql_query); + + if(pg_numrows($result)>0) + $this->erg = $stg; + else + return false; + + return true; + } + /******************************************************************** + * @brief Überprüft ob das Lehrfach existiert + * + * @param $lehrf LehrfachsKurzbz + * $stg Studiengang + * $sem Semester + ********************************************************************/ + function check_lehrfach($lehrf, $stg, $sem) + { + $sql_query = "SELECT * FROM tbl_lehrfach where kurzbz = upper('$lehrf') AND studiengang_kz=$stg AND semester=$sem"; + + $result = pg_exec($this->connection, $sql_query); + + if($row=pg_fetch_object($result)) + $this->erg = $row->lehrfach_nr; + else + return false; + + return true; + } + + /******************************************************************** + * @brief Überprüft das Semester + * + * @param $sem Semster + ********************************************************************/ + function check_semester($sem) + { + if(is_numeric($sem) AND $sem<10) + $this->erg = $sem; + else + return false; + + return true; + } +} +?> \ No newline at end of file diff --git a/include/einheit.class.php b/include/einheit.class.php new file mode 100644 index 000000000..77f137b02 --- /dev/null +++ b/include/einheit.class.php @@ -0,0 +1,315 @@ +conn = $conn; + + if (strlen($kurzbz)>0) + { + $this->kurzbz=$kurzbz; + $this->load(); + + } + } + + + /** + * Speichert die Einheit in der Datenbank. Bei Fehler ist der Rueckgabewert + * 'false' und die Fehlermeldung steht in 'errormsg'. INSERT oder DELETE wird + * durch 'new' bestimmt. + * @param string $kurzbz_new Kurzbezeichnung ist optional + * @return boolean true=ok, false=fehler + */ + function save($kurzbz_new='') + { + if (is_null($this->conn)) + { + return false; + } + + if (strlen($this->kurzbz)==0) + { + $this->errormsg="kurzbz nicht gesetzt"; + return false; + } + + if ($this->new) + { + if (is_numeric($this->semester)) $semester=$this->semester; + else $semester='NULL'; + if (is_numeric($this->typ)) $typ=$this->typ; + else $typ='NULL'; + if(!strlen($this->mailgrp_kurzbz)>0) + $this->mailgrp_kurzbz='NULL'; + $qry="insert into tbl_einheit(einheit_kurzbz,studiengang_kz,bezeichnung,semester,typ,mailgrp_kurzbz) ". + "values('".$this->kurzbz."','".$this->stg_kz."','".$this->bezeichnung."',$semester,$typ,$this->mailgrp_kurzbz)"; + } else + { + if (is_numeric($this->semester)) $semester='semester='.$this->semester; + else $semester='semester=NULL'; + if (is_numeric($this->typ)) $typ='typ='.$this->typ; + else $typ='NULL'; + if(!strlen($this->mailgrp_kurzbz)>0) + $this->mailgrp_kurzbz='mailgrp_kurzbz=NULL'; + else + $this->mailgrp_kurzbz="mailgrp_kurzbz='$this->mailgrp_kurzbz'"; + + $qry="update tbl_einheit set studiengang_kz=".$this->stg_kz.",bezeichnung='".$this->bezeichnung."',". + "$semester,$typ,".$this->mailgrp_kurzbz.",einheit_kurzbz='".(strlen($kurzbz_new)>0?$kurzbz_new:$this->kurzbz)."' ". + "where einheit_kurzbz='".$this->kurzbz."'"; + + } + //echo $qry; + if(!($erg=pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + return true; + + } + + /** + * @return boolean true=ok, false=fehler + */ + function load($kurzbz='') + { + // optional: kurzbz setzen + if (strlen($uid)>0) + $this->kurzbz=$kurzbz; + // uid vorhanden? + if (strlen($this->kurzbz)==0) { + $this->errormsg='einheit_kurzbz nicht gesetzt'; + return false; + } + if (is_null($this->conn)) { + return false; + } + $qry="select einheit_kurzbz,studiengang_kz,bezeichnung,semester,typ, mailgrp_kurzbz ". + "from tbl_einheit ". + "where einheit_kurzbz='".$this->kurzbz."'"; + + if(!($erg=pg_exec($this->conn, $qry))) { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + if($num_rows!=1) { + $this->errormsg="Zuwenige oder zuviele Ergebnisse (Anzahl: $num_rows)!"; + return false; + } + $row=pg_fetch_object($erg,0); + + $this->stg_kz=$row->studiengang_kz; + $this->bezeichnung=$row->bezeichnung; + $this->semester=$row->semester; + $this->typ=$row->typ; + $this->mailgrp_kurzbz=$row->mailgrp_kurzbz; + + return true; + + } + + /** + * Loescht die Funktion aus der Datenbank. Bei Fehler ist der Rueckgabewert + * 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true=ok, false=fehler + */ + function delete() + { + if (is_null($this->conn)) { + return false; + } + $qry="delete from tbl_einheit where einheit_kurzbz='".$this->kurzbz."'"; + + if(!($erg=pg_exec($this->conn, $qry))) { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + return true; + } + + function addStudent($uid) { + if (is_null($this->conn)) { + return false; + } + $qry="insert into tbl_einheitstudent(einheit_kurzbz,uid,updateamum,updatevon) ". + "values('".$this->kurzbz."','".$uid."',now(),'".$_SERVER['PHP_AUTH_USER']."')"; + + if(!($erg=pg_exec($this->conn, $qry))) { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + return true; + } + + function deleteStudent($uid) { + if (is_null($this->conn)) { + return false; + } + $qry="delete from tbl_einheitstudent ". + "where einheit_kurzbz='".$this->kurzbz."' and uid='$uid'"; + + if(!($erg=pg_exec($this->conn, $qry))) { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + return true; + } + + + /** + * Alle Einheiten zurueckgeben + * @return array Array der einheiten + */ + function getAll($studiengang_kz='') + { + if (is_null($this->conn)) { + return false; + } + if (strlen($studiengang_kz)>0) + { + $where=" where tbl_einheit.studiengang_kz='".$studiengang_kz."' "; + } else + { + $where=""; + } + $qry="select tbl_einheit.*,tbl_studiengang.kurzbz from tbl_einheit join tbl_studiengang using(studiengang_kz) ". + "$where order by einheit_kurzbz;"; + if(!($erg=pg_exec($this->conn, $qry))) { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + $result=array(); + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + $l=new einheit($this->conn); + $l->kurzbz=$row->einheit_kurzbz; + $l->stg_kz=$row->studiengang_kz; + $l->stg_kurzbz=$row->kurzbz; + $l->bezeichnung=$row->bezeichnung; + $l->semester=$row->semester; + $l->typ=$row->typ; + $l->mailgrp_kurzbz=$row->mailgrp_kurzbz; + $result[]=$l; + } + return $result; + } + + /** + * Liste aller Studenten zurueckgeben + * @param string $studiengang_kz optional + * @return array Array mit allen Studenten, false bei fehler + */ + function getStudenten($studiengang_kz='') + { + if (is_null($this->conn)) { + return false; + } + if (strlen($studiengang_kz)>0) + { + $where=" and tbl_einheit.studiengang_kz='".$studiengang_kz."' "; + } else + { + $where=""; + } + $qry="select einheit_kurzbz,uid ". + "from tbl_einheitstudent join tbl_student using(uid) join tbl_person using(uid) ". + " join tbl_einheit using (einheit_kurzbz) ". + "where einheit_kurzbz='".$this->kurzbz."' $where ". + "order by upper(tbl_person.nachname),upper(tbl_person.vornamen)"; + + if(!($erg=pg_exec($this->conn, $qry))) { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + $result=array(); + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + $l=new student($this->conn,$row->uid); + $result[]=$l; + } + return $result; + } + + /** + * Liefert die Anzahl der Studenten in einer Einheit + * @param string kurzbzlang + * @return anzahl der Studenten + */ + function countStudenten($einheit_kurzbz) + { + $qry = "Select count(*) as anzahl from tbl_einheitstudent where einheit_kurzbz='$einheit_kurzbz'"; + if($result=pg_query($this->conn,$qry)) + { + if($row=pg_fetch_object($result)) + return $row->anzahl; + else + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + } + else + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + } + +} +?> \ No newline at end of file diff --git a/include/fachbereich.class.php b/include/fachbereich.class.php new file mode 100644 index 000000000..2c8da72dc --- /dev/null +++ b/include/fachbereich.class.php @@ -0,0 +1,92 @@ +conn = $conn; + } + + + /** + * Alle Fachbereiche zurückgeben + * @return array mit Fachbereichen oder false=fehler + */ + function getAll() + { + if (is_null($this->conn)) + { + return false; + } + $qry = "select fachbereich_id,tbl_fachbereich.kurzbz,tbl_fachbereich.bezeichnung,tbl_fachbereich.farbe,tbl_fachbereich.studiengang_kz,". + "tbl_studiengang.kurzbz as studiengang_kurzbz ". + "from tbl_fachbereich join tbl_studiengang using(studiengang_kz) ". + "order by tbl_Fachbereich.kurzbz"; + //echo $qry; + if (!($erg = pg_exec($this->conn, $qry))) + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + $result = array(); + $num_rows = pg_numrows($erg); + for ($i = 0; $i < $num_rows; $i ++) + { + // Record holen + $row = pg_fetch_object($erg, $i); + // Instanz erzeugen + $fb = new fachbereich($this->conn); + $fb->id = $row->fachbereich_id; + $fb->kurzbz = $row->kurzbz; + $fb->bezeichnung = $row->bezeichnung; + $fb->farbe = $row->farbe; + $fb->studiengang_kz = $row->studiengang_kz; + $fb->studiengang_kurzbz = $row->studiengang_kurzbz; + // in array speichern + $result[] = $fb; + } + return $result; + } + +} +?> \ No newline at end of file diff --git a/include/fas/adresse.class.php b/include/fas/adresse.class.php new file mode 100644 index 000000000..a1df7eff2 --- /dev/null +++ b/include/fas/adresse.class.php @@ -0,0 +1,355 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($adress_id != null) + $this->load($adress_id); + } + + /** + * Laedt die Funktion mit der ID $adress_id + * @param $adress_id ID der zu ladenden Funktion + * @return true wenn ok, false im Fehlerfall + */ + function load($adress_id) + { + + //Pruefen ob adress_id eine gueltige Zahl ist + if(!is_numeric($adress_id) || $adress_id == '') + { + $this->errormsg = 'Adress_id muss eine Zahl sein'; + return false; + } + + //Daten aus der Datenbank lesen + $qry = "SELECT * FROM adresse WHERE adresse_pk=$adress_id"; + + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->adresse_id = $row->adresse_pk; + $this->bismeldeadresse = ($row->bismeldeadresse=='J'?true:false); + $this->gemeinde = $row->gemeinde; + $this->name = $row->name; + $this->nation = $row->nation; + $this->ort = $row->ort; + $this->person_id = $row->person_fk; + $this->plz = $row->plz; + $this->strasse = $row->strasse; + $this->typ = $row->typ; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + $this->zustelladresse = ($row->zustelladresse=='J'?true:false); + } + else + { + $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; + return false; + } + + return true; + } + + /** + * Laedt alle adressen zu der Person die uebergeben wird + * @param $pers_id ID der Person zu der die Adressen geladen werden sollen + * @return true wenn ok, false im Fehlerfall + */ + function load_pers($pers_id) + { + //Pruefen ob pers_id eine gueltige Zahl ist + if(!is_numeric($pers_id) || $pers_id == '') + { + $this->errormsg = 'person_id muss eine gueltige Zahl sein'; + return false; + } + + //Lesen der Daten aus der Datenbank + $qry = "SELECT * FROM adresse WHERE person_fk=$pers_id"; + + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $adr_obj = new adresse($this->conn); + + $adr_obj->adresse_id = $row->adresse_pk; + $adr_obj->bismeldeadresse = ($row->bismeldeadresse=='J'?true:false); + $adr_obj->gemeinde = $row->gemeinde; + $adr_obj->name = $row->name; + $adr_obj->nation = $row->nation; + $adr_obj->ort = $row->ort; + $adr_obj->person_id = $row->person_fk; + $adr_obj->plz = $row->plz; + $adr_obj->strasse = $row->strasse; + $adr_obj->typ = $row->typ; + $adr_obj->updateamum = $row->creationdate; + $adr_obj->updatevon = $row->creationuser; + $adr_obj->zustelladresse = ($row->zustelladresse=='J'?true:false); + + $this->result[] = $adr_obj; + } + return true; + } + + /** + * Laedt alle Adressen aus der Datenbank + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + $qry = "SELECT * FROM adresse"; + + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $adr_obj = new adresse($this->conn); + + $adr_obj->adresse_id = $row->adresse_pk; + $adr_obj->bismeldeadresse = ($row->bismeldeadresse=='J'?true:false); + $adr_obj->gemeinde = $row->gemeinde; + $adr_obj->name = $row->name; + $adr_obj->nation = $row->nation; + $adr_obj->ort = $row->ort; + $adr_obj->person_id = $row->person_fk; + $adr_obj->plz = $row->plz; + $adr_obj->strasse = $row->strasse; + $adr_obj->typ = $row->typ; + $adr_obj->updateamum = $row->creationdate; + $adr_obj->updatevon = $row->creationuser; + $adr_obj->zustelladresse = ($row->zustelladresse=='J'?true:false); + + $this->result[] = $adr_obj; + } + + return true; + } + + /** + * Prueft die Variablen auf gueltigkeit + * @return true wenn ok, false im Fehlerfall + */ + function checkvars() + { + //Zahlenfelder pruefen + $this->errormsg='Ein Zahlenfeld enthaelt ungueltige Zeichen'; + if(!is_numeric($this->person_id)) + { + $this->errormsg='Person_id enthaelt ungueltige Zeichen:'.$this->person_id; + return false; + } + if(!is_numeric($this->typ)) + { + $this->errormsg='Typ enthaelt ungueltige Zeichen'; + return false; + } + + //Gesamtlaenge pruefen + $this->errormsg='Eine der Gesamtlaengen wurde ueberschritten'; + if(strlen($this->name)>255) + { + $this->errormsg = 'Name darf nicht länger als 255 Zeichen sein'; + return false; + } + if(strlen($this->strasse)>255) + { + $this->errormsg = 'Strasse darf nicht länger als 255 Zeichen sein'; + return false; + } + if(strlen($this->plz)>10) + { + $this->errormsg = 'Plz darf nicht länger als 10 Zeichen sein'; + return false; + } + if(strlen($this->ort)>255) + { + $this->errormsg = 'Ort darf nicht länger als 255 Zeichen sein'; + return false; + } + if(strlen($this->nation)>3) + { + $this->errormsg = 'Nation darf nicht länger als 3 Zeichen sein'; + return false; + } + if(strlen($this->gemeinde)>255) + { + $this->errormsg = 'Gemeinde darf nicht länger als 255 Zeichen sein'; + return false; + } + + $this->errormsg = ''; + return true; + } + + /** + * Speichert den aktuellen Datensatz in die Datenbank + * Wenn $neu auf true gesetzt ist wird ein neuer Datensatz angelegt + * andernfalls wird der Datensatz mit der ID in $adresse_id aktualisiert + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + //Variablen pruefen + if(!$this->checkvars()) + return false; + + if($this->new) + { + //Neuen Datensatz einfuegen + + //naechste ID aus der Sequence holen + $qry="SELECT nextval('adresse_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn,$qry))) + { + $this->errormsg = 'Fehler beim auslesen der Sequence'; + return false; + } + $this->adresse_id = $row->id; + + $qry="INSERT INTO adresse (adresse_pk, person_fk, name, strasse, plz, typ, ort, nation, creationdate, creationuser,". + " gemeinde, bismeldeadresse, zustelladresse) VALUES(". + " $this->adresse_id, $this->person_id, '$this->name', '$this->strasse', '$this->plz', $this->typ, '$this->ort',". + " '$this->nation', now(), $this->updatevon, '$this->gemeinde', '".($this->bismeldeadresse?'J':'N')."',". + " '".($this->zustelladresse?'J':'N')."');"; + } + else + { + //Updaten des bestehenden Datensatzes + + //Pruefen ob adresse_id eine gueltige Zahl ist + if(!is_numeric($this->adresse_id)) + { + $this->errormsg = 'adresse_id muss eine gueltige Zahl sein'; + return false; + } + + $qry="UPDATE adresse SET person_fk='$this->person_id', name='$this->name', strasse='$this->strasse', plz='$this->plz',". + " typ='$this->typ', ort='$this->ort', nation='$this->nation', gemeinde='$this->gemeinde',". + " bismeldeadresse='".($this->bismeldeadresse?'J':'N')."', zustelladresse='".($this->zustelladresse?'J':'N')."'". + " WHERE adresse_pk='$this->adresse_id'"; + } + + if(pg_query($this->conn,$qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim Speichern der Daten'; + return false; + } + } + + /** + * Loescht den Datenensatz mit der ID die uebergeben wird + * @param $adress_id ID die geloescht werden soll + * @return true wenn ok, false im Fehlerfall + */ + function delete($adress_id) + { + //Pruefen ob adresse_id eine gueltige Zahl ist + if(!is_numeric($adress_id) || $adress_id == '') + { + $this->errormsg = 'adresse_id muss eine gueltige Zahl sein'; + return false; + } + + //loeschen des Datensatzes + $qry="DELETE FROM adresse WHERE adresse_pk=$adress_id;"; + + if(pg_query($this->conn,$qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim loeschen der Daten'; + return false; + } + } +} +?> \ No newline at end of file diff --git a/include/fas/ausbildungssemester.class.php b/include/fas/ausbildungssemester.class.php new file mode 100644 index 000000000..dc94d4414 --- /dev/null +++ b/include/fas/ausbildungssemester.class.php @@ -0,0 +1,182 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($ausbildungssemester_id != null) + $this->load($ausbildungssemester_id); + } + + /** + * Laedt einen Datensatz aus der Datenbank + * @param $ausbildungssemester_id ID des zu ladenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function load($ausbildungssemester_id) + { + if(!is_numeric($ausbildungssemester_id) || $ausbildungssemester_id == '') + { + $this->errormsg = 'ausbildungssemester_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM ausbildungssemester WHERE ausbildungssemester_pk = '$ausbildungssemester_id';"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + if($row=pg_fetch_object($res)) + { + $this->ausbildungssemester_id = $row->ausbildungssemester_pk; + $this->studiengang_id = $row->studiengang_fk; + $this->semester = $row->semester; + $this->name = $row->name; + $this->personenstatus = $row->personenstatus; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + return true; + } + + /** + * Liefert alle ausbildungssemester zu einem Studiengang + * @param $studiengang_id Studiengang_id des Ausbildungssemesters + * @return true wenn ok, false im Fehlerfall + */ + function load_stg($studiengang_id) + { + if(!is_numeric($studiengang_id) || $studiengang_id == '') + { + $this->errormsg = 'studiengang_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM ausbildungssemester WHERE studiengang_fk = '$studiengang_id' order by semester"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $ausb_obj = new ausbildungssemester($this->conn); + + $ausb_obj->ausbildungssemester_id = $row->ausbildungssemester_pk; + $ausb_obj->studiengang_id = $row->studiengang_fk; + $ausb_obj->semester = $row->semester; + $ausb_obj->name = $row->name; + $ausb_obj->personenstatus = $row->personenstatus; + $ausb_obj->updateamum = $row->creationdate; + $ausb_obj->updatevon = $row->creationuser; + + $this->result[] = $ausb_obj; + } + return true; + } + + /** + * Liefert alle Ausbildungssemester + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + $qry = "SELECT * FROM ausbildungssemester;"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $ausb_obj = new ausbildungssemester($this->conn); + + $ausb_obj->ausbildungssemester_id = $row->ausbildungssemester_pk; + $ausb_obj->studiengang_id = $row->studiengang_fk; + $ausb_obj->semester = $row->semester; + $ausb_obj->name = $row->name; + $ausb_obj->personenstatus = $row->personenstatus; + $ausb_obj->updateamum = $row->creationdate; + $ausb_obj->updatevon = $row->creationuser; + + $this->result[] = $ausb_obj; + } + return true; + } + + /** + * Checkt die Variablen vor dem Speichern + * @return true wenn ok, false im Fehlerfall + */ + function checkvars() + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } + + /** + * Speichert den aktuellen Datensatz + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + if(!checkvars()) + return false; + + $this->errormsg = 'Noch nicht implementiert'; + return false; + } + + /** + * Loescht den Datensatz mit der ID die uebergeben wurde + * @param $ausbildungssemester_id ID des zu loeschenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function delete($ausbildungssemester_id) + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } +} +?> \ No newline at end of file diff --git a/include/fas/bankverbindung.class.php b/include/fas/bankverbindung.class.php new file mode 100644 index 000000000..62630d19e --- /dev/null +++ b/include/fas/bankverbindung.class.php @@ -0,0 +1,340 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($bank_id != null) + $this->load($bank_id); + } + + /** + * Prueft die gueltigkeit der Variablen + * @return true wenn ok, false im Fehlerfall + */ + function checkvars() + { + //Gesamtlaenge pruefen + $this->errormsg = 'Eine der Maximiallaengen wurde ueberschritten'; + if(strlen($this->name)>255) + { + $this->errormsg = 'Name darf nicht länger als 255 Zeichen sein'; + return false; + } + if(strlen($this->anschrift)>255) + { + $this->errormsg = 'Anschrift darf nicht länger als 255 Zeichen sein'; + return false; + } + if(strlen($this->blz)>15) + { + $this->errormsg = 'BLZ darf nicht länger als 15 Zeichen sein'; + return false; + } + if(strlen($this->bic)>15) + { + $this->errormsg = 'BIC darf nicht länger als 15 Zeichen sein'; + return false; + } + if(strlen($this->kontonr)>25) + { + $this->errormsg = 'KontoNr darf nicht länger als 25 Zeichen sein'; + return false; + } + if(strlen($this->iban)>25) + { + $this->errormsg = 'IBAN darf nicht länger als 25 Zeichen sein'; + return false; + } + + //Zahlenwerte ueberpruefen + $this->errormsg = 'Ein Zahlenfeld enthaelt ungueltige Zeichen'; + if(!is_numeric($this->person_id)) return false; + if(!is_numeric($this->typ)) return false; + + $this->errormsg = ''; + return true; + } + + + /** + * Speichert den aktuellen Datensatz + * Wenn $neu auf true gesetzt ist wird ein neuer Datensatz angelegt + * andernfalls wird der Datensatz mit der ID in $bankverbindung_id aktualisiert + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + //Gueltigkeit der Variablen pruefen + if(!$this->checkvars()) + return false; + + if($this->new) + { + //Neuen Datensatz einfuegen + + //Naechste ID aus der Sequence holen + $qry = "SELECT nextval('bankverbindung_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim auslesen der Sequence'; + return false; + } + $this->bankverbindung_id = $row->id; + + $qry = "INSERT INTO bankverbindung (bankverbindung_pk, person_fk, name, anschrift, blz, bic,". + " kontonr, iban, typ, creationdate, creationuser) VALUES(". + " '$this->bankverbindung_id', '$this->person_id', '$this->name', '$this->anschrift',". + " '$this->blz', '$this->bic', '$this->kontonr', '$this->iban', '$this->typ', now(), $this->updatevon);"; + } + else + { + //Datensatz Updaten + + //ID pruefen + if(!is_numeric($this->bankverbindung_id)) + { + $this->errormsg = 'bankverbindung_id muss eine Zahl sein'; + return false; + } + + $qry="UPDATE bankverbindung SET person_fk='$this->person_id', name='$this->name',". + " anschrift='$this->anschrift', blz='$this->blz', bic='$this->bic',". + " kontonr='$this->kontonr', iban='$this->iban', typ='$this->typ'". + " WHERE bankverbindung_pk=$this->bankverbindung_id"; + } + + if(pg_query($this->conn, $qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim Speichern der Daten'; + return false; + } + } + + /** + * Loescht den Datensatz mit der uebergebenen ID + * @param $bank_id ID des zu loeschenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function delete($bank_id) + { + if(!is_numeric($bank_id) || $bank_id == '') + { + $this->errormsg = 'bank_id muss eine Zahl sein'; + return false; + } + + $qry="DELETE FROM bankverbindung WHERE bankverbindung_pk=$bank_id"; + + if(!pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim loeschen der Daten'; + return false; + } + else + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + } + + /** + * Liefert die Bankverbindung mit der uebergebenen ID + * @param $bank_id ID der bankverbindung + * @return true wenn ok, false im Fehlerfall + */ + function load($bank_id) + { + if(!is_numeric($bank_id) || $bank_id == '') + { + $this->errormsg = 'bank_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM bankverbindung WHERE bankverbindung_pk=$bank_id"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->bankverbindung_id = $row->bankverbindung_pk; + $this->person_id = $row->person_fk; + $this->name = $row->name; + $this->anschrift = $row->anschrift; + $this->blz = $row->blz; + $this->bic = $row->bic; + $this->kontonr = $row->kontonr; + $this->iban = $row->iban; + $this->typ = $row->typ; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; + return false; + } + + return true; + } + + /** + * Liefert alle Bankverbindungen der Person die uebergeben wird + * @param $pers_id ID der Person + * @return true wenn ok, false im Fehlerfall + */ + function load_pers($pers_id) + { + if(!is_numeric($pers_id) || $pers_id == '') + { + $this->errormsg = 'pers_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM bankverbindung WHERE person_fk=$pers_id"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $bank_obj = new bankverbindung($this->conn); + + $bank_obj->bankverbindung_id = $row->bankverbindung_pk; + $bank_obj->person_id = $row->person_fk; + $bank_obj->name = $row->name; + $bank_obj->anschrift = $row->anschrift; + $bank_obj->blz = $row->blz; + $bank_obj->bic = $row->bic; + $bank_obj->kontonr = $row->kontonr; + $bank_obj->iban = $row->iban; + $bank_obj->typ = $row->typ; + $bank_obj->updateamum = $row->creationdate; + $bank_obj->updatevon = $row->creationuser; + + $this->result[] = $bank_obj; + } + return true; + } + + /** + * Liefert alle Bankverbindungen + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + $qry = "SELECT * FROM bankverbindung"; + + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $bank_obj = new bankverbindung($this->conn); + + $bank_obj->bankverbindung_id = $row->bankverbindung_pk; + $bank_obj->person_id = $row->person_fk; + $bank_obj->name = $row->name; + $bank_obj->anschrift = $row->anschrift; + $bank_obj->blz = $row->blz; + $bank_obj->bic = $row->bic; + $bank_obj->kontonr = $row->kontonr; + $bank_obj->iban = $row->iban; + $bank_obj->typ = $row->typ; + $bank_obj->updateamum = $row->creationdate; + $bank_obj->updatevon = $row->creationuser; + + $this->result[] = $bank_obj; + } + return true; + } + + function getTypBezeichnung($id) + { + switch($id) + { + case 1: return 'Privatkonto'; + case 2: return 'Firmenkonto'; + default: return ''; + } + } +} +?> \ No newline at end of file diff --git a/include/fas/benutzer.class.php b/include/fas/benutzer.class.php new file mode 100644 index 000000000..31f9ac952 --- /dev/null +++ b/include/fas/benutzer.class.php @@ -0,0 +1,386 @@ +conn=$conn; + $this->new=true; + } + + + /** + * Ladet die Attribute der Berechtigung aus der Datenbank. Bei Fehler ist der + * Rueckgabewert 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true=ok, false=fehler + */ + function load($id) + { + // Berechtigung holen + $sql_query="SELECT * FROM tbl_userberechtigung WHERE userberechtigung_id=$id"; + //echo $sql_query; + if(!($erg=pg_exec($this->conn, $sql_query))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + if($num_rows!=1) + { + $this->errormsg="Zuwenige oder zuviele Ergebnisse (Anzahl: $num_rows)!"; + return false; + } + $row=pg_fetch_object($erg,0); + + $this->userberechtigung_id=$row->userberechtigung_id; + $this->studiengang_kz=$row->studiengang_kz; + $this->fachbereich_id=$row->fachbereich_id; + $this->berechtigung_kurzbz=$row->berechtigung_kurzbz; + $this->uid=$row->uid; + $this->studiensemester_kurzbz=$row->studiensemester_kurzbz; + $this->start=$row->start; + $this->ende=$row->ende; + $this->art=$row->art; + $this->new=false; + + return true; + } + + /** + * @return boolean true=ok, false=fehler + */ + function save() + { + /* + // Connection holen + if (is_null($conn=$this->getConnection())) + { + return false; + } + // Daten zur Person speichern + + if (!person::save()) { + $this->errormsg.="Daten zur LVA konnten nicht gespeichert werden."; + return false; + } + if ($this->new) { + $qry="INSERT INTO tbl_lehrveranstaltung(lvnr,unr,einheit_kurzbz,". + "lektor,lehrfach_nr,studiengang_kz,fachbereich_id,semester,verband,". + "gruppe,raumtyp,raumtypalternativ,semesterstunden,stundenblockung,". + "wochenrythmus,start_kw,anmerkung)". + "values(". + "'".$this->lvnr."',". + "'".$this->unr."',". + "'".$this->einheit_kurzbz."',". + "'".$this->lektor."',". + (strlen($this->lehrfach_nr)>0?$this->lehrfach_nr:NULL).",". + (strlen($this->studiengang_kz)>0?$this->studiengang_kz:NULL).",". + (strlen($this->fachbereich_id)>0?$this->fachbereich_id:NULL).",". + (strlen($this->semester)>0?$this->semester:NULL).",". + "'".$this->verband."',". + "'".$this->gruppe."',". + (strlen($this->raumtyp)>0?"'".$this->raumtyp."'":NULL).",". + (strlen($this->raumtypalternativ)>0?"'".$this->raumtypalternativ."'":NULL).",". + (strlen($this->semesterstunden)>0?$this->semesterstunden:NULL).",". + (strlen($this->stundenblockung)>0?$this->stundenblockung:NULL).",". + (strlen($this->wochenrythmus)>0?$this->wochenrythmus:NULL).",". + (strlen($this->start_kw)>0?$this->start_kw:NULL).",". + (strlen($this->anmerkung)>0?"'".$this->anmerkung."'":NULL).",". + ")"; + } else + { + $qry="UPDATE tbl_lehrveranstaltung ". + "SET lvnr='".$this->lvnr."',". + "unr='".$this->unr."',". + "einheit_kurzbz='".$this->einheit_kurzbz."',". + "lektor='".$this->lehrfach_nr."',". + "lehrfach_nr=".(strlen($this->lehrfach_nr)>0?$this->lehrfach_nr:NULL).",". + "studiengang_kz=".(strlen($this->studiengang_kz)>0?$this->studiengang_kz:NULL).",". + "fachbereich_id=".(strlen($this->fachbereich_id)>0?$this->fachbereich_id:NULL).",". + "semester=".(strlen($this->semester)>0?$this->semester:NULL).",". + "verband='".$this->verband."',". + "gruppe='".$this->gruppe."',". + "raumtyp=".(strlen($this->raumtyp)>0?"'".$this->raumtyp."'":NULL).",". + "raumtypalternativ=".(strlen($this->raumtypalternativ)>0?"'".$this->raumtypalternativ."'":NULL).",". + "semesterstunden=".(strlen($this->semesterstunden)>0?$this->semesterstunden:NULL).",". + "stundenblockung=".(strlen($this->stundenblockung)>0?$this->stundenblockung:NULL).",". + "wochenrythmus=".(strlen($this->wochenrythmus)>0?$this->wochenrythmus:NULL).",". + "start_kw=".(strlen($this->start_kw)>0?$this->start_kw:NULL).",". + "anmerkung=".(strlen($this->anmerkung)>0?"'".$this->anmerkung."'":NULL). + " WHERE lehrveranstaltung_id='".$this->lehrveranstaltung_id."'"; + } + //echo "
    ".$qry; + if(!@pg_query($conn, $qry)) + { + $this->errormsg=pg_errormessage($conn); + return false; + } + return true; + */ + } + + + /** + * Rueckgabewert ist ein Array mit den Ergebnissen. Bei Fehler false und die + * Fehlermeldung liegt in errormsg. + * Wenn der Parameter stg_kz NULL ist tritt einheit_kurzbzb in Kraft. + * @param string $uid UserID + * @return variabel Array mit LVA; false bei Fehler + */ + function getBerechtigungen($uid) + { + // Berechtigungen holen + $sql_query="SELECT * FROM tbl_userberechtigung WHERE uid='$uid' AND (startnow() OR ende IS NULL)"; + //echo $sql_query; + if(!$erg=@pg_query($this->conn, $sql_query)) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + //$num_rows=pg_numrows($erg); + while($row=pg_fetch_object($erg)) + { + $b=new berechtigung($this->conn); + $b->userberechtigung_id=$row->userberechtigung_id; + $b->studiengang_kz=$row->studiengang_kz; + $b->fachbereich_id=$row->fachbereich_id; + $b->berechtigung_kurzbz=$row->berechtigung_kurzbz; + $b->uid=$row->uid; + $b->studiensemester_kurzbz=$row->studiensemester_kurzbz; + $b->start=$row->start; + if ($row->start!=null) + $b->starttimestamp=mktime(0,0,0,substr($row->start,5,2),substr($row->start,8),substr($row->start,0,4)); + else + $b->starttimestamp=null; + $b->ende=$row->ende; + if ($row->ende!=null) + $b->endetimestamp=mktime(23,59,59,substr($row->ende,5,2),substr($row->ende,8),substr($row->ende,0,4)); + else + $b->endetimestamp=null; + $b->art=$row->art; + $this->berechtigungen[]=$b; + } + return true; + } + + + function isBerechtigt($berechtigung,$studiengang_kz=null,$art=null) + { + $timestamp=time(); + foreach ($this->berechtigungen as $b) + { + if($berechtigung == $b->berechtigung_kurzbz && $studiengang_kz==null && $art==null) + if ($b->starttimestamp!=null && $b->endetimestamp!=null) + { + if ($timestamp>$b->starttimestamp && $timestamp<$b->endetimestamp) + return true; + } + else + return true; + + if ($berechtigung==$b->berechtigung_kurzbz + && ($studiengang_kz==$b->studiengang_kz || $b->studiengang_kz==0) && $art==null) + if ($b->starttimestamp!=null && $b->endetimestamp!=null) + { + if ($timestamp>$b->starttimestamp && $timestamp<$b->endetimestamp) + return true; + } + else + return true; + + if ($berechtigung==$b->berechtigung_kurzbz + && ($studiengang_kz==$b->studiengang_kz || $b->studiengang_kz==0) + && strstr($b->art,$art)) + if ($b->starttimestamp!=null && $b->endetimestamp!=null) + { + if ($timestamp>$b->starttimestamp && $timestamp<$b->endetimestamp) + return true; + } + else + return true; + } + return false; + } + + /** + * Gibt Array mit Kennzahlen der Studiengaenge sortiert zurueck. + * Optional wird auf Berechtigung eingeschraenkt. + * Wenn Berechtigung ueber alle Studiengaenge steht im ersten Feld 0. + */ + function getStgKz($berechtigung=null) + { + $studiengang_kz=array(); + $timestamp=time(); + + foreach ($this->berechtigungen as $b) + if ($berechtigung==$b->berechtigung_kurzbz || $berechtigung==null) + $studiengang_kz[]=$b->studiengang_kz; + $studiengang_kz=array_unique($studiengang_kz); + sort($studiengang_kz); + return $studiengang_kz; + } + + /** + * Setzt die Studiensemester Variable + */ + function setVariableStudiensemester($user,$stsem) + { + //Vorhandende Variable aendern + $qry = "Update tbl_variable SET wert='$stsem' WHERE uid='$user' AND name='semester_aktuell'"; + if($result = pg_query($this->conn,$qry)) + { + if(pg_affected_rows($result)==0) + { + //Falls Variable nicht vorhanden ist eine neue anlegen + $qry = "INSERT INTO tbl_variable(uid, name, wert) values('$user', 'semester_aktuell', '$stsem')"; + if(pg_query($this->conn,$qry)) + return true; + else + { + $this->errormsg.=pg_errormessage($this->conn); + return false; + } + } + else + return true; + } + else + { + $this->errormsg.=pg_errormessage($this->conn); + return false; + } + } + + function getpossibilities($variable) + { + $ret = array(); + + switch($variable) + { + case 'semester_aktuell': + $qry = "Select * from tbl_studiensemester order by start"; + if($result = pg_query($this->conn,$qry)) + { + while($row=pg_fetch_object($result)) + $ret[] = $row->studiensemester_kurzbz; + } + break; + } + return $ret; + } + + function loadVariables($user) + { + if(!($result=@pg_query($this->conn, "SELECT * FROM tbl_variable WHERE uid='$user'"))) + { + $this->errormsg.=pg_errormessage($this->conn); + return false; + } + else + $num_rows=@pg_numrows($result); + + while($row=pg_fetch_object($result)) + { + $this->variable->{$row->name}=$row->wert; + } + + if (!isset($this->variable->semester_aktuell)) + { + if(!($result=@pg_query($this->conn, 'SELECT * FROM tbl_studiensemester WHERE ende>now() ORDER BY start LIMIT 1'))) + { + $this->errormsg.=pg_errormessage($this->conn); + return false; + } + else + { + $num_rows=@pg_numrows($result); + if ($num_rows>0) + { + $row=pg_fetch_object($result); + $this->variable->semester_aktuell=$row->studiensemester_kurzbz; + } + } + } + + if (!isset($this->variable->db_stpl_table)) + $this->variable->db_stpl_table='stundenplan'; + + if (!isset($this->variable->fas_id)) + $this->variable->fas_id=0; + + if (!isset($this->variable->sleep_time)) + $this->variable->sleep_time=300; + + return true; + } +} +?> \ No newline at end of file diff --git a/include/fas/email.class.php b/include/fas/email.class.php new file mode 100644 index 000000000..399e84d99 --- /dev/null +++ b/include/fas/email.class.php @@ -0,0 +1,310 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($mail_id != null) + $this->load($mail_id); + } + + /** + * Laedt einen Datensatz + * @param mail_id ID des zu ladenden Datensatzes + */ + function load($mail_id) + { + //mail_id auf gueltigkeit pruefen + if(!is_numeric($mail_id) || $mail_id == '') + { + $this->errormsg = 'mail_id muss eine gueltige Zahl sein'; + return false; + } + + //laden des Datensatzes + $qry = "SELECT * FROM email WHERE email_pk='$mail_id';"; + + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler bei der Datenbankabfrage'; + return false; + } + + if($row=pg_fetch_object($res)) + { + $this->email_id = $row->email_pk; + $this->person_id = $row->person_fk; + $this->email = $row->email; + $this->name = $row->name; + $this->typ = $row->typ; + $this->zustelladresse = ($row->zustelladresse=='J'?true:false); + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Fehler bei der Datenbankabfrage'; + return false; + } + + return true; + } + + /** + * Laedt alle Datensaetze + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + /* Frisst zu viel Speicher und wird beendet + + $qry = "SELECT * FROM email;"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $mail_obj = new email($this->conn); + + $mail_obj->email_id = $row->email_pk; + $mail_obj->person_id = $row->person_fk; + $mail_obj->email = $row->email; + $mail_obj->name = $row->name; + $mail_obj->typ = $row->typ; + $mail_obj->zustelladresse = ($row->zustelladresse=='J'?true:false); + $mail_obj->updateamum = $row->creationdate; + $mail_obj->updatevon = $row->creationuser; + + $this->result[] = $mail_obj; + } + + return true; + */ + return false; + } + + /** + * Laedt alle Datensaetze zu einer person + * @param pers_id ID der Person zu der die Mails geladen werden sollen + * @return true wenn ok, false im Fehlerfall + */ + function load_pers($pers_id) + { + //pers_id auf gueltigkeit pruefen + if(!is_numeric($pers_id) || $pers_id == '') + { + $this->errormsg = 'pers_id muss eine gueltige Zahl sein'; + return false; + } + + //Datensaetze laden + $qry = "SELECT * FROM email WHERE person_fk='$pers_id';"; + + if(!$result = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + while($row = pg_fetch_object($result)) + { + $mail_obj = new email($this->conn); + + $mail_obj->email_id = $row->email_pk; + $mail_obj->person_id = $row->person_fk; + $mail_obj->email = $row->email; + $mail_obj->name = $row->name; + $mail_obj->typ = $row->typ; + $mail_obj->zustelladresse = ($row->zustelladresse=='J'?true:false); + $mail_obj->updateamum = $row->creationdate; + $mail_obj->updatevon = $row->creationuser; + + $this->result[] = $mail_obj; + } + + return true; + } + + /** + * Loescht einen Datensatz + * @param mail_id ID des zu leoschenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function delete($mail_id) + { + //mail_id auf gueltigkeit pruefen + if(!is_numeric($mail_id) || $mail_id == '') + { + $this->errormsg = 'mail_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "DELETE FROM email WHERE email_pk = '$mail_id';"; + + if(pg_query($this->conn,$qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim loeschen'; + return false; + } + } + + /** + * Prueft die variablen auf gueltigkeit + * @return true wenn ok, false im Fehlerfall + */ + function checkvars() + { + //Gesamtlaenge pruefen + if(strlen($this->name)>255) + { + $this->errormsg = 'Name darf nicht mehr als 255 Zeichen lang sein'; + return false; + } + if(strlen($this->email)>255) + { + $this->errormsg = 'EMail darf nicht mehr als 255 Zeichen lang sein'; + return false; + } + + //Zahlenfelder pruefen + if(!is_numeric($this->person_id)) + { + $this->errormsg = 'Person_id muss eine gueltige Zahl sein'; + return false; + } + if(!is_numeric($this->typ)) + { + $this->errormsg = 'Typ muss eine gueltige Zahl sein'; + return false; + } + + $this->errormsg = ''; + return true; + } + + /** + * Speichert den aktuellen Datensatz + * Wenn $neu auf true gesetzt ist wird ein neuer Datensatz angelegt + * andernfalls wird der Datensatz mit der ID in $email_id aktualisiert + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + if(!$this->checkvars()) + return false; + + if($this->new) + { + //Neuen Datensatz anlegen + + //Naechste ID aus Sequence holen + $qry = "SELECT nextval('email_seq') as id;"; + if(!$row=pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim auslesen der ID aus der Sequence'; + return false; + } + $this->email_id = $row->id; + + $qry = "INSERT INTO email (email_pk, person_fk, name, email, typ, creationdate, creationuser, zustelladresse)". + " VALUES ('$this->email_id', '$this->person_id', '$this->name', '$this->email', '$this->typ', now(),". + " $this->updatevon, '".($this->zustelladresse?'J':'N')."');"; + } + else + { + //Bestehenden Datensatz aktualisieren + + //email_id auf gueltigkeit pruefen + if(!is_numeric($this->email_id) || $this->email_id == '') + { + $this->errormsg = 'email_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "UPDATE email SET person_fk = '$this->person_id', name = '$this->name', email = '$this->email',". + " typ = '$this->typ', zustelladresse = '".($this->zustelladresse?'J':'N')."' WHERE email_pk = '$this->email_id';"; + } + + if(pg_query($this->conn, $qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim speichern des Datensatzes'; + return false; + } + } +} +?> \ No newline at end of file diff --git a/include/fas/fachbereich.class.php b/include/fas/fachbereich.class.php new file mode 100644 index 000000000..95f93716b --- /dev/null +++ b/include/fas/fachbereich.class.php @@ -0,0 +1,127 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($fachb_id != null) + $this->load($fachb_id); + } + + /** + * Laedt alle verfuegbaren Fachbereiche + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + $qry = 'SELECT * FROM fachbereich order by name;'; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden der Datensaetze'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $fachb_obj = new fachbereich($this->conn); + + $fachb_obj->fachbereich_id = $row->fachbereich_pk; + $fachb_obj->erhalter_id = $row->erhalter_fk; + $fachb_obj->name = $row->name; + $fachb_obj->updateamum = $row->creationdate; + $fachb_obj->updatevon = $row->creationuser; + + $this->result[] = $fachb_obj; + } + return true; + } + + /** + * Laedt einen Fachbereich + * @param $fachb_id ID des zu ladenden Fachbereiches + * @return true wenn ok, false im Fehlerfall + */ + function load($fachb_id) + { + if(!is_numeric($fachb_id) || $fachb_id == '') + { + $this->errormsg = 'fachb_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM fachbereich WHERE fachbereich_pk = '$fachb_id';"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + if($row=pg_fetch_object($res)) + { + $this->fachbereich_id = $row->fachbereich_pk; + $this->erhalter_id = $row->erhalter_fk; + $this->name = $row->name; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; + return false; + } + + return true; + } + + /** + * Loescht einen Datensatz + * @param $fachb_id id des Datensatzes der geloescht werden soll + * @return true wenn ok, false im Fehlerfall + */ + function delete($fachb_id) + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } + + /** + * Speichert den aktuellen Datensatz + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } +} +?> \ No newline at end of file diff --git a/include/fas/functions.inc.php b/include/fas/functions.inc.php new file mode 100644 index 000000000..8149dc00a --- /dev/null +++ b/include/fas/functions.inc.php @@ -0,0 +1,29 @@ +studiensemester_pk; + else + echo pg_last_error($conn_fas); + return $stsem_id; +} + + +?> \ No newline at end of file diff --git a/include/fas/funktion.class.php b/include/fas/funktion.class.php new file mode 100644 index 000000000..bd274e06e --- /dev/null +++ b/include/fas/funktion.class.php @@ -0,0 +1,691 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($fkt_id != null) + $this->load($fkt_id); + } + + /** + * loescht die Funktion mit der uebergebenen ID + * @param $funktion_id ID des zu loeschenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function delete($funktion_id) + { + //Pruefen ob funktion_id gueltig ist + if(is_numeric($funktion_id) && $funktion_id != '') + { + //Person ermitteln + $person_id=0; + $mitarbeiter_id=0; + $qry = "Select person_fk, mitarbeiter_pk from mitarbeiter join funktion on(mitarbeiter_pk=mitarbeiter_fk) where funktion_pk = $funktion_id"; + if($row=pg_fetch_object(pg_query($this->conn,$qry))) + { + $person_id = $row->person_fk; + $mitarbeiter_id = $row->mitarbeiter_pk; + } + else + { + $this->errormsg = 'Fehler beim ermitteln der Person'; + return false; + } + + $qry = "DELETE FROM funktion WHERE funktion_pk=$funktion_id;"; + $sql = $qry; + if(pg_query($this->conn,$qry)) + { + //Neuen aktstatus ermitteln + $qry = "Select aktstatus from person where person_pk=$person_id"; + if($row=pg_fetch_object(pg_query($this->conn,$qry))) + { + $aktstatus = $row->aktstatus; + if($aktstatus!=150) //wenn er nicht ausgeschieden ist + { + //Funktionen holen + $qry = "Select funktion from funktion where ". + "studiensemester_fk = (Select studiensemester_pk from studiensemester where aktuell='J')". + " AND mitarbeiter_fk = '$mitarbeiter_id'"; + if($result = pg_query($this->conn, $qry)) + { + $fkt=array(); + $i=0; + while($row=pg_fetch_object($result)) + { + $fkt[$i]=$row->funktion; + $i++; + } + + //Aktstatus ermitteln + if(in_array(5,$fkt)) //STGL + $aktstatus = 104; + elseif(in_array(6,$fkt)) //FBL + $aktstatus = 103; + elseif(in_array(2,$fkt)) //FBK + $aktstatus = 102; + elseif(in_array(1,$fkt)) //LKT + $aktstatus = 101; + else + $aktstatus = 100; //Mitarbeiter + + $this->status = $aktstatus; + //neuen akstatus setzen + $qry = "Update person set aktstatus = $aktstatus where person_pk = $person_id"; + if(pg_query($qry)) + { + //Log schreiben + $sql .= $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim setzen des Aktstatus'; + return false; + } + } + } + else + return true; + + } + else + { + $this->errormsg = 'Fehler beim Laden des aktuellen Status'; + return false; + } + } + else + { + $this->errormsg = 'Beim loeschen ist ein Fehler aufgetreten'; + return false; + } + } + else + { + $this->errormsg = 'funktion_id muss eine gueltige Zahl sein'; + return false; + } + } + + + /** + * Prueft die Variablen auf Gueltigkeit + * @return true wenn ok, false im Fehlerfall + */ + function checkvars() + { + //Hochkomma und HTML Tags ersetzen + //$this->name = htmlentities($this->name, ENT_QUOTES); + + //Maximallaenge pruefen + $this->errormsg = 'Die Maximallaenge eines Feldes wurde ueberschritten'; + if(strlen($this->name)>255) return false; + + //Zahlenwerte ueberpruefen + /* + $this->errormsg = 'Ein Zahlenfeld enthaelt ungueltige Zeichen'; + + if(!is_numeric($this->funktion)) return false; + if(!is_numeric($this->beschart1)) return false; + if(!is_numeric($this->beschart2)) return false; + if(!is_numeric($this->verwendung)) return false; + if(!is_numeric($this->hauptberuf)) return false; + if(!is_numeric($this->sws)) $this->sws=0; + if(!is_numeric($this->ausmass)) return false; + if(!is_numeric($this->mitarbeiter_id)) return false; + if(!is_numeric($this->erhalter_id)) return false; + if(!is_numeric($this->studiengang_id)) return false; + if(!is_numeric($this->fachbereich_id)) return false; + if(!is_numeric($this->studiensemester_id)) return false; + if(!is_numeric($this->besonderequalifikation)) return false; + */ + $this->errormsg = ''; + return true; + } + + /** + * Speichert die Daten in die Datenbank + * @return true wenn OK, false im Fehlerfall + */ + function save() + { + if(!$this->checkvars()) + return false; + + //neuen aktstatus ermitteln + if($status=$this->getaktstatus()) + $statusqry = "Update person SET aktstatus=$status where person_pk = (Select person_fk from mitarbeiter where mitarbeiter_pk='$this->mitarbeiter_id');"; + else + $statusqry = ""; + + if($this->new) + { + //Naechste ID aus der Sequence holen + $qry = "SELECT nextval('funktion_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn,$qry))) + { + $this->errormsg = 'Sequence konnte nicht ausgelesen werden'; + return false; + } + $this->funktion_id = $row->id; + + $qry= $statusqry."INSERT INTO funktion (funktion_pk, mitarbeiter_fk, studiensemester_fk, erhalter_fk, studiengang_fk,". + " fachbereich_fk, name, funktion, creationdate, creationuser, beschart1, beschart2, verwendung,". + " hauptberuflich, hauptberuf, entwicklungsteam, besonderequalifikation, sws, ausmass) VALUES(". + " '$this->funktion_id','$this->mitarbeiter_id', '$this->studiensemester_id', '$this->erhalter_id',". + ($this->studiengang_id!=''?" '$this->studiengang_id'":'null').",". + ($this->fachbereich_id!=''?" '$this->fachbereich_id'":'null').",". + ($this->name!=''?" '$this->name'":'null').",". + ($this->funktion!=''?" '$this->funktion'":'null').", now(), $this->updatevon,". + ($this->beschart1!=''?" '$this->beschart1'":'null').",". + ($this->beschart2!=''?" '$this->beschart2'":'null').",". + ($this->verwendung!=''?" '$this->verwendung'":'null').", '".($this->hauptberuflich?'J':'N')."',". + ($this->hauptberuf!=''?" '$this->hauptberuf'":'null').", '".($this->entwicklungsteam?'J':'N')."',". + ($this->besonderequalifikation!=''?" '$this->besonderequalifikation'":'null').", null,". + ($this->ausmass!=''?" '$this->ausmass'":'null').")"; + + } + else + { + if(!is_numeric($this->mitarbeiter_id) && !is_numeric($this->funktion_id)) + { + $this->errormsg = 'mitarbeiter_id und funktion_id muessen eine gueltige Zahl sein'; + return false; + } + + $qry= $statusqry. "UPDATE funktion SET ". + " studiensemester_fk=".($this->studiensemester_id!=''?"'$this->studiensemester_id'":'null').",". + " erhalter_fk=".($this->erhalter_id!=''?"'$this->erhalter_id'":'null').",". + " studiengang_fk=".($this->studiengang_id!=''?"'$this->studiengang_id'":'null').",". + " fachbereich_fk=".($this->fachbereich_id!=''?"'$this->fachbereich_id'":'null').",". + " name=".($this->name!=''?"'$this->name'":'null').",". + " funktion=".($this->funktion!=''?"'$this->funktion'":'null').",". + " beschart1=".($this->beschart1!=''?"'$this->beschart1'":'null').",". + " beschart2=".($this->beschart2!=''?"'$this->beschart2'":'null').",". + " verwendung=".($this->verwendung!=''?"'$this->verwendung'":'null').",". + " hauptberuflich='".($this->hauptberuflich?'J':'N')."',". + " hauptberuf=".($this->hauptberuf!=''?"'$this->hauptberuf'":'null').",". + " entwicklungsteam='".($this->entwicklungsteam?'J':'N')."',". + " besonderequalifikation=".($this->besonderequalifikation!=''?"'$this->besonderequalifikation'":'null').",". + " sws=".($this->sws!=''?"'$this->sws'":'null').",". + " ausmass=".($this->ausmass!=''?"'$this->ausmass'":'null'). + " WHERE funktion_pk=$this->funktion_id"; // AND mitarbeiter_fk=$this->mitarbeiter_id"; + } + + if(pg_query($this->conn,$qry)) + { + $qry = "UPDATE funktion SET hauptberuflich='".($this->hauptberuflich?'J':'N')."', hauptberuf=".($this->hauptberuf!=''?"'$this->hauptberuf'":'null')." WHERE mitarbeiter_fk ='$this->mitarbeiter_id' AND studiensemester_fk='$this->studiensemester_id'"; + if(!pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler beim Updaten der Funktionen'; + return false; + } + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim Speichern der Daten'.$qry; + return false; + } + } + + /** + * Ermittelt den neuen aktstatus einer Person + */ + function getaktstatus() + { + $aktstatus=100; + //Aktuellen Status holen + $qry = "Select aktstatus from person join mitarbeiter on(person_fk=person_pk) where mitarbeiter_pk='".$this->mitarbeiter_id."'"; + if($result = pg_query($this->conn,$qry)) + { + if($row = pg_fetch_object($result)) + $aktstatus = $row->aktstatus; + else + { + $this->errormsg = 'Fehler beim Laden des aktuellen Status'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim Laden des aktuellen Status'; + return false; + } + + /* + //Wenn die Funktion das aktuelle Studiensemester betrifft + $qry = "Select studiensemester_pk from studiensemester where aktuell='J'"; + if($result = pg_query($this->conn,$qry)) + { + if($row=pg_fetch_object($result)) + { + if($row->studiensemester_pk == $this->studiensemester_id) + { + */ + //Neuen Status setzen + if($this->funktion == 1 && $aktstatus < 101) //Lektor + $aktstatus = 101; + elseif($this->funktion == 2 && $aktstatus < 102) //Fachbereichskoordinator + $aktstatus = 102; + elseif($this->funktion == 6 && $aktstatus < 103) //Fachbereichsleiter + $aktstatus = 103; + elseif($this->funktion == 5 && $aktstatus < 104) //Studiengangsleiter + $aktstatus = 104; + /* } + } + else + { + $this->errormsg = 'Fehler beim Laden des aktuellen Studiensemesters'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim Laden des aktuellen Studiensemesters'; + return false; + }*/ + $this->status = $aktstatus; + return $aktstatus; + } + + /** + * Laedt eine Funktion aus der DB + * @param $fkt_id ID der zu ladenden Funktion + * @return true wenn erfolgreich geladen, false im Fehlerfall + */ + function load($fkt_id) + { + //Pruefen ob fkt_id gueltig ist + if(!is_numeric($fkt_id)) + { + $this->errormsg = 'funktion_id muss eine Zahl sein'; + return false; + } + + $qry = "SELECT * FROM funktion WHERE funktion_pk=$fkt_id"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->funktion_id = $row->funktion_pk; + $this->mitarbeiter_id = $row->mitarbeiter_fk; + $this->studiensemester_id = $row->studiensemester_fk; + $this->erhalter_id = $row->erhalter_fk; + $this->studiengang_id = $row->studiengang_fk; + $this->fachbereich_id = $row->fachbereich_fk; + $this->name = $row->name; + $this->funktion = $row->funktion; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + $this->beschart1 = $row->beschart1; + $this->beschart2 = $row->beschart2; + $this->verwendung = $row->verwendung; + $this->hauptberuflich = ($row->hauptberuflich=='J'?true:false); + $this->hauptberuf = $row->hauptberuf; + $this->entwicklungsteam = ($row->entwicklungsteam=='J'?true:false); + $this->besonderequalifikation = $row->besonderequalifikation; + $this->sws = $row->sws; + $this->ausmass = $row->ausmass; + } + else + { + $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; + return false; + } + + return true; + } + + /** + * Laedt die Funktion(en) eines Mitarbeiters + * @param $ma_id ID des zu ladenden Mitarbeiters + * @return true wenn erfolgreich geladen, false im Fehlerfall + */ + function load_pers($ma_id, $stsem='') + { + //pruefen ob ma_id gueltig ist + if(!is_numeric($ma_id)) + { + $this->errormsg = 'mitarbeiter_id muss eine Zahl sein'; + return false; + } + + $qry="SELECT * FROM funktion WHERE mitarbeiter_fk=$ma_id"; + if($stsem!='') + $qry.= " AND studiensemester_fk='$stsem'"; + $qry.=" ORDER BY studiensemester_fk DESC, funktion_pk"; + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $fkt_obj = new funktion($this->conn); + + $fkt_obj->funktion_id = $row->funktion_pk; + $fkt_obj->mitarbeiter_id = $row->mitarbeiter_fk; + $fkt_obj->studiensemester_id = $row->studiensemester_fk; + $fkt_obj->erhalter_id = $row->erhalter_fk; + $fkt_obj->studiengang_id = $row->studiengang_fk; + $fkt_obj->fachbereich_id = $row->fachbereich_fk; + $fkt_obj->name = $row->name; + $fkt_obj->funktion = $row->funktion; + $fkt_obj->updateamum = $row->creationdate; + $fkt_obj->updatevon = $row->creationuser; + $fkt_obj->beschart1 = $row->beschart1; + $fkt_obj->beschart2 = $row->beschart2; + $fkt_obj->verwendung = $row->verwendung; + $fkt_obj->hauptberuflich = ($row->hauptberuflich=='J'?true:false); + $fkt_obj->hauptberuf = $row->hauptberuf; + $fkt_obj->entwicklungsteam = ($row->entwicklungsteam=='J'?true:false); + $fkt_obj->besonderequalifikation = $row->besonderequalifikation; + $fkt_obj->sws = $row->sws; + $fkt_obj->ausmass = $row->ausmass; + + $this->result[] = $fkt_obj; + } + + return true; + } + + function getMitarbeiter($stg,$fb,$funktion,$stsem=null) + { + $qry = "SELECT + mitarbeiter_fk + FROM + funktion + WHERE + studiengang_fk='$stg' AND + fachbereich_fk='$fb' + GROUP BY mitarbeiter_fk"; + if($result = pg_query($this->conn,$qry)) + { + while($row = pg_fetch_object($result)) + { + $fkt = new funktion($this->conn); + $fkt->mitarbeiter_id = $row->mitarbeiter_fk; + $this->result[] = $fkt; + } + return true; + } + else + { + $this->errormsg = 'Fehler beim laden der Mitarbeiter'; + return false; + } + } + + /** + * Laedt alle Funktionen + * @return true wenn erfolgreich geladen, false im Fehlerfall + */ + function getAll() + { + /*Eventuell Speicherprobleme + + $qry = "SELECT * FROM funktion"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + while($row=pg_fetch_object($res)) + { + $fkt_obj = new funktion($this->conn); + + $fkt_obj->funktion_id = $row->funktion_pk; + $fkt_obj->mitarbeiter_id = $row->mitarbeiter_fk; + $fkt_obj->studiensemester_id = $row->studiensemester_fk; + $fkt_obj->erhalter_id = $row->erhalter_fk; + $fkt_obj->studiengang_id = $row->studiengang_fk; + $fkt_obj->fachbereich_id = $row->fachbereich_fk; + $fkt_obj->name = $row->name; + $fkt_obj->funktion = $row->funktion; + $fkt_obj->updateamum = $row->creationdate; + $fkt_obj->updatevon = $row->creationuser; + $fkt_obj->beschart1 = $row->beschart1; + $fkt_obj->beschart2 = $row->beschart2; + $fkt_obj->verwendung = $row->verwendung; + $fkt_obj->hauptberuflich = ($row->hauptberuflich=='J'?true:false); + $fkt_obj->hauptberuf = $row->hauptberuf; + $fkt_obj->entwicklungsteam = ($row->entwicklungsteam=='J'?true:false); + $fkt_obj->besonderequalifikation = $row->besonderequalifikation; + $fkt_obj->sws = $row->sws; + $fkt_obj->ausmass = $row->ausmass; + + $this->result[] = $fkt_obj; + } + return true; + */ + return false; + } + + function FunktionExists($mitarbeiter_id, $studiengang_id, $fachbereich_id, $studiensemester_id, $funktion) + { + $qry = "SELECT + count(*) as anzahl + FROM + funktion + WHERE + mitarbeiter_fk='$mitarbeiter_id' AND + studiengang_fk='$studiengang_id' AND + fachbereich_fk='$fachbereich_id' AND + studiensemester_fk = '$studiensemester_id' AND + funktion='$funktion'"; + if($result = pg_query($this->conn, $qry)) + { + if($row = pg_fetch_object($result)) + { + if($row->anzahl>0) + return true; + else + { + return false; + } + } + else + { + return false; + $this->errormsg = 'Fehler beim auslesen der Funktionen'; + } + } + else + { + return false; + $this->errormsg = 'Fehler beim auslesen der Funktionen'; + } + } + + function getNameFunktion($id) + { + switch($id) + { + case 0: return 'Mitarbeiter'; + case 1: return 'Lektor'; + case 2: return 'Fachbereichskoordinatior'; + case 3: return 'Assistenz'; + case 4: return 'Rektor'; + case 5: return 'Studiengangsleiter'; + case 6: return 'Fachbereichsleiter'; + default: return ''; + } + } + + function getNameBeschart1($id) + { + switch($id) + { + case 1: return 'Dienstverhältnis zum Bund'; + case 2: return 'Dienstverhältnis zu einer anderen Gebietskörperschaft'; + case 3: return 'Echter Dienstvertrag'; + case 4: return 'Freier Dienstvertrag'; + case 5: return 'Lehr- oder Ausbildungsverhältnis'; + case 6: return 'Sonstiges Beschäftigungsverhältnis'; + default: return ''; + } + } + + function getNameBeschart2($id) + { + switch($id) + { + case 1: return 'befristet'; + case 2: return 'unbefristet'; + default: return ''; + } + } + + function getNameVerwendung($id) + { + switch($id) + { + case 1: return 'Lehr- und Forschungspersonal'; + case 2: return 'Lehr- und Forschungshilfspersonal'; + case 3: return 'Akademische dienste für Studierende'; + case 4: return 'Soziale Dienste und Gesundheitsdienste'; + case 5: return 'Studiengangsleiter/in'; + case 6: return 'Leiter/in FH-Kollegium'; + case 7: return 'Management'; + case 8: return 'Verwaltung'; + case 9: return 'Hauspersonal, Gebäude-/Haustechnik'; + default: return ''; + } + + } + + function getNameHauptberuf($id) + { + switch($id) + { + case '': return ''; + case 0: return 'Universität'; + case 1: return 'Fachhochschule'; + case 2: return 'Andere postsekundäre Bildungseinrichtung'; + case 3: return 'Allgemeinbildende höhere Schule'; + case 4: return 'Berufsbildende höhere Schule'; + case 5: return 'Andere Schule'; + case 6: return 'Öffentlicher Sektor'; + case 7: return 'Unternehmenssektor'; + case 8: return 'Freiberuflich tätig'; + case 9: return 'Privater gemeinnütziger Sektor'; + case 10: return 'Ausserhochschulische Forschungseinrichtung'; + case 11: return 'Internationale Organisation'; + case 12: return 'Sonstiges'; + default: return ''; + } + } + + function getNameBesonderequalifikation($id) + { + switch($id) + { + case 0: return 'keine'; + case 1: return 'Habilitation'; + case 2: return 'der Habilitation gleichwertige Qualifikation'; + case 3: return 'berufliche Tätigkeit'; + default: return ''; + } + } + + function getNameAusmass($id) + { + switch($id) + { + case 1: return 'Vollzeit'; + case 2: return '<= 15 Wochenstunden'; + case 3: return '16 - 25 Wochenstunden'; + case 4: return '26 - 35 Wochenstunden'; + case 5: return 'Karenz'; + default: return ''; + } + } +} +?> \ No newline at end of file diff --git a/include/fas/gruppe.class.php b/include/fas/gruppe.class.php new file mode 100644 index 000000000..c9f49216e --- /dev/null +++ b/include/fas/gruppe.class.php @@ -0,0 +1,202 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($gruppe_id != null) + $this->load($gruppe_id); + } + + /** + * Laedt eine Gruppe + * @param gruppe_id ID der Gruppe + * @return true wenn ok, false im Fehlerfall + */ + function load($gruppe_id) + { + //gruppe_id auf gueltigkeit pruefen + if(!is_numeric($gruppe_id) || $gruppe_id =='') + { + $this->errormsg = 'gruppe_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM gruppe WHERE gruppe_pk='$gruppe_id';"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->ausbildungssemester_id = $row->ausbildungssemester_fk; + $this->gruppe_id = $row->gruppe_pk; + $this->name = $row->name; + $this->nummerintern = $row->nummerintern; + $this->obergruppe_id = $row->obergruppe_fk; + $this->ordnung = $row->ordnung; + $this->studiengang_id = $row->studiengang_fk; + $this->typ = $row->typ; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + + $this->fullname = $this->getFullName($row->gruppe_pk); + } + else + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + return true; + } + + /** + * Liefert den vollen namen einer Gruppe + * @param $gruppe_id + * @return voller name, false im Fehlerfall + */ + function getFullName($gruppe_id) + { + //gruppe_id auf gueltigkeit pruefen + if(!is_numeric($gruppe_id) || $gruppe_id == '') + { + $this->errormsg = 'gruppe_id muss eine gueltige Zahl sein'; + return false; + } + + //gesamten gruppennamen ermitteln + $qry = "SELECT fas_function_get_fullname_from_gruppe($gruppe_id) as fullname;"; + + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Gruppenname konnte nicht ermittelt werden'; + return false; + } + + return $row->fullname; + } + + /** + * Laedt alle Gruppen eines Studienganges/studiensemesters/ausbildungssemesters + * @param studiengang_id ID des studienganges + * studiensemester_id ID des Studiensemesters (optional) + * ausbildungssemester_id ID des Ausbildungssemesters (optional) + * @return true wenn ok, false im Fehlerfall + */ + function load_gruppen($studiengang_id, $studiensemester_id=null, $ausbildungssemester_id=null) + { + //Pruefen ob gueltige Werte uebergeben wurden + if(!is_numeric($studiengang_id) || $studiengang_id == '') + { + $this->errormsg = 'studiengang_id muss eine gueltige Zahl sein'; + return false; + } + + if($studiensemester_id!=null && (!is_numeric($studiensemester_id) || $studiensemester_id == '')) + { + $this->errormsg = 'studiensemester_id muss eine gueltige Zahl sein'; + return false; + } + + if($ausbildungssemester_id!=null && (!is_numeric($ausbildungssemester_id) || $ausbildungssemester_id == '')) + { + $this->errormsg = 'ausbildungssemester_id muss eine gueltige Zahl sein'; + return false; + } + + //Befehl zusammenbauen + $qry = "SELECT * FROM gruppe WHERE studiengang_fk='$studiengang_id' "; + + if($ausbildungssemester_id!=null) + $qry .= "AND ausbildungssemester_fk='$ausbildungssemester_id' "; + + if($studiensemester_id != null) + $qry .= "AND studiensemester_fk='$studiensemester_id' "; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + //Daten laden + while($row = pg_fetch_object($res)) + { + $grp_obj = new gruppe($this->conn); + + $grp_obj->ausbildungssemester_id = $row->ausbildungssemester_fk; + $grp_obj->gruppe_id = $row->gruppe_pk; + $grp_obj->name = $row->name; + $grp_obj->nummerintern = $row->nummerintern; + $grp_obj->obergruppe_id = $row->obergruppe_fk; + $grp_obj->ordnung = $row->ordnung; + $grp_obj->studiengang_id = $row->studiengang_fk; + $grp_obj->typ = $row->typ; + $grp_obj->updateamum = $row->creationdate; + $grp_obj->updatevon = $row->creationuser; + + $grp_obj->fullname = $this->getFullName($row->gruppe_pk); + + $this->result[] = $grp_obj; + } + + return true; + } + + /** + * Speichert den aktuellen Datensatz in die DB + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } + + /** + * Loescht einen Datensatz + * @param $gruppe_id ID des zu loeschenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function delete($gruppe_id) + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } +} +?> \ No newline at end of file diff --git a/include/fas/lehreinheit.class.php b/include/fas/lehreinheit.class.php new file mode 100644 index 000000000..b7077575a --- /dev/null +++ b/include/fas/lehreinheit.class.php @@ -0,0 +1,1588 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($lehreinheit_id != null) + $this->load($lehreinheit_id); + } + + /** + * Laedt einen Datensatz + * @param $lehreinheit_id ID des zu ladenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function load($lehreinheit_id) + { + if(!is_numeric($lehreinheit_id) || $lehreinheit_id == '') + { + $this->errormsg = 'lehreinheit_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM lehreinheit WHERE lehreinheit_pk = '$lehreinheit_id'"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->lehreinheit_id = $row->lehreinheit_pk; + $this->studiengang_id = $row->studiengang_fk; + $this->studiensemester_id = $row->studiensemester_fk; + $this->ausbildungssemester_id = $row->ausbildungssemester_fk; + $this->fachbereich_id = $row->fachbereich_fk; + $this->gruppe_id = $row->gruppe_fk; + $this->koordinator_id = $row->bivar1; + $this->lehrform_id = $row->lehrform_fk; + $this->lehrveranstaltung_id = $row->lehrveranstaltung_fk; + $this->raumtyp_id = $row->raumtyp_fk; + $this->raumtypalternativ_id = $row->alternativraumtyp_fk; + $this->bemerkungen = $row->bemerkungen; + $this->bezeichnung = $row->bezeichnung; + $this->gesamtstunden = $row->gesamtstunden; + $this->kurzbezeichnung = $row->kurzbezeichnung; + $this->nummer = $row->nummer; + $this->planfaktor = $row->planfaktor; + $this->plankostenprolektor = $row->plankostenprolektor; + $this->planlektoren = $row->planlektoren; + $this->semesterwochenstunden = $row->semesterwochenstunden; + $this->start_kw = $row->ivar2; + $this->stundenblockung = $row->ivar3; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + $this->wochenrythmus = $row->ivar1; + } + else + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + return true; + } + + /** + * Laedt eine / mehrere Lehreinheit(en) + * @param $studiengang_id ID des zu ladenden Studienganges + * $studiensemester_id ID des zu ladenden Studiensemesters (optional) + * $ausbildungssemester_id ID des zu ladenden Ausbildungssemesters (optional) + * $lehrform_id ID der zu ladenden Lehrform (optional) + * @return true wenn ok, false im Fehlerfall + */ + function load_einheit($studiengang_id, $studiensemester_id=null, $ausbildungssemester_id=null, $lehrform_id=null) + { + //Gueltigkeit der Parameter pruefen + if(!is_numeric($studiengang_id) || $studiengang_id == '') + { + $this->errormsg = 'studiengang_id muss eine gueltige Zahl sein'; + return false; + } + if($studiensemester_id!=null && (!is_numeric($studiensemester_id) || $studiensemester_id == '')) + { + $this->errormsg = 'studiensemester_id muss eine gueltige Zahl oder null sein'; + return false; + } + if($ausbildungssemester_id!=null && (!is_numeric($ausbildungssemester_id) || $ausbildungssemester_id == '')) + { + $this->errormsg = 'ausbildungssemester_id muss eine gueltige Zahl oder null sein'; + return false; + } + if($lehrform_id!=null && (!is_numeric($lehrform_id) || $lehrform_id == '')) + { + $this->errormsg = 'lehrform_id muss eine gueltige Zahl oder null sein'; + return false; + } + + //Select Befehl zusammenbauen + $qry = "SELECT * FROM lehreinheit WHERE studiengang_fk = '$studiengang_id'"; + + if($studiensemester_id != null) + $qry .= " AND studiensemester_fk = '$studiensemester_id'"; + + if($ausbildungssemester_id != null) + $qry .= " AND ausbildungssemester_fk = '$ausbildungssemester_id'"; + + if($lehrform_id != null) + $qry .= " AND lehrform_fk = '$lehrform_id'"; + + //Daten auslesen + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $einh_obj = new lehreinheit($this->conn); + + $einh_obj->lehreinheit_id = $row->lehreinheit_pk; + $einh_obj->studiengang_id = $row->studiengang_fk; + $einh_obj->studiensemester_id = $row->studiensemester_fk; + $einh_obj->ausbildungssemester_id = $row->ausbildungssemester_fk; + $einh_obj->fachbereich_id = $row->fachbereich_fk; + $einh_obj->gruppe_id = $row->gruppe_fk; + $einh_obj->koordinator_id = $row->bivar1; + $einh_obj->lehrform_id = $row->lehrform_fk; + $einh_obj->lehrveranstaltung_id = $row->lehrveranstaltung_fk; + $einh_obj->raumtyp_id = $row->raumtyp_fk; + $einh_obj->raumtypalternativ_id = $row->alternativraumtyp_fk; + $einh_obj->bemerkungen = $row->bemerkungen; + $einh_obj->bezeichnung = $row->bezeichnung; + $einh_obj->gesamtstunden = $row->gesamtstunden; + $einh_obj->kurzbezeichnung = $row->kurzbezeichnung; + $einh_obj->nummer = $row->nummer; + $einh_obj->planfaktor = $row->planfaktor; + $einh_obj->plankostenprolektor = $row->plankostenprolektor; + $einh_obj->planlektoren = $row->planlektoren; + $einh_obj->semesterwochenstunden = $row->semesterwochenstunden; + $einh_obj->start_kw = $row->ivar2; + $einh_obj->stundenblockung = $row->ivar3; + $einh_obj->updateamum = $row->creationdate; + $einh_obj->updatevon = $row->creationuser; + $einh_obj->wochenrythmus = $row->ivar1; + + $this->result[] = $einh_obj; + } + return true; + } + + /** + * Prueft die Variablen auf Gueltigkeit + * Hochkomma und HTML Tags werden ersetzt + * @return true wenn ok, false im Fehlerfall + */ + function checkvars() + { + + //Hochkomma und HTML Tags codieren + $this->nummer = str_replace("'","`",$this->nummer); + $this->bezeichnung = str_replace("'","`",$this->bezeichnung); + $this->kurzbezeichnung = str_replace("'","`",$this->kurzbezeichnung); + $this->bemerkungen = str_replace("'","`",$this->bemerkungen); + + if(ereg("[^a-zA-Z0-9]", $this->kurzbezeichnung)) + { + $this->errormsg = "Die Kurzbezeichnung darf keine Umlaute oder Sonderzeichen enthalten"; + return false; + } + + //Gesamtlaenge pruefen + if(strlen($this->nummer)>20) + { + $this->errormsg = 'Nummer darf nicht laenger als 20 Zeichen sein'; + return false; + } + if(strlen($this->bezeichnung)>255) + { + $this->errormsg = 'Bezeichnung darf nicht laenger als 255 Zeichen sein'; + return false; + } + if(strlen($this->kurzbezeichnung)>5) + { + $this->errormsg = 'Kurzbezeichnung darf nicht laenger als 5 Zeichen sein'; + return false; + } + if(strlen($this->bemerkungen)>255) + { + $this->errormsg = 'Bemerkung darf nicht laenger als 255 Zeichen sein'; + return false; + } + + //Zahlenfelder pruefen + if(!is_numeric($this->studiengang_id)) + { + $this->errormsg = 'Studiengang ist ungueltig'; + return false; + } + if(!is_numeric($this->studiensemester_id)) + { + $this->errormsg = 'Studiensemester ist ungueltig'; + return false; + } + if($this->lehrveranstaltung_id!='' && !is_numeric($this->lehrveranstaltung_id)) + { + $this->errormsg = 'Lehrveranstaltung_id ist ungueltig'; + return false; + } + if($this->fachbereich_id!='' && !is_numeric($this->fachbereich_id)) + { + $this->errormsg = 'Fachbereich_id ist ungueltig'; + return false; + } + if($this->ausbildungssemester_id !='' && !is_numeric($this->ausbildungssemester_id)) + { + $this->errormsg = 'Ausbildungssemester_id ist ungueltig'; + return false; + } + if($this->lehrform_id!='' && !is_numeric($this->lehrform_id)) + { + $this->errormsg = 'Lehrform_id ist ungueltig'; + return false; + } + if($this->lehreinheit_fk!='' && !is_numeric($this->lehreinheit_fk)) + { + $this->errormsg = 'Lehreinheit_fk ist ungueltig'; + return false; + } + if($this->gruppe_id!='' && !is_numeric($this->gruppe_id)) + { + $this->errormsg = 'Gruppe ist ungueltig'; + return false; + } + if($this->semesterwochenstunden!='' && !is_numeric($this->semesterwochenstunden)) + { + $this->errormsg = 'Semesterwochenstunden muessen eine gueltige Zahl sein'; + return false; + } + if($this->gesamtstunden!='' && !is_numeric($this->gesamtstunden)) + { + $this->errormsg = 'Gesamtstunden muessen eine gueltige Zahl sein'; + return false; + } + if($this->plankostenprolektor!='' && !is_numeric($this->plankostenprolektor)) + { + $this->errormsg = 'Kosten pro Lektor muss eine gueltige Zahl sein'; + return false; + } + if($this->planfaktor!='' && !is_numeric($this->planfaktor)) + { + $this->errormsg = 'Geplanter Faktor muss eine gueltige Zahl sein'; + return false; + } + if($this->planlektoren!='' && !is_numeric($this->planlektoren)) + { + $this->errormsg = 'Anzahl der Lektoren muss eine gueltige Zahl sein'; + return false; + } + if($this->raumtyp_id!='' && !is_numeric($this->raumtyp_id)) + { + $this->errormsg = 'Raumtyp ist ungueltig'; + return false; + } + if($this->raumtypalternativ_id!='' && !is_numeric($this->raumtypalternativ_id)) + { + $this->errormsg = 'Alternativraumtyp ist ungueltig'; + return false; + } + if($this->wochenrythmus!='' && !is_numeric($this->wochenrythmus)) + { + $this->errormsg = 'Wochenrythmus muss eine gueltige Zahl sein'; + return false; + } + if($this->start_kw!='' && !is_numeric($this->start_kw)) + { + $this->errormsg = 'Kalenderwoche muss eine gueltige Zahl sein'; + return false; + } + if($this->stundenblockung!='' && !is_numeric($this->stundenblockung)) + { + $this->errormsg = 'Stundenblockung muss eine gueltige Zahl sein'; + return false; + } + if($this->koordinator_id!='' && !is_numeric($this->koordinator_id)) + { + $this->errormsg = 'Koordinator ist ungueltig'; + return false; + } + + $this->errormsg = ''; + return true; + } + + /** + * Speichert den aktuellen Datensatz + * Wenn new auf true gesetzt ist wird ein neuer Datensatz angelegt + * ansonsten wird der datensatz mit der ID lehreinheit_id aktualisiert + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + //Variablen pruefen + if(!$this->checkvars()) + return false; + + if($this->new) + { + //Neuen Datensatz anlegen + + //naechste ID aus Sequence holen + $qry = "SELECT nextval('lehreinheit_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim auslesen der Sequence'; + return false; + } + $this->lehreinheit_id = $row->id; + + //Insert Befehl zusammenbauen + $qry = "INSERT INTO lehreinheit (lehreinheit_pk, studiengang_fk, studiensemester_fk, lehrveranstaltung_fk,". + " fachbereich_fk, ausbildungssemester_fk, lehreinheit_fk, lehrform_fk, gruppe_fk, nummer, bezeichnung,". + " kurzbezeichnung, semesterwochenstunden, gesamtstunden, plankostenprolektor, planfaktor, planlektoren,". + " raumtyp_fk, alternativraumtyp_fk, bemerkungen, ivar1, ivar2, ivar3, bivar1, creationdate, creationuser)". + " VALUES('$this->lehreinheit_id', '$this->studiengang_id', '$this->studiensemester_id',". + ($this->lehrveranstaltung_id!=''?" '$this->lehrveranstaltung_id'":" null").",". + ($this->fachbereich_id!=''?" '$this->fachbereich_id'":" null").",". + ($this->ausbildungssemester_id!=''?" '$this->ausbildungssemester_id'":" null").",". + ($this->lehreinheit_fk!=''?" '$this->lehreinheit_fk'":" null").",". + ($this->lehrform_id!=''?" '$this->lehrform_id'":" null").",". + ($this->gruppe_id!=''?" '$this->gruppe_id'":" null").",". + ($this->nummer!=''?" '$this->nummer'":" null").",". + ($this->bezeichnung!=''?" '$this->bezeichnung'":" null").",". + ($this->kurzbezeichnung!=''?" '$this->kurzbezeichnung'":" null").",". + ($this->semesterwochenstunden!=''?" '$this->semesterwochenstunden'":" null").",". + ($this->gesamtstunden!=''?" '$this->gesamtstunden'":" null").",". + ($this->plankostenprolektor!=''?" '$this->plankostenprolektor'":" null").",". + ($this->planfaktor!=''?" '$this->planfaktor'":" null").",". + ($this->planlektoren!=''?" '$this->planlektoren'":" null").",". + ($this->raumtyp_id!=''?" '$this->raumtyp_id'":" null").",". + ($this->raumtypalternativ_id!=''?" '$this->raumtypalternativ_id'":" null").",". + ($this->bemerkungen!=''?" '$this->bemerkungen'":" null").",". + ($this->wochenrythmus!=''?" '$this->wochenrythmus'":" null").",". + ($this->start_kw!=''?" '$this->start_kw'":" null").",". + ($this->stundenblockung!=''?" '$this->stundenblockung'":" null").",". + ($this->koordinator_id!=''?" '$this->koordinator_id'":" null").", now(),$this->updatevon);"; + } + else + { + //lehreinheit_id auf gueltigkeit pruefen + if(!is_numeric($this->lehreinheit_id) || $this->lehreinheit_id == '') + { + $this->errormsg = 'lehreinheit_id muss eine gueltige Zahl sein'; + return false; + } + + //Update Befehl zusammenbauen + $qry = "UPDATE lehreinheit SET". + " studiengang_fk = '$this->studiengang_id',". + " studiensemester_fk = '$this->studiensemester_id',". + " lehrveranstaltung_fk = '$this->lehrveranstaltung_id',". + " fachbereich_fk = ".($this->fachbereich_id!=''?"'$this->fachbereich_id'":"null").",". + " ausbildungssemester_fk = ".($this->ausbildungssemester_id!=''?"'$this->ausbildungssemester_id'":"null").",". + " lehreinheit_fk = ".($this->lehreinheit_fk!=''?"'$this->lehreinheit_fk'":"null").",". + " lehrform_fk = ".($this->lehrform_id!=''?"'$this->lehrform_id'":"null").",". + " gruppe_fk = ".($this->gruppe_id!=''?"'$this->gruppe_id'":"null").",". + " nummer = '$this->nummer',". + " bezeichnung = '$this->bezeichnung',". + " kurzbezeichnung = '$this->kurzbezeichnung',". + " semesterwochenstunden = ".($this->semesterwochenstunden!=''?"'$this->semesterwochenstunden'":"null").",". + " gesamtstunden = ".($this->gesamtstunden!=''?"'$this->gesamtstunden'":"null").",". + " plankostenprolektor = ".($this->plankostenprolektor!=''?"'$this->plankostenprolektor'":"null").",". + " planfaktor = ".($this->planfaktor!=''?"'$this->planfaktor'":"null").",". + " planlektoren = ".($this->planlektoren!=''?"'$this->planlektoren'":"null").",". + " raumtyp_fk = ".($this->raumtyp_id!=''?"'$this->raumtyp_id'":"null").",". + " alternativraumtyp_fk = ".($this->raumtypalternativ_id!=''?"'$this->raumtypalternativ_id'":"null").",". + " bemerkungen = '$this->bemerkungen',". + " ivar1 = ".($this->wochenrythmus!=''?"'$this->wochenrythmus'":"null").",". + " ivar2 = ".($this->start_kw!=''?"'$this->start_kw'":"null").",". + " ivar3 = ".($this->stundenblockung!=''?"'$this->stundenblockung'":"null").",". + " bivar1= ".($this->koordinator_id!=''?"'$this->koordinator_id'":"null"). + " WHERE lehreinheit_pk = '$this->lehreinheit_id';"; + } + + if(pg_query($this->conn, $qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim Speichern des Datensatzes'.$qry.' '.pg_errormessage($this->conn); + return false; + } + } + + /** + * Loescht einen Datensatz + * @param $lehreinheit_id ID des zu leoschenden DS + * @return true wenn ok, false im Fehlerfall + */ + function delete($lehreinheit_id) + { + if(!is_numeric($lehreinheit_id) || $lehreinheit_id == '') + { + $this->errormsg = 'lehreinheit_id muss eine gueltige Zahl sein'; + return false; + } + //Pruefen ob diese Lehreinheit Partizipierte Lehreinheiten hat + $qry = "SELECT count(*) as anz FROM lehreinheit where lehreinheit_fk='$lehreinheit_id'"; + if(!$result = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim Auslesen der partizipierenden Lehreinheiten'; + return false; + } + else + { + if(!$row=pg_fetch_object($result) || $row->anz>0) + { + $this->errormsg = 'Sie können diese Lehreinheit nicht löschen da noch partizipierende Lehreinheiten vorhanden sind.'.$qry; + return false; + } + } + + $qry = "DELETE FROM lehreinheit where lehreinheit_pk = '$lehreinheit_id'"; + + if(!pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim loeschen des Datensatzes'; + return false; + } + else + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + } + + + + + /** + * Laedt alle/id des uebergebenen Mitarbeiter die zu einer Lehreinheit gehoeren + * @param $lehreinheit_id ID der Lehreinheit + * $mitarbeiter_id ID des Mitarbeiters (optional) + * @return true wenn ok, false im Fehlerfall + */ + function load_zuteilung($lehreinheit_id, $mitarbeiter_id=null) + { + //Variablen pruefen + if(!is_numeric($lehreinheit_id) || $lehreinheit_id == '') + { + $this->errormsg = 'lehreinheit_id muss eine gueltige Zahl sein'; + return false; + } + if($mitarbeiter_id != null && (!is_numeric($mitarbeiter_id) || $mitarbeiter_id == '')) + { + $this->errormsg = 'mitarbeiter_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM mitarbeiter_lehreinheit where lehreinheit_fk = '$lehreinheit_id'"; + + if($mitarbeiter_id != null) + $qry .= " AND mitarbeiter_id = '$mitarbeiter_id'"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $einh_obj = new lehreinheit($this->conn); + + $einh_obj->mitarbeiter_lehreinheit_id = $row->mitarbeiter_lehreinheit_pk; + $einh_obj->lehreinheit_fk = $row->lehreinheit_fk; + $einh_obj->lehrfunktion_id = $row->lehrfunktion_fk; + $einh_obj->mitarbeiter_id = $row->mitarbeiter_fk; + $einh_obj->faktor = $row->faktor; + $einh_obj->kosten = $row->kosten; + $einh_obj->gesamtstunden_mitarbeiter = $row->rvar1; + + $this->result[] = $einh_obj; + } + return true; + } + + /** + * Laedt die Mitarbeiterzuteilung + * @param $mitarbeiter_lehreinheit_id ID der Zuteilung + * @return true wenn ok, false im Fehlerfall + */ + function load_mitarbeiterzuteilung($mitarbeiter_lehreinheit_id) + { + //Variablen pruefen + if(!is_numeric($mitarbeiter_lehreinheit_id) || $mitarbeiter_lehreinheit_id == '') + { + $this->errormsg = 'mitarbeiter_lehreinheit_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM mitarbeiter_lehreinheit where mitarbeiter_lehreinheit_pk = '$mitarbeiter_lehreinheit_id'"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $einh_obj = new lehreinheit($this->conn); + + $einh_obj->mitarbeiter_lehreinheit_id = $row->mitarbeiter_lehreinheit_pk; + $einh_obj->lehreinheit_fk = $row->lehreinheit_fk; + $einh_obj->lehrfunktion_id = $row->lehrfunktion_fk; + $einh_obj->mitarbeiter_id = $row->mitarbeiter_fk; + $einh_obj->faktor = $row->faktor; + $einh_obj->kosten = $row->kosten; + $einh_obj->gesamtstunden_mitarbeiter = $row->rvar1; + + $this->result[] = $einh_obj; + } + return true; + } + + /** + * Prueft die variablen auf gueltigkeit + * @return true wenn ok, false im Fehlerfall + */ + function checkvars_zuteilung() + { + + if(!is_numeric($this->mitarbeiter_id)) + { + $this->errormsg = 'Bitte einen gueltigen Mitarbeiter auswaehlen'; + return false; + } + if(!is_numeric($this->lehreinheit_fk)) + { + $this->errormsg = 'lehreinheit_fk ist ungueltig'; + return false; + } + if(!is_numeric($this->lehrfunktion_id)) + { + $this->errormsg = 'Die Lehrfuntkion ist ungueltig'; + return false; + } + if(!is_numeric($this->kosten)) + { + $this->errormsg = 'Die Kosten muessen eine gueltige Zahl sein'; + return false; + } + if(!is_numeric($this->faktor)) + { + $this->errormsg = 'Faktor muss eine gueltige Zahl sein'; + return false; + } + if(!is_numeric($this->gesamtstunden_mitarbeiter)) + { + $this->errormsg = 'Gesamtstunden muss eine gueltige Zahl sein'; + return false; + } + + $this->errormsg = ''; + return true; + } + + /** + * Speichert die Zuteilung eines Mitarbeiters zu einer Lehreinheit + * @return true wenn ok, false im Fehlerfall + */ + function save_zuteilung() + { + if(!$this->checkvars_zuteilung()) + return false; + + if($this->new) + { + $qry = "SELECT nextval('mitarbeiter_lehreinheit_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Sequence konnte nicht ausgelesen werden'; + return false; + } + + $this->mitarbeiter_lehreinheit_id = $row->id; + + $qry = "INSERT INTO mitarbeiter_lehreinheit (mitarbeiter_lehreinheit_pk, mitarbeiter_fk, lehreinheit_fk,". + " lehrfunktion_fk, kosten, faktor, rvar1, creationdate, creationuser) VALUES(". + " '$this->mitarbeiter_lehreinheit_id', '$this->mitarbeiter_id', '$this->lehreinheit_fk', '$this->lehrfunktion_id',". + " '$this->kosten', '$this->faktor', '$this->gesamtstunden_mitarbeiter', now(), '$this->updatevon');"; + } + else + { + //mitarbeiter_lehreinheit_id auf gueltigkeit pruefen + if(!is_numeric($this->mitarbeiter_lehreinheit_id) || $this->mitarbeiter_lehreinheit_id =='') + { + $this->errormsg = 'mitarbeiter_lehreinheit muss eine gueltige Zahl sein'; + return false; + } + + $qry = "UPDATE mitarbeiter_lehreinheit SET mitarbeiter_fk = '$this->mitarbeiter_id',". + " lehreinheit_fk = '$this->lehreinheit_fk', lehrfunktion_fk = '$this->lehrfunktion_id',". + " kosten = '$this->kosten', faktor = '$this->faktor', rvar1 = '$this->gesamtstunden_mitarbeiter'". + " WHERE mitarbeiter_lehreinheit_pk = '$this->mitarbeiter_lehreinheit_id';"; + } + + if(pg_query($this->conn, $qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim Speichern des Datensatzes'; + return false; + } + } + + /** + * Loescht die Zuteilung eines Mitarbeiters zu einer Lehreinheit + * @param $mitarbeiter_lehreinheit_id ID des zu loeschenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function delete_zuteilung($mitarbeiter_lehreinheit_id) + { + //Pruefen ob mitarbeiter_lehreinheit_id eine gueltige Zahl ist + if(!is_numeric($mitarbeiter_lehreinheit_id) || $mitarbeiter_lehreinheit_id == '') + { + $this->errormsg = 'mitarbeiter_lehreinheit_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "DELETE FROM mitarbeiter_lehreinheit WHERE mitarbeiter_lehreinheit_pk = '$mitarbeiter_lehreinheit_id';"; + + if(!pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim loeschen der Zuteilung'; + return false; + } + else + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + + } + + /** + * Liefert die Lehreinheiten mit den dazugehoerigen Attributen + * @param stg Studiengang + * sem Semester + * stsem Studiensemester + */ + function getLehreinheiten($stg=null, $sem=null, $stsem=null, $lehreinheit_id=null, $include_partizipierungen=false) + { + $qry = "SELECT lehreinheit.lehreinheit_pk as lehreinheit_id, + studiengang.studiengang_pk as studiengang_id, + (CASE WHEN studiengang.studiengangsart=1 THEN 'B' + WHEN studiengang.studiengangsart=2 THEN 'M' + WHEN studiengang.studiengangsart=3 THEN 'D' END) || studiengang.kuerzel as studiengang_kurzbz, + studiensemester.studiensemester_pk as studiensemester_id, + (CASE WHEN studiensemester.art=1 THEN 'WS' + WHEN studiensemester.art=2 THEN 'SS' END) || studiensemester.jahr as studiensemester_kurzbz, + lehreinheit.lehrveranstaltung_fk as lehrveranstaltung_id, + lehreinheit.fachbereich_fk as fachbereich_id, + fachbereich.name as fachbereich_bezeichnung, + lehreinheit.ausbildungssemester_fk as ausbildungssemester_id, + ausbildungssemester.semester as ausbildungssemester_semester, + ausbildungssemester.name as ausbildungssemester_kurzbz, + lehreinheit.lehreinheit_fk as lehreinheit_fk, + lehreinheit.lehrform_fk as lehrform_id, + lehrform.kurzbezeichnung as lehrform_kurzbz, + lehreinheit.gruppe_fk as gruppe_id, + fas_function_get_fullname_from_gruppe(lehreinheit.gruppe_fk) as gruppe_kurzbz, + lehreinheit.nummer as nummer, + lehreinheit.bezeichnung as bezeichnung, + lehreinheit.kurzbezeichnung as kurzbezeichnung, + lehreinheit.semesterwochenstunden as semesterwochenstunden, + lehreinheit.gesamtstunden as gesamtstunden, + lehreinheit.plankostenprolektor as plankostenprolektor, + lehreinheit.planfaktor as planfaktor, + lehreinheit.planlektoren as planlektoren, + lehreinheit.raumtyp_fk as raumtyp_id, + lehreinheit.alternativraumtyp_fk as raumtypalternativ_id, + lehreinheit.bemerkungen as bemerkungen, + lehreinheit.ivar1 as wochenrythmus, + lehreinheit.ivar2 as kalenderwoche, + lehreinheit.ivar3 as stundenblockung, + lehreinheit.bivar1 as koordinator_id, + (Select vorname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_vorname, + (Select familienname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_nachname, + lehreinheit.creationdate as creationdate, + lehreinheit.creationuser as creationuser + FROM lehreinheit, studiengang, studiensemester, fachbereich, ausbildungssemester, lehrform + WHERE lehreinheit.studiengang_fk=studiengang.studiengang_pk + AND lehreinheit.studiensemester_fk=studiensemester.studiensemester_pk + AND lehreinheit.fachbereich_fk = fachbereich.fachbereich_pk + AND ausbildungssemester.ausbildungssemester_pk=lehreinheit.ausbildungssemester_fk + AND lehreinheit.lehrform_fk = lehrform.lehrform_pk"; + + if($stg!=null) + $qry .= " AND studiengang.studiengang_pk = '$stg'"; + if($sem!=null) + $qry .= " AND ausbildungssemester.semester= '$sem'"; + if($stsem!=null) + $qry .= " AND studiensemester.studiensemester_pk= '$stsem'"; + if($lehreinheit_id!=null) + $qry .= " AND lehreinheit_pk = '$lehreinheit_id'"; + $qry .= " Order by lehreinheit_fk"; + if($res=pg_query($this->conn, $qry)) + { + while($row=pg_fetch_object($res)) + { + $lehreinheit_obj = new lehreinheit($this->conn); + + $lehreinheit_obj->lehreinheit_id = $row->lehreinheit_id; + $lehreinheit_obj->studiengang_id = $row->studiengang_id; + $lehreinheit_obj->studiengang_kurzbz = $row->studiengang_kurzbz; + $lehreinheit_obj->studiensemester_id = $row->studiensemester_id; + $lehreinheit_obj->studiensemester_kurzbz = $row->studiensemester_kurzbz; + $lehreinheit_obj->lehrveranstaltung_id = $row->lehrveranstaltung_id; + $lehreinheit_obj->fachbereich_id = $row->fachbereich_id; + $lehreinheit_obj->fachbereich_bezeichnung = $row->fachbereich_bezeichnung; + $lehreinheit_obj->ausbildungssemester_id = $row->ausbildungssemester_id; + $lehreinheit_obj->ausbildungssemester_semester = $row->ausbildungssemester_semester; + $lehreinheit_obj->ausbildungssemester_kurzbz = $row->ausbildungssemester_kurzbz; + $lehreinheit_obj->lehreinheit_fk = $row->lehreinheit_fk; + $lehreinheit_obj->lehrform_id = $row->lehrform_id; + $lehreinheit_obj->lehrform_kurzbz = $row->lehrform_kurzbz; + $lehreinheit_obj->gruppe_id = $row->gruppe_id; + $lehreinheit_obj->gruppe_kurzbz = $row->gruppe_kurzbz; + $lehreinheit_obj->nummer = $row->nummer; + $lehreinheit_obj->bezeichnung = $row->bezeichnung; + $lehreinheit_obj->kurzbezeichnung = $row->kurzbezeichnung; + $lehreinheit_obj->semesterwochenstunden = $row->semesterwochenstunden; + $lehreinheit_obj->gesamtstunden = $row->gesamtstunden; + $lehreinheit_obj->plankostenprolektor = $row->plankostenprolektor; + $lehreinheit_obj->planfaktor = $row->planfaktor; + $lehreinheit_obj->planlektoren = $row->planlektoren; + $lehreinheit_obj->raumtyp_id = $row->raumtyp_id; + $lehreinheit_obj->raumtypalternativ_id = $row->raumtypalternativ_id; + $lehreinheit_obj->bemerkungen = $row->bemerkungen; + $lehreinheit_obj->wochenrythmus = $row->wochenrythmus; + $lehreinheit_obj->start_kw = $row->kalenderwoche; + $lehreinheit_obj->stundenblockung = $row->stundenblockung; + $lehreinheit_obj->koordinator_id = $row->koordinator_id; + $lehreinheit_obj->koordinator_vorname = $row->koordinator_vorname; + $lehreinheit_obj->koordinator_nachname = $row->koordinator_nachname; + $lehreinheit_obj->updateamum = $row->creationdate; + $lehreinheit_obj->updatevon = $row->creationuser; + + $this->result[] = $lehreinheit_obj; + $lehreinheit_id = $row->lehreinheit_id; + //Laden der Datensaetze die partizipiert sind aber in einem anderen Studiengang/Gruppe sind + if($include_partizipierungen) + { + if($row->lehreinheit_fk!='' && $row->lehreinheit_fk!='-1') + { + $qry = "SELECT lehreinheit.lehreinheit_pk as lehreinheit_id, + studiengang.studiengang_pk as studiengang_id, + (CASE WHEN studiengang.studiengangsart=1 THEN 'B' + WHEN studiengang.studiengangsart=2 THEN 'M' + WHEN studiengang.studiengangsart=3 THEN 'D' END) || studiengang.kuerzel as studiengang_kurzbz, + studiensemester.studiensemester_pk as studiensemester_id, + (CASE WHEN studiensemester.art=1 THEN 'WS' + WHEN studiensemester.art=2 THEN 'SS' END) || studiensemester.jahr as studiensemester_kurzbz, + lehreinheit.lehrveranstaltung_fk as lehrveranstaltung_id, + lehreinheit.fachbereich_fk as fachbereich_id, + fachbereich.name as fachbereich_bezeichnung, + lehreinheit.ausbildungssemester_fk as ausbildungssemester_id, + ausbildungssemester.semester as ausbildungssemester_semester, + ausbildungssemester.name as ausbildungssemester_kurzbz, + lehreinheit.lehreinheit_fk as lehreinheit_fk, + lehreinheit.lehrform_fk as lehrform_id, + lehrform.kurzbezeichnung as lehrform_kurzbz, + lehreinheit.gruppe_fk as gruppe_id, + fas_function_get_fullname_from_gruppe(lehreinheit.gruppe_fk) as gruppe_kurzbz, + lehreinheit.nummer as nummer, + lehreinheit.bezeichnung as bezeichnung, + lehreinheit.kurzbezeichnung as kurzbezeichnung, + lehreinheit.semesterwochenstunden as semesterwochenstunden, + lehreinheit.gesamtstunden as gesamtstunden, + lehreinheit.plankostenprolektor as plankostenprolektor, + lehreinheit.planfaktor as planfaktor, + lehreinheit.planlektoren as planlektoren, + lehreinheit.raumtyp_fk as raumtyp_id, + lehreinheit.alternativraumtyp_fk as raumtypalternativ_id, + lehreinheit.bemerkungen as bemerkungen, + lehreinheit.ivar1 as wochenrythmus, + lehreinheit.ivar2 as kalenderwoche, + lehreinheit.ivar3 as stundenblockung, + lehreinheit.bivar1 as koordinator_id, + (Select vorname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_vorname, + (Select familienname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_nachname, + lehreinheit.creationdate as creationdate, + lehreinheit.creationuser as creationuser + FROM lehreinheit, studiengang, studiensemester, fachbereich, ausbildungssemester, lehrform + WHERE lehreinheit.studiengang_fk=studiengang.studiengang_pk + AND lehreinheit.studiensemester_fk=studiensemester.studiensemester_pk + AND lehreinheit.fachbereich_fk = fachbereich.fachbereich_pk + AND ausbildungssemester.ausbildungssemester_pk=lehreinheit.ausbildungssemester_fk + AND lehreinheit.lehrform_fk = lehrform.lehrform_pk + AND lehreinheit_pk='$row->lehreinheit_fk'"; + + if($result=pg_query($this->conn,$qry)) + { + if($row=pg_fetch_object($result)) + { + if($row->studiengang_id!=$stg) + { + $lehreinheit_obj = new lehreinheit($this->conn); + + $lehreinheit_obj->lehreinheit_id = $row->lehreinheit_id; + $lehreinheit_obj->studiengang_id = $row->studiengang_id; + $lehreinheit_obj->studiengang_kurzbz = $row->studiengang_kurzbz; + $lehreinheit_obj->studiensemester_id = $row->studiensemester_id; + $lehreinheit_obj->studiensemester_kurzbz = $row->studiensemester_kurzbz; + $lehreinheit_obj->lehrveranstaltung_id = $row->lehrveranstaltung_id; + $lehreinheit_obj->fachbereich_id = $row->fachbereich_id; + $lehreinheit_obj->fachbereich_bezeichnung = $row->fachbereich_bezeichnung; + $lehreinheit_obj->ausbildungssemester_id = $row->ausbildungssemester_id; + $lehreinheit_obj->ausbildungssemester_semester = $row->ausbildungssemester_semester; + $lehreinheit_obj->ausbildungssemester_kurzbz = $row->ausbildungssemester_kurzbz; + $lehreinheit_obj->lehreinheit_fk = $row->lehreinheit_fk; + $lehreinheit_obj->lehrform_id = $row->lehrform_id; + $lehreinheit_obj->lehrform_kurzbz = $row->lehrform_kurzbz; + $lehreinheit_obj->gruppe_id = $row->gruppe_id; + $lehreinheit_obj->gruppe_kurzbz = $row->gruppe_kurzbz; + $lehreinheit_obj->nummer = $row->nummer; + $lehreinheit_obj->bezeichnung = $row->bezeichnung; + $lehreinheit_obj->kurzbezeichnung = $row->kurzbezeichnung; + $lehreinheit_obj->semesterwochenstunden = $row->semesterwochenstunden; + $lehreinheit_obj->gesamtstunden = $row->gesamtstunden; + $lehreinheit_obj->plankostenprolektor = $row->plankostenprolektor; + $lehreinheit_obj->planfaktor = $row->planfaktor; + $lehreinheit_obj->planlektoren = $row->planlektoren; + $lehreinheit_obj->raumtyp_id = $row->raumtyp_id; + $lehreinheit_obj->raumtypalternativ_id = $row->raumtypalternativ_id; + $lehreinheit_obj->bemerkungen = $row->bemerkungen; + $lehreinheit_obj->wochenrythmus = $row->wochenrythmus; + $lehreinheit_obj->start_kw = $row->kalenderwoche; + $lehreinheit_obj->stundenblockung = $row->stundenblockung; + $lehreinheit_obj->koordinator_id = $row->koordinator_id; + $lehreinheit_obj->koordinator_vorname = $row->koordinator_vorname; + $lehreinheit_obj->koordinator_nachname = $row->koordinator_nachname; + $lehreinheit_obj->updateamum = $row->creationdate; + $lehreinheit_obj->updatevon = $row->creationuser; + + $this->result[] = $lehreinheit_obj; + } + } + } + else + { + $this->errormsg = 'Fehler beim laden der Partizipierungen aus anderen Studiengaengen'; + return false; + } + } + + //Laden der uebergeordneten + + $qry = "SELECT lehreinheit.lehreinheit_pk as lehreinheit_id, + studiengang.studiengang_pk as studiengang_id, + (CASE WHEN studiengang.studiengangsart=1 THEN 'B' + WHEN studiengang.studiengangsart=2 THEN 'M' + WHEN studiengang.studiengangsart=3 THEN 'D' END) || studiengang.kuerzel as studiengang_kurzbz, + studiensemester.studiensemester_pk as studiensemester_id, + (CASE WHEN studiensemester.art=1 THEN 'WS' + WHEN studiensemester.art=2 THEN 'SS' END) || studiensemester.jahr as studiensemester_kurzbz, + lehreinheit.lehrveranstaltung_fk as lehrveranstaltung_id, + lehreinheit.fachbereich_fk as fachbereich_id, + fachbereich.name as fachbereich_bezeichnung, + lehreinheit.ausbildungssemester_fk as ausbildungssemester_id, + ausbildungssemester.semester as ausbildungssemester_semester, + ausbildungssemester.name as ausbildungssemester_kurzbz, + lehreinheit.lehreinheit_fk as lehreinheit_fk, + lehreinheit.lehrform_fk as lehrform_id, + lehrform.kurzbezeichnung as lehrform_kurzbz, + lehreinheit.gruppe_fk as gruppe_id, + fas_function_get_fullname_from_gruppe(lehreinheit.gruppe_fk) as gruppe_kurzbz, + lehreinheit.nummer as nummer, + lehreinheit.bezeichnung as bezeichnung, + lehreinheit.kurzbezeichnung as kurzbezeichnung, + lehreinheit.semesterwochenstunden as semesterwochenstunden, + lehreinheit.gesamtstunden as gesamtstunden, + lehreinheit.plankostenprolektor as plankostenprolektor, + lehreinheit.planfaktor as planfaktor, + lehreinheit.planlektoren as planlektoren, + lehreinheit.raumtyp_fk as raumtyp_id, + lehreinheit.alternativraumtyp_fk as raumtypalternativ_id, + lehreinheit.bemerkungen as bemerkungen, + lehreinheit.ivar1 as wochenrythmus, + lehreinheit.ivar2 as kalenderwoche, + lehreinheit.ivar3 as stundenblockung, + lehreinheit.bivar1 as koordinator_id, + (Select vorname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_vorname, + (Select familienname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_nachname, + lehreinheit.creationdate as creationdate, + lehreinheit.creationuser as creationuser + FROM lehreinheit, studiengang, studiensemester, fachbereich, ausbildungssemester, lehrform + WHERE lehreinheit.studiengang_fk=studiengang.studiengang_pk + AND lehreinheit.studiensemester_fk=studiensemester.studiensemester_pk + AND lehreinheit.fachbereich_fk = fachbereich.fachbereich_pk + AND ausbildungssemester.ausbildungssemester_pk=lehreinheit.ausbildungssemester_fk + AND lehreinheit.lehrform_fk = lehrform.lehrform_pk + AND lehreinheit_fk='$lehreinheit_id'"; + + if($result=pg_query($this->conn,$qry)) + { + while($row=pg_fetch_object($result)) + { + if($row->studiengang_id!=$stg) + { + $lehreinheit_obj = new lehreinheit($this->conn); + + $lehreinheit_obj->lehreinheit_id = $row->lehreinheit_id; + $lehreinheit_obj->studiengang_id = $row->studiengang_id; + $lehreinheit_obj->studiengang_kurzbz = $row->studiengang_kurzbz; + $lehreinheit_obj->studiensemester_id = $row->studiensemester_id; + $lehreinheit_obj->studiensemester_kurzbz = $row->studiensemester_kurzbz; + $lehreinheit_obj->lehrveranstaltung_id = $row->lehrveranstaltung_id; + $lehreinheit_obj->fachbereich_id = $row->fachbereich_id; + $lehreinheit_obj->fachbereich_bezeichnung = $row->fachbereich_bezeichnung; + $lehreinheit_obj->ausbildungssemester_id = $row->ausbildungssemester_id; + $lehreinheit_obj->ausbildungssemester_semester = $row->ausbildungssemester_semester; + $lehreinheit_obj->ausbildungssemester_kurzbz = $row->ausbildungssemester_kurzbz; + $lehreinheit_obj->lehreinheit_fk = $row->lehreinheit_fk; + $lehreinheit_obj->lehrform_id = $row->lehrform_id; + $lehreinheit_obj->lehrform_kurzbz = $row->lehrform_kurzbz; + $lehreinheit_obj->gruppe_id = $row->gruppe_id; + $lehreinheit_obj->gruppe_kurzbz = $row->gruppe_kurzbz; + $lehreinheit_obj->nummer = $row->nummer; + $lehreinheit_obj->bezeichnung = $row->bezeichnung; + $lehreinheit_obj->kurzbezeichnung = $row->kurzbezeichnung; + $lehreinheit_obj->semesterwochenstunden = $row->semesterwochenstunden; + $lehreinheit_obj->gesamtstunden = $row->gesamtstunden; + $lehreinheit_obj->plankostenprolektor = $row->plankostenprolektor; + $lehreinheit_obj->planfaktor = $row->planfaktor; + $lehreinheit_obj->planlektoren = $row->planlektoren; + $lehreinheit_obj->raumtyp_id = $row->raumtyp_id; + $lehreinheit_obj->raumtypalternativ_id = $row->raumtypalternativ_id; + $lehreinheit_obj->bemerkungen = $row->bemerkungen; + $lehreinheit_obj->wochenrythmus = $row->wochenrythmus; + $lehreinheit_obj->start_kw = $row->kalenderwoche; + $lehreinheit_obj->stundenblockung = $row->stundenblockung; + $lehreinheit_obj->koordinator_id = $row->koordinator_id; + $lehreinheit_obj->koordinator_vorname = $row->koordinator_vorname; + $lehreinheit_obj->koordinator_nachname = $row->koordinator_nachname; + $lehreinheit_obj->updateamum = $row->creationdate; + $lehreinheit_obj->updatevon = $row->creationuser; + + $this->result[] = $lehreinheit_obj; + } + } + } + else + { + $this->errormsg = 'Fehler beim laden der Partizipierungen aus anderen Studiengaengen'; + return false; + } + + } + } + } + else + { + $this->errormsg = "Fehler bei einer SQL Abfrage"; + return false; + } + return true; + } + + /** + * Liefert die Lehreinheiten mit den dazugehoerigen Attributen + * @param stg Studiengang + * sem Semester + * stsem Studiensemester + */ + function getLehreinheitenfromGruppe($gruppe_id, $stsem) + { + + $qry = "SELECT lehreinheit.lehreinheit_pk as lehreinheit_id, + studiengang.studiengang_pk as studiengang_id, + (CASE WHEN studiengang.studiengangsart=1 THEN 'B' + WHEN studiengang.studiengangsart=2 THEN 'M' + WHEN studiengang.studiengangsart=3 THEN 'D' END) || studiengang.kuerzel as studiengang_kurzbz, + studiensemester.studiensemester_pk as studiensemester_id, + (CASE WHEN studiensemester.art=1 THEN 'WS' + WHEN studiensemester.art=2 THEN 'SS' END) || studiensemester.jahr as studiensemester_kurzbz, + lehreinheit.lehrveranstaltung_fk as lehrveranstaltung_id, + lehreinheit.fachbereich_fk as fachbereich_id, + fachbereich.name as fachbereich_bezeichnung, + lehreinheit.ausbildungssemester_fk as ausbildungssemester_id, + ausbildungssemester.semester as ausbildungssemester_semester, + ausbildungssemester.name as ausbildungssemester_kurzbz, + lehreinheit.lehreinheit_fk as lehreinheit_fk, + lehreinheit.lehrform_fk as lehrform_id, + lehrform.kurzbezeichnung as lehrform_kurzbz, + lehreinheit.gruppe_fk as gruppe_id, + fas_function_get_fullname_from_gruppe(lehreinheit.gruppe_fk) as gruppe_kurzbz, + lehreinheit.nummer as nummer, + lehreinheit.bezeichnung as bezeichnung, + lehreinheit.kurzbezeichnung as kurzbezeichnung, + lehreinheit.semesterwochenstunden as semesterwochenstunden, + lehreinheit.gesamtstunden as gesamtstunden, + lehreinheit.plankostenprolektor as plankostenprolektor, + lehreinheit.planfaktor as planfaktor, + lehreinheit.planlektoren as planlektoren, + lehreinheit.raumtyp_fk as raumtyp_id, + lehreinheit.alternativraumtyp_fk as raumtypalternativ_id, + lehreinheit.bemerkungen as bemerkungen, + lehreinheit.ivar1 as wochenrythmus, + lehreinheit.ivar2 as kalenderwoche, + lehreinheit.ivar3 as stundenblockung, + lehreinheit.bivar1 as koordinator_id, + (Select vorname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_vorname, + (Select familienname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_nachname, + lehreinheit.creationdate as creationdate, + lehreinheit.creationuser as creationuser + FROM lehreinheit, studiengang, studiensemester, fachbereich, ausbildungssemester, lehrform + WHERE lehreinheit.studiengang_fk=studiengang.studiengang_pk + AND lehreinheit.studiensemester_fk=studiensemester.studiensemester_pk + AND lehreinheit.fachbereich_fk = fachbereich.fachbereich_pk + AND ausbildungssemester.ausbildungssemester_pk=lehreinheit.ausbildungssemester_fk + AND lehreinheit.lehrform_fk = lehrform.lehrform_pk + AND gruppe_fk in (Select gruppe_pk from gruppe where gruppe_pk=$gruppe_id union Select gruppe_pk from gruppe where gruppe_pk in (Select gruppe_pk from gruppe where obergruppe_fk=$gruppe_id) union Select gruppe_pk from gruppe where obergruppe_fk in (Select gruppe_pk from gruppe where obergruppe_fk in (Select gruppe_pk from gruppe where gruppe_pk=$gruppe_id))) + "; + $qry .= " AND studiensemester.studiensemester_pk= '$stsem'"; + + $qry .= " Order by lehreinheit_fk"; + if($res=pg_query($this->conn, $qry)) + { + while($row=pg_fetch_object($res)) + { + $lehreinheit_obj = new lehreinheit($this->conn); + + $lehreinheit_obj->lehreinheit_id = $row->lehreinheit_id; + $lehreinheit_obj->studiengang_id = $row->studiengang_id; + $lehreinheit_obj->studiengang_kurzbz = $row->studiengang_kurzbz; + $lehreinheit_obj->studiensemester_id = $row->studiensemester_id; + $lehreinheit_obj->studiensemester_kurzbz = $row->studiensemester_kurzbz; + $lehreinheit_obj->lehrveranstaltung_id = $row->lehrveranstaltung_id; + $lehreinheit_obj->fachbereich_id = $row->fachbereich_id; + $lehreinheit_obj->fachbereich_bezeichnung = $row->fachbereich_bezeichnung; + $lehreinheit_obj->ausbildungssemester_id = $row->ausbildungssemester_id; + $lehreinheit_obj->ausbildungssemester_semester = $row->ausbildungssemester_semester; + $lehreinheit_obj->ausbildungssemester_kurzbz = $row->ausbildungssemester_kurzbz; + $lehreinheit_obj->lehreinheit_fk = $row->lehreinheit_fk; + $lehreinheit_obj->lehrform_id = $row->lehrform_id; + $lehreinheit_obj->lehrform_kurzbz = $row->lehrform_kurzbz; + $lehreinheit_obj->gruppe_id = $row->gruppe_id; + $lehreinheit_obj->gruppe_kurzbz = $row->gruppe_kurzbz; + $lehreinheit_obj->nummer = $row->nummer; + $lehreinheit_obj->bezeichnung = $row->bezeichnung; + $lehreinheit_obj->kurzbezeichnung = $row->kurzbezeichnung; + $lehreinheit_obj->semesterwochenstunden = $row->semesterwochenstunden; + $lehreinheit_obj->gesamtstunden = $row->gesamtstunden; + $lehreinheit_obj->plankostenprolektor = $row->plankostenprolektor; + $lehreinheit_obj->planfaktor = $row->planfaktor; + $lehreinheit_obj->planlektoren = $row->planlektoren; + $lehreinheit_obj->raumtyp_id = $row->raumtyp_id; + $lehreinheit_obj->raumtypalternativ_id = $row->raumtypalternativ_id; + $lehreinheit_obj->bemerkungen = $row->bemerkungen; + $lehreinheit_obj->wochenrythmus = $row->wochenrythmus; + $lehreinheit_obj->start_kw = $row->kalenderwoche; + $lehreinheit_obj->stundenblockung = $row->stundenblockung; + $lehreinheit_obj->koordinator_id = $row->koordinator_id; + $lehreinheit_obj->koordinator_vorname = $row->koordinator_vorname; + $lehreinheit_obj->koordinator_nachname = $row->koordinator_nachname; + $lehreinheit_obj->updateamum = $row->creationdate; + $lehreinheit_obj->updatevon = $row->creationuser; + + $this->result[] = $lehreinheit_obj; + + $lehreinheit_id = $row->lehreinheit_id; + //Wenn eine Obergruppe existiert und diese nicht in der selben Gruppe ist + //dann wird diese auch geladen + + if($row->lehreinheit_fk!='' && $row->lehreinheit_fk!='-1' ) + { + + $qry = "SELECT lehreinheit.lehreinheit_pk as lehreinheit_id, + studiengang.studiengang_pk as studiengang_id, + (CASE WHEN studiengang.studiengangsart=1 THEN 'B' + WHEN studiengang.studiengangsart=2 THEN 'M' + WHEN studiengang.studiengangsart=3 THEN 'D' END) || studiengang.kuerzel as studiengang_kurzbz, + studiensemester.studiensemester_pk as studiensemester_id, + (CASE WHEN studiensemester.art=1 THEN 'WS' + WHEN studiensemester.art=2 THEN 'SS' END) || studiensemester.jahr as studiensemester_kurzbz, + lehreinheit.lehrveranstaltung_fk as lehrveranstaltung_id, + lehreinheit.fachbereich_fk as fachbereich_id, + fachbereich.name as fachbereich_bezeichnung, + lehreinheit.ausbildungssemester_fk as ausbildungssemester_id, + ausbildungssemester.semester as ausbildungssemester_semester, + ausbildungssemester.name as ausbildungssemester_kurzbz, + lehreinheit.lehreinheit_fk as lehreinheit_fk, + lehreinheit.lehrform_fk as lehrform_id, + lehrform.kurzbezeichnung as lehrform_kurzbz, + lehreinheit.gruppe_fk as gruppe_id, + fas_function_get_fullname_from_gruppe(lehreinheit.gruppe_fk) as gruppe_kurzbz, + lehreinheit.nummer as nummer, + lehreinheit.bezeichnung as bezeichnung, + lehreinheit.kurzbezeichnung as kurzbezeichnung, + lehreinheit.semesterwochenstunden as semesterwochenstunden, + lehreinheit.gesamtstunden as gesamtstunden, + lehreinheit.plankostenprolektor as plankostenprolektor, + lehreinheit.planfaktor as planfaktor, + lehreinheit.planlektoren as planlektoren, + lehreinheit.raumtyp_fk as raumtyp_id, + lehreinheit.alternativraumtyp_fk as raumtypalternativ_id, + lehreinheit.bemerkungen as bemerkungen, + lehreinheit.ivar1 as wochenrythmus, + lehreinheit.ivar2 as kalenderwoche, + lehreinheit.ivar3 as stundenblockung, + lehreinheit.bivar1 as koordinator_id, + (Select vorname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_vorname, + (Select familienname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_nachname, + lehreinheit.creationdate as creationdate, + lehreinheit.creationuser as creationuser + FROM lehreinheit, studiengang, studiensemester, fachbereich, ausbildungssemester, lehrform + WHERE lehreinheit.studiengang_fk=studiengang.studiengang_pk + AND lehreinheit.studiensemester_fk=studiensemester.studiensemester_pk + AND lehreinheit.fachbereich_fk = fachbereich.fachbereich_pk + AND ausbildungssemester.ausbildungssemester_pk=lehreinheit.ausbildungssemester_fk + AND lehreinheit.lehrform_fk = lehrform.lehrform_pk + AND studiensemester.studiensemester_pk= '$stsem' + AND lehreinheit_pk='$row->lehreinheit_fk'"; + + if($result=pg_query($this->conn,$qry)) + { + if($row=pg_fetch_object($result)) + { + + if($row->gruppe_id!=$gruppe_id) + { + + $lehreinheit_obj = new lehreinheit($this->conn); + + $lehreinheit_obj->lehreinheit_id = $row->lehreinheit_id; + $lehreinheit_obj->studiengang_id = $row->studiengang_id; + $lehreinheit_obj->studiengang_kurzbz = $row->studiengang_kurzbz; + $lehreinheit_obj->studiensemester_id = $row->studiensemester_id; + $lehreinheit_obj->studiensemester_kurzbz = $row->studiensemester_kurzbz; + $lehreinheit_obj->lehrveranstaltung_id = $row->lehrveranstaltung_id; + $lehreinheit_obj->fachbereich_id = $row->fachbereich_id; + $lehreinheit_obj->fachbereich_bezeichnung = $row->fachbereich_bezeichnung; + $lehreinheit_obj->ausbildungssemester_id = $row->ausbildungssemester_id; + $lehreinheit_obj->ausbildungssemester_semester = $row->ausbildungssemester_semester; + $lehreinheit_obj->ausbildungssemester_kurzbz = $row->ausbildungssemester_kurzbz; + $lehreinheit_obj->lehreinheit_fk = $row->lehreinheit_fk; + $lehreinheit_obj->lehrform_id = $row->lehrform_id; + $lehreinheit_obj->lehrform_kurzbz = $row->lehrform_kurzbz; + $lehreinheit_obj->gruppe_id = $row->gruppe_id; + $lehreinheit_obj->gruppe_kurzbz = $row->gruppe_kurzbz; + $lehreinheit_obj->nummer = $row->nummer; + $lehreinheit_obj->bezeichnung = $row->bezeichnung; + $lehreinheit_obj->kurzbezeichnung = $row->kurzbezeichnung; + $lehreinheit_obj->semesterwochenstunden = $row->semesterwochenstunden; + $lehreinheit_obj->gesamtstunden = $row->gesamtstunden; + $lehreinheit_obj->plankostenprolektor = $row->plankostenprolektor; + $lehreinheit_obj->planfaktor = $row->planfaktor; + $lehreinheit_obj->planlektoren = $row->planlektoren; + $lehreinheit_obj->raumtyp_id = $row->raumtyp_id; + $lehreinheit_obj->raumtypalternativ_id = $row->raumtypalternativ_id; + $lehreinheit_obj->bemerkungen = $row->bemerkungen; + $lehreinheit_obj->wochenrythmus = $row->wochenrythmus; + $lehreinheit_obj->start_kw = $row->kalenderwoche; + $lehreinheit_obj->stundenblockung = $row->stundenblockung; + $lehreinheit_obj->koordinator_id = $row->koordinator_id; + $lehreinheit_obj->koordinator_vorname = $row->koordinator_vorname; + $lehreinheit_obj->koordinator_nachname = $row->koordinator_nachname; + $lehreinheit_obj->updateamum = $row->creationdate; + $lehreinheit_obj->updatevon = $row->creationuser; + + $this->result[] = $lehreinheit_obj; + } + } + else + { + $this->errormsg = 'Fehler beim laden der partizipierenden Lehreinheiten'.$qry; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim laden der partizipierenden Lehreinheiten'; + return false; + } + } + + //Laden der Datensaetze die partizipiert sind aber in einem anderen Studiengang/Gruppe sind + $qry = "SELECT lehreinheit.lehreinheit_pk as lehreinheit_id, + studiengang.studiengang_pk as studiengang_id, + (CASE WHEN studiengang.studiengangsart=1 THEN 'B' + WHEN studiengang.studiengangsart=2 THEN 'M' + WHEN studiengang.studiengangsart=3 THEN 'D' END) || studiengang.kuerzel as studiengang_kurzbz, + studiensemester.studiensemester_pk as studiensemester_id, + (CASE WHEN studiensemester.art=1 THEN 'WS' + WHEN studiensemester.art=2 THEN 'SS' END) || studiensemester.jahr as studiensemester_kurzbz, + lehreinheit.lehrveranstaltung_fk as lehrveranstaltung_id, + lehreinheit.fachbereich_fk as fachbereich_id, + fachbereich.name as fachbereich_bezeichnung, + lehreinheit.ausbildungssemester_fk as ausbildungssemester_id, + ausbildungssemester.semester as ausbildungssemester_semester, + ausbildungssemester.name as ausbildungssemester_kurzbz, + lehreinheit.lehreinheit_fk as lehreinheit_fk, + lehreinheit.lehrform_fk as lehrform_id, + lehrform.kurzbezeichnung as lehrform_kurzbz, + lehreinheit.gruppe_fk as gruppe_id, + fas_function_get_fullname_from_gruppe(lehreinheit.gruppe_fk) as gruppe_kurzbz, + lehreinheit.nummer as nummer, + lehreinheit.bezeichnung as bezeichnung, + lehreinheit.kurzbezeichnung as kurzbezeichnung, + lehreinheit.semesterwochenstunden as semesterwochenstunden, + lehreinheit.gesamtstunden as gesamtstunden, + lehreinheit.plankostenprolektor as plankostenprolektor, + lehreinheit.planfaktor as planfaktor, + lehreinheit.planlektoren as planlektoren, + lehreinheit.raumtyp_fk as raumtyp_id, + lehreinheit.alternativraumtyp_fk as raumtypalternativ_id, + lehreinheit.bemerkungen as bemerkungen, + lehreinheit.ivar1 as wochenrythmus, + lehreinheit.ivar2 as kalenderwoche, + lehreinheit.ivar3 as stundenblockung, + lehreinheit.bivar1 as koordinator_id, + (Select vorname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_vorname, + (Select familienname from person join mitarbeiter on (person_fk=person_pk) where mitarbeiter_pk=lehreinheit.bivar1) as koordinator_nachname, + lehreinheit.creationdate as creationdate, + lehreinheit.creationuser as creationuser + FROM lehreinheit, studiengang, studiensemester, fachbereich, ausbildungssemester, lehrform + WHERE lehreinheit.studiengang_fk=studiengang.studiengang_pk + AND lehreinheit.studiensemester_fk=studiensemester.studiensemester_pk + AND lehreinheit.fachbereich_fk = fachbereich.fachbereich_pk + AND ausbildungssemester.ausbildungssemester_pk=lehreinheit.ausbildungssemester_fk + AND lehreinheit.lehrform_fk = lehrform.lehrform_pk + AND studiensemester.studiensemester_pk= '$stsem' + AND lehreinheit_fk='$lehreinheit_id'"; + + if($result=pg_query($this->conn,$qry)) + { + while($row=pg_fetch_object($result)) + { + + if($row->gruppe_id!=$gruppe_id) + { + + $lehreinheit_obj = new lehreinheit($this->conn); + + $lehreinheit_obj->lehreinheit_id = $row->lehreinheit_id; + $lehreinheit_obj->studiengang_id = $row->studiengang_id; + $lehreinheit_obj->studiengang_kurzbz = $row->studiengang_kurzbz; + $lehreinheit_obj->studiensemester_id = $row->studiensemester_id; + $lehreinheit_obj->studiensemester_kurzbz = $row->studiensemester_kurzbz; + $lehreinheit_obj->lehrveranstaltung_id = $row->lehrveranstaltung_id; + $lehreinheit_obj->fachbereich_id = $row->fachbereich_id; + $lehreinheit_obj->fachbereich_bezeichnung = $row->fachbereich_bezeichnung; + $lehreinheit_obj->ausbildungssemester_id = $row->ausbildungssemester_id; + $lehreinheit_obj->ausbildungssemester_semester = $row->ausbildungssemester_semester; + $lehreinheit_obj->ausbildungssemester_kurzbz = $row->ausbildungssemester_kurzbz; + $lehreinheit_obj->lehreinheit_fk = $row->lehreinheit_fk; + $lehreinheit_obj->lehrform_id = $row->lehrform_id; + $lehreinheit_obj->lehrform_kurzbz = $row->lehrform_kurzbz; + $lehreinheit_obj->gruppe_id = $row->gruppe_id; + $lehreinheit_obj->gruppe_kurzbz = $row->gruppe_kurzbz; + $lehreinheit_obj->nummer = $row->nummer; + $lehreinheit_obj->bezeichnung = $row->bezeichnung; + $lehreinheit_obj->kurzbezeichnung = $row->kurzbezeichnung; + $lehreinheit_obj->semesterwochenstunden = $row->semesterwochenstunden; + $lehreinheit_obj->gesamtstunden = $row->gesamtstunden; + $lehreinheit_obj->plankostenprolektor = $row->plankostenprolektor; + $lehreinheit_obj->planfaktor = $row->planfaktor; + $lehreinheit_obj->planlektoren = $row->planlektoren; + $lehreinheit_obj->raumtyp_id = $row->raumtyp_id; + $lehreinheit_obj->raumtypalternativ_id = $row->raumtypalternativ_id; + $lehreinheit_obj->bemerkungen = $row->bemerkungen; + $lehreinheit_obj->wochenrythmus = $row->wochenrythmus; + $lehreinheit_obj->start_kw = $row->kalenderwoche; + $lehreinheit_obj->stundenblockung = $row->stundenblockung; + $lehreinheit_obj->koordinator_id = $row->koordinator_id; + $lehreinheit_obj->koordinator_vorname = $row->koordinator_vorname; + $lehreinheit_obj->koordinator_nachname = $row->koordinator_nachname; + $lehreinheit_obj->updateamum = $row->creationdate; + $lehreinheit_obj->updatevon = $row->creationuser; + + $this->result[] = $lehreinheit_obj; + } + } + } + else + { + $this->errormsg = "Fehler beim Auslesen der partizipierenden Lehreinheiten"; + return false; + } + } + + } + else + { + $this->errormsg = "Fehler bei einer SQL Abfrage"; + return false; + } + //$this->errormsg = $qry; + // return false; + return true; + } + + /** + * Setzt eine Partizipierung + * @param $quell_lehreinheit_id ... Lehreinheit welche an eine andere Lehreinheit angehaengt wird + * $ziel_lehreinheit_id .... Lehreinheit an welche die andere Lehreinheit angehaengt wird + * + * Wenn $ziel_lehreinheit_id = -1 dann wird die zuteilung entfernt + * Wenn Ziel Lehreinheit bereits eine Partizipierende ist, dann wird automatisch die uebergeordnete genommen + */ + function setPartizipierung($quell_lehreinheit_id, $ziel_lehreinheit_id) + { + //Parameter auf gueltigkeit pruefen + if(is_numeric($quell_lehreinheit_id) && is_numeric($ziel_lehreinheit_id)) + { + //Keine Aktion bei gleicher ID + if($quell_lehreinheit_id != $ziel_lehreinheit_id) + { + //Wenn Ziel = -1 dann die Partizipierung loeschen + if($ziel_lehreinheit_id!=-1) + { + //Wenn die Quell-Lehreinheit eine Partizipierende Lehreinheit hat dann kann Sie nicht an eine andere + //angehaengt werden + $qry = "SELECT count(*) as anz FROM lehreinheit WHERE lehreinheit_fk='$quell_lehreinheit_id'"; + if($result = pg_query($this->conn,$qry)) + { + if($row = pg_fetch_object($result)) + { + if($row->anz>0) + { + $this->errormsg = 'Operation nicht zulaessig'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim Auslesen der Quell-Lehreinheit'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim Auslesen der Quell-Lehreinheit'; + return false; + } + //Nummer der Ziel Lehreinheit ermitteln + $qry = "SELECT nummer, lehreinheit_fk FROM lehreinheit WHERE lehreinheit_pk='$ziel_lehreinheit_id'"; + if($result = pg_query($this->conn, $qry)) + { + if($row = pg_fetch_object($result)) + { + if($row->lehreinheit_fk==-1 || $row->lehreinheit_fk==null) + { + $nummer = $row->nummer; + } + else + { + //Wenn Ziel Lehreinheit selbst eine Partizipierende Lehreinheit ist, + //wird die uebergeordnete Lehreinheit genommen + $ziel_lehreinheit_id = $row->lehreinheit_fk; + + $qry = "SELECT nummer FROM lehreinheit WHERE lehreinheit_pk='$ziel_lehreinheit_id'"; + if($result = pg_query($this->conn, $qry)) + { + if($row = pg_fetch_object($result)) + $nummer = $row->nummer; + else + { + $this->errormsg = 'Fehler beim Auslesen der Nummer'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim Auslesen der Nummer'; + return false; + } + } + //Zuteilung speichern + $qry = "UPDATE lehreinheit SET lehreinheit_fk='$ziel_lehreinheit_id', + bemerkungen=(bemerkungen || ' Partizipierende LVA bei $nummer') + WHERE lehreinheit_pk = '$quell_lehreinheit_id'"; + + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim speichern'; + return false; + } + + } + else + { + $this->errormsg = 'Ziel Lehreinheit konnte nicht ermittelt werden'; + return true; + } + } + else + { + $this->errormsg = 'Ziel Lehreinheit konnte nicht ermittelt werden'; + return false; + } + } + else + { + $qry = "SELECT b.nummer as nummer, a.bemerkungen as bemerkung FROM lehreinheit as a, lehreinheit as b where a.lehreinheit_fk=b.lehreinheit_pk AND a.lehreinheit_pk='$quell_lehreinheit_id'"; + if($result = pg_query($this->conn, $qry)) + { + if($row = pg_fetch_object($result)) + { + $bemerkung = $row->bemerkung; + $bemerkung = str_replace('Partizipierende LVA bei '.$row->nummer,'',$bemerkung); + + //Loeschen der Zuteilung + $qry = "UPDATE lehreinheit SET lehreinheit_fk='-1', bemerkungen = '$bemerkung' WHERE lehreinheit_pk='$quell_lehreinheit_id'"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim speichern'; + return false; + } + } + else + { + $this->errormsg = 'Nummer konnte nicht ermittelt werden'; + return false; + } + } + else + { + $this->errormsg = 'Nummer konnte nicht ermittelt werden'; + return false; + } + } + } + else + { + $this->errormsg = 'Quell und Ziel ID sind identisch'; + return false; + } + } + else + { + $this->errormsg = 'Quell und Ziel ID muessen gueltige Zahlen sein'; + return false; + } + } +} +?> \ No newline at end of file diff --git a/include/fas/lehrform.class.php b/include/fas/lehrform.class.php new file mode 100644 index 000000000..d35c9287c --- /dev/null +++ b/include/fas/lehrform.class.php @@ -0,0 +1,131 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($lehrform_id != null) + $this->load($lehrform_id); + } + + /** + * Laedt einen Datensatz + * @param $lform_id ID des zu ladenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function load($lform_id) + { + //pruefen ob lform_id eine gueltige Zahl ist + if(!is_numeric($lform_id) || $lform_id == '') + { + $this->errormsg = 'lehrform_id muss eine gueltige Zahl sein'; + return false; + } + + //Datensatz laden + $qry = "SELECT * FROM lehrform WHERE lehrform_pk = '$lform_id';"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Der Datensatz konnte nicht geladen werden'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->lehrform_id = $row->lehrform_pk; + $this->bezeichnung = $row->bezeichnung; + $this->kurzbezeichnung = $row->kurzbezeichnung; + $this->standardfaktor = $row->standardfaktor; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Der Datensatz konnte nicht geladen werden'; + return false; + } + + return true; + } + + /** + * Liefert alle lehrformen + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + $qry = "SELECT * FROM lehrform;"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Der Datensatz konnte nicht geladen werden'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $form_obj = new lehrform($this->conn); + + $form_obj->lehrform_id = $row->lehrform_pk; + $form_obj->bezeichnung = $row->bezeichnung; + $form_obj->kurzbezeichnung = $row->kurzbezeichnung; + $form_obj->standardfaktor = $row->standardfaktor; + $form_obj->updateamum = $row->creationdate; + $form_obj->updatevon = $row->creationdate; + + $this->result[] = $form_obj; + } + + return true; + } + + /** + * Loescht einen Datensatz + * @param lehrform_id ID des zu loeschenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function delete($lehrform_id) + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } + + /** + * Speichert einen Datensatz + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + $this->errormsg = 'Noch nicht implemeniert'; + return false; + } +} +?> \ No newline at end of file diff --git a/include/fas/lehrfunktion.class.php b/include/fas/lehrfunktion.class.php new file mode 100644 index 000000000..a2bd65a33 --- /dev/null +++ b/include/fas/lehrfunktion.class.php @@ -0,0 +1,124 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($lehrfkt_id != null) + $this->load($lehrfkt_id); + } + + /** + * Laedt eine Lehrfunktion + * @param lehrfkt_id ID des Datensatzes der zu laden ist + * @return true wenn ok, false im Fehlerfall + */ + function load($lehrfkt_id) + { + if(!is_numeric($lehrfkt_id) || $lehrfkt_id == '') + { + $this->errormsg = 'lehrfunktion_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM lehrfunktion WHERE lehrfunktion_pk = '$lehrfkt_id';"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->lehrfunktion_id = $row->lehrfunktion_pk; + $this->bezeichnung = $row->bezeichnung; + $this->standardfaktor = $row->standardfaktor; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; + return false; + } + return true; + } + + /** + * Laedt alle Lehrfunktionen + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + $qry = "SELECT * FROM lehrfunktion;"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden der Datensaetze'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $lehrfkt_obj = new lehrfunktion($this->conn); + + $lehrfkt_obj->lehrfunktion_id = $row->lehrfunktion_id; + $lehrfkt_obj->bezeichnung = $row->bezeichnung; + $lehrfkt_obj->standardfaktor = $row->standardfaktor; + $lehrfkt_obj->updateamum = $row->creationdate; + $lehrfkt_obj->updatevon = $row->creationuser; + + $this->result[] = $lehrfkt_obj; + } + return true; + } + + /** + * Speichert den aktuellen Datensatz in die Datenbank + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } + + /** + * Loescht den Datensatz mit der ID die uebergeben wird + * @param lehrfkt_id ID des zu loeschenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function delete($lehrfkt_id) + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } +} +?> \ No newline at end of file diff --git a/include/fas/lehrveranstaltung.class.php b/include/fas/lehrveranstaltung.class.php new file mode 100644 index 000000000..8b145f5aa --- /dev/null +++ b/include/fas/lehrveranstaltung.class.php @@ -0,0 +1,427 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($lehrveranstaltung_id != null) + $this->load($lehrveranstaltung_id); + } + + /** + * Laedt einen Datensatz + * @param $lehrveranstaltung_id ID des zu ladenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function load($lehrveranstaltung_id) + { + //gueltigkeit von lehrveranstaltung_id pruefen + if(!is_numeric($lehrveranstaltung_id) || $lehrveranstaltung_id == '') + { + $this->errormsg = 'lehrveranstaltung_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM lehrveranstaltung WHERE lehrveranstaltung_pk = '$lehrveranstaltung_id';"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->lehrveranstaltung_id = $row->lehrveranstaltung_pk; + $this->art = $row->art; + $this->ausbildungssemester_id = $row->ausbildungssemester_fk; + $this->beschreibung = $row->beschreibung; + $this->ectspunkte = $row->ectspunkte; + $this->fachbereich_id = $row->fachbereich_fk; + $this->kategorie = $row->kategorie; + $this->kurzbezeichnung = $row->kurzbezeichnung; + $this->name = $row->name; + $this->notenlektor_id = $row->notenlektor_fk; + $this->nummer = $row->nummer; + $this->nummerintern = $row->nummerintern; + $this->sortierung = $row->sortierung; + $this->studentenwochenstunden = $row->studentenwochenstunden; + $this->studiengang_id = $row->studiengang_fk; + $this->studiensemester_id = $row->studiensemester_fk; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + return true; + } + + /** + * Liefert alle Lehrveranstaltungen + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + $qry = "SELECT * FROM lehrveranstaltung;"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $lv_obj = new lehrveranstaltung($this->conn); + + $lv_obj->lehrveranstaltung_id = $row->lehrveranstaltung_pk; + $lv_obj->art = $row->art; + $lv_obj->ausbildungssemester_id = $row->ausbildungssemester_fk; + $lv_obj->beschreibung = $row->beschreibung; + $lv_obj->ectspunkte = $row->ectspunkte; + $lv_obj->fachbereich_id = $row->fachbereich_fk; + $lv_obj->kategorie = $row->kategorie; + $lv_obj->kurzbezeichnung = $row->kurzbezeichnung; + $lv_obj->name = $row->name; + $lv_obj->notenlektor_id = $row->notenlektor_fk; + $lv_obj->nummer = $row->nummer; + $lv_obj->nummerintern = $row->nummerintern; + $lv_obj->sortierung = $row->sortierung; + $lv_obj->studentenwochenstunden = $row->studentenwochenstunden; + $lv_obj->studiengang_id = $row->studiengang_fk; + $lv_obj->studiensemester_id = $row->studiensemester_fk; + $lv_obj->updateamum = $row->creationdate; + $lv_obj->updatevon = $row->creationuser; + + $this->result[] = $lv_obj; + } + + return true; + } + + /** + * Liefert alle Lehrveranstaltungen zu einem Studiengang/Studiensemester/Ausbildungssemester + * @param $studiengang_id ID des Studienganges + * $studiensemester_id ID des Studiensemesters (optional) + * $ausbildungssemester_id ID des ausbildungssemesters (optional) + * @return true wenn ok, false im Fehlerfall + */ + function load_lva($studiengang_id, $studiensemester_id=null, $ausbildungssemester_id=null) + { + //Variablen pruefen + if(!is_numeric($studiengang_id) || $studiengang_id =='') + { + $this->errormsg = 'studiengang_id muss eine gueltige Zahl sein'; + return false; + } + if($studiensemester_id != null && (!is_numeric($studiensemester_id) || $studiensemester_id == '')) + { + $this->errormsg = 'studiensemester_id muss eine gueltige Zahl sein'; + return false; + } + if($ausbildungssemester_id != null && (!is_numeric($ausbildungssemester_id) || $ausbildungssemester_id == '')) + { + $this->errormsg = 'ausbildungssemester_id muss eine gueltige Zahl sein'; + return false; + } + + //Select Befehl zusammenbauen + $qry = "SELECT * FROM lehrveranstaltung WHERE studiengang_fk = '$studiengang_id'"; + + if($studiensemester_id != null) + $qry .= " AND studiensemester_fk = '$studiensemester_id'"; + + if($ausbildungssemester_id != null) + $qry .= " AND ausbildungssemester_fk = '$ausbildungssemester_id'"; + $qry .= " ORDER BY name"; + //Datensaetze laden + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $lv_obj = new lehrveranstaltung($this->conn); + + $lv_obj->lehrveranstaltung_id = $row->lehrveranstaltung_pk; + $lv_obj->art = $row->art; + $lv_obj->ausbildungssemester_id = $row->ausbildungssemester_fk; + $lv_obj->beschreibung = $row->beschreibung; + $lv_obj->ectspunkte = $row->ectspunkte; + $lv_obj->fachbereich_id = $row->fachbereich_fk; + $lv_obj->kategorie = $row->kategorie; + $lv_obj->kurzbezeichnung = $row->kurzbezeichnung; + $lv_obj->name = $row->name; + $lv_obj->notenlektor_id = $row->notenlektor_fk; + $lv_obj->nummer = $row->nummer; + $lv_obj->nummerintern = $row->nummerintern; + $lv_obj->sortierung = $row->sortierung; + $lv_obj->studentenwochenstunden = $row->studentenwochenstunden; + $lv_obj->studiengang_id = $row->studiengang_fk; + $lv_obj->studiensemester_id = $row->studiensemester_fk; + $lv_obj->updateamum = $row->creationdate; + $lv_obj->updatevon = $row->creationuser; + + $this->result[] = $lv_obj; + } + + return true; + } + + /** + * Prueft die Gueltigkeit der Variablen + * @return true wenn ok, false im Fehlerfall + */ + function checkvars() + { + $this->name = str_replace("'",'´',$this->name); + $this->nummer = str_replace("'",'´',$this->nummer); + $this->kurzbezeichnung = str_replace("'",'´',$this->kurzbezeichnung); + + //Laenge Pruefen + $this->errormsg = 'Eine der Gesamtlaengen wurde ueberschritten'; + if(strlen($this->name)>255) + { + $this->errormsg = 'Name darf nicht laenger als 255 Zeichen sein'; + return false; + } + if(strlen($this->nummer)>20) + { + $this->errormsg = 'Nummer darf nicht laenger als 20 Zeichen sein'; + return false; + } + if(strlen($this->kurzbezeichnung)>20) + { + $this->errormsg = 'kurzbezeichnung darf nicht laenger als 20 Zeichen sein'; + return false; + } + + if(!is_numeric($this->fachbereich_id)) + { + $this->errormsg = 'Fachbereich_id ist ungueltig'; + return false; + } + if(!is_numeric($this->studiengang_id)) + { + $this->errormsg = 'Studiengang_id ist ungueltig'; + return false; + } + if(!is_numeric($this->ausbildungssemester_id)) + { + $this->errormsg = 'Ausbildungssemester_id ist ungueltig'; + return false; + } + if($this->art!='' && !is_numeric($this->art)) + { + $this->errormsg = 'Art ist ungueltig'; + return false; + } + if($this->studentenwochenstunden!='' && !is_numeric($this->studentenwochenstunden)) + { + $this->errormsg = 'Studentenwochenstunden ist ungueltig'; + return false; + } + if($this->kategorie!='' && !is_numeric($this->kategorie)) + { + $this->errormsg = "Kategorie ist ungueltig"; + return false; + } + if($this->ectspunkte!='' && !is_numeric($this->ectspunkte)) + { + $this->errormsg = 'ECTSPunkte sind ungueltig'; + return false; + } + if($this->notentlektor_id!='' && !is_numeric($this->notenlektor_id)) + { + $this->errormsg = 'Notenlektor ist ungueltig'; + return false; + } + if($this->sortierung!='' && !is_numeric($this->sortierung)) + { + $this->errormsg = 'Sortierung ist ungueltig'; + return false; + } + if($this->nummerintern!='' && !is_numeric($this->nummerintern)) + { + $this->errormsg = 'NummerIntern ist ungueltig'; + return false; + } + + if(!is_numeric($this->studiensemester_id)) + { + $this->errormsg = 'Studiensemester_id ist ungueltig'; + return false; + } + + $this->errormsg = ''; + return true; + } + + /** + * Speichert den aktuellen Datensatz + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + //Gueltigkeit der Variablen pruefen + if(!$this->checkvars()) + return false; + + if($this->new) + { + //Neuen Datensatz anlegen + + //naechste ID aus der Sequence holen + $qry = "SELECT nextval('lehrveranstaltung_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Sequence konnte nicht ausgelesen werden'; + return false; + } + $this->lehrveranstaltung_id = $row->id; + + $qry = "INSERT INTO lehrveranstaltung(lehrveranstaltung_pk, fachbereich_fk, studiengang_fk, ausbildungssemester_fk,". + " name, nummer, kurzbezeichnung, beschreibung, art, studentenwochenstunden, creationdate, creationuser,". + " kategorie, ectspunkte, studiensemester_fk, notenlektor_fk, sortierung, nummerintern) VALUES(". + " '$this->lehrveranstaltung_id', '$this->fachbereich_id', '$this->studiengang_id', '$this->ausbildungssemester_id',". + " '$this->name', '$this->nummer', '$this->kurzbezeichnung', '$this->beschreibung', '$this->art',". + " '$this->studentenwochenstunden', now(), $this->updatevon, '$this->kategorie', '$this->ectspunkte', '$this->studiensemester_id',". + " '$this->notenlektor_id', '$this->sortierung', '$this->nummerintern');"; + } + else + { + //bestehenden Datensatz akualisieren + + //Pruefen ob lehrveranstaltung_id eine gueltige Zahl ist + if(!is_numeric($this->lehrveranstaltung_id) || $this->lehrveranstaltung_id == '') + { + $this->errormsg = 'lehrveranstaltung_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "UPDATE lehrveranstaltung SET fachbereich_fk = '$this->fachbereich_id', studiengang_fk = '$this->studiengang_id',". + " ausbildungssemester_fk = '$this->ausbildungssemester_id', name = '$this->name', nummer = '$this->nummer',". + " kurzbezeichnung = '$this->kurzbezeichnung', beschreibung = '$this->beschreibung', art = '$this->art',". + " studentenwochenstunden = '$this->studentenwochenstunden', kategorie = '$this->kategorie', ". + " ectspunkte = '$this->ectspunkte', studiensemester_fk = '$this->studiensemester_id',". + " notenlektor_fk = '$this->notenlektor_id', sortierung = '$this->sortierung', nummerintern = '$this->nummerintern'". + " WHERE lehrveranstaltung_pk = '$this->lehrveranstaltung_id';"; + } + + if(pg_query($this->conn, $qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim speichern des Datensatzes'; + return false; + } + } + + /** + * Loescht einen Datensatz + * @param $lehrveranstaltung_id ID des zu loeeschenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function delete($lehrveranstaltung_id) + { + //lehrveranstaltung_id auf gueltigkeit pruefen + if(!is_numeric($lehrveranstaltung_id) || $lehrveranstaltung_id == '') + { + $this->errormsg = 'lehrveranstaltung_id muss eine gueltige Zahl sein'; + return false; + } + + //Loeschen des Datensatzes + $qry = "DELETE FROM lehrveranstaltung WHERE lehrveranstaltung_pk = '$lehrveranstaltung_id';"; + + if(pg_query($this->conn, $qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim loeschen des Datensatzes'; + return false; + } + } +} +?> \ No newline at end of file diff --git a/include/fas/mitarbeiter.class.php b/include/fas/mitarbeiter.class.php new file mode 100644 index 000000000..a53bdfcdb --- /dev/null +++ b/include/fas/mitarbeiter.class.php @@ -0,0 +1,742 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + //Mitarbeiter laden + if($person_id!=null) + $this->load($person_id); + } + + /** + * ueberprueft die Variablen auf Gueltigkeit + * @return true wenn gueltig, false im Fehlerfall + */ + function checkvars() + { + //Hochkomma herausfiltern + $this->persnr = str_replace("'","`", $this->persnr); + $this->kurzbez = str_replace("'","`", $this->kurzbez); + + //Maximallaenge pruefen + $this->errormsg='Die Maximallaenge eines Feldes wurde ueberschritten'; + if(strlen($this->persnr)>20) + { + $this->errormsg='PersonalNr darf nicht länger als 20 Zeichen sein'; + return false; + } + if(strlen($this->kurzbez)>10) + { + $this->errormsg="Kurzbezeichnung darf nicht länger als 10 Zeichen sein:".strlen($this->kurzbez); + return false; + } + + //Zahlenwerte ueberpruefen + $this->errormsg='Ein Zahlenfeld enthaelt ungueltige Zeichen'; + //if(!is_numeric($this->qualifikation)) return false; + //if(!is_numeric($this->hauptberuf)) return false; + if(!is_numeric($this->stundensatz) && $this->stundensatz!='') + { + $this->errormsg='Stundensatz muss eine gueltige Zahl sein'; + return false; + } + if(!is_numeric($this->ausbildung) && $this->ausbildung!='') + { + $this->errormsg='ausbildung muss eine gueltige Zahl sein'; + return false; + } + /*if(!is_numeric($this->semesterwochenstunden)) + { + $this->errormsg='SWS muss eine gueltige Zahl sein'; + return false; + }*/ + + if($this->kurzbz_exists($this->kurzbez, $this->mitarbeiter_id)) + { + $this->errormsg = 'Diese Kurzbezeichnung wird bereits verwendet'; + return false; + } + + $this->errormsg = ''; + return true; + } + + + /** + * Speichert die Mitarbeiterdaten in die Datenbank + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + //Variablen checken + if(!$this->checkvars()) + return false; + + pg_query($this->conn,"Begin;"); + //Basisdaten speichern + if(!person::save()) + { + pg_query($this->conn,"Rollback;"); + return false; + } + + if($this->new) + { + //Neuen Datensatz einfuegen + + //naechste ID aus Sequence auslesen + $qry = "SELECT nextval('mitarbeiter_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn,$qry))) + { + $this->errormsg = 'Fehler beim auslesen der Sequence'; + return false; + } + $this->mitarbeiter_id = $row->id; + + $qry = "INSERT INTO mitarbeiter (mitarbeiter_pk, beginndatum, akadgrad, habilitation,". + //" mitgliedentwicklungsteam,". + //" qualifikation, hauptberuflich, hauptberuf, semesterwochenstunden,". + " creationdate, creationuser, persnr,". + " person_fk, beendigungsdatum, ausgeschieden, kurzbez, stundensatz, ausbildung, aktiv) VALUES (". + " '$this->mitarbeiter_id',". + (strlen($this->beginndatum)>0?"'$this->beginndatum'":"NULL") .", '".($this->akadgrad?'J':'N')."',". + " '".($this->habilitation?'J':'N')."', ". + //"'".($this->mitgliedentwicklungsteam?'J':'N')."',". + //" '$this->qualifikation', '".($this->hauptberuflich?'J':'N')."', '$this->hauptberuf', '$this->semesterwochenstunden',". + " now(),". + " '$this->updatevon', '$this->persnr', '$this->person_id',". + (strlen($this->beendigungsdatum)>0?"'$this->beendigungsdatum'":"null").",". + " '".($this->ausgeschieden?'J':'N')."',". + (strlen($this->kurzbez)>0?"'$this->kurzbez'":"null").", '$this->stundensatz',". + ($this->ausbildung!=''?"'$this->ausbildung'":'null').",'$this->aktiv');"; + } + else + { + //Bestehenden Datensatz ueberschreiben + + //mitarbeiter_id auf Gueltigkeit pruefen + if(!is_numeric($this->mitarbeiter_id)) + { + $this->errormsg = 'mitarbeiter_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "UPDATE mitarbeiter SET". + " beginndatum=".($this->beginndatum!=''?"'$this->beginndatum'":'null').",". + " akadgrad='".($this->akadgrad?'J':'N')."',". + " habilitation='".($this->habilitation?'J':'N')."',". + //" mitgliedentwicklungsteam='".($this->mitgliedentwicklungsteam?'J':'N')."',". + //" qualifikation='$this->qualifikation', hauptberuflich='".($this->hauptberuflich?'J':'N')."',". + //" hauptberuf='$this->hauptberuf', semesterwochenstunden='$this->semesterwochenstunden',". + " persnr=".($this->persnr!=''?"'$this->persnr'":'null').",". + " person_fk='$this->person_id',". + " beendigungsdatum=".($this->beendigungsdatum!=''?"'$this->beendigungsdatum'":'null').",". + " ausgeschieden='".($this->ausgeschieden?'J':'N')."',". + " kurzbez=".($this->kurzbez!=''?"'$this->kurzbez'":'null').",". + " stundensatz=".($this->stundensatz!=''?"'$this->stundensatz'":'null').",". + " ausbildung=".($this->ausbildung!=''?"'$this->ausbildung'":'null').",". + " aktiv='$this->aktiv'". + " WHERE mitarbeiter_pk=$this->mitarbeiter_id;"; + } + + if(pg_query($this->conn,$qry)) + { + //Wenn nicht ausgeschieden dann den Status neu setzen + //Da sonst beim ruecksetzen des Hakerls ausgeschieden der status bleibt + if(!$this->ausgeschieden) + { + if(!person::updateaktstatus($this->person_id)) + { + pg_query($this->conn,"Rollback;"); + return false; + } + } + else + { + if(!person::setaktstatus(150,$this->person_id)) + { + pg_query($this->conn,"Rollback;"); + return false; + } + } + pg_query($this->conn,"Commit;"); + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + pg_query($this->conn,"Rollback;"); + $this->errormsg = 'Fehler beim Speichern des Mitarbeiter-Datensatzes'; + return false; + } + } + + /** + * Ladet die Daten aus der Datenbank + * @param $fix wenn 'true' Fixangestellte laden + * wenn 'false' Freie MA laden + * $stgl wenn 'true' Studiengangsleiter laden + * $fbl wenn 'true' Fachbereichsleiter laden + * $aktiv wenn 'true' Aktive MA laden + * $karrenziert wenn 'true' Karenzierte laden + * $ausgesch wenn 'true' Ausgeschiedene laden + * @return true wenn ok, false im Fehlerfall + */ + function getMitarbeiter($mitarbeiter_id='', $fix='', $stgl='', $fbl='', $aktiv='', $karenziert='', $ausgesch='', $adresse=false, $studiensemester_id='') + { + $qry = "SELECT * FROM (mitarbeiter JOIN person ON (person_pk=mitarbeiter.person_fk))"; + if($adresse) + $qry .= " LEFT JOIN adresse on(person_pk=adresse.person_fk)"; + $qry .= " WHERE true"; + + if($mitarbeiter_id!='') + if(is_numeric($mitarbeiter_id)) + $qry .= " AND mitarbeiter_pk = $mitarbeiter_id"; + else + { + $this->errormsg = "mitarbeiter_id muss eine gueltige Zahl sein"; + return false; + } + + if($studiensemester_id=='') + { + $query = "Select studiensemester_pk FROM studiensemester WHERE aktuell='J'"; + if($row = pg_fetch_object(pg_query($this->conn, $query))) + $studiensemester_id = $row->studiensemester_pk; + } + + if($fix=='true') // Alle Fixangestellten + $qry .= " AND mitarbeiter_pk IN(SELECT distinct funktion.mitarbeiter_fk FROM funktion WHERE funktion.beschart1=3 AND funktion.studiensemester_fk='$studiensemester_id')"; + + if($fix=='false') // Freie Mitarbeiter + $qry .= " AND mitarbeiter_pk IN(SELECT distinct funktion.mitarbeiter_fk FROM funktion WHERE funktion.beschart1=4 AND funktion.studiensemester_fk='$studiensemester_id')"; + + if($stgl=='true') //Alle Studiengangsleiter + $qry .= " AND mitarbeiter_pk IN(SELECT distinct funktion.mitarbeiter_fk FROM funktion WHERE funktion.funktion=5 AND funktion.studiensemester_fk='$studiensemester_id')"; + + + if($fbl=='true') //Alle Fachbereichsleiter + $qry .= " AND mitarbeiter_pk IN(SELECT distinct funktion.mitarbeiter_fk FROM funktion WHERE funktion.funktion=6 AND funktion.studiensemester_fk='$studiensemester_id')"; + + if($aktiv=='true') //Alle aktiven + $qry .= " AND aktiv=true"; + + if($karenziert=='true') //Alle Karenzierten + $qry .= " AND mitarbeiter_pk IN(SELECT distinct funktion.mitarbeiter_fk FROM funktion WHERE funktion.ausmass=5 AND funktion.studiensemester_fk='$studiensemester_id')"; + + if($ausgesch=='true') // Alle Ausgeschiedenen + $qry .= " AND beendigungsdatum is not null"; + + $qry .= " ORDER BY familienname"; + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $mitarb = new mitarbeiter($this->conn); + //Personendaten + $mitarb->person_id = $row->person_pk; + $mitarb->familienname = $row->familienname; + $mitarb->angelegtam = $row->angelegtam; + $mitarb->vorname = $row->vorname; + $mitarb->anrede = $row->anrede; + $mitarb->vornamen = $row->vornamen; + $mitarb->geschlecht = $row->geschlecht; + $mitarb->gebdat = $row->gebdat; + $mitarb->gebort = $row->gebort; + $mitarb->staatsbuergerschaft = $row->staatsbuergerschaft; + $mitarb->familienstand = $row->familienstand; + $mitarb->familienstand_bezeichnung = $this->getFamilienstandBezeichnung($row->familienstand); + $mitarb->svnr = $row->svnr; + $mitarb->anzahlderkinder = $row->anzahlderkinder; + $mitarb->ersatzkennzeichen = $row->ersatzkennzeichen; + $mitarb->bemerkung = $row->bemerkung; + $mitarb->aktstatus = $row->aktstatus; + $mitarb->aktstatus_bezeichnung = $this->getAktstatusBezeichnung($row->aktstatus); + $mitarb->bismelden = ($row->bismelden=='J'?true:false); + $mitarb->bismelden_bezeichnung = ($row->bismelden=='J'?'Ja':'Nein'); + $mitarb->titelpre = $row->titel; + $mitarb->titelpost = $row->postnomentitel; + $mitarb->uid = $row->uid; + $mitarb->gebnation = $row->gebnation; + + //Mitarbeiterdaten + $mitarb->mitarbeiter_id = $row->mitarbeiter_pk; + $mitarb->beginndatum = $row->beginndatum; + $mitarb->akadgrad = ($row->akadgrad=='J'?true:false); + $mitarb->akadgrad_bezeichnung = ($row->akadgrad=='J'?'Ja':'Nein'); + $mitarb->habilitation = ($row->habilitation=='J'?true:false); + $mitarb->habilitation_bezeichnung = ($row->habilitation=='J'?'Ja':'Nein'); + $mitarb->mitgliedentwicklungsteam = ($row->mitgliedentwicklungsteam=='J'?true:false); + $mitarb->qualifikation = $row->qualifikation; + $mitarb->hauptberuflich = ($row->hauptberuflich=='J'?true:false); + $mitarb->hauptberuf = $row->hauptberuf; + $mitarb->updateamum = $row->creationdate; + $mitarb->updatevon = $row->creationuser; + $mitarb->semesterwochenstunden = $row->semesterwochenstunden; + $mitarb->persnr = $row->persnr; + $mitarb->beendigungsdatum = $row->beendigungsdatum; + $mitarb->ausgeschieden = ($row->ausgeschieden=='J'?true:false); + $mitarb->ausgeschieden_bezeichnung = ($row->ausgeschieden=='J'?'Ja':'Nein'); + $mitarb->kurzbez = $row->kurzbez; + $mitarb->stundensatz = $row->stundensatz; + $mitarb->ausbildung = $row->ausbildung; + $mitarb->ausbildung_bezeichnung = $this->getAusbildungBezeichnung($row->ausbildung); + $mitarb->aktiv = ($row->aktiv=='t'?true:false); + $mitarb->aktiv_bezeichnung = ($row->aktiv=='t'?'Ja':'Nein'); + + if($adresse) + { + $mitarb->zustelladresse_plz = $row->plz; + $mitarb->zustelladresse_strasse = $row->strasse; + $mitarb->zustelladresse_ort = $row->ort; + } + $this->result[] = $mitarb; + } + return true; + } + + /** + * Liefert alle Mitarbeiter + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + + $qry = "Select person_pk, familienname, angelegtam, vorname, anrede, vornamen, geschlecht, gebdat, gebort, staatsbuergerschaft, ". + "familienstand, svnr, anzahlderkinder, ersatzkennzeichen, bemerkung, aktstatus, bismelden, titel, postnomentitel, uid, gebnation, ". + "mitarbeiter_pk, beginndatum, akadgrad, habilitation, mitgliedentwicklungsteam, qualifikation, hauptberuflich, hauptberuf, ". + "mitarbeiter.creationdate, mitarbeiter.creationuser, semesterwochenstunden, persnr, beendigungsdatum, ausgeschieden, ". + "kurzbez, stundensatz, ausbildung, aktiv FROM mitarbeiter JOIN person ON(person_pk=person_fk)"; + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $mitarb = new mitarbeiter($this->conn); + //Personendaten + $mitarb->person_id = $row->person_pk; + $mitarb->familienname = $row->familienname; + $mitarb->angelegtam = $row->angelegtam; + $mitarb->vorname = $row->vorname; + $mitarb->anrede = $row->anrede; + $mitarb->vornamen = $row->vornamen; + $mitarb->geschlecht = $row->geschlecht; + $mitarb->gebdat = $row->gebdat; + $mitarb->gebort = $row->gebort; + $mitarb->staatsbuergerschaft = $row->staatsbuergerschaft; + $mitarb->familienstand = $row->familienstand; + $mitarb->svnr = $row->svnr; + $mitarb->anzahlderkinder = $row->anzahlderkinder; + $mitarb->ersatzkennzeichen = $row->ersatzkennzeichen; + $mitarb->bemerkung = $row->bemerkung; + $mitarb->aktstatus = $row->aktstatus; + $mitarb->bismelden = ($row->bismelden=='J'?true:false); + $mitarb->titelpre = $row->titel; + $mitarb->titelpost = $row->postnomentitel; + $mitarb->uid = $row->uid; + $mitarb->gebnation = $row->gebnation; + //Mitarbeiterdaten + $mitarb->mitarbeiter_id = $row->mitarbeiter_pk; + $mitarb->beginndatum = $row->beginndatum; + $mitarb->akadgrad = ($row->akadgrad=='J'?true:false); + $mitarb->habilitation = ($row->habilitation=='J'?true:false); + $mitarb->mitgliedentwicklungsteam = ($row->mitgliedentwicklungsteam=='J'?true:false); + $mitarb->qualifikation = $row->qualifikation; + $mitarb->hauptberuflich = ($row->hauptberuflich=='J'?true:false); + $mitarb->hauptberuf = $row->hauptberuf; + $mitarb->updateamum = $row->creationdate; + $mitarb->updatevon = $row->creationuser; + $mitarb->semesterwochenstunden = $row->semesterwochenstunden; + $mitarb->persnr = $row->persnr; + $mitarb->beendigungsdatum = $row->beendigungsdatum; + $mitarb->ausgeschieden = ($row->ausgeschieden=='J'?true:false); + $mitarb->kurzbez = $row->kurzbez; + $mitarb->stundensatz = $row->stundensatz; + $mitarb->ausbildung = $row->ausbildung; + $mitarb->aktiv = ($row->aktiv=='t'?true:false); + + $this->result[] = $mitarb; + } + return true; + + } + + /** + * Laedt die Mitarbeiterdaten der uebergebenen ID + * @param $person_id ID der Person die geladen werden soll + * @return true wenn ok, false im Fehlerfall + */ + function load($person_id) + { + //person_id auf Gueltigkeit pruefen + if(!is_numeric($person_id) || $person_id=='') + { + $this->errormsg = 'Person_id muss eine Zahl sein'; + return false; + } + + $qry = "SELECT person_pk, familienname, angelegtam, vorname, anrede, vornamen, geschlecht, gebdat, gebort, staatsbuergerschaft, ". + "familienstand, svnr, anzahlderkinder, ersatzkennzeichen, bemerkung, aktstatus, bismelden, titel, postnomentitel, uid, gebnation, ". + "mitarbeiter_pk, beginndatum, akadgrad, habilitation, mitgliedentwicklungsteam, qualifikation, hauptberuflich, hauptberuf, ". + "mitarbeiter.creationdate, mitarbeiter.creationuser, semesterwochenstunden, persnr, beendigungsdatum, ausgeschieden, ". + "kurzbez, stundensatz, ausbildung, aktiv FROM mitarbeiter JOIN person ON(person_pk=person_fk) where person_pk=$person_id"; + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + if($row = pg_fetch_object($res)) + { + //Personendaten + $this->person_id = $row->person_pk; + $this->familienname = $row->familienname; + $this->angelegtam = $row->angelegtam; + $this->vorname = $row->vorname; + $this->anrede = $row->anrede; + $this->vornamen = $row->vornamen; + $this->geschlecht = $row->geschlecht; + $this->gebdat = $row->gebdat; + $this->gebort = $row->gebort; + $this->staatsbuergerschaft = $row->staatsbuergerschaft; + $this->familienstand = $row->familienstand; + $this->svnr = $row->svnr; + $this->anzahlderkinder = $row->anzahlderkinder; + $this->ersatzkennzeichen = $row->ersatzkennzeichen; + $this->bemerkung = $row->bemerkung; + $this->aktstatus = $row->aktstatus; + $this->bismelden = ($row->bismelden=='J'?true:false); + $this->titelpre = $row->titel; + $this->titelpost = $row->postnomentitel; + $this->uid = $row->uid; + $this->gebnation = $row->gebnation; + //Mitarbeiterdaten + $this->mitarbeiter_id = $row->mitarbeiter_pk; + $this->beginndatum = $row->beginndatum; + $this->akadgrad = ($row->akadgrad=='J'?true:false); + $this->habilitation = ($row->habilitation=='J'?true:false); + $this->mitgliedentwicklungsteam = ($row->mitgliedentwicklungsteam=='J'?true:false); + $this->qualifikation = $row->qualifikation; + $this->hauptberuflich = ($row->hauptberuflich=='J'?true:false); + $this->hauptberuf = $row->hauptberuf; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + $this->semesterwochenstunden = $row->semesterwochenstunden; + $this->persnr = $row->persnr; + $this->beendigungsdatum = $row->beendigungsdatum; + $this->ausgeschieden = ($row->ausgeschieden=='J'?true:false); + $this->kurzbez = $row->kurzbez; + $this->stundensatz = $row->stundensatz; + $this->ausbildung = $row->ausbildung; + $this->aktiv = ($row->aktiv=='t'?true:false); + } + else + { + $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; + return false; + } + + return true; + } + + /** + * Laedt die Mitarbeiterdaten der uebergebenen ID + * @param $mitarbeiter_id ID der Person die geladen werden soll + * @return true wenn ok, false im Fehlerfall + */ + function load_mitarbeiter($mitarbeiter_id) + { + //person_id auf Gueltigkeit pruefen + if(!is_numeric($mitarbeiter_id) || $mitarbeiter_id=='') + { + $this->errormsg = 'Person_id muss eine Zahl sein'; + return false; + } + + $qry = "SELECT person_pk, familienname, angelegtam, vorname, anrede, vornamen, geschlecht, gebdat, gebort, staatsbuergerschaft, ". + "familienstand, svnr, anzahlderkinder, ersatzkennzeichen, bemerkung, aktstatus, bismelden, titel, postnomentitel, uid, gebnation, ". + "mitarbeiter_pk, beginndatum, akadgrad, habilitation, mitgliedentwicklungsteam, qualifikation, hauptberuflich, hauptberuf, ". + "mitarbeiter.creationdate, mitarbeiter.creationuser, semesterwochenstunden, persnr, beendigungsdatum, ausgeschieden, ". + "kurzbez, stundensatz, ausbildung, aktiv FROM mitarbeiter JOIN person ON(person_pk=person_fk) where mitarbeiter_pk=$mitarbeiter_id"; + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + if($row = pg_fetch_object($res)) + { + //Personendaten + $this->person_id = $row->person_pk; + $this->familienname = $row->familienname; + $this->angelegtam = $row->angelegtam; + $this->vorname = $row->vorname; + $this->anrede = $row->anrede; + $this->vornamen = $row->vornamen; + $this->geschlecht = $row->geschlecht; + $this->gebdat = $row->gebdat; + $this->gebort = $row->gebort; + $this->staatsbuergerschaft = $row->staatsbuergerschaft; + $this->familienstand = $row->familienstand; + $this->svnr = $row->svnr; + $this->anzahlderkinder = $row->anzahlderkinder; + $this->ersatzkennzeichen = $row->ersatzkennzeichen; + $this->bemerkung = $row->bemerkung; + $this->aktstatus = $row->aktstatus; + $this->bismelden = ($row->bismelden=='J'?true:false); + $this->titelpre = $row->titel; + $this->titelpost = $row->postnomentitel; + $this->uid = $row->uid; + $this->gebnation = $row->gebnation; + //Mitarbeiterdaten + $this->mitarbeiter_id = $row->mitarbeiter_pk; + $this->beginndatum = $row->beginndatum; + $this->akadgrad = ($row->akadgrad=='J'?true:false); + $this->habilitation = ($row->habilitation=='J'?true:false); + $this->mitgliedentwicklungsteam = ($row->mitgliedentwicklungsteam=='J'?true:false); + $this->qualifikation = $row->qualifikation; + $this->hauptberuflich = ($row->hauptberuflich=='J'?true:false); + $this->hauptberuf = $row->hauptberuf; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + $this->semesterwochenstunden = $row->semesterwochenstunden; + $this->persnr = $row->persnr; + $this->beendigungsdatum = $row->beendigungsdatum; + $this->ausgeschieden = ($row->ausgeschieden=='J'?true:false); + $this->kurzbez = $row->kurzbez; + $this->stundensatz = $row->stundensatz; + $this->ausbildung = $row->ausbildung; + $this->aktiv = ($row->aktiv=='t'?true:false); + } + else + { + $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; + return false; + } + + return true; + } + + /** + * loescht den Mitarbeiter mit der uebergebenen ID + * @param ma_id Mitarbeiter_id + * @return true wenn ok, false im Fehlerfall + */ + function delete($person_id) + { + //person_id auf Gueltigkeit pruefen + if(!is_numeric($person_id) || $person_id=='') + { + $this->errormsg = 'Person_id muss eine Zahl sein'; + return false; + } + + $qry = "DELETE FROM funktion where mitarbeiter_fk=(Select mitarbeiter_pk from mitarbeiter where person_fk=$person_id);". + " DELETE FROM adresse where person_fk=$person_id;". + " DELETE FROM telefonnummer where person_fk=$person_id;". + " DELETE FROM email where person_fk=$person_id;". + " DELETE FROM mitarbeiter where person_fk=$person_id"; + + if(!pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler beim Loeschen'; + return false; + } + else + { + if(!person::delete($person_id)) + return false; + else + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + } + return true; + } + + /** + * Liefert die passende Bezeichnung des Familienstandes + * @param $id ID des Familienstandes + */ + function getFamilienstandBezeichnung($id) + { + switch($id) + { + case 1: return 'ledig'; + case 2: return 'verheiratet'; + case 3: return 'geschieden'; + case 4: return 'verwitwet'; + default: return ''; + } + } + + /** + * Liefert die passende Bezeichnung der Ausbildung + * @param $id ID der Ausbildung + */ + function getAusbildungBezeichnung($id) + { + switch($id) + { + case 1: return 'Universitätsabschluss mit Doktorat als Zweit- oder Dritt- oder PhD-Abschluss'; + case 2: return 'Universitäts- oder Hochschulabschluss auf Diplom oder Magisterebene, Doktor als Erstabschluss'; + case 3: return 'Fachhochschulabschluss auf Diplom- oder Magisterebene'; + case 4: return 'Universitätsabschluss auf Bakkalaureatsebene'; + case 5: return 'Fachhochschulabschluss auf Bakkalaureatsebene'; + case 6: return 'Diplom einer Akademie'; + case 7: return 'Anderer tertiärer Bildungsabschluss'; + case 8: return 'Reifeprüfung einer allgemeinbildenden höheren Schule'; + case 9: return 'Reifeprüfung einer berufsbildenden höheren Schule'; + case 10: return 'Lehrabschlussprüfung'; + case 11: return 'Pflichtschule'; + default: return ''; + } + } + + /** + * Liefert die passende Bezeichnung des Aktuellen Status + * @param $id ID des Status + */ + function getAktstatusBezeichnung($id) + { + switch($id) + { + case 100: return 'Mitarbeiter'; + case 101: return 'Lektor'; + case 102: return 'Koordinator'; + case 103: return 'Fachbereichsleiter'; + case 104: return 'Studiengangsleiter'; + case 150: return 'Ausgeschieden'; + default: return ''; + } + } + + /** + * Prüft ob eine Kurzbezeichnung schon existiert. Falls eine mitarbeiter_id + * angegeben wird, dann wird dieser Datensatz von der ueberpruefung ausgeschlossen + * ( fuer Update eines Datensatzes) + */ + function kurzbz_exists($kurzbz, $mitarbeiter_id='') + { + if($kurzbz!='') + { + $this->errormsg = ''; + $qry = "SELECT count(*) as anz from mitarbeiter where kurzbez='$kurzbz'"; + if($mitarbeiter_id!='') + $qry .= " AND mitarbeiter_pk<>".$mitarbeiter_id; + + if($result = pg_query($this->conn,$qry)) + { + while ($row=pg_fetch_object($result)) + { + if($row->anz == 0) + { + return false; + } + else + { + return true; + } + } + } + else + { + $this->errormsg = 'Fehler beim pruefen der Kurzbezeichnung'; + return false; + } + } + return false; + } + + /** + * Liefert die naechste Personalnummer + */ + function getNextPersonalnr() + { + $qry = "SELECT max(persnr) AS persnr FROM mitarbeiter WHERE length(persnr)=(SELECT max(length(persnr)) FROM mitarbeiter)"; + if($row = pg_fetch_object(pg_query($this->conn,$qry))) + return $row->persnr+1; + else + return false; + } +} +?> \ No newline at end of file diff --git a/include/fas/nation.class.php b/include/fas/nation.class.php new file mode 100644 index 000000000..5e9e240e0 --- /dev/null +++ b/include/fas/nation.class.php @@ -0,0 +1,92 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($code != null) + $this->load($code); + } + + /** + * Laedt die Funktion mit der ID $adress_id + * @param $code code der zu ladenden Nation + * @return true wenn ok, false im Fehlerfall + */ + function load($code) + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } + + /** + * Laedt alle Nationen + * @param ohnesperre wenn dieser Parameter auf true gesetzt ist werden + * nur die nationen geliefert dessen Buerger bei uns studieren duerfen + */ + function getAll($ohnesperre=false) + { + //Lesen der Daten aus der Datenbank + $qry = "SELECT * FROM nation"; + if($ohnesperre) + $qry .= " where sperre='N'"; + + $qry .=" order by kurztext"; + + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler bei einer Datenbankabfrage'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $nation_obj = new nation($this->conn); + + $nation_obj->code = $row->code; + $nation_obj->sperre = $row->sperre; + $nation_obj->kontinent = $row->sperre; + $nation_obj->entwland = $row->entwland; + $nation_obj->euflag = $row->euflag; + $nation_obj->ewrflag = $row->ewrflag; + $nation_obj->kurztext = $row->kurztext; + $nation_obj->langtext = $row->langtext; + $nation_obj->engltext = $row->engltext; + + $this->result[] = $nation_obj; + } + return true; + } +} +?> \ No newline at end of file diff --git a/include/fas/person.class.php b/include/fas/person.class.php new file mode 100644 index 000000000..2d353c7e3 --- /dev/null +++ b/include/fas/person.class.php @@ -0,0 +1,615 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($pers_id != null) + $this->load($pers_id); + } + + /** + * Laden einen Datensatz mit der Personal_id die uebergeben wird + * @param $person_id ID der Person die geladen werden soll + */ + function load($person_id) + { + //person_id auf gueltigkeit pruefen + if(is_numeric($person_id) && $person_id!='') + { + $qry = "SELECT * FROM person WHERE person_pk=$person_id"; + if(!$res=pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler beim auslesen der Daten'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->person_id = $row->person_pk; + $this->aktstatus = $row->aktstatus; + $this->angelegtam = $row->angelegtam; + $this->anrede = $row->anrede; + $this->anzahlderkinder = $row->anzahlderkinder; + $this->bemerkung = $row->bemerkung; + $this->bismelden = ($row->bismelden=='J'?true:false); + $this->ersatzkennzeichen = $row->ersatzkennzeichen; + $this->familienname = $row->familienname; + $this->familienstand = $row->familienstand; + $this->gebdat = $row->gebdat; + $this->gebnation = $row->gebnation; + $this->gebort = $row->gebort; + $this->geschlecht = $row->geschlecht; + $this->staatsbuergerschaft = $row->staatsbuergerschaft; + $this->svnr = $row->svnr; + $this->titelpre = $row->titel; + $this->titlepost = $row->postnomentitel; + $this->uid = $row->uid; + $this->vorname = $row->vorname; + $this->vornamen = $row->vornamen; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; + return false; + } + + return true; + } + else + { + $this->errormsg = "Die person_id muss eine Zahl sein"; + return false; + } + } + + // Clean stuff from a string + function clean_string1($string) + { + $trans = array("ä" => "ae", + "Ä" => "Ae", + "ö" => "oe", + "Ö" => "Oe", + "ü" => "ue", + "Ü" => "Ue", + "á" => "a", + "à" => "a", + "é" => "e", + "è" => "e", + "ó" => "o", + "ò" => "o", + "í" => "i", + "ì" => "i", + "ú" => "u", + "ù" => "u", + "ß" => "ss"); + $string = strtr($string, $trans); + return ereg_replace("[^a-zA-Z0-9]", "", $string); + //[:space:] + } + + /** + * Prueft die Variablen auf Gueltigkeit + * @return true wenn ok, false wenn Variablen ungueltig sind + */ + function checkvars1() + { + //Hochkomma herausfiltern + $this->familienname = str_replace("'","`", $this->familienname); + $this->vorname = str_replace("'","`", $this->vorname); + $this->anrede = str_replace("'","`", $this->anrede); + $this->vornamen = str_replace("'","`", $this->vornamen); + $this->gebort = str_replace("'","`", $this->gebort); + $this->svnr = str_replace("'","`", $this->svnr); + $this->titelpre = str_replace("'","`", $this->titelpre); + $this->titelpost = str_replace("'","`", $this->titelpost); + $this->gebnation = str_replace("'","`", $this->gebnation); + $this->ersatzkennzeichen = str_replace("'","`", $this->ersatzkennzeichen); + $this->bemerkung = str_replace("'","`", $this->bemerkung); + if(ereg("[^a-zA-Z0-9]", $this->uid)) + { + $this->errormsg = "UID darf keine Umlaute oder Sonderzeichen enthalten"; + return false; + } + + //Maximallaenge pruefen + if(strlen($this->familienname)>255) + { + $this->errormsg = 'Familienname darf nicht laenger als 255 Zeichen sein'; + return false; + } + if(strlen($this->vorname)>255) + { + $this->errormsg = 'Vorname darf nicht laenger als 255 Zeichen sein'; + return false; + } + if(strlen($this->anrede)>20) + { + $this->errormsg = 'Anrede darf nicht laenger als 20 Zeichen sein'; + return false; + } + if(strlen($this->vornamen)>255) + { + $this->errormsg = 'Vornamen darf nicht laenger als 255 Zeichen sein'; + return false; + } + if(strlen($this->geschlecht)>1) + { + $this->errormsg = 'Geschlecht darf nicht laenger als 1 Zeichen sein'; + return false; + } + if(strlen($this->gebort)>255) + { + $this->errormsg = 'Geburtsort darf nicht laenger als 255 Zeichen sein'; + return false; + } + if(strlen($this->svnr)!=10) + { + $this->errormsg = 'SVNR muss 10 Zeichen lang sein'; + return false; + } + if(!is_numeric($this->svnr)) + { + $this->errormsg = 'SVNR muss eine gueltige Zahl sein'; + return false; + } + + if($this->svnr=='0000000000') //Leere SVNR wird zum anlegen des neuen Leerdatensatzes benoetigt + $this->svnr=''; + else + { + //SVNR mit Pruefziffer pruefen + //Die 4. Stelle in der SVNR ist die Pruefziffer + //(Summe von (gewichtung[i]*svnr[i])) modulo 11 ergibt diese Pruefziffer + //Falls nicht, ist die SVNR ungueltig + $gewichtung = array(3,7,9,0,5,8,4,2,1,6); + $erg=0; + //Quersumme bilden + for($i=0;$i<10;$i++) + $erg += $gewichtung[$i] * $this->svnr{$i}; + + if($this->svnr{3}!=($erg%11)) //Vergleichen der Pruefziffer mit Quersumme Modulo 11 + { + $this->errormsg = 'SVNR ist ungueltig'; + return false; + } + } + if(strlen($this->bismelden)>1) + { + $this->errormsg = 'bismelden darf nicht laenger als 1 Zeichen sein'; + return false; + } + if(strlen($this->titelpre)>30) + { + $this->errormsg = 'titelpre darf nicht laenger als 30 Zeichen sein'; + return false; + } + if(strlen($this->titelpost)>30) + { + $this->errormsg = 'titelpost darf nicht laenger als 30 Zeichen sein'; + return false; + } + if(strlen($this->uid)>20) + { + $this->errormsg = 'uid darf nicht laenger als 20 Zeichen sein'; + return false; + } + if(strlen($this->gebnation)>3) + { + $this->errormsg = 'Geburtsnation darf nicht laenger als 3 Zeichen sein'; + return false; + } + if(strlen($this->staatsbuergerschaft)>3) + { + $this->errormsg = 'Staatsbürgerschaft darf nicht laenger als 3 Zeichen sein'; + return false; + } + if(strlen($this->ersatzkennzeichen)>10) + { + $this->errormsg = 'ersatzkennzeichen darf nicht laenger als 10 Zeichen sein'; + return false; + } + + //Zahlenwerte ueberpruefen + $this->errormsg = 'Ein Zahlenfeld enthaelt ungueltige Zeichen'; + if(!is_numeric($this->familienstand) && $this->familienstand!='') return false; + if(!is_numeric($this->anzahlderkinder) && $this->anzahlderkinder!='') return false; + if(!is_numeric($this->aktstatus) && $this->aktstatus!='') return false; + + if($this->gebdat!='' && (time() - strtotime($this->gebdat))<315360000) // Wenn nicht aelter als 10 Jahre = 315360000 Sekunden + { + $this->errormsg = 'Geburtsdatum ist falsch: Person muss älter als 10 Jahre sein'; + return false; + } + + if($this->uid_exists($this->uid, $this->person_id)) + { + $this->errormsg = 'Diese UID existiert bereits'; + return false; + } + + $this->errormsg=''; + return true; + } + + /** + * Speichert die Daten in die Datenbank + * Wenn $new auf true gesetzt ist wird eingefuegt + * ansonsten der datensatz $person_id upgedated + * @return true wenn erfolgreich, false im Fehlerfall + */ + function save() + { + //Variablen auf Gueltigkeit pruefen + if(!$this->checkvars1()) + return false; + + if($this->new) //Wenn new true ist dann ein INSERT absetzen ansonsten ein UPDATE + { + //Naechste ID aus Sequence holen + $qry = "SELECT nextval('person_seq') as id;"; + if(!$row=pg_fetch_object(pg_query($this->conn,$qry))) + { + $this->errormsg = "Fehler beim Auslesen der Sequence"; + return false; + } + $this->person_id = $row->id; + + $qry = "INSERT INTO person (person_pk, familienname, angelegtam, vorname, anrede, vornamen,". + " geschlecht, gebdat, gebort, staatsbuergerschaft, familienstand, svnr, anzahlderkinder,". + " ersatzkennzeichen, bemerkung, creationdate,creationuser, aktstatus, bismelden, titel, postnomentitel,". + " uid, gebnation) VALUES( $this->person_id,". + " '$this->familienname', now(), '$this->vorname', '$this->anrede', '$this->vornamen',". + ($this->geschlecht!=''?"'$this->geschlecht'":"'M'").", ". + ($this->gebdat!=''?"'$this->gebdat'":'null').", '$this->gebort', '$this->staatsbuergerschaft',". + ($this->familienstand!=''?"'$this->familienstand'":'null').",". + " '$this->svnr', ". + ($this->anzahlderkinder!=''?"'$this->anzahlderkinder'":'null').",". + " '$this->ersatzkennzeichen', '$this->bemerkung', now(),". + " '$this->updatevon', '".($this->aktstatus>0?$this->aktstatus:100)."', '".($this->bismelden?'J':'N')."', '$this->titelpre', '$this->titelpost',". + (strlen($this->uid)>0?" '$this->uid'":'null').",". + " '$this->gebnation');"; + + } + else + { + //peson_id auf gueltigkeit pruefen + if(!is_numeric($this->person_id)) + { + $this->errormsg = 'person_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "UPDATE person SET ". + " familienname='$this->familienname',". + " vorname='$this->vorname',". + " anrede='$this->anrede',". + " vornamen='$this->vornamen',". + " geschlecht=".($this->geschlecht!=''?"'$this->geschlecht'":"'M'").",". + " gebdat=".($this->gebdat!=''?"'$this->gebdat'":'null').",". + " gebort='$this->gebort',". + " staatsbuergerschaft='$this->staatsbuergerschaft',". + " familienstand=".($this->familienstand!=''?"'$this->familienstand'":'0').",". + " svnr=".($this->svnr!=''?"'$this->svnr'":'null').",". + " anzahlderkinder=".($this->anzahlderkinder!=''?"'$this->anzahlderkinder'":'0').",". + " ersatzkennzeichen='$this->ersatzkennzeichen',". + " bemerkung='$this->bemerkung',". + " aktstatus='$this->aktstatus',". + " bismelden='".($this->bismelden?'J':'N')."',". + " titel='$this->titelpre',". + " postnomentitel='$this->titelpost',". + " uid='$this->uid',". + " gebnation='$this->gebnation'". + " WHERE person_pk='$this->person_id'"; + } + + if(pg_query($this->conn,$qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = "Fehler beim Speichern des Person-Datensatzes:".$qry; + return false; + } + } + + /** + * Loescht einen Datensatz + * @param $person_id ID des zu loeschenden Datensatzes + * @return true wenn OK false im Fehlerfall + */ + function delete($person_id) + { + //person_id auf Gueltigkeit pruefen + if(!is_numeric($person_id) || $person_id=='') + { + $this->errormsg = 'Person_id muss eine Zahl sein'; + return false; + } + + $qry = "Delete from person where person_pk=$person_id"; + + if(!pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler beim Loeschen'; + return false; + } + else + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + + } + + /** + * Holt alle Personen aus der Datenbank + * @return true wenn OK, false im Fehlerfall + */ + function getAll() + { + /** Braucht zuviel Speicher + + $qry = "SELECT * FROM person"; + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler beim auslesen der Datensaetze'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $pers=new person($this->conn); + + $pers->person_id = $row->person_pk; + $pers->aktstatus = $row->aktstatus; + $pers->angelegtam = $row->angelegtam; + $pers->anrede = $row->anrede; + $pers->anzahlderkinder = $row->anzahlderkinder; + $pers->bemerkung = $row->bemerkung; + $pers->bismelden = ($row->bismelden=='J'?true:false); + $pers->ersatzkennzeichen = $row->ersatzkennzeichen; + $pers->familienname = $row->familienname; + $pers->familienstand = $row->familienstand; + $pers->gebdat = $row->gebdat; + $pers->gebnation = $row->gebnation; + $pers->gebort = $row->gebort; + $pers->geschlecht = $row->geschlecht; + $pers->staatsbuergerschaft = $row->staatsbuergerschaft; + $pers->svnr = $row->svnr; + $pers->titelpre = $row->titel; + $pers->titelpost = $row->postnomentitel; + $pers->uid = $row->uid; + $pers->vorname = $row->vorname; + $pers->vornamen = $row->vornamen; + $pers->updateamum = $row->creationdate; + $pers->updatevon = $row->creationuser; + + $this->result[] = $pers; + } + return true; + */ + return false; + } + + /** + * Prueft ob die UID schon vergeben ist. Wenn ein zweiter + * Parameter angegeben wird, wird diese ID von der ueberpruefung + * ausgeschlossen ( fuer Update eines Datensatzes ) + */ + function uid_exists($uid, $person_id='') + { + if($uid!='') + { + $this->errormsg = ''; + //Datenbank Check + $qry = "SELECT count(*) as anz from person where uid='$uid'"; + if($person_id!='') + $qry .= " AND person_pk<>".$person_id; + + if($result = pg_query($this->conn,$qry)) + { + while ($row=pg_fetch_object($result)) + { + if($row->anz == 0) + { + //Wurde deaktiviert weil der Zugriff vom auf den LDAP Server + //vom der Calva aus nicht funktioniert + //Ldap Check + //$ds = ldap_connect(LDAP_SERVER); + //$dn = "ou=People, dc=technikum-wien, dc=at"; + //$sr = ldap_search($ds,$dn,"uid=$uid"); + + //if(ldap_count_entries($ds,$sr)>0) + // return true; + //else + return false; + } + else + return true; + } + } + else + { + $this->errormsg = 'Fehler beim checken der uid'; + return false; + } + } + return false; + } + + /** + * Aktualisiert den AktStatus + */ + function updateaktstatus($person_id) + { + $mitarbeiter_id = ''; + $qry = "Select mitarbeiter_pk from mitarbeiter where person_fk='$person_id'"; + if($result = pg_query($this->conn, $qry)) + { + if($row = pg_fetch_object($result)) + $mitarbeiter_id = $row->mitarbeiter_pk; + else + { + $this->errormsg = 'Fehler beim ermitteln der Mitarbeiter_id'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim ermitteln der mitarbeiter_id'; + return false; + } + + //Funktionen holen + $qry = "Select funktion from funktion where ". + "studiensemester_fk = (Select studiensemester_pk from studiensemester where aktuell='J')". + " AND mitarbeiter_fk = '$mitarbeiter_id'"; + if($result = pg_query($this->conn, $qry)) + { + $fkt=array(); + $i=0; + while($row=pg_fetch_object($result)) + { + $fkt[$i]=$row->funktion; + $i++; + } + + //Aktstatus ermitteln + if(in_array(5,$fkt)) //STGL + $aktstatus = 104; + elseif(in_array(6,$fkt)) //FBL + $aktstatus = 103; + elseif(in_array(2,$fkt)) //FBK + $aktstatus = 102; + elseif(in_array(1,$fkt)) //LKT + $aktstatus = 101; + else + $aktstatus = 100; //Mitarbeiter + + $this->status = $aktstatus; + //neuen akstatus setzen + $qry = "Update person set aktstatus = $aktstatus where person_pk = $person_id"; + if(pg_query($qry)) + { + //Log schreiben + $sql .= $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim setzen des Aktstatus'; + return false; + } + } + } + + function setaktstatus($status, $person_id) + { + $qry = "Update person set aktstatus = '$status' where person_pk='$person_id'"; + if(!pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim Setzen des aktuellen Status'.$qry; + return false; + } + return true; + } +} +?> \ No newline at end of file diff --git a/include/fas/raumtyp.class.php b/include/fas/raumtyp.class.php new file mode 100644 index 000000000..f162e27a7 --- /dev/null +++ b/include/fas/raumtyp.class.php @@ -0,0 +1,126 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($raum_id != null) + $this->load($raum_id); + } + + /** + * Laedt einen Datensatz + * @param $raum_id ID des zu ladenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function load($raum_id) + { + if(!is_numeric($raum_id) || $raum_id == '') + { + $this->errormsg = 'raum_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM raumtyp WHERE raumtyp_pk = '$raum_id';"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden des Datenstatzes'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->raumtyp_id = $row->raumtyp_pk; + $this->bezeichnung = $row->bezeichnung; + $this->kurzbezeichnung = $row->kurzbezeichnung; + $this->plaetze = $row->plaetze; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; + return false; + } + return true; + } + + /** + * Laedt alle Datensaetze + * @return ture wenn ok, false im Fehlerfall + */ + function getAll() + { + $qry = "SELECT * FROM raumtyp;"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden der Datensaetze'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $raum_obj = new raumtyp($this->conn); + + $raum_obj->raumtyp_id = $row->raumtyp_pk; + $raum_obj->bezeichnung = $row->bezeichnung; + $raum_obj->kurzbezeichnung = $row->kurzbezeichnung; + $raum_obj->plaetze = $row->plaetze; + $raum_obj->updateamum = $row->creationdate; + $raum_obj->updatevon = $row->creationuser; + + $this->result[] = $raum_obj; + } + return true; + } + + /** + * Speichert den aktuellen Datensatz + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + $this->errormsg = 'Noch nicht Implementiert'; + return false; + } + + /** + * Loescht einen Datensatz + * @return true wenn ok, false im Fehlerfall + */ + function delete($raum_id) + { + $this->errormsg = 'Noch nicht Implementiert'; + return false; + } +} +?> \ No newline at end of file diff --git a/include/fas/studiengang.class.php b/include/fas/studiengang.class.php new file mode 100644 index 000000000..7f9958f3a --- /dev/null +++ b/include/fas/studiengang.class.php @@ -0,0 +1,228 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($studiengang_id != null) + $this->load($studiengang_id); + } + + /** + * Laedt einen Studiengang + * @param stg_id ID des Studienganges der zu laden ist + * @return true wenn ok, false im Fehlerfall + */ + function load($stg_id) + { + //Pruefen ob stg_id eine gueltige Zahl ist + if(!is_numeric($stg_id) || $stg_id == '') + { + $this->errormsg = 'stg_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM studiengang WHERE studiengang_pk = '$stg_id'"; + + if(!$res=pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->studiengang_id = $row->studiengang_pk; + $this->name = $row->name; + $this->erhalter_id = $row->erhalter_fk; + $this->kuerzel = $row->kuerzel; + $this->studiengangsart = $row->studiengangsart; + $this->organisationsform = $row->organisationsform; + $this->kennzahl = $row->kennzahl; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + $this->standort = $row->standort; + $this->regelstudiendauer = $row->regelstudiendauer; + $this->emailkuerzel = $row->emailkuerzel; + $this->beschreibung = $row->beschreibung; + $this->telefonnummer = $row->telefonnummer; + $this->bescheid = $row->bescheid; + $this->bescheidvom = $row->bescheidvom; + $this->bescheidgz = $row->bescheidgz; + $this->bescheidbgbl1 = $row->bescheidbgbl1; + $this->bescheidbgbl2 = $row->bescheidbgbl2; + $this->kennzahl_neu = $row->kennzahl_neu; + $this->nummerintern = $row->nummerintern; + $this->bafirmaaufzeugnis = ($row->bafirmaaufzeugnis=='t'?true:false); + $this->batitelaufzeugnis = ($row->batitelaufzeugnis=='t'?true:false); + } + else + { + $this->errormsg = 'Kein Datensatz mit dieser Nummer vorhanden'; + return false; + } + return true; + } + + /** + * Laedt Studiengang und Studiensemester + * @param stg_id Studiengangs_id + * stsem_id Studiensemester_id + */ + function load_stsem($stg_id, $stsem_id) + { + //Studiengang laden + if(!$this->load($stg_id)) + return false; + + //pruefen ob stsem_id eine gueltige Zahl ist + if(!is_numeric($stsem_id) || $stsem_id == '') + { + $this->errormsg = 'studiensemester_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * FROM studiengang_studiensemester WHERE studiengang_fk='$this->studiengang_id' ". + "AND studiensemester_fk='$stsem_id';"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->studiensemester_id = $row->studiensemester_fk; + $this->startdatum = $row->startdatum; + $this->endedatum = $row->endedatum; + $this->regelwochenstunden = $row->regelwochen; + $this->betreuerstunden = $row->rvar1; + } + else + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + return true; + } + + /** + * Liefert alle Studiengaenge + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + $qry = "SELECT * FROM studiengang order by name;"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Datensatz konnte nicht geladen werden'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $stg_obj = new studiengang($this->conn); + + $stg_obj->studiengang_id = $row->studiengang_pk; + $stg_obj->name = $row->name; + $stg_obj->erhalter_id = $row->erhalter_fk; + $stg_obj->kuerzel = $row->kuerzel; + $stg_obj->studiengangsart = $row->studiengangsart; + $stg_obj->organisationsform = $row->organisationsform; + $stg_obj->kennzahl = $row->kennzahl; + $stg_obj->updateamum = $row->creationdate; + $stg_obj->updatevon = $row->creationuser; + $stg_obj->standort = $row->standort; + $stg_obj->regelstudiendauer = $row->regelstudiendauer; + $stg_obj->emailkuerzel = $row->emailkuerzel; + $stg_obj->beschreibung = $row->beschreibung; + $stg_obj->telefonnummer = $row->telefonnummer; + $stg_obj->bescheid = $row->bescheid; + $stg_obj->bescheidvom = $row->bescheidvom; + $stg_obj->bescheidgz = $row->bescheidgz; + $stg_obj->bescheidbgbl1 = $row->bescheidbgbl1; + $stg_obj->bescheidbgbl2 = $row->bescheidbgbl2; + $stg_obj->kennzahl_neu = $row->kennzahl_neu; + $stg_obj->nummerintern = $row->nummerintern; + $stg_obj->bafirmaaufzeugnis = ($row->bafirmaaufzeugnis=='t'?true:false); + $stg_obj->batitelaufzeugnis = ($row->batitelaufzeugnis=='t'?true:false); + + $this->result[] = $stg_obj; + } + + return true; + } + + /** + * Loescht einen Studiengang + * @param $stg_id ID des zu loeschenden Studienganges + * @return true wenn ok, false im Fehlerfall + */ + function delete($stg_id) + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } + + /** + * Speichert den aktuellen Datensatz + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } +} +?> \ No newline at end of file diff --git a/include/fas/studiensemester.class.php b/include/fas/studiensemester.class.php new file mode 100644 index 000000000..f22a474c0 --- /dev/null +++ b/include/fas/studiensemester.class.php @@ -0,0 +1,163 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($stsem_id != null) + $this->load($stsem_id); + } + + /** + * Laedt den Datensatz mit der ID die uebergeben wird + * @param stsem_id ID des zu ladenden Datensatzes + * @return true wenn ok, false im fehlerfall; + */ + function load($stsem_id) + { + //Pruefen ob stsem_id eine gueltige Zahl ist + if(!is_numeric($stsem_id) || $stsem_id == '') + { + $this->errormsg = 'stsem_id muss eine gueltige Zahl sein'; + return false; + } + + //Laden eines Datensatzes + $qry = "SELECT * FROM studiensemester WHERE studiensemester_pk = '$stsem_id';"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->studiensemester_id = $row->studiensemester_pk; + $this->aktuell = ($row->aktuell=='J'?true:false); + $this->art = $row->art; + $this->jahr = $row->jahr; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + return true; + } + + + /** + * Laedt das aktuelle Studiensemester + * @return true wenn ok, false im Fehlerfall + */ + function load_akt() + { + $qry = "SELECT * FROM studiensemester WHERE aktuell='J'"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->studiensemester_id = $row->studiensemester_pk; + $this->aktuell = ($row->aktuell=='J'?true:false); + $this->art = $row->art; + $this->jahr = $row->jahr; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + return true; + } + + /** + * Laedt alle studiensemester + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + $qry = "SELECT * FROM studiensemester order by jahr, art desc;"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden des Datensatzes'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $stsem_obj = new studiensemester($this->conn); + + $stsem_obj->studiensemester_id = $row->studiensemester_pk; + $stsem_obj->aktuell = ($row->aktuell=='J'?true:false); + $stsem_obj->art = $row->art; + $stsem_obj->jahr = $row->jahr; + $stsem_obj->updateamum = $row->creationdate; + $stsem_obj->updatevon = $row->creationuser; + + $this->result[] = $stsem_obj; + } + return true; + } + + /** + * Loescht einen Datensatz + * @param $stsem_id ID des zu loeschenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function delete($stsem_id) + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } + + /** + * Speichert den aktuellen Datensatz + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + $this->errormsg = 'Noch nicht implementiert'; + return false; + } +} +?> \ No newline at end of file diff --git a/include/fas/telefonnummer.class.php b/include/fas/telefonnummer.class.php new file mode 100644 index 000000000..93528e06d --- /dev/null +++ b/include/fas/telefonnummer.class.php @@ -0,0 +1,296 @@ +conn = $conn; + $qry = "SET CLIENT_ENCODING TO 'UNICODE';"; + if(!pg_query($conn,$qry)) + { + $this->errormsg = "Encoding konnte nicht gesetzt werden"; + return false; + } + if($telefonnummer_id != null) + $this->load($telefonnummer_id); + } + + /** + * Laedt den Datensatz mit der ID die uebergeben wurde + * @param $telefonnummer_id ID des zu ladenden Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function load($telefonnummer_id) + { + //Gueltigkeit von telefonnummer_id pruefen + if(!is_numeric($telefonnummer_id) || $telefonnummer_id == '') + { + $this->errormsg = 'telefonnummer_id muss eine Zahl sein'; + return false; + } + + $qry = "SELECT * FROM telefonnummer WHERE telefonnummer_pk=$telefonnummer_id"; + + if(!$res = pg_query($this->conn,$qry)) + { + $this->errormsg = 'Fehler beim Laden des Datensatzes'; + return false; + } + + if($row = pg_fetch_object($res)) + { + $this->telefonnummer_id = $row->telefonnummer_pk; + $this->name = $row->name; + $this->nummer = $row->nummer; + $this->person_id = $row->person_fk; + $this->typ = $row->typ; + $this->updateamum = $row->creationdate; + $this->updatevon = $row->creationuser; + } + else + { + $this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden'; + return false; + } + + return true; + } + + /** + * Laedt alle Telefonnummern einer Person + * @param $person_id Person zu der die Telefonnummern gesucht werden sollen + * @return true wenn ok, false im Fehlerfall + */ + function load_pers($person_id) + { + //Gueltigkeit von person_id pruefen + if(!is_numeric($person_id) || $person_id == '') + { + $this->errormsg = 'person_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "SELECT * from telefonnummer where person_fk=$person_id"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Der Datensatz konnte nicht geladen werden'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $tel_obj = new telefonnummer($this->conn); + + $tel_obj->telefonnummer_id = $row->telefonnummer_pk; + $tel_obj->name = $row->name; + $tel_obj->nummer = $row->nummer; + $tel_obj->person_id = $row->person_fk; + $tel_obj->typ = $row->typ; + $tel_obj->updateamum = $row->creationdate; + $tel_obj->updatevon = $row->creationuser; + + $this->result[] = $tel_obj; + } + return true; + } + + /** + * Liefert alle Telefonnummern + * @return true wenn ok, false im Fehlerfall + */ + function getAll() + { + /* Benoetigt zu viel Speicher + + $qry = "SELECT * FROM telefonnummer;"; + + if(!$res = pg_query($this->conn, $qry)) + { + $this->errormsg = 'Fehler beim laden der Telefonnummern'; + return false; + } + + while($row = pg_fetch_object($res)) + { + $tel_obj = new telefonnummer($this->conn); + + $tel_obj->telefonnummer_id = $row->telefonnummer_pk; + $tel_obj->name = $row->name; + $tel_obj->nummer = $row->nummer; + $tel_obj->person_id = $row->person_fk; + $tel_obj->typ = $row->typ; + $tel_obj->updateamum = $row->creationdate; + $tel_obj->updatevon = $row->creationuser; + + $this->result[] = $tel_obj; + } + + return true; + */ + return false; + } + + /** + * Prueft die gueltigkeit der Variablen + * @return true wenn ok, false im Fehlerfall + */ + function checkvars() + { + //Hochkomma und HTML Tags ersetzen + //$this->name = htmlentities($this->name, ENT_QUOTES); + //$this->nummer = htmlentities($this->nummer, ENT_QUOTES); + + //Laenge pruefen + $this->errormsg = 'Eine der Gesamtlaengen wurde ueberschritten'; + if(strlen($this->name)>255) return false; + if(strlen($this->nummer)>30) return false; + + //Zahlenfelder pruefen + $this->errormsg = 'Ein Zahlenfeld enthaelt ungueltige Zeichen'; + if(!is_numeric($this->person_id)) return false; + if(!is_numeric($this->typ)) return false; + + $this->errormsg = ''; + return true; + } + + /** + * Speichert den aktuellen Datensatz + * Wenn $neu auf true gesetzt ist wird ein neuer Datensatz angelegt + * andernfalls wird der Datensatz mit der ID in $telefonnummer_id aktualisiert + * @return true wenn ok, false im Fehlerfall + */ + function save() + { + //Variablen pruefen + if(!$this->checkvars()) + return false; + + if($this->new) + { + //Neuen Datensatz anlegen + + //neue ID aus der Sequence holen + $qry = "SELECT nextval('telefonnummer_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim auslesen der Sequence'; + return false; + } + + $this->telefonnummer_id = $row->id; + + $qry = "INSERT INTO telefonnummer (telefonnummer_pk, person_fk, name, nummer, typ, creationdate, creationuser)". + " VALUES('$this->telefonnummer_id', '$this->person_id', '$this->name', '$this->nummer', '$this->typ', now(), '$this->updatevon');"; + } + else + { + //Bestehenden Datensatz aktualisieren + + //Pruefen der ID + if(!is_numeric($this->telefonnummer_id) || $this->telefonnummer_id == '') + { + $this->errormsg = 'telefonnummer_id muss eine gueltige Zahl sein'; + return false; + } + + $qry = "UPDATE telefonnummer SET person_fk='$this->person_id', name='$this->name', typ='$this->typ', nummer='$this->nummer'". + " WHERE telefonnummer_pk='$this->telefonnummer_id'"; + } + + if(pg_query($this->conn, $qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim Speichern der Daten'; + return false; + } + } + + /** + * Loescht den Datensatz mit der uebergebenen ID + * @param telefonnummer_id ID des zu leoschenen Datensatzes + * @return true wenn ok, false im Fehlerfall + */ + function delete($telefonnummer_id) + { + //Pruefen der ID + if(!is_numeric($telefonnummer_id) || $telefonnummer_id == '') + { + $this->errormsg = 'telefonnummer_id muss eine gueltige Zahl sein'; + return false; + } + + //loeschen des Datensatzes + $qry = "DELETE FROM telefonnummer where telefonnummer_pk='$telefonnummer_id'"; + + if(pg_query($this->conn, $qry)) + { + //Log schreiben + $sql = $qry; + $qry = "SELECT nextval('log_seq') as id;"; + if(!$row = pg_fetch_object(pg_query($this->conn, $qry))) + { + $this->errormsg = 'Fehler beim Auslesen der Log-Sequence'; + return false; + } + + $qry = "INSERT INTO log(log_pk, creationdate, creationuser, sql) VALUES('$row->id', now(), '$this->updatevon', '".addslashes($sql)."')"; + if(pg_query($this->conn, $qry)) + return true; + else + { + $this->errormsg = 'Fehler beim Speichern des Log-Eintrages'; + return false; + } + } + else + { + $this->errormsg = 'Fehler beim loeschen eines Datensatzes'; + return false; + } + } +} +?> \ No newline at end of file diff --git a/include/ferien.class.php b/include/ferien.class.php new file mode 100644 index 000000000..f22e6844b --- /dev/null +++ b/include/ferien.class.php @@ -0,0 +1,88 @@ +conn=$conn; + } + + + /** + * Alle Fachbereiche zurueckgeben + * @return array mit Fachbereichen oder false=fehler + */ + function getAll($stg_kz) + { + $sql_query="SELECT * FROM tbl_ferien WHERE studiengang_kz=0 OR studiengang_kz=$stg_kz ORDER BY vondatum"; + if (!$result=@pg_query($this->conn, $sql_query)) + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + //$num_rows=pg_numrows($result); + //for ($i=0; $i<$num_rows; $i++) + while ($row=@pg_fetch_object($result)) + { + // Record holen + // Instanz erzeugen + $f = new ferien($this->conn); + $f->bezeichnung=$row->bezeichnung; + $f->studiengang_kz = $row->studiengang_kz; + $f->vondatum=$row->vondatum; + $f->bisdatum=$row->bisdatum; + $f->vontimestamp=mktime(0,0,0,substr($row->vondatum,5,2),substr($row->vondatum,8),substr($row->vondatum,0,4));; + $f->bistimestamp=mktime(23,59,59,substr($row->bisdatum,5,2),substr($row->bisdatum,8),substr($row->bisdatum,0,4));; + // in array speichern + $this->ferien[]=$f; + } + return true; + } + + function isferien($timestamp) + { + foreach ($this->ferien AS $f) + if ($timestamp>=$f->vontimestamp && $timestamp<=$f->bistimestamp) + return true; + return false; + } +} +?> \ No newline at end of file diff --git a/include/functions.inc.php b/include/functions.inc.php new file mode 100644 index 000000000..8ee93e955 --- /dev/null +++ b/include/functions.inc.php @@ -0,0 +1,155 @@ +0) + { + $row=pg_fetch_object($result); + return $row->uid; + } + else + return 0; +} + +function check_student($uid, $conn) +{ + // uid von Tabelle 'Student' holen + $sql_query="SELECT uid FROM tbl_student WHERE uid='$uid'"; + //echo $sql_query; + $result=pg_query($conn, $sql_query) or die(pg_last_error($conn)); + $num_rows=pg_numrows($result); + // Wenn kein ergebnis return 0 sonst ID + if ($num_rows>0) + return pg_result($result,0,'uid'); + else + return 0; +} + +function kalenderwoche($datum) +{ + //$woche=date("W",mktime($date[hours],$date[minutes],$date[seconds],$date[mon],$date[mday],$date[year])); + if (!date("w",$datum)) + $datum+=86400; + //echo date("l j.m.Y - W",$datum); + $woche=date("W",$datum); + //if ($woche==53) + // $woche=1; + return $woche; +} + +/****************************************************************************** + * Springt zum vorhergehenden Montag, wenn $datum kein Sonntag oder Montag ist. + * + */ +function montag($datum) +{ + // Wochentag + $wt=date("w",$datum); + // Sonntag? + if (!$wt) + $wt++; + if($wt!=1) + $datum-=86400*($wt-1); + + return $datum; +} + +function jump_day($datum, $tage) +{ + // Ein Tag sind 86400 Sekunden + $datum+=86400*$tage; + return $datum; +} + +function jump_week($datum, $wochen) +{ + $stunde_vor=date("G",$datum); + // Eine Woche sind 604800 Sekunden + $datum+=604800*$wochen; + $stunde_nach=date("G",$datum); + if ($stunde_nach!=$stunde_vor) + $datum+=3600; + return $datum; +} + +function jahreskalenderjump($link) +{ + $datum=mktime(); + $woche=kalenderwoche($datum); + $datum=montag($datum); + echo '
    Jump to KW
    '; + for ($anz=1;$anz<26;$anz++) + { + $linknew=$link.'&datum='.$datum; + if ($woche==54) + $woche=1; + echo ' '.$woche.' '; + if ($anz%5==0) + echo '
    '; + $datum+=60*60*24*7; + $woche++; + } + echo '
    '; +} + +function loadVariables($conn, $user) +{ + $error_msg=''; + if(!($result=@pg_query($conn, "SELECT * FROM tbl_variable WHERE uid='$user'"))) + $error_msg.=pg_errormessage($conn).'
    '.$sql_query; + else + $num_rows=@pg_numrows($result); + + for ($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($result,$i); + global ${$row->name}; + ${$row->name}=$row->wert; + } + if (!isset($semester_aktuell)) + if(!($result=@pg_query($conn, 'SELECT * FROM tbl_studiensemester WHERE ende>now() ORDER BY start LIMIT 1'))) + $error_msg.=pg_errormessage($conn).'
    '.$sql_query; + else + { + $num_rows=@pg_numrows($result); + if ($num_rows>0) + { + $row=pg_fetch_object($result,$i); + global $semester_aktuell; + $semester_aktuell=$row->studiensemester_kurzbz; + } + } + if (!isset($db_stpl_table)) + $db_stpl_table='stundenplan'; + + return $error_msg; +} + +function writeCISlog($stat, $rm = '') +{ + if($stat=='STOP') + $stat = 'STOP '; + $handle = fopen(CIS_LOG_PATH,'a'); + fwrite($handle, date('Y-m-d H:i:s').' '. $stat .' '. getmypid() .' '. $_SERVER['REMOTE_USER'] .' '. $_SERVER['REQUEST_URI'] .' '.$rm.' +'); +} + +?> diff --git a/include/funktion.class.php b/include/funktion.class.php new file mode 100644 index 000000000..08dd03f75 --- /dev/null +++ b/include/funktion.class.php @@ -0,0 +1,279 @@ +conn = $conn; + } + + + /** + * Ladet die Attribute der Funktion aus der Datenbank. Bei Fehler ist der + * Rueckgabewert 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true=ok, false=fehler + */ + function load($kurzbz) + { + $this->kurzbz=$kurzbz; + $qry="select * from tbl_funktion where funktion_kurzbz='$kurzbz'"; + if (is_null($this->conn)) { + return false; + } + if(!($erg=@pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + if($num_rows!=1) { + $this->errormsg="Zuwenige oder zuviele Ergebnisse (Anzahl: $num_rows)!"; + return false; + } + $row=pg_fetch_object($erg,0); + $this->bezeichnung=$row->bezeichnung; + $this->aktiv=$row->aktiv=='t'?true:false; + $this->new=false; + return true; + } + + /** + * Speichert die Funktion in die Datenbank. Bei Fehler ist der Rueckgabewert + * 'false' und die Fehlermeldung steht in 'errormsg'. INSERT oder DELETE wird + * durch 'new' bestimmt. + * @return boolean true=ok, false=fehler + */ + function save() + { + if (is_null($this->conn)) { + return false; + } + if (strlen($this->kurzbz)==0) + { + $this->errormsg="kurzbz nicht gesetzt"; + return false; + } + if ($this->new) + { + $qry="insert into tbl_funktion(funktion_kurzbz,bezeichnung,aktiv) ". + "values('".$this->kurzbz."','".$this->bezeichnung."',".($this->aktiv?'t':'f').")"; + } else + { + $qry="update tbl_funktion set bezeichnung='".$this->bezeichnung."',". + "aktiv=".($this->aktiv?'t':'f')." where funktion_kurzbzb='$this->kurzbz'"; + } + if(!($erg=@pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + return true; + } + + /** + * Loescht die Funktion aus der Datenbank. Bei Fehler ist der Rueckgabewert + * 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true=ok, false=fehler + */ + function delete() + { + if (is_null($this->conn)) { + return false; + } + if (strlen($this->kurzbz)==0) + { + $this->errormsg="kurzbz nicht gesetzt"; + return false; + } + $qry="delete from tbl_funktion where funktion_kurzbz='".$this->kurzbz."'"; + if(!($erg=@pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + return true; + } + + /** + * alle Personen mit dieser Funktion holen + * @param string $kurzbz Kurzbezeichnung der Funktion (wenn nicht angegeben + * wird lokale $kurzbz verwendet) + * @return array key=personfunktion_id, value=array('person','studiengang_kz'', + * 'studiengang_kurzbz','fachbereich_id', 'fachbereich_kurzbz') oder false, wenn Fehler + */ + function getPersonen($kurzbz='') + { + // Array für Suchergebnis + $result=array(); + + if (strlen($kurzbz)==0) + { + $search_kurzbz=$this->kurzbz; + } else + { + $search_kurzbz=$kurzbz; + } + $qry="select tbl_personfunktion.*,tbl_studiengang.kurzbz as studiengang_kurzbz,tbl_fachbereich.kurzbz as fachbereich_kurzbz from tbl_personfunktion join tbl_person using(uid) ". + "left join tbl_studiengang using(studiengang_kz) ". + "left join tbl_fachbereich using(fachbereich_id) ". + "where funktion_kurzbz='$search_kurzbz' ". + "order by upper(tbl_person.nachname)"; + if (is_null($this->conn)) { + return false; + } + //echo "'".$qry."'"; + if(!($erg=@pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + for ($i=0;$i<$num_rows;$i++) + { + // Person laden (nicht für große Anzahl von Personen geeignet) + $temp_person=new person($this->conn); + $temp_person->load(pg_result($erg,$i,'uid')); + // und in Array speichern + $result[pg_result($erg,$i,'personfunktion_id')]=array( + 'person'=>$temp_person, + 'studiengang_kz'=>@pg_result($erg,$i,'studiengang_kz'), + 'studiengang_kurzbz'=>@pg_result($erg,$i,'studiengang_kurzbz'), + 'fachbereich_kurzbz'=>@pg_result($erg,$i,'fachbereich_kurzbz'), + 'fachbereich_id'=>@pg_result($erg,$i,'fachbereich_id') + ); + } + return $result; + } + + /** + * Person Funktion dazugeben + * @param string $uid User-ID + * @param string $studiengang_kz Studiengang-Kennzahl (optional) + * @param integer $fachbereich_id optional + * @return boolean true=ok, false=fehler + */ + function addPerson($uid,$studiengang_kz=null,$fachbereich_id=null) + { + if (is_null($this->conn)) { + return false; + } + $targetlist="uid,funktion_kurzbz"; + if (strlen($studiengang_kz)>0) $targetlist.=",studiengang_kz"; + if (strlen($fachbereich_id)>0) $targetlist.=",fachbereich_id"; + $values="'$uid','".$this->kurzbz."'"; + if (strlen($studiengang_kz)>0) $values.=",$studiengang_kz"; + if (strlen($fachbereich_id)>0) $values.=",$fachbereich_id"; + $qry="insert into tbl_personfunktion($targetlist) ". + "values($values)"; + //echo $qry; + if(!($erg=@pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + return true; + } + + /** + * Person Funktion wegnehmen + * @param string $uid User-ID + * @param string $studiengang_kz Studiengang-Kennzahl (optional) + * @param integer $fachbereich_id optional + * @return boolean true=ok, false=fehler + */ + function removePerson($personfunktion_id) + { + if (is_null($this->conn)) { + return false; + } + if (strlen($personfunktion_id)==0) { + $this->errormsg="personfunktion_id darf nicht NULL sein"; + return false; + } + $qry="delete from tbl_personfunktion where personfunktion_id=$personfunktion_id"; + if(!($erg=@pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + return true; + } + + /** + * Personfunktion aktualisieren + * @param integer $personfunktion ID aus der Zuordnungstabelle + * @param string $uid User-ID + * @param string $studiengang_kz Studiengang-Kennzahl (optional) + * @param integer $fachbereich_id optional + * @return boolean true=ok, false=fehler + */ + function updatePerson($personfunktion_id,$uid,$studiengang_kz=null, + $fachbereich_id=null) { + if (is_null($this->conn)) { + return false; + } + if (strlen($studiengang_kz)>0) + { + $values.=",studiengang_kz=$studiengang_kz "; + } else + { + $values.=",studiengang_kz=NULL "; + } + if (strlen($fachbereich_id)>0) + { + $values.=",fachbereich_id=$fachbereich_id"; + } else + { + if (strlen($studiengang_kz)==0) { + $this->errormsg="Studiengang oder Fachbereich fehlt."; + return false; + } + $values.=",fachbereich_id=NULL"; + } + $qry="update tbl_personfunktion set ". + "uid='$uid'$values ". + "where personfunktion_id=$personfunktion_id"; + //echo $qry; + if(!($erg=@pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + return true; + } +} +?> \ No newline at end of file diff --git a/include/globals.inc.php b/include/globals.inc.php new file mode 100644 index 000000000..1d8b54a85 --- /dev/null +++ b/include/globals.inc.php @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/include/lehrfach.class.php b/include/lehrfach.class.php new file mode 100644 index 000000000..86ca6065e --- /dev/null +++ b/include/lehrfach.class.php @@ -0,0 +1,206 @@ +conn=$conn; + } + + /** + * Ladet einen Datensatz mit der id $id + * @param $id lehrfach_nr + * @return true wenn erfolgreich sonst false + */ + function load($id) + { + $sql_query = "Select * from tbl_lehrfach where lehrfach_nr=$id"; + if($result=pg_exec($sql_query)) + { + if($row=pg_fetch_object($result)) + { + $this->lehrfach_nr = $id; + $this->studiengang_kz = $row->studiengang_kz; + $this->fachbereich_id = $row->fachbereich_id; + $this->kurzbz = $row->kurzbz; + $this->bezeichnung = $row->bezeichnung; + $this->lehrevz = $row->lehrevz; + $this->farbe = $row->farbe; + //$this->lehrform = $row->lehrform; + $this->aktiv = $row->aktiv; + $this->ects = $row->ects; + $this->semester = $row->semester; + $this->sprache = $row->sprache; + return true; + } + } + return false; + } + + /** + * Liefert die Tabellenelemente die den Kriterien der Parameter entsprechen + * @param $stg Studiengangs_kz + * $sem Semester + * $order Sortierkriterium + * $fachb fachbereichs_id + * @return array mit Fachbereichen oder false=fehler + */ + function getTab($stg='-1',$sem='-1', $order='lehrfach_nr', $fachb='-1',$lehre='') + { + + $sql_query = "SELECT * FROM tbl_lehrfach"; + + if($stg!=-1 || $sem!=-1 || $fachb!=-1) + $sql_query .= " WHERE true"; + + if($stg!=-1) + { + $sql_query .= " AND studiengang_kz=$stg"; + } + + if($sem!=-1) + { + $sql_query .= " AND semester=$sem"; + } + + if($fachb!=-1) + { + $sql_query .= " AND fachbereich_id=$fachb"; + } + + if($lehre!='') + { + $sql_query .= " AND lehre=$lehre"; + } + + $sql_query .= " ORDER BY $order"; + + if($result=pg_exec($this->conn,$sql_query)) + { + while($row=pg_fetch_object($result)) + { + $l = new lehrfach($this->conn); + $l->lehrfach_nr = $row->lehrfach_nr; + $l->fachbereich_id = $row->fachbereich_id; + $l->kurzbz = $row->kurzbz; + $l->bezeichnung = $row->bezeichnung; + $l->lehrevz = $row->lehrevz; + $l->farbe = $row->farbe; + //$l->lehrform_kurzbz = $row->lehrform_kurzbz; + $l->aktiv = $row->aktiv; + $l->ects = $row->ects; + $l->studiengang_kz = $row->studiengang_kz; + $l->semester = $row->semester; + $this->fkterg[]=$l; + } + } + else + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + return true; + } + + /** + * Alle Fachbereiche zurückgeben + * @return array mit Fachbereichen oder false=fehler + */ + function getAll() + { + if (is_null($this->conn)) + { + return false; + } + $qry = "select * from tbl_lehrfach ". + "order by kurzbz"; + //echo $qry; + if (!($erg = pg_exec($this->conn, $qry))) + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + $result = array(); + $num_rows = pg_numrows($erg); + for ($i = 0; $i < $num_rows; $i ++) + { + // Record holen + $row = pg_fetch_object($erg, $i); + // Instanz erzeugen + $lf = new lehrfach($this->conn); + $lf->lehrfach_nr = $row->lehrfach_nr; + $lf->fachbereich_id = $row->fachbereich_id; + $lf->kurzbz = $row->kurzbz; + $lf->bezeichnung = $row->bezeichnung; + $lf->lehrelink = $row->lehrelink; + $lf->farbe = $row->farbe; + //$lf->lehrform_kurzbz = $row->lehrform_kurzbz; + $lf->aktiv = $row->aktiv; + $lf->ects = $row->ects; + $lf->studiengang_kz = $row->studiengang_kz; + // in array speichern + $result[] = $lf; + } + return $result; + } +} +?> \ No newline at end of file diff --git a/include/lehrform.class.php b/include/lehrform.class.php new file mode 100644 index 000000000..094822551 --- /dev/null +++ b/include/lehrform.class.php @@ -0,0 +1,62 @@ +conn = $conn; + } + + /** + * Alle Fachbereiche zurückgeben + * @return array mit Fachbereichen oder false=fehler + */ + function getAll() + { + if (is_null($this->conn)) + { + return false; + } + $qry = "select lehrform_kurzbz, bezeichnung from tbl_lehrform ". + "order by lehrform_kurzbz"; + //echo $qry; + if (!($erg = pg_exec($this->conn, $qry))) + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + $result = array(); + $num_rows = pg_numrows($erg); + for ($i = 0; $i < $num_rows; $i ++) + { + // Record holen + $row = pg_fetch_object($erg, $i); + // Instanz erzeugen + $lf = new lehrform($this->conn); + $lf->kurzbz = $row->lehrform_kurzbz; + $lf->bezeichnung = $row->bezeichnung; + // in array speichern + $result[] = $lf; + } + return $result; + } +} +?> \ No newline at end of file diff --git a/include/lehrstunde.class.php b/include/lehrstunde.class.php new file mode 100644 index 000000000..9e5a19376 --- /dev/null +++ b/include/lehrstunde.class.php @@ -0,0 +1,457 @@ +conn=$conn; + $this->new=TRUE; + } + + + /** + * Einen Datensatz laden + * + */ + function load($stundenplan_id,$stpl_table='stundenplandev') + { + /////////////////////////////////////////////////////////////////////// + // Parameter Checken + // Bezeichnung der Stundenplan-Tabelle und des Keys + $stpl_id=$stpl_table.TABLE_ID; + $stpl_view=VIEW_BEGIN.$stpl_table; + $stpl_table=TABLE_BEGIN.$stpl_table; + + $sql_query="SELECT * FROM $stpl_view WHERE $stpl_id=$stundenplan_id;"; + //echo $sql_query.'
    '; + + + //Datenbankabfrage + if (! $stpl_tbl=pg_query($this->conn, $sql_query)) + { + $this->errormsg=pg_last_error($this->conn); + //echo $this->errormsg; + return false; + } + $this->anzahl=pg_numrows($stpl_tbl); + //Daten uebernehmen + if ($this->anzahl!=1) + { + $this->errormsg='Keinen Datensatz gefunden'; + return false; + } + else + { + $row=pg_fetch_object ($stpl_tbl); + $this->stundenplan_id=$row->{$stpl_id}; + $this->unr=$row->unr; + $this->lektor_uid=$row->uid; + $this->lektor_kurzbz=$row->lektor; + $this->datum=$row->datum; + $this->stunde=$row->stunde; + $this->ort_kurzbz=$row->ort_kurzbz; + $this->lehrfach=$row->lehrfach; + $this->lehrfach_bez=$row->lehrfach_bez; + $this->lehrfach_nr=$row->lehrfach_nr; + $this->lehrform=$row->lehrform; + $this->studiengang_kz=$row->studiengang_kz; + $this->studiengang=$row->stg_kurzbz; + $this->sem=$row->semester; + $this->ver=$row->verband; + $this->grp=$row->gruppe; + $this->einheit_kurzbz=$row->einheit_kurzbz; + $this->titel=$row->titel; + $this->anmerkung=$row->anmerkung; + $this->updateamum=$row->updateamum; + $this->updatevon=$row->updatevon; + $this->new=false; + } + return true; + } + + /** + * Datensatz in DB speichern + * + */ + function save($uid, $stpl_table='stundenplandev') + { + // Parameter Checken + // Bezeichnung der Stundenplan-Tabelle und des Keys + $stpl_id=$stpl_table.TABLE_ID; + $stpl_table=TABLE_BEGIN.$stpl_table; + if ($this->new) + { + // insert + } + else + { + // update + $sql_query='UPDATE '.$stpl_table; + $sql_query.=" SET datum='$this->datum', stunde=$this->stunde"; + $sql_query.=", ort_kurzbz='$this->ort_kurzbz', uid='$this->lektor_uid'"; + $sql_query.=", updateamum=now(), updatevon='$uid'"; + $sql_query.=" WHERE $stpl_id=$this->stundenplan_id"; + //echo $sql_query."
    "; + + //Datenbankabfrage + if (! @pg_query($this->conn, $sql_query)) + { + $this->errormsg=$sql_query.pg_last_error($this->conn); + //echo $this->errormsg; + return false; + } + //$this->errormsg.=$sql_query; + } + + return true; + } + + /** + * Datensatz aus DB entfernen + * @param id ID des Datensatzes in der Tabelle + * @param stpl_table Name der Tabelle + * + */ + function delete($id, $stpl_table='stundenplandev') + { + // Parameter Checken + // Bezeichnung der Stundenplan-Tabelle und des Keys + $stpl_id=$stpl_table.TABLE_ID; + $stpl_table=TABLE_BEGIN.$stpl_table; + // Delete SQL vorbereiten + $sql_query='DELETE FROM '.$stpl_table; + $sql_query.=" WHERE $stpl_id=$id"; + //echo $sql_query."
    "; + + //Datenbankrequest + if (! pg_query($this->conn, $sql_query)) + { + $this->errormsg=$sql_query.pg_last_error($this->conn); + //echo $this->errormsg; + return false; + } + else + return true; + } + + /** + * @param type (student, lektor, lehrverband, einheit, ort, ....) + * @param datum_von (inklusive) Startdatum der Abfrage + * @param datum_bis (exklusive) Enddatum der Abfrage + * @param uid (des Lektors oder Studenten) kann auch NULL sein + * @param ort_kurzbz (Kurzbezeichnung des Orts) kann auch NULL sein + * @param studiengang_kz + * @param sem + * @param ver + * @param grp + * @param einheit_kurzbz + * + */ + function load_lehrstunden($type, $datum_von, $datum_bis, $uid, $ort_kurzbz=NULL, $studiengang_kz=NULL, $sem=NULL, $ver=NULL, $grp=NULL, $einheit_kurzbz=NULL, $stpl_view='stundenplan') + { + /////////////////////////////////////////////////////////////////////// + // Parameter Checken + // Bezeichnung der Stundenplan-Tabelle und des Keys + $stpl_id=$stpl_view.TABLE_ID; + $stpl_view=VIEW_BEGIN.$stpl_view; + // Datum im Format YYYY-MM-TT ? + if (!ereg("([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})",$datum_von) ) + { + $this->errormsg='Fehler: Startdatum hat falsches Format!'; + return -1; + } + if (!ereg("([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})",$datum_bis) ) + { + $this->errormsg='Fehler: Enddatum hat falsches Format!'; + return -1; + } + // Person + if (($type=='student' || $type=='lektor') && $uid==NULL) + { + $this->errormsg='Fehler: uid der Person ist nicht gesetzt'; + return -1; + } + // Ort + if ($type=='ort' && $ort_kurzbz==NULL) + { + $this->errormsg='Fehler: Kurzbezeichnung des Orts ist nicht gesetzt'; + return -1; + } + // Einheit + if ($type=='einheit' && $einheit_kurzbz==NULL) + { + $this->errormsg='Fehler: Kurzbezeichnung der Einheit ist nicht gesetzt'; + return -1; + } + + /////////////////////////////////////////////////////////////////////// + // Zusaetzliche Daten ermitteln + // Personendaten + if ($type=='student') + { + // Lehrverband ermitteln + $sql_query="SELECT studiengang_kz, semester, verband, gruppe FROM tbl_student WHERE uid='$uid'"; + //echo $sql_query; + if (! $result=@pg_query($this->conn, $sql_query) ) + { + $this->errormsg=pg_last_error($this->conn); + return -2; + } + $num_rows=pg_num_rows($result); + if ($num_rows>0) + $row=pg_fetch_object($result); + else + { + $this->errormsg='Fehler: Student ('.$uid.') wurde nicht gefunden!'; + return -2; + } + $studiengang_kz=$row->studiengang_kz; + $sem=$row->semester; + $ver=$row->verband; + $grp=$row->gruppe; + + // Einheiten ermitteln + $sql_query="SELECT einheit_kurzbz FROM tbl_einheitstudent WHERE uid='$uid'"; + //echo $sql_query; + if (! $result_einheit=@pg_query($this->conn, $sql_query) ) + { + $this->errormsg=pg_last_error($this->conn); + return -2; + } + $num_rows_einheit=pg_num_rows($result_einheit); + } + + /////////////////////////////////////////////////////////////////////// + // Stundenplandaten ermitteln + // Abfrage generieren + $sql_query_stdplan='SELECT * FROM '.$stpl_view; + $sql_query=" WHERE datum>='$datum_von' AND datum<'$datum_bis'"; + if ($type=='lektor') + $sql_query.=" AND uid='$uid'"; + elseif ($type=='ort') + $sql_query.=" AND ort_kurzbz='$ort_kurzbz'"; + elseif ($type=='einheit') + $sql_query.=" AND einheit_kurzbz='$einheit_kurzbz'"; + else + { + $sql_query.=' AND ( (studiengang_kz='.$studiengang_kz; + if ($sem!='0' && $sem!=null && $sem!=0 && $sem!='') + { + $sql_query.=" AND (semester=$sem OR semester IS NULL"; + if ($type=='student') + $sql_query.=' OR semester='.($sem+1); + $sql_query.=')'; + } + if ($ver!='0' && $ver!=null && $ver!='') + $sql_query.=" AND (verband='$ver' OR verband IS NULL OR verband='0' OR verband='')"; + if ($grp!='0' && $grp!=null && $grp!='') + $sql_query.=" AND (gruppe='$grp' OR gruppe IS NULL OR gruppe='0' OR gruppe='')"; + if ($type=='student') + $sql_query.=' AND einheit_kurzbz IS NULL'; + $sql_query.=' )'; + for ($i=0;$i<$num_rows_einheit;$i++) + { + $row=pg_fetch_object($result_einheit,$i); + $sql_query.=" OR einheit_kurzbz='$row->einheit_kurzbz'"; + } + $sql_query.=')'; + } + $sql_query.=' ORDER BY datum, stunde, studiengang_kz, semester, verband, gruppe, einheit_kurzbz, uid'; + $sql_query_stdplan.=$sql_query; + //echo ''; + + //Datenbankabfrage + if (! $stpl_tbl=pg_query($this->conn, $sql_query_stdplan)) + { + $this->errormsg=pg_last_error($this->conn); + //echo $this->errormsg; + return -2; + } + $num_rows=pg_numrows($stpl_tbl); + $this->anzahl=$num_rows; + //Daten uebernehmen + for ($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object ($stpl_tbl, $i); + $stunde=new lehrstunde($this->conn); + $stunde->stundenplan_id=$row->{$stpl_id}; + $stunde->unr=$row->unr; + $stunde->lektor_uid=$row->uid; + $stunde->lektor_kurzbz=$row->lektor; + $stunde->datum=$row->datum; + $stunde->stunde=$row->stunde; + $stunde->ort_kurzbz=$row->ort_kurzbz; + $stunde->lehrfach=$row->lehrfach; + $stunde->lehrfach_bez=$row->lehrfach_bez; + $stunde->lehrfach_nr=$row->lehrfach_nr; + $stunde->lehrform=$row->lehrform; + if ($row->farbe!=' ' && $row->farbe!=null) + $stunde->farbe=$row->farbe; + else + $stunde->farbe='FFFFFF'; + $stunde->studiengang_kz=$row->studiengang_kz; + $stunde->studiengang=$row->stg_kurzbz; + $stunde->sem=$row->semester; + $stunde->ver=$row->verband; + $stunde->grp=$row->gruppe; + $stunde->einheit_kurzbz=$row->einheit_kurzbz; + $stunde->titel=$row->titel; + $stunde->anmerkung=$row->anmerkung; + $stunde->updateamum=$row->updateamum; + $stunde->updatevon=$row->updatevon; + $stunde->reservierung=false; + $this->lehrstunden[$i]=$stunde; + } + + /////////////////////////////////////////////////////////////////////// + // Reservierungsdaten ermitteln + // Datenbankabfrage generieren + $sql_query_reservierung='SELECT * FROM vw_reservierung'; + $sql_query_reservierung.=$sql_query; + //echo $sql_query_reservierung; + //Datenbankabfrage + if (! $stpl_tbl=pg_query($this->conn, $sql_query_reservierung)) + { + $this->errormsg=pg_last_error($this->conn); + return -2; + } + $num_rows=pg_numrows($stpl_tbl); + $this->anzahl+=$num_rows; + + //Daten uebernehmen + for ($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object ($stpl_tbl, $i); + $stunde=new lehrstunde($this->conn); + $stunde->reservierung=true; + $stunde->stundenplan_id=$row->reservierung_id; + $stunde->unr=0; + $stunde->lektor_uid=$row->uid; + $stunde->lektor_kurzbz=$row->uid; + $stunde->datum=$row->datum; + $stunde->stunde=$row->stunde; + $stunde->ort_kurzbz=$row->ort_kurzbz; + //$stunde->lehrfach_nr=$row->lehrfach_nr; + $stunde->lehrfach=$row->titel; + $stunde->lehrfach_bez=$row->beschreibung; + $stunde->studiengang_kz=$row->studiengang_kz; + $stunde->studiengang=$row->stg_kurzbz; + $stunde->sem=$row->semester; + $stunde->ver=$row->verband; + $stunde->grp=$row->gruppe; + $stunde->einheit_kurzbz=$row->einheit_kurzbz; + $stunde->titel=$row->titel; + $stunde->anmerkung=$row->beschreibung; + $this->lehrstunden[]=$stunde; + //var_dump($stunde); + } + //echo $this->anzahl; + return $this->anzahl; + } + + /************************************************************************* + * Prueft die geladene Lehrveranstaltung auf Kollisionen im Stundenplan. + * Rueckgabewert 'false' und die Fehlermeldung steht in '$this->errormsg'. + * @param string datum gewuenschtes Datum YYYY-MM-TT + * @param integer stunde gewuenschte Stunde + * @param string ort gewuenschter Ort + * @param string db_stpl_table Tabllenname des Stundenplans im DBMS + * @return boolean true=ok, false=fehler + *************************************************************************/ + function kollision($stpl_table='stundenplandev') + { + // Parameter Checken + // Bezeichnung der Stundenplan-Tabelle und des Keys + $stpl_id=$stpl_table.TABLE_ID; + $stpl_table=VIEW_BEGIN.$stpl_table; + + // Datenbank abfragen + $sql_query="SELECT $stpl_id AS id, lektor, stg_kurzbz, ort_kurzbz, semester, verband, gruppe, einheit_kurzbz, datum, stunde FROM $stpl_table + WHERE datum='$this->datum' AND stunde=$this->stunde AND (ort_kurzbz='$this->ort_kurzbz' OR "; + if ($this->lektor_uid!='_DummyLektor') + $sql_query.="(uid='$this->lektor_uid') AND uid!='_DummyLektor' OR "; + $sql_query.="(studiengang_kz=$this->studiengang_kz AND semester=$this->sem"; + if ($this->ver!=null && $this->ver!='' && $this->ver!=' ') + $sql_query.=" AND (verband='$this->ver' OR verband IS NULL OR verband='' OR verband=' ')"; + if ($this->grp!=null && $this->grp!='' && $this->grp!=' ') + $sql_query.=" AND (gruppe='$this->grp' OR gruppe IS NULL OR gruppe='' OR gruppe=' ')"; + if ($this->einheit_kurzbz!=null && $this->einheit_kurzbz!='' && $this->einheit_kurzbz!=' ') + $sql_query.=" AND (einheit_kurzbz='$this->einheit_kurzbz')"; + $sql_query.=")) AND unr!=$this->unr"; + + //echo $sql_query.'
    '; + if (! $erg_stpl=pg_query($this->conn, $sql_query)) + { + $this->errormsg=pg_last_error($this->conn); + return true; + } + $anz=pg_numrows($erg_stpl); + //Check + if ($anz==0) + return false; + else + { + $row=pg_fetch_object($erg_stpl); + $this->errormsg="Kollision ($stpl_table): $row->id|$row->lektor|$row->ort_kurzbz|$row->stg_kurzbz-$row->semester$row->verband$row->gruppe$row->einheit_kurzbz - $row->datum/$row->stunde"; + return true; + } + } +} + +?> \ No newline at end of file diff --git a/include/lehrveranstaltung.class.php b/include/lehrveranstaltung.class.php new file mode 100644 index 000000000..265d5477b --- /dev/null +++ b/include/lehrveranstaltung.class.php @@ -0,0 +1,392 @@ +conn=$conn; + $this->errormsg=''; + if (strlen($id)>0) + { + $this->lehrveranstaltung_id=$id; + $this->load($id); + } + } + + + /************************************************************************* + * Prueft die geladene Lehrveranstaltung auf Kollisionen im Stundenplan. + * Rueckgabewert 'false' und die Fehlermeldung steht in '$this->errormsg'. + * @param string datum gewuenschtes Datum YYYY-MM-TT + * @param integer stunde gewuenschte Stunde + * @param string ort gewuenschter Ort + * @param string db_stpl_table Tabllenname des Stundenplans im DBMS + * @return boolean true=ok, false=fehler + *************************************************************************/ + function check_lva($datum,$stunde,$ort,$stpl_table) + { + // Parameter Checken + // Bezeichnung der Stundenplan-Tabelle und des Keys + $stpl_id=$stpl_table.TABLE_ID; + $stpl_table=TABLE_BEGIN.$stpl_table; + + /*// Connection holen + if (is_null($conn=$this->getConnection())) + { + return false; + }*/ + + // Datenbank abfragen + $sql_query="SELECT $stpl_id FROM $stpl_table + WHERE datum='$datum' AND stunde=$stunde + AND ((ort_kurzbz='$ort' OR (uid='$this->lektor' AND uid!='_DummyLektor')) + AND unr!=$this->unr)"; //AND lehrveranstaltung_id!=$this->lehrveranstaltung_id + //$this->errormsg=$sql_query; + if (! $erg_stpl=pg_query($this->conn, $sql_query)) + { + $this->errormsg=pg_last_error($this->conn); + //echo $this->errormsg; + return false; + } + $anzahl=pg_numrows($erg_stpl); + //Check + if ($anzahl==0) + return true; + else + { + $row=pg_fetch_row($erg_stpl); + $this->errormsg="Kollision mit StundenplanID($stpl_table.$stpl_id): $row[0]"; + return false; + } + } + + /************************************************************************* + * Speichert die geladene Lehrveranstaltung im Stundenplan. + * Rueckgabewert 'false' und die Fehlermeldung steht in '$this->errormsg'. + * @param string datum gewuenschtes Datum YYYY-MM-TT + * @param integer stunde gewuenschte Stunde + * @param string ort gewuenschter Ort + * @param string db_stpl_table Tabllenname des Stundenplans im DBMS + * @param string user UID des aktuellen Bentzers + * @return boolean true=ok, false=fehler + *************************************************************************/ + function save_stpl($datum,$stunde,$ort,$stpl_table, $user) + { + // Parameter Checken + // Bezeichnung der Stundenplan-Tabelle und des Keys + $stpl_id=$stpl_table.TABLE_ID; + $stpl_table=TABLE_BEGIN.$stpl_table; + + // Datenbank abfragen + $sql_query="INSERT INTO $stpl_table + (unr,uid,datum, stunde, ort_kurzbz,lehrfach_nr,lehrform_kurzbz,studiengang_kz,semester,verband, + gruppe, einheit_kurzbz, titel, anmerkung, updatevon, lehrveranstaltung_id) + VALUES ($this->unr,'$this->lektor','$datum',$stunde, + '$ort',$this->lehrfach_nr, '$this->lehrform', $this->studiengang_kz,$this->semester, + '$this->verband','$this->gruppe'"; + if ($this->einheit_kurzbz==null) + $sql_query.=',NULL'; + else + $sql_query.=",'$this->einheit_kurzbz'"; + $sql_query.=",'$this->titel','$this->anmerkung','$user',$this->lehrveranstaltung_id)"; + //$this->errormsg=$sql_query.'
    '; + //return false; + if (! $erg_stpl=pg_query($this->conn, $sql_query)) + { + $this->errormsg=pg_last_error($this->conn); + //echo $this->errormsg; + return false; + } + return true; + } + + /** + * Ladet die Attribute der LVA aus der Datenbank. Bei Fehler ist der + * Rueckgabewert 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true=ok, false=fehler + */ + function load($id='') + { + // optional: id setzen + if ($id!='') + $this->lehrveranstaltung_id=$id; + // id vorhanden? + if (strlen($this->lehrveranstaltung_id)==0) + { + $this->errormsg='lehrveranstaltung_id nicht gesetzt.'; + return false; + } + + // LVA-Daten holen + $sql_query='SELECT * FROM tbl_lehrveranstaltung WHERE lehrveranstaltung_id='.$this->lehrveranstaltung_id; + //$this->errormsg.=$sql_query; + //return false; + if(!($erg=pg_exec($this->conn, $sql_query))) + { + $this->errormsg.=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + if($num_rows!=1) + { + $this->errormsg.="Zuwenige oder zuviele Ergebnisse (Anzahl: $num_rows)!"; + return false; + } + $row=pg_fetch_object($erg,0); + + $this->lvnr=$row->lvnr; + $this->unr=$row->unr; + $this->einheit_kurzbz=$row->einheit_kurzbz; + $this->lektor=$row->lektor; + $this->lehrfach_nr=$row->lehrfach_nr; + $this->lehrform=$row->lehrform_kurzbz; + $this->studiengang_kz=$row->studiengang_kz; + $this->fachbereich_id=$row->fachbereich_id; + $this->semester=$row->semester; + $this->verband=$row->verband; + $this->gruppe=$row->gruppe; + $this->raumtyp=$row->raumtyp; + $this->raumtypalternativ=$row->raumtypalternativ; + $this->semesterstunden=$row->semesterstunden; + $this->stundenblockung=$row->stundenblockung; + $this->wochenrythmus=$row->wochenrythmus; + $this->start_kw=$row->start_kw; + $this->anmerkung=$row->anmerkung; + $this->studiensemester_kurzbz=$row->studiensemester_kurzbz; + //$this->fas_id=$row->fas_id; + $this->new=false; + return true; + } + + /** + * @return boolean true=ok, false=fehler + */ + function save() + { + global $auth; + + // Daten zur Person speichern + + if (!person::save()) { + $this->errormsg.="Daten zur LVA konnten nicht gespeichert werden."; + return false; + } + if ($this->new) { + $sql_query="INSERT INTO tbl_lehrveranstaltung(lvnr,unr,einheit_kurzbz,". + "lektor,lehrfach_nr,lehrform_kurzbz,studiengang_kz,fachbereich_id,semester,verband,". + "gruppe,raumtyp,raumtypalternativ,semesterstunden,stundenblockung,". + "wochenrythmus,start_kw,anmerkung)". + "values(". + "'".$this->lvnr."',". + "'".$this->unr."',". + "'".$this->einheit_kurzbz."',". + "'".$this->lektor."',". + (strlen($this->lehrfach_nr)>0?$this->lehrfach_nr:NULL).",". + "'".$this->lehrform."',". + (strlen($this->studiengang_kz)>0?$this->studiengang_kz:NULL).",". + (strlen($this->fachbereich_id)>0?$this->fachbereich_id:NULL).",". + (strlen($this->semester)>0?$this->semester:NULL).",". + "'".$this->verband."',". + "'".$this->gruppe."',". + (strlen($this->raumtyp)>0?"'".$this->raumtyp."'":NULL).",". + (strlen($this->raumtypalternativ)>0?"'".$this->raumtypalternativ."'":NULL).",". + (strlen($this->semesterstunden)>0?$this->semesterstunden:NULL).",". + (strlen($this->stundenblockung)>0?$this->stundenblockung:NULL).",". + (strlen($this->wochenrythmus)>0?$this->wochenrythmus:NULL).",". + (strlen($this->start_kw)>0?$this->start_kw:NULL).",". + (strlen($this->anmerkung)>0?"'".$this->anmerkung."'":NULL).",". + ")"; + } else + { + $sql_query="UPDATE tbl_lehrveranstaltung ". + "SET lvnr='".$this->lvnr."',". + "unr='".$this->unr."',". + "einheit_kurzbz='".$this->einheit_kurzbz."',". + "lektor='".$this->lektor."',". + "lehrfach_nr=".(strlen($this->lehrfach_nr)>0?$this->lehrfach_nr:NULL).",". + "lehrform_kurzbz=".(strlen($this->lehrform)>0?$this->lehrform:NULL).",". + "studiengang_kz=".(strlen($this->studiengang_kz)>0?$this->studiengang_kz:NULL).",". + "fachbereich_id=".(strlen($this->fachbereich_id)>0?$this->fachbereich_id:NULL).",". + "semester=".(strlen($this->semester)>0?$this->semester:NULL).",". + "verband='".$this->verband."',". + "gruppe='".$this->gruppe."',". + "raumtyp=".(strlen($this->raumtyp)>0?"'".$this->raumtyp."'":NULL).",". + "raumtypalternativ=".(strlen($this->raumtypalternativ)>0?"'".$this->raumtypalternativ."'":NULL).",". + "semesterstunden=".(strlen($this->semesterstunden)>0?$this->semesterstunden:NULL).",". + "stundenblockung=".(strlen($this->stundenblockung)>0?$this->stundenblockung:NULL).",". + "wochenrythmus=".(strlen($this->wochenrythmus)>0?$this->wochenrythmus:NULL).",". + "start_kw=".(strlen($this->start_kw)>0?$this->start_kw:NULL).",". + "anmerkung=".(strlen($this->anmerkung)>0?"'".$this->anmerkung."'":NULL). + " WHERE lehrveranstaltung_id='".$this->lehrveranstaltung_id."'"; + } + //echo "
    ".$sql_query; + if(!($erg=pg_exec($this->conn, $sql_query))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + return true; + } + + + /** + * Rueckgabewert ist ein Array mit den Ergebnissen. Bei Fehler false und die + * Fehlermeldung liegt in errormsg. + * Wenn der Parameter stg_kz NULL ist tritt einheit_kurzbzb in Kraft. + * @param string $einheit_kurzbz Einheit + * @param string grp Gruppe + * @param string ver Verband + * @param integer sem Semester + * @param integer stg_kz Kennzahl des Studiengangs + * @return variabel Array mit LVA; false bei Fehler + */ + function getLehrveranstaltungSTPL($db_stpl_table,$studiensemester, $type, $stg_kz, $sem, $lektor, $ver=null, $grp=null, $einheit=null) + { + $lva_stpl_view=VIEW_BEGIN.'lva_'.$db_stpl_table; + + if (strlen($studiensemester)<=0) + { + $this->errormsg='Ausbildungssemester ist nicht gesetzt!'; + return false; + } + else $where=" studiensemester_kurzbz='$studiensemester'"; + + if ($type=='lektor') + $where.=" AND lektor_uid='$lektor'"; + elseif ($type=='einheit') + $where.=" AND einheit='$einheit'"; + elseif ($type=='verband') + { + $where.=" AND studiengang_kz='$stg_kz'"; + if ($sem>0) + $where.=" AND semester=$sem"; + if (strlen($ver)>0 && $ver!=' ') + $where.=" AND verband='$ver'"; + if (strlen($grp)>0 && $grp!=' ') + $where.=" AND gruppe='$grp' "; + } + $sql_query='SELECT *, semesterstunden-verplant::smallint AS offenestunden + FROM '.$lva_stpl_view.' JOIN tbl_lehrform ON '.$lva_stpl_view.'.lehrform=tbl_lehrform.lehrform_kurzbz + WHERE '.$where.' AND verplanen ORDER BY offenestunden DESC, lehrfach, lehrform, semester, verband, gruppe, einheit;'; + //$this->errormsg=$sql_query; + //return false; + if(!($erg=@pg_exec($this->conn, $sql_query))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + $l=array(); + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + //$l[$row->unr]=new lehrveranstaltung(); + $l[$row->unr]->lehrveranstaltung_id[]=$row->lehrveranstaltung_id; + $l[$row->unr]->lvnr[]=$row->lvnr; + $l[$row->unr]->unr=$row->unr; + $l[$row->unr]->fachbereich_id=$row->fachbereich_id; + $l[$row->unr]->fachbereich=$row->fachbereich_kurzbz; + $l[$row->unr]->lehrfach_nr=$row->lehrfach_nr; + $l[$row->unr]->lehrfach[]=$row->lehrfach; + $l[$row->unr]->lehrfach_bez[]=$row->lehrfach_bez; + $l[$row->unr]->lehrfach_farbe[]=$row->lehrfach_farbe; + $l[$row->unr]->lehrform[]=$row->lehrform; + $l[$row->unr]->lektor_uid[]=$row->lektor_uid; + $l[$row->unr]->lektor[]=trim($row->lektor); + $l[$row->unr]->stg_kz[]=$row->studiengang_kz; + $l[$row->unr]->stg[]=$row->studiengang; + $l[$row->unr]->einheit[]=$row->einheit; + $l[$row->unr]->semester[]=$row->semester; + $l[$row->unr]->verband[]=$row->verband; + $l[$row->unr]->gruppe[]=$row->gruppe; + $l[$row->unr]->raumtyp=$row->raumtyp; + $l[$row->unr]->raumtypalternativ=$row->raumtypalternativ; + $l[$row->unr]->stundenblockung[]=$row->stundenblockung; + $l[$row->unr]->wochenrythmus[]=$row->wochenrythmus; + $l[$row->unr]->semesterstunden[]=$row->semesterstunden; + $l[$row->unr]->start_kw[]=$row->start_kw; + $l[$row->unr]->anmerkung[]=$row->anmerkung; + $l[$row->unr]->studiensemester_kurzbz=$row->studiensemester_kurzbz; + $l[$row->unr]->verplant[]=$row->verplant; + $l[$row->unr]->offenestunden[]=$row->offenestunden; + if (isset($l[$row->unr]->verplant_gesamt)) + $l[$row->unr]->verplant_gesamt+=$row->verplant; + else + $l[$row->unr]->verplant_gesamt=$row->verplant; + $lvb=$row->studiengang.'-'.$row->semester; + if ($row->verband!='' && $row->verband!=' ' && $row->verband!='0' && $row->verband!=null) + $lvb.=$row->verband; + if ($row->gruppe!='' && $row->gruppe!=' ' && $row->gruppe!='0' && $row->gruppe!=null) + $lvb.=$row->gruppe; + if ($row->einheit!='' && $row->einheit!=null) + $l[$row->unr]->lehrverband[]=$row->einheit; + else + $l[$row->unr]->lehrverband[]=$lvb; + } + return $l; + } +} \ No newline at end of file diff --git a/include/lfvt.class.php b/include/lfvt.class.php new file mode 100644 index 000000000..8430b7b88 --- /dev/null +++ b/include/lfvt.class.php @@ -0,0 +1,423 @@ +conn=$conn; + if (strlen($id)>0) { + $this->$lehrveranstaltung_id=$id; + $this->load(); + } + } + + /** + * Ladet die Attribute der LVA aus der Datenbank. Bei Fehler ist der + * Rueckgabewert 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true=ok, false=fehler + */ + function load($id='') + { + // optional: id setzen + if (strlen($id)>0) + $this->$lehrveranstaltung_id=$id; + // id vorhanden? + if (strlen($this->$this->$lehrveranstaltung_id)==0) { + $this->errormsg='lehrveranstaltung_id nicht gesetzt.'; + return false; + } + // LVA-Daten holen + $sql_query="SELECT lva.* ". + "FROM tbl_lehrveranstaltung as lva ". + "WHERE lehrveranstaltung_id='".$this->lehrveranstaltung_id."'"; + if(!($erg=pg_exec($this->conn, $sql_query))) + die(pg_errormessage($this->conn)); + $num_rows=pg_numrows($erg); + if($num_rows!=1) { + $this->errormsg="Zuwenige oder zuviele Ergebnisse (Anzahl: $num_rows)!"; + return false; + } + $row=pg_fetch_object($erg,0); + + $this->lvnr=$row->lvnr; + $this->unr=$row->unr; + $this->einheit_kurzbz=$row->einheit_kurzbz; + $this->lektor=$row->lektor; + $this->lehrfach_nr=$row->lehrfach_nr; + $this->lehrform=$row->lehrform_kurzbz; + $this->studiengang_kz=$row->studiengang_kz; + $this->fachbereich_id=$row->fachbereich_id; + $this->semester=$row->semester; + $this->verband=$row->verband; + $this->gruppe=$row->gruppe; + $this->raumtyp=$row->raumtyp; + $this->raumtypalternativ=$row->raumtypalternativ; + $this->semesterstunden=$row->semesterstunden; + $this->stundenblockung=$row->stundenblockung; + $this->wochenrythmus=$row->wochenrythmus; + $this->start_kw=$row->start_kw; + $this->anmerkung=$row->anmerkung; + $this->studiensemester_kurzbz=$row->studiensemester_kurzbz; + //$this->fas_id=$row->fas_id; + $this->new=false; + return true; + } + + + + /** + * @return boolean true=ok, false=fehler + */ + function save() + { + global $auth; + if (!isset($this->unr)) { + $this->errormsg='unr fehlt'; + return false; + } + if (!isset($this->lvnr)) { + $this->errormsg='lvnr fehlt'; + return false; + } + if (!isset($this->lektor)) { + $this->errormsg='lektor fehlt'; + return false; + } + if (!isset($this->lehrfach_nr)) { + $this->errormsg='lehrfach_nr fehlt'; + return false; + } + if (!isset($this->lehrform)) + { + $this->errormsg='lehrform fehlt'; + return false; + } + if (!isset($this->studiengang_kz)) { + $this->errormsg='studiengang_kz fehlt'; + return false; + } + if (!isset($this->fachbereich_id)) { + $this->errormsg='fachbereich_id fehlt'; + return false; + } + if (!isset($this->raumtyp)) { + $this->errormsg='raumtyp fehlt'; + return false; + } + if (!isset($this->semesterstunden)) { + $this->errormsg='semesterstunden fehlt'; + return false; + } + if (!isset($this->stundenblockung)) { + $this->errormsg='stundenblockung fehlt'; + return false; + } + if (!isset($this->wochenrythmus)) { + $this->errormsg='wochenrythmus fehlt'; + return false; + } + if (!isset($this->studiensemester_kurzbz)) { + $this->errormsg='studiensemester_kurzbz fehlt'; + return false; + } + + if ($this->new) { + $qry="INSERT INTO tbl_lehrveranstaltung(lvnr,unr,einheit_kurzbz,". + "lektor,lehrfach_nr,lehrform_kurzbz,studiengang_kz,fachbereich_id,semester,verband,". + "gruppe,raumtyp,raumtypalternativ,semesterstunden,stundenblockung,". + "wochenrythmus,start_kw,anmerkung,studiensemester_kurzbz)\n". + "values(". + "'".$this->lvnr."',". + "'".$this->unr."',". + (strlen($this->einheit_kurzbz)>0?"'".$this->einheit_kurzbz."'":'NULL').",". + "'".$this->lektor."',". + (strlen($this->lehrfach_nr)>0?$this->lehrfach_nr:'NULL').",". + "'".$this->lehrform."',". + (strlen($this->studiengang_kz)>0?$this->studiengang_kz:'NULL').",". + (strlen($this->fachbereich_id)>0?$this->fachbereich_id:'NULL').",". + (strlen($this->semester)>0?$this->semester:'NULL').",". + "'".$this->verband."',". + "'".$this->gruppe."',". + (strlen($this->raumtyp)>0?"'".$this->raumtyp."'":'NULL').",". + (strlen($this->raumtypalternativ)>0?"'".$this->raumtypalternativ."'":'NULL').",". + (strlen($this->semesterstunden)>0?$this->semesterstunden:'NULL').",". + (strlen($this->stundenblockung)>0?$this->stundenblockung:'NULL').",". + (strlen($this->wochenrythmus)>0?$this->wochenrythmus:'NULL').",". + (strlen($this->start_kw)>0?$this->start_kw:'NULL').",". + (strlen($this->anmerkung)>0?"'".$this->anmerkung."'":'NULL').','. + (strlen($this->studiensemester_kurzbz)>0?"'".$this->studiensemester_kurzbz."'":'NULL'). + ")"; + } else + { + $qry="UPDATE tbl_lehrveranstaltung ". + "SET lvnr='".$this->lvnr."',". + "unr='".$this->unr."',". + "einheit_kurzbz=".(strlen($this->einheit_kurzbz)>0?"'".$this->einheit_kurzbz."'":'NULL').",". + "lektor='".$this->lektor."',\n". + "lehrfach_nr=".(strlen($this->lehrfach_nr)>0?$this->lehrfach_nr:'NULL').",". + "lehrform_kurzbz='".$this->lehrform."',\n". + "studiengang_kz=".(strlen($this->studiengang_kz)>0?$this->studiengang_kz:'NULL').",". + "fachbereich_id=".(strlen($this->fachbereich_id)>0?$this->fachbereich_id:'NULL').",". + "semester=".(strlen($this->semester)>0?$this->semester:'NULL').",\n". + "verband='".$this->verband."',". + "gruppe='".$this->gruppe."',". + "raumtyp='".$this->raumtyp."',". + "raumtypalternativ=".(strlen($this->raumtypalternativ)>0?"'".$this->raumtypalternativ."'":'NULL').",\n". + "semesterstunden=".(strlen($this->semesterstunden)>0?$this->semesterstunden:'NULL').",". + "stundenblockung=".(strlen($this->stundenblockung)>0?$this->stundenblockung:'NULL').",". + "wochenrythmus=".(strlen($this->wochenrythmus)>0?$this->wochenrythmus:'NULL').",\n". + "start_kw=".($this->start_kw>0?$this->start_kw:'NULL').",". + "anmerkung=".(strlen($this->anmerkung)>0?"'".$this->anmerkung."'":'NULL'). + " WHERE lehrveranstaltung_id=".$this->lehrveranstaltung_id; + } + //echo "
    ".$qry.'start_kw: <'.$this->start_kw.'>'; + if(!($erg=pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn).' sql: '.$qry; + return false; + } + if ($this->new) { + // neue Lehrveranstaltungs-ID herausfinden und speichern + $lastoid=pg_getlastoid($erg); + $qry="select lehrveranstaltung_id from tbl_lehrveranstaltung where oid=$lastoid"; + if(!($erg=pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn).' sql: '.$qry;; + return false; + } + $row=pg_fetch_object($erg,0); + $this->lehrveranstaltung_id=$row->lehrveranstaltung_id; + $this->new=false; + } + return true; + } + + function delete() { + global $auth; + if ($this->new) { + $this->errormsg='Datensatz mit new=true kann nicht gel?scht werden.'; + return false; + } + $qry="delete from tbl_lehrveranstaltung where lehrveranstaltung_id=".addslashes($this->lehrveranstaltung_id); + if(!($erg=pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn)." \nSQL: ".$qry; + return false; + } + return true; + } + + + /** + * Rueckgabewert ist ein Array mit den Ergebnissen. Bei Fehler false und die + * Fehlermeldung liegt in errormsg. + * Wenn der Parameter stg_kz NULL ist tritt einheit_kurzbzb in Kraft. + * @param string $einheit_kurzbz Einheit + * @param string grp Gruppe + * @param string ver Verband + * @param integer sem Semester + * @param integer stg_kz Kennzahl des Studiengangs + * @return variabel Array mit LVA; false bei Fehler + */ + function getLVAs($einheit_kurzbz, $grp, $ver, $sem, $stg_kz,$lektor, $stsem='') + { + if (strlen($einheit_kurzbz)>0) + { + // einheit? + //$join=" join tbl_einheitstudent on (m.uid=tbl_einheitstudent.uid) "; + $where=" lva.einheit_kurzbz='".$einheit_kurzbz."'"; + } + if (strlen($grp)>0) + { + // Gruppe + $where.=(strlen($where)>0?' and ':'')." lva.gruppe='".$grp."' "; + } + if (strlen($ver)>0) + { + // Verband + $where.=(strlen($where)>0?' and ':'')." lva.verband='".$ver."' "; + } + if (strlen($sem)>0) + { + // Semester + $where.=(strlen($where)>0?' and ':'')." lva.semester=".$sem." "; + } + if (strlen($stg_kz)>0) + { + // Studiengang + $where.=(strlen($where)>0?' and ':'')." lva.studiengang_kz='".$stg_kz."' "; + } + if (strlen($lektor)>0) + { + // Lektor + $where.=(strlen($where)>0?' and ':'')." lva.lektor='".$lektor."' "; + } + if (strlen($stsem)>0) + { + // Studiensemester + $where.=(strlen($where)>0?' and ':'')." lva.studiensemester_kurzbz='".$stsem."' "; + } + $sql_query="set datestyle to german;SELECT lva.*,tbl_lehrfach.bezeichnung as lehrfach_bezeichnung, ". + " tbl_person.nachname || ', ' || tbl_person.titel || ' ' || tbl_person.vornamen as lektorName ". + "FROM tbl_lehrveranstaltung as lva join tbl_lehrfach using(lehrfach_nr) ". + " left join tbl_person on(lva.lektor=tbl_person.uid) ". + (strlen($where)>1?'WHERE '.$where:''). + "ORDER by upper(lva.unr),upper(lva.lvnr)"; + //echo $sql_query; + if(!($erg=pg_exec($this->conn, $sql_query))) { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + $result=array(); + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + $l=new lfvt($this->conn); + $l->lehrveranstaltung_id=$row->lehrveranstaltung_id; + $l->lvnr=$row->lvnr; + $l->unr=$row->unr; + $l->einheit_kurzbz=$row->einheit_kurzbz; + $l->lektor=$row->lektor; + $l->lektorPrettyPrint=$row->lektorname; + $l->lehrfach_nr=$row->lehrfach_nr; + $l->lehrform=$row->lehrform_kurzbz; + $l->studiengang_kz=$row->studiengang_kz; + $l->fachbereich_id=$row->fachbereich_id; + $l->semester=$row->semester; + $l->verband=strlen($row->verband)>0?$row->verband:null; + $l->gruppe=$row->gruppe; + $l->raumtyp=$row->raumtyp; + $l->raumtypalternativ=$row->raumtypalternativ; + $l->semesterstunden=$row->semesterstunden; + $l->stundenblockung=$row->stundenblockung; + $l->wochenrythmus=$row->wochenrythmus; + $l->start_kw=$row->start_kw; + $l->anmerkung=$row->anmerkung; + $l->studiensemester_kurzbz=$row->studiensemester_kurzbz; + $l->lehrfach=$row->lehrfach_bezeichnung; + // lva in Array speichern + $result[]=$l; + } + return $result; + } + +} diff --git a/include/lv_info.class.php b/include/lv_info.class.php new file mode 100644 index 000000000..c161767df --- /dev/null +++ b/include/lv_info.class.php @@ -0,0 +1,324 @@ +conn = $conn; + } + + /******************************************************************** + * @brief Speichert die Daten in der Datenbank ab. Wenn new auf true + * gesetzt ist wird INSERT ausgefuehrt sonst UPDATE + * @param keine + * + * @return true=Ok false=Fehler + ********************************************************************/ + function save() + { + + if (is_null($this->conn)) + { + $this->errormsg = "Fehler: Keine Datenbank connection vorhanden"; + return false; + } + + //Variablen ueberpruefen + //$this->checkvars(); + + if($this->neu) + { + $sql_query = "INSERT INTO tbl_lvinfo (studiensemester_kurzbz,lehrziele,lehrinhalte,voraussetzungen,basiert_auf,". + "kooperiert_mit, liefert_fuer, unterlagen, pruefungsordnung, anmerkungen, niveau,". + "lehrformen, genehmigt, aktiv,updatevon,lehrfach_nr, sprache, lehrende, lehrfach, semstunden)". + " VALUES('$this->studiensemester_kurzbz',". + (strlen($this->lehrziele)>0?"'".$this->lehrziele."'":'NULL').",". + (strlen($this->lehrinhalte)>0?"'".$this->lehrinhalte."'":'NULL').",". + (strlen($this->voraussetzungen)>0?"'".$this->voraussetzungen."'":'NULL').",". + (strlen($this->basiert_auf)>0?"'".$this->basiert_auf."'":'NULL').",". + (strlen($this->kooperiert_mit)>0?"'".$this->kooperiert_mit."'":'NULL').",". + (strlen($this->liefert_fuer)>0?"'".$this->liefert_fuer."'":'NULL').",". + (strlen($this->unterlagen)>0?"'".$this->unterlagen."'":'NULL').",". + (strlen($this->pruefungsordnung)>0?"'".$this->pruefungsordnung."'":'NULL').",". + (strlen($this->anmerkungen)>0?"'".$this->anmerkungen."'":'NULL').",". + (strlen($this->niveau)>0?"'".$this->niveau."'":'NULL').",". + (strlen($this->lehrformen)>0?"'".$this->lehrformen."'":'NULL').",". + ($this->genehmigt=="'true'"?'true':'false').",".($this->aktiv=='true'?'true':'false').",'$this->updatevon',$this->lehrfach_nr,'$this->sprache',". + (strlen($this->lehrende)>0?"'".$this->lehrende."'":'NULL').",". + (strlen($this->lehrfach)>0?"'".$this->lehrfach."'":'NULL').",". + ($this->semstunden!=''?"'".$this->semstunden."'":'NULL') .");"; + + } + else + { + $sql_query = "UPDATE tbl_lvinfo SET". + " studiensemester_kurzbz='$this->studiensemester_kurzbz'". + ", lehrziele=".(strlen($this->lehrziele)>0?"'".$this->lehrziele."'":'NULL') . + ", lehrinhalte=".(strlen($this->lehrinhalte)>0?"'".$this->lehrinhalte."'":'NULL') . + ", voraussetzungen=".(strlen($this->voraussetzungen)>0?"'".$this->voraussetzungen."'":'NULL') . + ", basiert_auf=".(strlen($this->basiert_auf)>0?"'".$this->basiert_auf."'":'NULL') . + ", kooperiert_mit=".(strlen($this->kooperiert_mit)>0?"'".$this->kooperiert_mit."'":'NULL') . + ", liefert_fuer=".(strlen($this->liefert_fuer)>0?"'".$this->liefert_fuer."'":'NULL') . + ", unterlagen=".(strlen($this->unterlagen)>0?"'".$this->unterlagen."'":'NULL') . + ", pruefungsordnung=".(strlen($this->pruefungsordnung)>0?"'".$this->pruefungsordnung."'":'NULL') . + ", anmerkungen=".(strlen($this->anmerkungen)>0?"'".$this->anmerkungen."'":'NULL') . + ", niveau=".(strlen($this->niveau)>0?"'".$this->niveau."'":'NULL') . + ", lehrformen=".(strlen($this->lehrformen)>0?"'".$this->lehrformen."'":'NULL') . + ", lehrende=".(strlen($this->lehrende)>0?"'".$this->lehrende."'":'NULL') . + ($this->genehmigt==''?'':", genehmigt=$this->genehmigt"). + ($this->aktiv==''?'':", aktiv=$this->aktiv"). + ", updateamum=now()". + ", updatevon='".$_SERVER["REMOTE_USER"]."'". + ", lehrfach_nr=$this->lehrfach_nr". + ", lehrfach='$this->lehrfach'". + ($this->semstunden!=''?", semstunden=$this->semstunden ":''). + ", sprache='$this->sprache' WHERE lvinfo_id=$this->lvinfo_id"; + + } + + $this->lastqry=$sql_query."--$this->genehmigt--"; + //echo $sql_query; + if(pg_exec($this->conn,$sql_query)) + { + return true; + } + else + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + } + + /******************************************************************** + * @brief Fuehrt einen Selectbefehl aus und Schreibt das Ergebnis in + * $result + * + * @param $sql_query - Select befehl + * + * @return true=Ok, Erg in $Result false=Fehler, Meldung in $errormsg + * Anzahl der Datensaetze steht in $anz + ********************************************************************/ + function getData($sql_query) + { + if (is_null($this->conn)) + { + $this->errormsg = "Fehler: Keine Datenbank connection vorhanden"; + return false; + } + + if($res=pg_exec($this->conn,$sql_query)) + { + while($row=pg_fetch_object($res)) + { + $elem = new lv_info($this->conn); + $elem->lvinfo_id = $row->lvinfo_id; + $elem->studiensemester_kurzbz = $row->studiensemester_kurzbz; + $elem->lehrziele = $row->lehrziele; + $elem->lehrinhalte = $row->lehrinhalte; + $elem->voraussetzungen = $row->voraussetzungen; + $elem->basiert_auf = $row->basiert_auf; + $elem->kooperiert_mit = $row->kooperiert_mit; + $elem->liefert_fuer = $row->liefert_fuer; + $elem->unterlagen = $row->unterlagen; + $elem->pruefungsordnung = $row->pruefungsordnung; + $elem->anmerkungen = $row->anmerkungen; + $elem->niveau = $row->niveau; + $elem->lehrformen = $row->lehrformen; + $elem->genehmigt = $row->genehmigt; + $elem->aktiv = $row->aktiv; + $elem->updateamum = $row->updateamum; + $elem->updatevon = $row->updatevon; + $elem->lehrfach_nr = $row->lehrfach_nr; + $elem->lehrfach = $row->lehrfach; + $elem->sprache = $row->sprache; + $elem->lehrende = $row->lehrende; + $elem->semstunden = $row->semstunden; + $this->result[] = $elem; + } + $this->anz = pg_num_rows($res); + } + else + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + return true; + } + + /******************************************************************** + * @brief Liefert alle Datensaetze der Tabelle tbl_lvinfo + * + * @param keine + * + * @return true=Ok, Erg in $Result false=Fehler, Meldung in $errormsg + ********************************************************************/ + function getAll() + { + $sql_query = "Select * from tbl_lvinfo"; + return $this->getData($sql_query); + } + + /******************************************************************** + * @brief Liefert alle Datensaetze der Tabelle tbl_lvinfo mit der + * lvinfo_id $id + * @param $id lvinfo_id + * + * @return true=Ok, Erg in $Result false=Fehler, Meldung in $errormsg + ********************************************************************/ + function getByID($id) + { + $sql_query = "SELECT * from tbl_lvinfo WHERE lvinfo_id=$id"; + return $this->getData($sql_query); + } + + /******************************************************************** + * @brief Liefert alle Datensaetze mit den Kriterien die ueberg. wurden + * + * @param $lf Lehrfach + * $stg Studiengang + * $sem Semester + * $sprache Sprache + * $studiensemester_kurzbz Studiensemester + * + * @return true=Ok, Erg in $Result false=Fehler, Meldung in $errormsg + ********************************************************************/ + function getByElem($lf,$stg,$sem,$sprache='',$studiensemester_kurzbz='',$order='version DESC') + { + if($sprache=='') + { + if($studiensemester_kurzbz=='') + { + $sql_query = "SELECT * from tbl_lvinfo, tbl_lehrfach WHERE tbl_lvinfo.lehrfach_nr=tbl_lehrfach.lehrfach_nr ". + "AND tbl_lvinfo.lehrfach_nr=$lf AND studiengang_kz = $stg AND semester = $sem AND tbl_lvinfo.aktiv=true ORDER BY $order"; + } + else + { + $sql_query = "SELECT * from tbl_lvinfo, tbl_lehrfach WHERE tbl_lvinfo.lehrfach_nr=tbl_lehrfach.lehrfach_nr ". + "AND tbl_lvinfo.lehrfach_nr=$lf AND studiengang_kz = $stg AND semester = $sem AND studiensemester_kurzbz='$studiensemester_kurzbz' AND tbl_lvinfo.aktiv=true ORDER BY $order"; + } + } + else + { + if($studiensemester_kurzbz=='') + { + $sql_query = "SELECT * from tbl_lvinfo, tbl_lehrfach WHERE tbl_lvinfo.lehrfach_nr=tbl_lehrfach.lehrfach_nr ". + "AND tbl_lvinfo.sprache='$sprache' AND tbl_lvinfo.lehrfach_nr=$lf AND studiengang_kz = $stg AND semester = $sem AND tbl_lvinfo.aktiv=true ORDER BY $order"; + } + else + { + $sql_query = "SELECT * from tbl_lvinfo, tbl_lehrfach WHERE tbl_lvinfo.lehrfach_nr=tbl_lehrfach.lehrfach_nr ". + "AND tbl_lvinfo.sprache='$sprache' AND tbl_lvinfo.lehrfach_nr=$lf AND studiengang_kz = $stg AND semester = $sem AND studiensemester_kurzbz='$studiensemester_kurzbz' AND tbl_lvinfo.aktiv=true ORDER BY $order"; + } + } + return $this->getData($sql_query); + } + + /******************************************************************** + * @brief Sieht in der DB nach ob ein Eintrag mit den Kriterien + * vorhanden ist. + * @param $studiensemester_kurzbz Studiensemester + * $lf Lehrfach + * + * @return true=Vorhanden, id des DS in $lvinfo_id false=Nicht vorhanden + ********************************************************************/ + function vorhanden($lf, $studiensemester_kurzbz, $sprache) + { + $sql_query = "SELECT * from tbl_lvinfo WHERE ". + "lehrfach_nr=$lf AND studiensemester_kurzbz='$studiensemester_kurzbz' AND sprache='$sprache' AND aktiv=true"; + $res=pg_exec($this->conn, $sql_query); + if(pg_numrows($res)>0) + { + $row=pg_fetch_object($res); + $this->lvinfo_id=$row->lvinfo_id; + return true; + } + else + { + return false; + } + } +} +?> \ No newline at end of file diff --git a/include/lv_verteilung.class.php b/include/lv_verteilung.class.php new file mode 100644 index 000000000..6d2f82b2a --- /dev/null +++ b/include/lv_verteilung.class.php @@ -0,0 +1,359 @@ +connection = $conn; + } + + function load($lv_id) + { + $sql_query = "SELECT * FROM tbl_lehrveranstaltung where lehrveranstaltung_id='$lv_id'"; + + $result = pg_exec($this->connection,$sql_query); + + if($row=pg_fetch_object($result)) + { + $this->lehrveranstaltung_id = $row->lehrveranstaltung_id; + $this->lvnr = $row->lvnr; + $this->einheit_kurzbz = $row->einheit_kurzbz; + $this->lektor = $row->lektor; + $this->lehrfach_nr = $row->lehrfach_nr; + $this->lehrform = $row->lehrform_kurzbz; + $this->studiengang_kz = $row->studiengang_kz; + $this->fachbereich_id = $row->fachbereich_id; + $this->semester = $row->semester; + $this->verband = $row->verband; + $this->gruppe = $row->gruppe; + $this->raumtyp = $row->raumtyp; + $this->raumtypalternativ = $row->raumtypalernativ; + $this->semesterstunden = $row->semesterstunden; + $this->stundenblockung = $row->stundenblockung; + $this->wochenrythmus = $row->wochenrythmus; + $this->start_kw = $row->start_kw; + $this->anmerkung = $row->anmerkung; + $this->studiensemester_kurzbz = $row->studiensemester_kurzbz; + $this->fas_id = $row->fas_id; + $this->unr = $row->unr; + $this->lehre = $row->lehre; + } + else + { + $this->errormsg = "Kein Datensatz mit dieser ID vorhanden"; + return false; + } + + return true; + } + + /******************************************************************** + * @brief Prüft ob die Variablen gültige Werte enthalten + * + * @return true=OK false=Fehler + ********************************************************************/ + function checkvars() + { + if(!is_numeric($this->semesterstunden)) + { + $this->errormsg = "Fehler: Semesterstunden muss eine Zahl sein"; + return false; + } + + if(!is_numeric($this->stundenblockung)) + { + $this->errormsg = "Fehler: Stundenblockung muss eine Zahl sein"; + return false; + } + + if(!is_numeric($this->wochenrythmus)) + { + $this->errormsg = "Fehler: Wochenrythmus muss eine Zahl sein"; + return false; + } + + if(strlen($this->lvnr)==0) + { + $this->errormsg = "Fehler: LVNR muss eingegeben werden"; + return false; + } + + if(!is_numeric($this->start_kw) AND strlen($this->start_kw)>0) + { + $this->errormsg = "Fehler: Start-KW muss eine Zahl sein"; + return false; + } + + return true; + } + + /******************************************************************** + * @brief Speichert die Daten in der Datenbank ab. Wenn new auf true + * gesetzt ist wird INSERT ausgeführt sonst UPDATE + * @param keine + * + * @return true=Ok false=Fehler + ********************************************************************/ + function save() + { + // Connection überprüfen + if (is_null($this->connection)) + { + $this->errormsg = "Fehler: Keine Datenbank connection vorhanden"; + return false; + } + + if ($this->new) { + $qry="INSERT INTO tbl_lehrveranstaltung(lvnr,unr,einheit_kurzbz,". + "lektor,lehrfach_nr,lehrform_kurzbz,studiengang_kz,fachbereich_id,semester,verband,". + "gruppe,raumtyp,raumtypalternativ,semesterstunden,stundenblockung,". + "wochenrythmus,start_kw,anmerkung,studiensemester_kurzbz,lehre)". + "values(". + "'".$this->lvnr."',". + (strlen($this->unr)>0?"'".$this->unr."'":'NULL').",". + (strlen($this->einheit_kurzbz)>0?"'".$this->einheit_kurzbz."'":'NULL').",". + "'".$this->lektor."',". + (strlen($this->lehrfach_nr)>0?$this->lehrfach_nr:'0').",". + "'".$this->lehrform."',". + (strlen($this->studiengang_kz)>0?$this->studiengang_kz:'0').",". + (strlen($this->fachbereich_id)>0?$this->fachbereich_id:'NULL').",". + (strlen($this->semester)>0?$this->semester:'NULL').",". + (strlen($this->verband)>0?"'".$this->verband."'":'NULL').",". + (strlen($this->gruppe)>0?"'".$this->gruppe."'":'NULL').",". + (strlen($this->raumtyp)>0?"'".$this->raumtyp."'":'0').",". + (strlen($this->raumtypalternativ)>0?"'".$this->raumtypalternativ."'":'NULL').",". + (strlen($this->semesterstunden)>0?$this->semesterstunden:'1').",". + (strlen($this->stundenblockung)>0?$this->stundenblockung:'1').",". + (strlen($this->wochenrythmus)>0?$this->wochenrythmus:'1').",". + (strlen($this->start_kw)>0?$this->start_kw:'NULL').",". + (strlen($this->anmerkung)>0?"'".$this->anmerkung."'":'NULL').",". + (strlen($this->studiensemester_kurzbz)>0?"'".$this->studiensemester_kurzbz."'":'0').",". + (($this->lehre=='on')?'true':'false'). + ")"; + } + else + { + $qry="UPDATE tbl_lehrveranstaltung ". + "SET lvnr='".$this->lvnr."',". + "unr=".(strlen($this->unr)>0?"'".$this->unr."'":'NULL').",". + "einheit_kurzbz=".(strlen($this->einheit_kurzbz)>0?"'".$this->einheit_kurzbz."'":'NULL').",". + "lektor='".$this->lektor."',". + "lehrfach_nr=".(strlen($this->lehrfach_nr)>0?$this->lehrfach_nr:'0').",". + "lehrform_kurzbz='".$this->lehrform."',". + "studiengang_kz=".(strlen($this->studiengang_kz)>0?$this->studiengang_kz:'0').",". + "fachbereich_id=".(strlen($this->fachbereich_id)>0?$this->fachbereich_id:'NULL').",". + "semester=".(strlen($this->semester)>0?$this->semester:'NULL').",". + "verband=".(strlen($this->verband)>0?"'".$this->verband."'":'NULL').",". + "gruppe=".(strlen($this->gruppe)>0?"'".$this->gruppe."'":'NULL').",". + "raumtyp=".(strlen($this->raumtyp)>0?"'".$this->raumtyp."'":'0').",". + "raumtypalternativ=".(strlen($this->raumtypalternativ)>0?"'".$this->raumtypalternativ."'":'NULL').",". + "semesterstunden=".(strlen($this->semesterstunden)>0?$this->semesterstunden:'1').",". + "stundenblockung=".(strlen($this->stundenblockung)>0?$this->stundenblockung:'1').",". + "wochenrythmus=".(strlen($this->wochenrythmus)>0?$this->wochenrythmus:'1').",". + "start_kw=".(strlen($this->start_kw)>0?$this->start_kw:'NULL').",". + "anmerkung=".(strlen($this->anmerkung)>0?"'".$this->anmerkung."'":'NULL').",". + "studiensemester_kurzbz=".(strlen($this->studiensemester_kurzbz)>0?"'".$this->studiensemester_kurzbz."'":'0').",". + "lehre=".(($this->lehre=='on')?'true':'false'). + " WHERE lehrveranstaltung_id='".$this->lehrveranstaltung_id."'"; + } + //echo $qry.':'.$this->lehre; + if($this->checkvars()) + { + if(!($erg=pg_exec($this->connection, $qry))) + { + $this->errormsg=pg_errormessage($this->connection); + return false; + } + } + else + { + return false; + } + return true; + } + + + + /******************************************************************** + * @brief Liefert die Datensätze aus der Tabelle tbl_lehrveranstaltung + * die zu diesen Kriterien passen + * @param $stsem Studiensemester / -1 wenn keines gewählt + * $sem Semester / -1 wenn keines gewählt + * $stg Studiengang / -1 wenn keiner gewählt + * $lektor Lektor / -1 wenn keiner gewählt + * @return $result=Array mit den Elementen false=Fehler + ********************************************************************/ + function getTab($stsem, $sem, $stg, $lektor, $order) + { + $sql_query="SELECT a.semester As sem,a.lehre as lvlehre, * FROM (SELECT * FROM public.tbl_lehrveranstaltung"; + $and = false; + + //Zusammenstöpseln des SQL Strings + if($lektor!=-1 OR $stsem!=-1 OR $stg!=-1) + { + $sql_query = $sql_query." WHERE"; + } + + //Zusammenstöpseln des SQL Strings + if($lektor!=-1) + { + $sql_query = $sql_query." lektor='$lektor'"; + $and=true; + } + + if($stsem!=-1) + { + if($and) + $sql_query = $sql_query." AND studiensemester_kurzbz='$stsem'"; + else + $sql_query = $sql_query." studiensemester_kurzbz='$stsem'"; + $and=true; + } + + if($stg!=-1) + { + if($sem!=-1) + { + if($and) + $sql_query = $sql_query." AND studiengang_kz='$stg' AND semester='$sem'"; + else + $sql_query = $sql_query." studiengang_kz='$stg' AND semester='$sem'"; + } + else + { + if($and) + $sql_query = $sql_query." AND studiengang_kz='$stg'"; + else + $sql_query = $sql_query." studiengang_kz='$stg'"; + } + } + + $sql_query = $sql_query.") AS a, tbl_lehrfach b WHERE a.lehrfach_nr=b.lehrfach_nr ORDER BY $order"; + //echo $sql_query; + + $result = pg_exec($this->connection,$sql_query); + $this->anz = pg_numrows($result); + while($row=pg_fetch_object($result)) + { + $lv = new lv_verteilung($connection); + $lv->lehrveranstaltung_id=$row->lehrveranstaltung_id; + $lv->lvnr = $row->lvnr; + $lv->einheit_kurzbz = $row->einheit_kurzbz; + $lv->lektor = $row->lektor; + $lv->lehrfach_nr = $row->lehrfach_nr; + $lv->lehrform = $row->lehrform_kurzbz; + $lv->studiengang_kz = $row->studiengang_kz; + $lv->fachbereich_id = $row->fachbereich_id; + $lv->semester = $row->sem; + $lv->verband = $row->verband; + $lv->gruppe = $row->gruppe; + $lv->raumtyp = $row->raumtyp; + $lv->raumtypalternativ = $row->raumtypalternativ; + $lv->semesterstunden = $row->semesterstunden; + $lv->stundenblockung = $row->stundenblockung; + $lv->wochenrythmus = $row->wochenrythmus; + $lv->start_kw = $row->start_kw; + $lv->anmerkung = $row->anmerkung; + $lv->studiensemester_kurzbz = $row->studiensemester_kurzbz; + $lv->fas_id = $row->fas_id; + $lv->unr = $row->unr; + $lv->lehrfach_kurzbz = $row->kurzbz; + $lv->lehrevz = $row->lehrevz; + $lv->lehre = $row->lvlehre; + $lv->lehrfach_bz = $row->bezeichnung; + $this->retwert[] = $lv; + } + + if($this->anz>0) + return true; + else + return false; + } +} \ No newline at end of file diff --git a/include/mailgrp.class.php b/include/mailgrp.class.php new file mode 100644 index 000000000..5e7c1d284 --- /dev/null +++ b/include/mailgrp.class.php @@ -0,0 +1,84 @@ +conn=$conn; + + } + + /** + * Verbindung zur Datenbank herstellen + * @return PostgreSQL-Connection oder NULL + + function getConnection() { + if (!$conn = @pg_pconnect(CONN_STRING)) { + $this->errormsg="Es konnte keine Verbindung zum Server ". + "aufgebaut werden."; + return null; + } + return $conn; + }*/ + + /** + * Liefert alle Elemente der tbl_mailgrp + * @param studiengang_kz + * @return true wenn OK false wenn Fehler + */ + function getAll($studiengang_kz='') + { + if (is_null($this->conn)) { + $this->errormsg = "Keine Connection vorhanden"; + return false; + } + if (strlen($this->studiengang_kz)>0) + { + $where=" where studiengang_kz='".$studiengang_kz."' "; + } else + { + $where=""; + } + $qry="select * FROM tbl_mailgrp". + "$where order by mailgrp_kurzbz"; + if(!($erg=pg_exec($this->conn, $qry))) { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + + + while($row=pg_fetch_object($erg)) + { + $l=new mailgrp($this->conn); + $l->mailgrp_kurzbz = $row->mailgrp_kurzbz; + $l->studiengang_kz = $row->studiengang_kz; + $l->beschreibung = $row->beschreibung; + $l->aktiv = $row->aktiv; + $l->generiert = $row->generiert; + $l->sichtbar = $row->sichtbar; + $result[]=$l; + } + return $result; + } +} +?> \ No newline at end of file diff --git a/include/mitarbeiter.class.php b/include/mitarbeiter.class.php new file mode 100644 index 000000000..66bc84b5c --- /dev/null +++ b/include/mitarbeiter.class.php @@ -0,0 +1,362 @@ +conn=$conn; + if (strlen($uid)>0) { + $this->uid=$uid; + $this->load(); + } + } + + /** + * @return boolean true=ok, false=fehler + */ + function save() + { + global $auth; + // uid vorhanden? + if (strlen($this->uid)==0) { + $this->errormsg='uid nicht gesetzt.'; + return false; + } + // Connection holen + if (is_null($conn=person::getConnection())) { + return false; + } + // Daten zur Person speichern + + if (!person::save()) { + $this->errormsg.="
    Daten zur Person konnten nicht gespeichert werden."; + return false; + } + if ($this->new) { + $qry="INSERT INTO tbl_mitarbeiter(uid,personalnummer,kurzbz,". + "lektor,fixangestellt,telefonklappe,updateamum,updatevon, ort_kurzbz)". + "values(". + "'".$this->uid."',". + "'".$this->personalnummer."',". + "'".$this->kurzbz."','". + ($this->lektor?'t':'f')."','". + ($this->fixangestellt?'t':'f')."',". + "'".$this->telefonklappe."',". + "now(),'".$_SERVER['PHP_AUTH_USER']."', ".($this->ort_kurzbz!='0'?"'$this->ort_kurzbz'":'NULL'). + ")"; + } else + { + $qry="UPDATE tbl_mitarbeiter ". + "SET personalnummer='".$this->personalnummer."',". + "kurzbz='".$this->kurzbz."',". + "lektor='".($this->lektor?'t':'f')."',". + "fixangestellt='".($this->fixangestellt?'t':'f')."',". + "telefonklappe='".$this->telefonklappe."',". + "updateamum=now(),updatevon='".$_SERVER['PHP_AUTH_USER']."', ort_kurzbz=".($this->ort_kurzbz!='0'?"'$this->ort_kurzbz'":'NULL'). + " WHERE uid='".$this->uid."'"; + } + //echo "
    ".$qry; + if(!($erg=pg_exec($conn, $qry))) + { + $this->errormsg=pg_errormessage($conn); + return false; + } + return true; + } + + /** + * Ladet die Attribute des Studenten aus der Datenbank. Bei Fehler ist der + * Rueckgabewert 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true=ok, false=fehler + */ + function load($uid='') + { + // optional: uid setzen + if (strlen($uid)>0) + $this->uid=$uid; + // uid vorhanden? + if (strlen($this->uid)==0) { + $this->errormsg='uid nicht gesetzt.'; + return false; + } + // Connection holen + if (is_null($conn=person::getConnection())) { + return false; + } + // Daten zur Person laden + if (!person::load()) { + $this->errormsg.="
    Daten zur Person konnten nicht geladen werden."; + return false; + } + // MA-Daten holen + $sql_query="SELECT m.personalnummer,m.kurzbz,m.lektor,m.fixangestellt,m.telefonklappe,m.updateamum,m.updatevon, m.ort_kurzbz ". + "FROM tbl_mitarbeiter as m ". + "WHERE uid='".$this->uid."'"; + if(!($erg=pg_exec($conn, $sql_query))) + die(pg_errormessage($conn)); + $num_rows=pg_numrows($erg); + if($num_rows!=1) { + $this->errormsg="Zuwenige oder zuviele Ergebnisse (Anzahl: $num_rows)!"; + return false; + } + $row=pg_fetch_object($erg,0); + + $this->personalnummer=$row->personalnummer; + $this->kurzbz=$row->kurzbz; + $this->lektor=$row->lektor=='t'?true:false; + $this->fixangestellt=$row->fixangestellt=='t'?true:false; + $this->telefonklappe=$row->telefonklappe; + $this->updateamum=$row->updateamum; + $this->updatevon=$row->updatevon; + $this->ort_kurzbz=$row->ort_kurzbz; + + + return true; + } + + /** + * Loescht den Mitarbeiter aus der Datenbank. Bei Fehler ist der Rueckgabewert + * 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true=ok, false=fehler + * vererbt, wenn Person gelöscht wird, sollte wahrscheinlich auch + * automatisch der Eintrag in den anderen Tabellen gelöscht werden + */ + /* + function delete() + { + if (is_null($conn=$this->getConnection())) { + return false; + } + + + return true; + }*/ + + /** + * gibt array mit allen Lektoren zurück + * @return array mit Lektoren + */ + function getLektoren() + { + if (is_null($conn=$this->getConnection())) + { + return false; + } + $sql_query="set datestyle to german;SELECT tbl_person.*,". + "m.personalnummer,m.kurzbz,m.lektor,m.fixangestellt,m.telefonklappe, m.ort_kurzbz ". + "FROM tbl_person join tbl_mitarbeiter as m using(uid) ". + "WHERE m.lektor=true ". + "ORDER by upper(tbl_person.nachname),upper(tbl_person.vornamen)"; + if(!($erg=@pg_exec($conn, $sql_query))) { + $this->errormsg=pg_errormessage($conn); + return false; + } + $num_rows=pg_numrows($erg); + $result=array(); + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + $l=new mitarbeiter($this->conn); + // Personendaten + $l->uid=$row->uid; + $l->titel=$row->titel; + $l->vornamen=$row->vornamen; + $l->nachname=$row->nachname; + $l->gebdatum=$row->gebdatum; + $l->gebort=$row->gebort; + $l->gebzeit=$row->gebzeit; + $l->foto=$row->foto; + $l->anmerkungen=$row->anmerkungen; + $l->aktiv=$row->aktiv=='t'?true:false; + $l->email=$row->email; + $l->homepage=$row->homepage; + $l->updateamum=$row->updateamum; + $l->updatevon=$row->updatevon; + // Lektorendaten + $l->personalnummer=$row->personalnummer; + $l->kurzbz=$row->kurzbz; + $l->lektor=$row->lektor=='t'?true:false; + $l->fixangestellt=$row->fixangestellt=='t'?true:false; + $l->telefonklappe=$row->telefonklappe; + $l->ort_kurzbz=$row->ort_kurzbz; + // Lektor in Array speichern + $result[]=$l; + } + return $result; + } + + /** + * gibt array mit allen Mitarbeitern zurück + * @param $order gibt die spalte an nach der Sortiert werden soll + * @return array mit MA + */ + function getAll($order='upper(tbl_person.nachname),upper(tbl_person.vornamen)') + { + if (is_null($conn=$this->getConnection())) + { + return false; + } + $sql_query="set datestyle to german;SELECT tbl_person.*,". + "m.personalnummer,m.kurzbz,m.lektor,m.fixangestellt,m.telefonklappe, m.ort_kurzbz ". + "FROM tbl_person join tbl_mitarbeiter as m using(uid) ". + "ORDER by $order"; + if(!($erg=@pg_exec($conn, $sql_query))) + { + $this->errormsg=pg_errormessage($conn); + return false; + } + $num_rows=pg_numrows($erg); + $result=array(); + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + $l=new mitarbeiter($this->conn); + // Personendaten + $l->uid=$row->uid; + $l->titel=$row->titel; + $l->vornamen=$row->vornamen; + $l->nachname=$row->nachname; + $l->gebdatum=$row->gebdatum; + $l->gebort=$row->gebort; + $l->gebzeit=$row->gebzeit; + $l->foto=$row->foto; + $l->anmerkungen=$row->anmerkungen; + $l->aktiv=$row->aktiv=='t'?true:false; + $l->email=$row->email; + $l->homepage=$row->homepage; + $l->updateamum=$row->updateamum; + $l->updatevon=$row->updatevon; + // Lektorendaten + $l->personalnummer=$row->personalnummer; + $l->kurzbz=$row->kurzbz; + $l->lektor=($row->lektor=='t'?'true':'false'); + $l->fixangestellt=($row->fixangestellt=='t'?'true':'false'); + $l->telefonklappe=$row->telefonklappe; + $l->ort_kurzbz=$row->ort_kurzbz; + // MA in Array speichern + $result[]=$l; + } + return $result; + + } + + /** + * gibt array mit allen Mitarbeitern zurueck + * @return array mit Mitarbeitern + */ + function getMitarbeiter($lektor=true,$fixangestellt=null,$stg_kz=null,$fachbereich_id=null) + { + if (is_null($conn=$this->getConnection())) + { + return false; + } + $sql_query='SELECT DISTINCT vw_mitarbeiter.* FROM vw_mitarbeiter + LEFT OUTER JOIN tbl_personfunktion USING(uid) + WHERE'; + if (!$lektor) + $sql_query.=' NOT'; + $sql_query.=' lektor'; + if ($fixangestellt!=null) + { + $sql_query.=' AND'; + if (!$fixangestellt) + $sql_query.=' NOT'; + $sql_query.=' fixangestellt'; + } + if ($stg_kz!=null) + $sql_query.=' AND studiengang_kz='.$stg_kz; + if ($fachbereich_id!=null) + $sql_query.=' AND fachbereich_id='.$fachbereich_id; + $sql_query.=' ORDER BY nachname, vornamen, kurzbz'; + //echo $sql_query; + if(!($erg=@pg_query($conn, $sql_query))) + { + $this->errormsg=pg_errormessage($conn); + return false; + } + $num_rows=pg_numrows($erg); + $result=array(); + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + $l=new mitarbeiter($this->conn); + // Personendaten + $l->uid=$row->uid; + $l->titel=$row->titel; + $l->vornamen=$row->vornamen; + $l->nachname=$row->nachname; + $l->gebdatum=$row->gebdatum; + $l->gebort=$row->gebort; + $l->gebzeit=$row->gebzeit; + $l->foto=$row->foto; + $l->anmerkungen=$row->anmerkungen; + $l->aktiv=$row->aktiv=='t'?true:false; + $l->email=$row->email; + $l->homepage=$row->homepage; + $l->updateamum=$row->updateamum; + $l->updatevon=$row->updatevon; + // Lektorendaten + $l->personalnummer=$row->personalnummer; + $l->kurzbz=$row->kurzbz; + $l->lektor=$row->lektor=='t'?true:false; + $l->fixangestellt=$row->fixangestellt=='t'?true:false; + $l->telefonklappe=$row->telefonklappe; + //$l->ort_kurzbz=$row->ort_kurzbz; + // Lektor in Array speichern + $result[]=$l; + } + return $result; + } +} +?> \ No newline at end of file diff --git a/include/pdf.inc.php b/include/pdf.inc.php new file mode 100644 index 000000000..04608593b --- /dev/null +++ b/include/pdf.inc.php @@ -0,0 +1,191 @@ +FPDF($orientation,$unit,$format); + //Initialization + $this->B=0; + $this->I=0; + $this->U=0; + $this->HREF=''; + } + + /** + * gibt eine Fusszeile aus + * + */ + function Footer() + { + // Check if Footer for this page already exists (do the same for Header()) + if(!$this->footerset[$this->page]) { + $this->SetY(-30); + //Page number + $this->Cell(0,10,'Seite '.$this->PageNo().'/{nb}',0,0,'C'); + // set footerset + $this->footerset[$this->page] = 1; + } + } + + /** + * gibt eine Kopfzeile aus + * + */ + function Header() + { + // Check if Header for this page already exists (do the same for Footer()) + if(!$this->headerset[$this->page]) { + $this->SetFont('Arial','B',10); + $this->SetY(25); + //Page number + $this->Cell(0,10,'',0,0,'C'); + // set headerset + $this->SetY(100); + $this->headerset[$this->page] = 1; + } + } + + /** + * Erzeugt eine Tabelle + * @param $datas Array - 1. Zeile = Spaltenueberschrift + * x. Zeile = Eintraege + * $lineheight Zeilenhoehe + * $aligns Array - enthaelt die ausrichtung der Spalten (L=Left,R=Right,C=Center) + */ + function morepagestable($datas,$lineheight=12,$aligns) + { + // some things to set and 'remember' + $l = $this->lMargin; + $startheight = $h = $this->GetY(); + $startpage = $currpage = $this->page; + + // calculate the whole width + foreach($this->tablewidths AS $width) + { + $fullwidth += $width; + } + + // Now let's start to write the table + $r=0; + $markline=false; + foreach($datas AS $row => $data) + { + $this->page = $currpage; + // write the horizontal borders + if($r<=1) + { + $this->SetLineWidth(1.5); + $this->Line($l,$h,$fullwidth+$l,$h); + } + else + { + //$this->SetLineWidth(0.001); + //$this->Line($l,$h,$fullwidth+$l,$h); NO-Line + } + + //Farben fuer die zeilenmarkierung setzen + if($markline) + $this->SetFillColor(230,230,230); + else + $this->SetFillColor(255,255,255); + + $markline=!$markline; + + // write the content and remember the height of the highest col + foreach($data AS $col => $txt) + { + $this->page = $currpage; + $this->SetXY($l,$h); + $align=($r==0)?'C':$aligns[$col]; + if($r==0) $this->SetFont('Arial','B',$lineheight-2); + else $this->SetFont('Arial','',$lineheight-2); + + //erste und zweite zeile nicht fuellen da sonst der rahmen verloren geht + if($row==0) + $this->MultiCell($this->tablewidths[$col],$lineheight,$txt,0,$align,0); + else + $this->MultiCell($this->tablewidths[$col],$lineheight,$txt,0,$align,1); + + $l += $this->tablewidths[$col]; + + if($tmpheight[$row.'-'.$this->page] < $this->GetY()) + { + $tmpheight[$row.'-'.$this->page] = $this->GetY(); + } + if($this->page > $maxpage) + $maxpage = $this->page; + } + + // get the height we were in the last used page + $h = $tmpheight[$row.'-'.$maxpage]; + // set the "pointer" to the left margin + $l = $this->lMargin; + // set the $currpage to the last page + $currpage = $maxpage; + $r++; + } + // draw the borders + // we start adding a horizontal line on the last page + $this->page = $maxpage; + $this->SetLineWidth(1.5); + //Immer gleich + if($h<=660) + $h=660; + else + $h=810; + + $this->Line($l,$h,$fullwidth+$l,$h); + // now we start at the top of the document and walk down + for($i = $startpage; $i <= $maxpage; $i++) + { + $this->page = $i; + $l = $this->lMargin; + $t = ($i == $startpage) ? $startheight : $this->tMargin; + $lh = ($i == $maxpage) ? $h : $this->h-$this->bMargin; + $this->SetLineWidth(1.5); + $this->Line($l,$t,$l,$lh); + $n=0; + $maxcol=count($this->tablewidths)-1; + foreach($this->tablewidths AS $width) + { + $l += $width; + if($n==$maxcol) $this->SetLineWidth(1.5); + else $this->SetLineWidth(0.5); + $this->Line($l,$t,$l,$lh); + $n++; + } + } + // set it to the last page, if not it'll cause some problems + $this->page = $maxpage; + $this->SetY($h); + } + +} +?> \ No newline at end of file diff --git a/include/pdf/FAQ.htm b/include/pdf/FAQ.htm new file mode 100644 index 000000000..6cabb39dc --- /dev/null +++ b/include/pdf/FAQ.htm @@ -0,0 +1,286 @@ + + + +FAQ + + + +

    FAQ

    +1. What's exactly the license of FPDF? Are there any usage restrictions?
    +2. When I try to create a PDF, a lot of weird characters show on the screen. Why?
    +3. I try to generate a PDF and IE displays a blank page. What happens?
    +4. I send parameters using the POST method and the values don't appear in the PDF.
    +5. When I use a PHP session, IE doesn't display my PDF any more but asks me to download it.
    +6. When I'm on SSL, IE can't open the PDF.
    +7. When I execute a script I get the message "FPDF error: Don't alter the locale before including class file".
    +8. I try to put a PNG and Acrobat says "There was an error processing a page. A drawing error occurred".
    +9. I encounter the following error when I try to generate a PDF: Warning: Cannot add header information - headers already sent by (output started at script.php:X)
    +10. I try to display a variable in the Header method but nothing prints.
    +11. I defined the Header and Footer methods in my PDF class but nothing appears.
    +12. I can't make line breaks work. I put \n in the string printed by MultiCell but it doesn't work.
    +13. I try to put the euro symbol but it doesn't work.
    +14. I draw a frame with very precise dimensions, but when printed I notice some differences.
    +15. I'd like to use the whole surface of the page, but when printed I always have some margins. How can I get rid of them?
    +16. What's the limit of the file sizes I can generate with FPDF?
    +17. Can I modify a PDF with FPDF?
    +18. I'd like to make a search engine in PHP and index PDF files. Can I do it with FPDF?
    +19. Can I convert an HTML page to PDF with FPDF?
    +20. Can I concatenate PDF files with FPDF?
    +

    +

    1. What's exactly the license of FPDF? Are there any usage restrictions?

    +FPDF is Freeware (it is stated at the beginning of the source file). There is no usage +restriction. You may embed it freely in your application (commercial or not), with or +without modification. You may redistribute it, too. +

    2. When I try to create a PDF, a lot of weird characters show on the screen. Why?

    +These "weird" characters are in fact the actual content of your PDF. This behaviour is a bug of +IE. When it first receives an HTML page, then a PDF from the same URL, it displays it directly +without launching Acrobat. This happens frequently during the development stage: on the least +script error, an HTML page is sent, and after correction, the PDF arrives. +
    +To solve the problem, simply quit and restart IE. You can also go to another URL and come +back. +
    +To avoid this kind of inconvenience during the development, you can generate the PDF directly +to a file and open it through the explorer. +

    3. I try to generate a PDF and IE displays a blank page. What happens?

    +First of all, check that you send nothing to the browser after the PDF (not even a space or a +carriage return). You can put an exit statement just after the call to the Output() method to +be sure. +
    +If it still doesn't work, it means you're a victim of the "blank page syndrome". IE used in +conjunction with the Acrobat plug-in suffers from numerous bugs, in all versions. You should +test your application with as many IE versions as possible (at least if you're on the Internet). +The problem occurs mostly with the POST method, so it is strongly advised to avoid it (all the +more that it causes other problems, see the next question). The GET works better but may fail +when the URL becomes too long: don't use a query string with more than 45 characters. However, a +tip exists to exceed this limit: end the URL with .pdf, which tricks IE. If you use a form, you +can add a hidden field at the last position: +
    +
    +
    + +<INPUT TYPE="HIDDEN" NAME="ext" VALUE=".pdf"> + +

    +The usage of PHP sessions also often causes trouble (avoid using HTTP headers preventing caching). +See question 5 for a workaround. +
    +
    +To avoid all these problems in a reliable manner, two main techniques exist: +
    +
    +- Disable the plug-in and use Acrobat as a helper application. To do this, launch Acrobat; in +the File menu, Preferences, General, uncheck the option "Web Browser Integration" (for Acrobat +5: Edit, Preferences, Options, "Display PDF in Browser"). Then, the next time you load a PDF in +IE, it displays the dialog box "Open it" or "Save it to disk". Uncheck the option "Always ask +before opening this type of file" and choose Open. From now on, PDF files will open +automatically in an external Acrobat window. +
    +The drawback of the method is that you need to alter the client configuration, which you can do +in an intranet environment but not for the Internet. +
    +
    +- Use a redirection technique. It consists in generating the PDF in a temporary file on the +server and redirect the client on it (by using JavaScript, not the Location HTTP header which +also causes trouble). For instance, at the end of the script, you can put the following: +
    +
    +
    + +//Determine a temporary file name in the current directory
    +$file=basename(tempnam(getcwd(),'tmp'));
    +//Save PDF to file
    +$pdf->Output($file);
    +//JavaScript redirection
    +echo "<HTML><SCRIPT>document.location='getpdf.php?f=$file';</SCRIPT></HTML>"; +
    +

    +Then create the getpdf.php file with this: +
    +
    +
    + +<?php
    +$f=$HTTP_GET_VARS['f'];
    +//Check file (don't skip it!)
    +if(substr($f,0,3)!='tmp' or strpos($f,'/') or strpos($f,'\\'))
    +    die('Incorrect file name');
    +if(!file_exists($f))
    +    die('File does not exist');
    +//Handle special IE request if needed
    +if($HTTP_SERVER_VARS['HTTP_USER_AGENT']=='contype')
    +{
    +    Header('Content-Type: application/pdf');
    +    exit;
    +}
    +//Output PDF
    +Header('Content-Type: application/pdf');
    +Header('Content-Length: '.filesize($f));
    +readfile($f);
    +//Remove file
    +unlink($f);
    +exit;
    +?> +
    +

    +This method works in most cases but IE6 can still experience trouble. The "ultimate" method +consists in redirecting directly to the temporary file. The file name must therefore end with .pdf: +
    +
    +
    + +//Determine a temporary file name in the current directory
    +$file=basename(tempnam(getcwd(),'tmp'));
    +rename($file,$file.'.pdf');
    +$file.='.pdf';
    +//Save PDF to file
    +$pdf->Output($file);
    +//JavaScript redirection
    +echo "<HTML><SCRIPT>document.location='$file';</SCRIPT></HTML>"; +
    +

    +This method turns the dynamic PDF into a static one and avoids all troubles. But you have to do +some cleaning in order to delete the temporary files. For instance: +
    +
    +
    + +function CleanFiles($dir)
    +{
    +    //Delete temporary files
    +    $t=time();
    +    $h=opendir($dir);
    +    while($file=readdir($h))
    +    {
    +        if(substr($file,0,3)=='tmp' and substr($file,-4)=='.pdf')
    +        {
    +            $path=$dir.'/'.$file;
    +            if($t-filemtime($path)>3600)
    +                @unlink($path);
    +        }
    +    }
    +    closedir($h);
    +} +
    +

    +This function deletes all files of the form tmp*.pdf older than an hour in the specified +directory. You may call it where you want, for instance in the script which generates the PDF. +
    +
    +Remark: it is necessary to open the PDF in a new window, as you can't go backwards due to the +redirection. +

    4. I send parameters using the POST method and the values don't appear in the PDF.

    +It's a problem affecting some versions of IE (especially the first 5.5). See the previous +question for the ways to work around it. +

    5. When I use a PHP session, IE doesn't display my PDF any more but asks me to download it.

    +It's a problem affecting some versions of IE. To work around it, add the following line before +session_start(): +
    +
    +
    + +session_cache_limiter('private'); + +

    +or do a redirection as explained in question 3. +

    6. When I'm on SSL, IE can't open the PDF.

    +The problem may be fixed by adding this line:
    +
    +
    + +Header('Pragma: public'); + +

    + +

    7. When I execute a script I get the message "FPDF error: Don't alter the locale before including class file".

    +When the decimal separator is configured as a comma before including a file, there is a +bug in some PHP versions and decimal +numbers get truncated. Therefore you shouldn't make a call to setlocale() before including the class. +On Unix, you shouldn't set the LC_ALL environment variable neither, for it is equivalent to a +setlocale() call. +

    8. I try to put a PNG and Acrobat says "There was an error processing a page. A drawing error occurred".

    +Acrobat 5 has a bug and is unable to display transparent monochrome images (i.e. with 1 bit per +pixel). Remove transparency or save your image in 16 colors (4 bits per pixel) or more. +

    9. I encounter the following error when I try to generate a PDF: Warning: Cannot add header information - headers already sent by (output started at script.php:X)

    +You must send nothing to the browser except the PDF itself: no HTML, no space, no carriage return, +neither before nor after. The script outputs something at line X. +

    10. I try to display a variable in the Header method but nothing prints.

    +You have to use the global keyword, for instance: +
    +
    +
    + +function Header()
    +{
    +    global $title;
    +
    +    $this->SetFont('Arial','B',15);
    +    $this->Cell(0,10,$title,1,1,'C');
    +} +
    +

    + +

    11. I defined the Header and Footer methods in my PDF class but nothing appears.

    +You have to create an object from the PDF class, not FPDF:
    +
    +
    + +$pdf=new PDF(); + +

    + +

    12. I can't make line breaks work. I put \n in the string printed by MultiCell but it doesn't work.

    +You have to enclose your string with double quotes, not single ones. +

    13. I try to put the euro symbol but it doesn't work.

    +The standard fonts have the euro character at position 128. You can define a constant like this +for convenience: +
    +
    +
    + +define('EURO',chr(128)); + +

    +Note: Acrobat 4 or higher is required to display euro. +

    14. I draw a frame with very precise dimensions, but when printed I notice some differences.

    +To respect dimensions, you have to uncheck the option "Fit to page" in the print dialog box. +

    15. I'd like to use the whole surface of the page, but when printed I always have some margins. How can I get rid of them?

    +All printers have physical margins (different depending on the model), it is therefore impossible +to remove them and print on the totality of the paper. +

    16. What's the limit of the file sizes I can generate with FPDF?

    +There is no particular limit. There are some constraints however: +
    +
    +- The maximum memory size allocated to PHP scripts defaults to 8MB. For very big documents, +especially with images, this limit may be reached (the file being built into memory). The +parameter is configured in the php.ini file. +
    +
    +- The maximum execution time allocated defaults to 30 seconds. This limit can of course be easily +reached. It is configured in php.ini and may be altered dynamically with set_time_limit(). +
    +
    +- Browsers generally have a 5 minute time-out. If you send the PDF directly to the browser and +reach the limit, it will be lost. It is therefore advised for very big documents to +generate them in a file, and to send some data to the browser from time to time (for instance +page 1, page 2... with flush() to force the output). When the document is finished, you can send +a redirection on it with JavaScript or create a link. +
    +Remark: even when the browser goes in time-out, the script may continue to run on the server. +

    17. Can I modify a PDF with FPDF?

    +No. +

    18. I'd like to make a search engine in PHP and index PDF files. Can I do it with FPDF?

    +No. But a GPL C utility does exist, pdftotext, which is able to extract the textual content from +a PDF. It is provided with the Xpdf package:
    +
    +http://www.foolabs.com/xpdf/ +

    19. Can I convert an HTML page to PDF with FPDF?

    +No. But a GPL C utility does exist, htmldoc, which allows to do it and gives good results:
    +
    +http://www.easysw.com/htmldoc/ +

    20. Can I concatenate PDF files with FPDF?

    +No. But a free C utility exists to perform this task:
    +
    +http://thierry.schmit.free.fr/dev/mbtPdfAsm/enMbtPdfAsm2.html + + diff --git a/include/pdf/doc/acceptpagebreak.htm b/include/pdf/doc/acceptpagebreak.htm new file mode 100644 index 000000000..eb40f2b52 --- /dev/null +++ b/include/pdf/doc/acceptpagebreak.htm @@ -0,0 +1,70 @@ + + + +AcceptPageBreak + + + +

    AcceptPageBreak

    +boolean AcceptPageBreak() +

    Version

    +1.4 +

    Description

    +Whenever a page break condition is met, the method is called, and the break is issued or not +depending on the returned value. The default implementation returns a value according to the +mode selected by SetAutoPageBreak(). +
    +This method is called automatically and should not be called directly by the application. +

    Example

    +The method is overriden in an inherited class in order to obtain a 3 column layout: +
    +
    +
    + +class PDF extends FPDF
    +{
    +var $col=0;
    +
    +function SetCol($col)
    +{
    +    //Move position to a column
    +    $this->col=$col;
    +    $x=10+$col*65;
    +    $this->SetLeftMargin($x);
    +    $this->SetX($x);
    +}
    +
    +function AcceptPageBreak()
    +{
    +    if($this->col<2)
    +    {
    +        //Go to next column
    +        $this->SetCol($this->col+1);
    +        $this->SetY(10);
    +        return false;
    +    }
    +    else
    +    {
    +        //Go back to first column and issue page break
    +        $this->SetCol(0);
    +        return true;
    +    }
    +}
    +}
    +
    +$pdf=new PDF();
    +$pdf->Open();
    +$pdf->AddPage();
    +$pdf->SetFont('Arial','',12);
    +for($i=1;$i<=300;$i++)
    +    $pdf->Cell(0,5,"Line $i",0,1);
    +$pdf->Output(); +
    +

    +

    See also

    +SetAutoPageBreak(). +
    +
    + + + diff --git a/include/pdf/doc/addfont.htm b/include/pdf/doc/addfont.htm new file mode 100644 index 000000000..4912f5e1b --- /dev/null +++ b/include/pdf/doc/addfont.htm @@ -0,0 +1,62 @@ + + + +AddFont + + + +

    AddFont

    +AddFont(string family [, string style [, string file]]) +

    Version

    +1.5 +

    Description

    +Imports a TrueType or Type1 font and makes it available. It is necessary to generate a font +definition file first with the makefont.php utility. +
    +The definition file (and the font file itself when embedding) must be present either in the +current directory or in the one indicated by FPDF_FONTPATH if the constant is defined. +If it could not be found, the error "Could not include font definition file" is generated. +

    Parameters

    +family +
    +Font family. The name can be chosen arbitrarily. If it is a standard family name, it will +override the corresponding font. +
    +style +
    +Font style. Possible values are (case insensitive): +
      +
    • empty string: regular +
    • B: bold +
    • I: italic +
    • BI or IB: bold italic +
    +The default value is regular. +
    +file +
    +The font definition file. +
    +By default, the name is built from the family and style, in lower case with no space. +
    +

    Example

    +
    + +$pdf->AddFont('Comic','I'); + +

    +is equivalent to: +
    +
    +
    + +$pdf->AddFont('Comic','I','comici.php'); + +

    +

    See also

    +SetFont(). +
    +
    + + + diff --git a/include/pdf/doc/addlink.htm b/include/pdf/doc/addlink.htm new file mode 100644 index 000000000..1763ebf62 --- /dev/null +++ b/include/pdf/doc/addlink.htm @@ -0,0 +1,28 @@ + + + +AddLink + + + +

    AddLink

    +int AddLink() +

    Version

    +1.5 +

    Description

    +Creates a new internal link and returns its identifier. An internal link is a clickable area +which directs to another place within the document. +
    +The identifier can then be passed to Cell(), Write(), Image() or Link(). The destination is +defined with SetLink(). +

    See also

    +Cell(), +Write(), +Image(), +Link(), +SetLink(). +
    +
    + + + diff --git a/include/pdf/doc/addpage.htm b/include/pdf/doc/addpage.htm new file mode 100644 index 000000000..6f8b4c526 --- /dev/null +++ b/include/pdf/doc/addpage.htm @@ -0,0 +1,42 @@ + + + +AddPage + + + +

    AddPage

    +AddPage([string orientation]) +

    Version

    +1.0 +

    Description

    +Adds a new page to the document. If a page is already present, the Footer() method is called +first to output the footer. Then the page is added, the current position set to the top-left +corner according to the left and top margins, and Header() is called to display the header. +
    +The font which was set before calling is automatically restored. There is no need to call +SetFont() again if you want to continue with the same font. The same is true for colors and +line width. +
    +The origin of the coordinate system is at the top-left corner and increasing ordinates go +downwards. +

    Parameters

    +orientation +
    +Page orientation. Possible values are (case insensitive): +
      +
    • P or Portrait +
    • L or Landscape +
    +The default value is the one passed to the constructor. +
    +

    See also

    +FPDF(), +Header(), +Footer(), +SetMargins(). +
    +
    + + + diff --git a/include/pdf/doc/aliasnbpages.htm b/include/pdf/doc/aliasnbpages.htm new file mode 100644 index 000000000..8e1759e07 --- /dev/null +++ b/include/pdf/doc/aliasnbpages.htm @@ -0,0 +1,47 @@ + + + +AliasNbPages + + + +

    AliasNbPages

    +AliasNbPages([string alias]) +

    Version

    +1.4 +

    Description

    +Defines an alias for the total number of pages. It will be substituted as the document is +closed. +

    Parameters

    +alias +
    +The alias. Default value: {nb}. +
    +

    Example

    +
    + +class PDF extends FPDF
    +{
    +function Footer()
    +{
    +    //Go to 1.5 cm from bottom
    +    $this->SetY(-15);
    +    //Select Arial italic 8
    +    $this->SetFont('Arial','I',8);
    +    //Print current and total page numbers
    +    $this->Cell(0,10,'Page '.$this->PageNo().'/{nb}',0,0,'C');
    +}
    +}
    +
    +$pdf=new PDF();
    +$pdf->AliasNbPages(); +
    +

    +

    See also

    +PageNo(), +Footer(). +
    +
    + + + diff --git a/include/pdf/doc/cell.htm b/include/pdf/doc/cell.htm new file mode 100644 index 000000000..1f8dabd1d --- /dev/null +++ b/include/pdf/doc/cell.htm @@ -0,0 +1,106 @@ + + + +Cell + + + +

    Cell

    +Cell(float w [, float h [, string txt [, mixed border [, int ln [, string align [, int fill [, mixed link]]]]]]]) +

    Version

    +1.0 +

    Description

    +Prints a cell (rectangular area) with optional borders, background color and character string. +The upper-left corner of the cell corresponds to the current position. The text can be aligned +or centered. After the call, the current position moves to the right or to the next line. It is +possible to put a link on the text. +
    +If automatic page breaking is enabled and the cell goes beyond the limit, a page break is +done before outputting. +

    Parameters

    +w +
    +Cell width. If 0, the cell extends up to the right margin. +
    +h +
    +Cell height. +Default value: 0. +
    +txt +
    +String to print. +Default value: empty string. +
    +border +
    +Indicates if borders must be drawn around the cell. The value can be either a number: +
      +
    • 0: no border +
    • 1: frame +
    +or a string containing some or all of the following characters (in any order): +
      +
    • L: left +
    • T: top +
    • R: right +
    • B: bottom +
    +Default value: 0. +
    +ln +
    +Indicates where the current position should go after the call. Possible values are: +
      +
    • 0: to the right +
    • 1: to the beginning of the next line +
    • 2: below +
    +Putting 1 is equivalent to putting 0 and calling Ln() just after. +Default value: 0. +
    +align +
    +Allows to center or align the text. Possible values are: +
      +
    • L or empty string: left align (default value) +
    • C: center +
    • R: right align +
    +
    +fill +
    +Indicates if the cell background must be painted (1) or transparent (0). +Default value: 0. +
    +link +
    +URL or identifier returned by AddLink(). +
    +

    Example

    +
    + +//Set font
    +$pdf->SetFont('Arial','B',16);
    +//Move to 8 cm to the right
    +$pdf->Cell(80);
    +//Centered text in a framed 20*10 mm cell and line break
    +$pdf->Cell(20,10,'Title',1,1,'C'); +
    +

    +

    See also

    +SetFont(), +SetDrawColor(), +SetFillColor(), +SetTextColor(), +SetLineWidth(), +AddLink(), +Ln(), +MultiCell(), +Write(), +SetAutoPageBreak(). +
    +
    + + + diff --git a/include/pdf/doc/close.htm b/include/pdf/doc/close.htm new file mode 100644 index 000000000..dcce911b0 --- /dev/null +++ b/include/pdf/doc/close.htm @@ -0,0 +1,24 @@ + + + +Close + + + +

    Close

    +Close() +

    Version

    +1.0 +

    Description

    +Terminates the PDF document. It is not necessary to call this method explicitly because Output() +does it automatically. +
    +If the document contains no page, AddPage() is called to prevent from getting an invalid document. +

    See also

    +Open(), +Output(). +
    +
    + + + diff --git a/include/pdf/doc/error.htm b/include/pdf/doc/error.htm new file mode 100644 index 000000000..e31a921ab --- /dev/null +++ b/include/pdf/doc/error.htm @@ -0,0 +1,25 @@ + + + +Error + + + +

    Error

    +Error(string msg) +

    Version

    +1.0 +

    Description

    +This method is automatically called in case of fatal error; it simply outputs the message +and halts the execution. An inherited class may override it to customize the error handling +but should always halt the script, or the resulting document would probably be invalid. +

    Parameters

    +msg +
    +The error message. +
    +
    +
    + + + diff --git a/include/pdf/doc/footer.htm b/include/pdf/doc/footer.htm new file mode 100644 index 000000000..3ff01dfc7 --- /dev/null +++ b/include/pdf/doc/footer.htm @@ -0,0 +1,39 @@ + + + +Footer + + + +

    Footer

    +Footer() +

    Version

    +1.0 +

    Description

    +This method is used to render the page footer. It is automatically called by AddPage() and +Close() and should not be called directly by the application. The implementation in FPDF is +empty, so you have to subclass it and override the method if you want a specific processing. +

    Example

    +
    + +class PDF extends FPDF
    +{
    +function Footer()
    +{
    +    //Go to 1.5 cm from bottom
    +    $this->SetY(-15);
    +    //Select Arial italic 8
    +    $this->SetFont('Arial','I',8);
    +    //Print centered page number
    +    $this->Cell(0,10,'Page '.$this->PageNo(),0,0,'C');
    +}
    +} +
    +

    +

    See also

    +Header(). +
    +
    + + + diff --git a/include/pdf/doc/fpdf.htm b/include/pdf/doc/fpdf.htm new file mode 100644 index 000000000..dffea26b2 --- /dev/null +++ b/include/pdf/doc/fpdf.htm @@ -0,0 +1,57 @@ + + + +FPDF + + + +

    FPDF

    +FPDF([string orientation [, string unit [, mixed format]]]) +

    Version

    +1.0 +

    Description

    +This is the class constructor. It allows to set up the page format, the orientation and the +measure unit used in all the methods (except for the font sizes). +

    Parameters

    +orientation +
    +Default page orientation. Possible values are (case insensitive): +
      +
    • P or Portrait +
    • L or Landscape +
    +Default value is P. +
    +unit +
    +User measure unit. Possible values are: +
      +
    • pt: point +
    • mm: millimeter +
    • cm: centimeter +
    • in: inch +
    +A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This +is a very common unit in typography; font sizes are expressed in that unit. +
    +
    +Default value is mm. +
    +format +
    +The format used for pages. It can be either one of the following values (case insensitive): +
      +
    • A3 +
    • A4 +
    • A5 +
    • Letter +
    • Legal +
    +or a custom format in the form of a two-element array containing the width and the height +(expressed in the unit given by unit). +
    +
    +
    + + + diff --git a/include/pdf/doc/getstringwidth.htm b/include/pdf/doc/getstringwidth.htm new file mode 100644 index 000000000..b879b95e4 --- /dev/null +++ b/include/pdf/doc/getstringwidth.htm @@ -0,0 +1,23 @@ + + + +GetStringWidth + + + +

    GetStringWidth

    +float GetStringWidth(string s) +

    Version

    +1.2 +

    Description

    +Returns the length of a string in user unit. A font must be selected. +

    Parameters

    +s +
    +The string whose length is to be computed. +
    +
    +
    + + + diff --git a/include/pdf/doc/getx.htm b/include/pdf/doc/getx.htm new file mode 100644 index 000000000..ba49feca5 --- /dev/null +++ b/include/pdf/doc/getx.htm @@ -0,0 +1,22 @@ + + + +GetX + + + +

    GetX

    +float GetX() +

    Version

    +1.2 +

    Description

    +Returns the abscissa of the current position. +

    See also

    +SetX(), +GetY(), +SetY(). +
    +
    + + + diff --git a/include/pdf/doc/gety.htm b/include/pdf/doc/gety.htm new file mode 100644 index 000000000..e04eff01d --- /dev/null +++ b/include/pdf/doc/gety.htm @@ -0,0 +1,22 @@ + + + +GetY + + + +

    GetY

    +float GetY() +

    Version

    +1.0 +

    Description

    +Returns the ordinate of the current position. +

    See also

    +SetY(), +GetX(), +SetX(). +
    +
    + + + diff --git a/include/pdf/doc/header.htm b/include/pdf/doc/header.htm new file mode 100644 index 000000000..88701cb2b --- /dev/null +++ b/include/pdf/doc/header.htm @@ -0,0 +1,41 @@ + + + +Header + + + +

    Header

    +Header() +

    Version

    +1.0 +

    Description

    +This method is used to render the page header. It is automatically called by AddPage() and +should not be called directly by the application. The implementation in FPDF is empty, so +you have to subclass it and override the method if you want a specific processing. +

    Example

    +
    + +class PDF extends FPDF
    +{
    +function Header()
    +{
    +    //Select Arial bold 15
    +    $this->SetFont('Arial','B',15);
    +    //Move to the right
    +    $this->Cell(80);
    +    //Framed title
    +    $this->Cell(30,10,'Title',1,0,'C');
    +    //Line break
    +    $this->Ln(20);
    +}
    +} +
    +

    +

    See also

    +Footer(). +
    +
    + + + diff --git a/include/pdf/doc/image.htm b/include/pdf/doc/image.htm new file mode 100644 index 000000000..35e83b36e --- /dev/null +++ b/include/pdf/doc/image.htm @@ -0,0 +1,88 @@ + + + +Image + + + +

    Image

    +Image(string file, float x, float y [, float w [, float h [, string type [, mixed link]]]]) +

    Version

    +1.1 +

    Description

    +Puts an image in the page. The upper-left corner must be given. The dimensions can be specified +in different ways: +
      +
    • explicit width and height (expressed in user unit) +
    • one explicit dimension, the other being calculated automatically in order to keep the original +proportions +
    • no explicit dimension, in which case the image is put at 72 dpi +
    +Supported formats are JPEG and PNG. +
    +
    +For JPEG, all flavors are allowed: +
      +
    • gray scales +
    • true colors (24 bits) +
    • CMYK (32 bits) +
    +For PNG, are allowed: +
      +
    • gray scales on at most 8 bits (256 levels) +
    • indexed colors +
    • true colors (24 bits) +
    +but are not supported: +
      +
    • Interlacing +
    • Alpha channel +
    +If a transparent color is defined, it will be taken into account (but will be only interpreted +by Acrobat 4 and above). +
    +The format can be specified explicitly or inferred from the file extension. +
    +It is possible to put a link on the image. +
    +
    +Remark: if an image is used several times, only one copy will be embedded in the file. +

    Parameters

    +file +
    +Name of the file containing the image. +
    +x +
    +Abscissa of the upper-left corner. +
    +y +
    +Ordinate of the upper-left corner. +
    +w +
    +Width of the image in the page. If not specified or equal to zero, it is automatically +calculated. +
    +h +
    +Height of the image in the page. If not specified or equal to zero, it is automatically +calculated. +
    +type +
    +Image format. Possible values are (case insensitive): JPG, JPEG, PNG. +If not specified, the type is inferred from the file extension. +
    +link +
    +URL or identifier returned by AddLink(). +
    +

    See also

    +AddLink(). +
    +
    + + + diff --git a/include/pdf/doc/index.htm b/include/pdf/doc/index.htm new file mode 100644 index 000000000..74a4f5c73 --- /dev/null +++ b/include/pdf/doc/index.htm @@ -0,0 +1,57 @@ + + + +FPDF 1.52 Reference Manual + + + +

    FPDF 1.52 Reference Manual

    +AcceptPageBreak - accept or not automatic page break
    +AddFont - add a new font
    +AddLink - create an internal link
    +AddPage - add a new page
    +AliasNbPages - define an alias for number of pages
    +Cell - print a cell
    +Close - terminate the document
    +Error - fatal error
    +Footer - page footer
    +FPDF - constructor
    +GetStringWidth - compute string length
    +GetX - get current x position
    +GetY - get current y position
    +Header - page header
    +Image - output an image
    +Line - draw a line
    +Link - put a link
    +Ln - line break
    +MultiCell - print text with line breaks
    +Open - create a document
    +Output - save or send the document
    +PageNo - page number
    +Rect - draw a rectangle
    +SetAuthor - set the document author
    +SetAutoPageBreak - set the automatic page breaking mode
    +SetCompression - turn compression on or off
    +SetCreator - set document creator
    +SetDisplayMode - set display mode
    +SetDrawColor - set drawing color
    +SetFillColor - set filling color
    +SetFont - set font
    +SetFontSize - set font size
    +SetKeywords - associate keywords with document
    +SetLeftMargin - set left margin
    +SetLineWidth - set line width
    +SetLink - set internal link destination
    +SetMargins - set margins
    +SetRightMargin - set right margin
    +SetSubject - set document subject
    +SetTextColor - set text color
    +SetTitle - set document title
    +SetTopMargin - set top margin
    +SetX - set current x position
    +SetXY - set current x and y positions
    +SetY - set current y position
    +Text - print a string
    +Write - print flowing text
    + + diff --git a/include/pdf/doc/line.htm b/include/pdf/doc/line.htm new file mode 100644 index 000000000..f9c1e5afd --- /dev/null +++ b/include/pdf/doc/line.htm @@ -0,0 +1,38 @@ + + + +Line + + + +

    Line

    +Line(float x1, float y1, float x2, float y2) +

    Version

    +1.0 +

    Description

    +Draws a line between two points. +

    Parameters

    +x1 +
    +Abscissa of first point. +
    +y1 +
    +Ordinate of first point. +
    +x2 +
    +Abscissa of second point. +
    +y2 +
    +Ordinate of second point. +
    +

    See also

    +SetLineWidth(), +SetDrawColor(). +
    +
    + + + diff --git a/include/pdf/doc/link.htm b/include/pdf/doc/link.htm new file mode 100644 index 000000000..4a7b8560c --- /dev/null +++ b/include/pdf/doc/link.htm @@ -0,0 +1,46 @@ + + + +Link + + + +

    Link

    +Link(float x, float y, float w, float h, mixed link) +

    Version

    +1.5 +

    Description

    +Puts a link on a rectangular area of the page. Text or image links are generally put via Cell(), +Write() or Image(), but this method can be useful for instance to define a clickable area inside +an image. +

    Parameters

    +x +
    +Abscissa of the upper-left corner of the rectangle. +
    +y +
    +Ordinate of the upper-left corner of the rectangle. +
    +w +
    +Width of the rectangle. +
    +h +
    +Height of the rectangle. +
    +link +
    +URL or identifier returned by AddLink(). +
    +

    See also

    +AddLink(), +Cell(), +Write(), +Image(). +
    +
    + + + diff --git a/include/pdf/doc/ln.htm b/include/pdf/doc/ln.htm new file mode 100644 index 000000000..c9f3bc895 --- /dev/null +++ b/include/pdf/doc/ln.htm @@ -0,0 +1,28 @@ + + + +Ln + + + +

    Ln

    +Ln([float h]) +

    Version

    +1.0 +

    Description

    +Performs a line break. The current abscissa goes back to the left margin and the ordinate +increases by the amount passed in parameter. +

    Parameters

    +h +
    +The height of the break. +
    +By default, the value equals the height of the last printed cell. +
    +

    See also

    +Cell(). +
    +
    + + + diff --git a/include/pdf/doc/multicell.htm b/include/pdf/doc/multicell.htm new file mode 100644 index 000000000..fb0be4650 --- /dev/null +++ b/include/pdf/doc/multicell.htm @@ -0,0 +1,76 @@ + + + +MultiCell + + + +

    MultiCell

    +MultiCell(float w, float h, string txt [, mixed border [, string align [, int fill]]]) +

    Version

    +1.3 +

    Description

    +This method allows printing text with line breaks. They can be automatic (as soon as the +text reaches the right border of the cell) or explicit (via the \n character). As many cells +as necessary are output, one below the other. +
    +Text can be aligned, centered or justified. The cell block can be framed and the background +painted. +

    Parameters

    +w +
    +Width of cells. If 0, they extend up to the right margin of the page. +
    +h +
    +Height of cells. +
    +txt +
    +String to print. +
    +border +
    +Indicates if borders must be drawn around the cell block. The value can be either a number: +
      +
    • 0: no border +
    • 1: frame +
    +or a string containing some or all of the following characters (in any order): +
      +
    • L: left +
    • T: top +
    • R: right +
    • B: bottom +
    +Default value: 0. +
    +align +
    +Sets the text alignment. Possible values are: +
      +
    • L: left alignment +
    • C: center +
    • R: right alignment +
    • J: justification (default value) +
    +
    +fill +
    +Indicates if the cell background must be painted (1) or transparent (0). +Default value: 0. +
    +

    See also

    +SetFont(), +SetDrawColor(), +SetFillColor(), +SetTextColor(), +SetLineWidth(), +Cell(), +Write(), +SetAutoPageBreak(). +
    +
    + + + diff --git a/include/pdf/doc/open.htm b/include/pdf/doc/open.htm new file mode 100644 index 000000000..010ce230f --- /dev/null +++ b/include/pdf/doc/open.htm @@ -0,0 +1,23 @@ + + + +Open + + + +

    Open

    +Open() +

    Version

    +1.0 +

    Description

    +This method begins the generation of the PDF document. It is not necessary to call it +explicitly because AddPage() does it automatically.
    +Note: no page is created by this method. +

    See also

    +AddPage(), +Close(). +
    +
    + + + diff --git a/include/pdf/doc/output.htm b/include/pdf/doc/output.htm new file mode 100644 index 000000000..8317c09c7 --- /dev/null +++ b/include/pdf/doc/output.htm @@ -0,0 +1,47 @@ + + + +Output + + + +

    Output

    +string Output([string name [, string dest]]) +

    Version

    +1.0 +

    Description

    +Send the document to a given destination: string, local file or browser. In the last case, the +plug-in may be used (if present) or a download ("Save as" dialog box) may be forced. +
    +The method first calls Close() if necessary to terminate the document. +

    Parameters

    +name +
    +The name of the file. If not given, the document will be sent to the browser +(destination I) with the name doc.pdf. +
    +dest +
    +Destination where to send the document. It can take one of the following values: +
      +
    • I: send the file inline to the browser. The plug-in is used if available. +The name given by name is used when one selects the "Save as" option on the +link generating the PDF. +
    • D: send to the browser and force a file download with the name given by +name. +
    • F: save to a local file with the name given by name. +
    • S: return the document as a string. name is ignored. +
    +If the parameter is not specified but a name is given, destination is F. If no +parameter is specified at all, destination is I.
    +
    +Note: for compatibility with previous versions, a boolean value is also accepted +(false for F and true for D). +
    +

    See also

    +Close(). +
    +
    + + + diff --git a/include/pdf/doc/pageno.htm b/include/pdf/doc/pageno.htm new file mode 100644 index 000000000..5aab5f616 --- /dev/null +++ b/include/pdf/doc/pageno.htm @@ -0,0 +1,20 @@ + + + +PageNo + + + +

    PageNo

    +int PageNo() +

    Version

    +1.0 +

    Description

    +Returns the current page number. +

    See also

    +AliasNbPages(). +
    +
    + + + diff --git a/include/pdf/doc/rect.htm b/include/pdf/doc/rect.htm new file mode 100644 index 000000000..e639b51e9 --- /dev/null +++ b/include/pdf/doc/rect.htm @@ -0,0 +1,48 @@ + + + +Rect + + + +

    Rect

    +Rect(float x, float y, float w, float h [, string style]) +

    Version

    +1.0 +

    Description

    +Outputs a rectangle. It can be drawn (border only), filled (with no border) or both. +

    Parameters

    +x +
    +Abscissa of upper-left corner. +
    +y +
    +Ordinate of upper-left corner. +
    +w +
    +Width. +
    +h +
    +Height. +
    +style +
    +Style of rendering. Possible values are: +
      +
    • D or empty string: draw. This is the default value. +
    • F: fill +
    • DF or FD: draw and fill +
    +
    +

    See also

    +SetLineWidth(), +SetDrawColor(), +SetFillColor(). +
    +
    + + + diff --git a/include/pdf/doc/setauthor.htm b/include/pdf/doc/setauthor.htm new file mode 100644 index 000000000..2e9769463 --- /dev/null +++ b/include/pdf/doc/setauthor.htm @@ -0,0 +1,28 @@ + + + +SetAuthor + + + +

    SetAuthor

    +SetAuthor(string author) +

    Version

    +1.2 +

    Description

    +Defines the author of the document. +

    Parameters

    +author +
    +The name of the author. +
    +

    See also

    +SetCreator(), +SetKeywords(), +SetSubject(), +SetTitle(). +
    +
    + + + diff --git a/include/pdf/doc/setautopagebreak.htm b/include/pdf/doc/setautopagebreak.htm new file mode 100644 index 000000000..98193f987 --- /dev/null +++ b/include/pdf/doc/setautopagebreak.htm @@ -0,0 +1,33 @@ + + + +SetAutoPageBreak + + + +

    SetAutoPageBreak

    +SetAutoPageBreak(boolean auto [, float margin]) +

    Version

    +1.0 +

    Description

    +Enables or disables the automatic page breaking mode. When enabling, the second parameter is +the distance from the bottom of the page that defines the triggering limit. By default, the +mode is on and the margin is 2 cm. +

    Parameters

    +auto +
    +Boolean indicating if mode should be on or off. +
    +margin +
    +Distance from the bottom of the page. +
    +

    See also

    +Cell(), +MultiCell(), +AcceptPageBreak(). +
    +
    + + + diff --git a/include/pdf/doc/setcompression.htm b/include/pdf/doc/setcompression.htm new file mode 100644 index 000000000..33c15f159 --- /dev/null +++ b/include/pdf/doc/setcompression.htm @@ -0,0 +1,31 @@ + + + +SetCompression + + + +

    SetCompression

    +SetCompression(boolean compress) +

    Version

    +1.4 +

    Description

    +Activates or deactivates page compression. When activated, the internal representation of +each page is compressed, which leads to a compression ratio of about 2 for the resulting +document. +
    +Compression is on by default. +
    +
    +Note: the Zlib extension is required for this feature. If not present, compression +will be turned off. +

    Parameters

    +compress +
    +Boolean indicating if compression must be enabled. +
    +
    +
    + + + diff --git a/include/pdf/doc/setcreator.htm b/include/pdf/doc/setcreator.htm new file mode 100644 index 000000000..abdd887f5 --- /dev/null +++ b/include/pdf/doc/setcreator.htm @@ -0,0 +1,29 @@ + + + +SetCreator + + + +

    SetCreator

    +SetCreator(string creator) +

    Version

    +1.2 +

    Description

    +Defines the creator of the document. This is typically the name of the application that +generates the PDF. +

    Parameters

    +creator +
    +The name of the creator. +
    +

    See also

    +SetAuthor(), +SetKeywords(), +SetSubject(), +SetTitle(). +
    +
    + + + diff --git a/include/pdf/doc/setdisplaymode.htm b/include/pdf/doc/setdisplaymode.htm new file mode 100644 index 000000000..5211db556 --- /dev/null +++ b/include/pdf/doc/setdisplaymode.htm @@ -0,0 +1,47 @@ + + + +SetDisplayMode + + + +

    SetDisplayMode

    +SetDisplayMode(mixed zoom [, string layout]) +

    Version

    +1.2 +

    Description

    +Defines the way the document is to be displayed by the viewer. The zoom level can be set: pages can be +displayed entirely on screen, occupy the full width of the window, use real size, be scaled by a +specific zooming factor or use viewer default (configured in the Preferences menu of Acrobat). +The page layout can be specified too: single at once, continuous display, two columns or viewer +default. +
    +By default, documents use the full width mode with continuous display. +

    Parameters

    +zoom +
    +The zoom to use. It can be one of the following string values: +
      +
    • fullpage: displays the entire page on screen +
    • fullwidth: uses maximum width of window +
    • real: uses real size (equivalent to 100% zoom) +
    • default: uses viewer default mode +
    +or a number indicating the zooming factor to use. +
    +layout +
    +The page layout. Possible values are: +
      +
    • single: displays one page at once +
    • continuous: displays pages continuously +
    • two: displays two pages on two columns +
    • default: uses viewer default mode +
    +Default value is continuous. +
    +
    +
    + + + diff --git a/include/pdf/doc/setdrawcolor.htm b/include/pdf/doc/setdrawcolor.htm new file mode 100644 index 000000000..ca54be265 --- /dev/null +++ b/include/pdf/doc/setdrawcolor.htm @@ -0,0 +1,41 @@ + + + +SetDrawColor + + + +

    SetDrawColor

    +SetDrawColor(int r [, int g, int b]) +

    Version

    +1.3 +

    Description

    +Defines the color used for all drawing operations (lines, rectangles and cell borders). It +can be expressed in RGB components or gray scale. The method can be called before the first +page is created and the value is retained from page to page. +

    Parameters

    +r +
    +If g et b are given, red component; if not, indicates the gray level. +Value between 0 and 255. +
    +g +
    +Green component (between 0 and 255). +
    +b +
    +Blue component (between 0 and 255). +
    +

    See also

    +SetFillColor(), +SetTextColor(), +Line(), +Rect(), +Cell(), +MultiCell(). +
    +
    + + + diff --git a/include/pdf/doc/setfillcolor.htm b/include/pdf/doc/setfillcolor.htm new file mode 100644 index 000000000..9e59e9529 --- /dev/null +++ b/include/pdf/doc/setfillcolor.htm @@ -0,0 +1,40 @@ + + + +SetFillColor + + + +

    SetFillColor

    +SetFillColor(int r [, int g, int b]) +

    Version

    +1.3 +

    Description

    +Defines the color used for all filling operations (filled rectangles and cell backgrounds). +It can be expressed in RGB components or gray scale. The method can be called before the first +page is created and the value is retained from page to page. +

    Parameters

    +r +
    +If g and b are given, red component; if not, indicates the gray level. +Value between 0 and 255. +
    +g +
    +Green component (between 0 and 255). +
    +b +
    +Blue component (between 0 and 255). +
    +

    See also

    +SetDrawColor(), +SetTextColor(), +Rect(), +Cell(), +MultiCell(). +
    +
    + + + diff --git a/include/pdf/doc/setfont.htm b/include/pdf/doc/setfont.htm new file mode 100644 index 000000000..5c2dc709c --- /dev/null +++ b/include/pdf/doc/setfont.htm @@ -0,0 +1,103 @@ + + + +SetFont + + + +

    SetFont

    +SetFont(string family [, string style [, float size]]) +

    Version

    +1.0 +

    Description

    +Sets the font used to print character strings. It is mandatory to call this method +at least once before printing text or the resulting document would not be valid. +
    +The font can be either a standard one or a font added via the AddFont() method. Standard fonts +use Windows encoding cp1252 (Western Europe). +
    +The method can be called before the first page is created and the font is retained from page +to page. +
    +If you just wish to change the current font size, it is simpler to call SetFontSize(). +
    +
    +Note: for the standard fonts, the font metric files must be accessible. There are three +possibilities for this: +
    +
    +
      +
    • They are in the current directory (the one where the running script lies) +
      +
    • They are in one of the directories defined by the include_path parameter +
      +
    • They are in the directory defined by the FPDF_FONTPATH constant +
    +Example for the last case (note the trailing slash): +
    +
    +
    + +define('FPDF_FONTPATH','/home/www/font/');
    +require('fpdf.php'); +
    +

    +If the file corresponding to the requested font is not found, the error "Could not include +font metric file" is generated. +

    Parameters

    +family +
    +Family font. It can be either a name defined by AddFont() or one of the standard families (case +insensitive): +
      +
    • Courier (fixed-width) +
    • Helvetica or Arial (synonymous; sans serif) +
    • Times (serif) +
    • Symbol (symbolic) +
    • ZapfDingbats (symbolic) +
    +It is also possible to pass an empty string. In that case, the current family is retained. +
    +style +
    +Font style. Possible values are (case insensitive): +
      +
    • empty string: regular +
    • B: bold +
    • I: italic +
    • U: underline +
    +or any combination. The default value is regular. +Bold and italic styles do not apply to Symbol and ZapfDingbats. +
    +size +
    +Font size in points. +
    +The default value is the current size. If no size has been specified since the beginning of +the document, the value taken is 12. +
    +

    Example

    +
    + +//Times regular 12
    +$pdf->SetFont('Times');
    +//Arial bold 14
    +$pdf->SetFont('Arial','B',14);
    +//Removes bold
    +$pdf->SetFont('');
    +//Times bold, italic and underlined 14
    +$pdf->SetFont('Times','BIU'); +
    +

    +

    See also

    +AddFont(), +SetFontSize(), +Cell(), +MultiCell(), +Write(). +
    +
    + + + diff --git a/include/pdf/doc/setfontsize.htm b/include/pdf/doc/setfontsize.htm new file mode 100644 index 000000000..b05205d46 --- /dev/null +++ b/include/pdf/doc/setfontsize.htm @@ -0,0 +1,25 @@ + + + +SetFontSize + + + +

    SetFontSize

    +SetFontSize(float size) +

    Version

    +1.0 +

    Description

    +Defines the size of the current font. +

    Parameters

    +size +
    +The size (in points). +
    +

    See also

    +SetFont(). +
    +
    + + + diff --git a/include/pdf/doc/setkeywords.htm b/include/pdf/doc/setkeywords.htm new file mode 100644 index 000000000..118ef5a5f --- /dev/null +++ b/include/pdf/doc/setkeywords.htm @@ -0,0 +1,28 @@ + + + +SetKeywords + + + +

    SetKeywords

    +SetKeywords(string keywords) +

    Version

    +1.2 +

    Description

    +Associates keywords with the document, generally in the form 'keyword1 keyword2 ...'. +

    Parameters

    +keywords +
    +The list of keywords. +
    +

    See also

    +SetAuthor(), +SetCreator(), +SetSubject(), +SetTitle(). +
    +
    + + + diff --git a/include/pdf/doc/setleftmargin.htm b/include/pdf/doc/setleftmargin.htm new file mode 100644 index 000000000..fd26d87c0 --- /dev/null +++ b/include/pdf/doc/setleftmargin.htm @@ -0,0 +1,30 @@ + + + +SetLeftMargin + + + +

    SetLeftMargin

    +SetLeftMargin(float margin) +

    Version

    +1.4 +

    Description

    +Defines the left margin. The method can be called before creating the first page. +
    +If the current abscissa gets out of page, it is brought back to the margin. +

    Parameters

    +margin +
    +The margin. +
    +

    See also

    +SetTopMargin(), +SetRightMargin(), +SetAutoPageBreak(), +SetMargins(). +
    +
    + + + diff --git a/include/pdf/doc/setlinewidth.htm b/include/pdf/doc/setlinewidth.htm new file mode 100644 index 000000000..85aa8feb1 --- /dev/null +++ b/include/pdf/doc/setlinewidth.htm @@ -0,0 +1,29 @@ + + + +SetLineWidth + + + +

    SetLineWidth

    +SetLineWidth(float width) +

    Version

    +1.0 +

    Description

    +Defines the line width. By default, the value equals 0.2 mm. The method can be called before +the first page is created and the value is retained from page to page. +

    Parameters

    +width +
    +The width. +
    +

    See also

    +Line(), +Rect(), +Cell(), +MultiCell(). +
    +
    + + + diff --git a/include/pdf/doc/setlink.htm b/include/pdf/doc/setlink.htm new file mode 100644 index 000000000..86a163f61 --- /dev/null +++ b/include/pdf/doc/setlink.htm @@ -0,0 +1,34 @@ + + + +SetLink + + + +

    SetLink

    +SetLink(int link [, float y [, int page]]) +

    Version

    +1.5 +

    Description

    +Defines the page and position a link points to. +

    Parameters

    +link +
    +The link identifier returned by AddLink(). +
    +y +
    +Ordinate of target position; -1 indicates the current position. +The default value is 0 (top of page). +
    +page +
    +Number of target page; -1 indicates the current page. This is the default value. +
    +

    See also

    +AddLink(). +
    +
    + + + diff --git a/include/pdf/doc/setmargins.htm b/include/pdf/doc/setmargins.htm new file mode 100644 index 000000000..766718bbe --- /dev/null +++ b/include/pdf/doc/setmargins.htm @@ -0,0 +1,37 @@ + + + +SetMargins + + + +

    SetMargins

    +SetMargins(float left, float top [, float right]) +

    Version

    +1.0 +

    Description

    +Defines the left, top and right margins. By default, they equal 1 cm. Call this method to change +them. +

    Parameters

    +left +
    +Left margin. +
    +top +
    +Top margin. +
    +right +
    +Right margin. Default value is the left one. +
    +

    See also

    +SetLeftMargin(), +SetTopMargin(), +SetRightMargin(), +SetAutoPageBreak(). +
    +
    + + + diff --git a/include/pdf/doc/setrightmargin.htm b/include/pdf/doc/setrightmargin.htm new file mode 100644 index 000000000..ff3ee90bd --- /dev/null +++ b/include/pdf/doc/setrightmargin.htm @@ -0,0 +1,28 @@ + + + +SetRightMargin + + + +

    SetRightMargin

    +SetRightMargin(float margin) +

    Version

    +1.5 +

    Description

    +Defines the right margin. The method can be called before creating the first page. +

    Parameters

    +margin +
    +The margin. +
    +

    See also

    +SetLeftMargin(), +SetTopMargin(), +SetAutoPageBreak(), +SetMargins(). +
    +
    + + + diff --git a/include/pdf/doc/setsubject.htm b/include/pdf/doc/setsubject.htm new file mode 100644 index 000000000..5c95ae892 --- /dev/null +++ b/include/pdf/doc/setsubject.htm @@ -0,0 +1,28 @@ + + + +SetSubject + + + +

    SetSubject

    +SetSubject(string subject) +

    Version

    +1.2 +

    Description

    +Defines the subject of the document. +

    Parameters

    +subject +
    +The subject. +
    +

    See also

    +SetAuthor(), +SetCreator(), +SetKeywords(), +SetTitle(). +
    +
    + + + diff --git a/include/pdf/doc/settextcolor.htm b/include/pdf/doc/settextcolor.htm new file mode 100644 index 000000000..7e6e12cf8 --- /dev/null +++ b/include/pdf/doc/settextcolor.htm @@ -0,0 +1,40 @@ + + + +SetTextColor + + + +

    SetTextColor

    +SetTextColor(int r [, int g, int b]) +

    Version

    +1.3 +

    Description

    +Defines the color used for text. It can be expressed in RGB components or gray scale. The +method can be called before the first page is created and the value is retained from page to +page. +

    Parameters

    +r +
    +If g et b are given, red component; if not, indicates the gray level. +Value between 0 and 255. +
    +g +
    +Green component (between 0 and 255). +
    +b +
    +Blue component (between 0 and 255). +
    +

    See also

    +SetDrawColor(), +SetFillColor(), +Text(), +Cell(), +MultiCell(). +
    +
    + + + diff --git a/include/pdf/doc/settitle.htm b/include/pdf/doc/settitle.htm new file mode 100644 index 000000000..6da2faa5b --- /dev/null +++ b/include/pdf/doc/settitle.htm @@ -0,0 +1,28 @@ + + + +SetTitle + + + +

    SetTitle

    +SetTitle(string title) +

    Version

    +1.2 +

    Description

    +Defines the title of the document. +

    Parameters

    +title +
    +The title. +
    +

    See also

    +SetAuthor(), +SetCreator(), +SetKeywords(), +SetSubject(). +
    +
    + + + diff --git a/include/pdf/doc/settopmargin.htm b/include/pdf/doc/settopmargin.htm new file mode 100644 index 000000000..380de708b --- /dev/null +++ b/include/pdf/doc/settopmargin.htm @@ -0,0 +1,28 @@ + + + +SetTopMargin + + + +

    SetTopMargin

    +SetTopMargin(float margin) +

    Version

    +1.5 +

    Description

    +Defines the top margin. The method can be called before creating the first page. +

    Parameters

    +margin +
    +The margin. +
    +

    See also

    +SetLeftMargin(), +SetRightMargin(), +SetAutoPageBreak(), +SetMargins(). +
    +
    + + + diff --git a/include/pdf/doc/setx.htm b/include/pdf/doc/setx.htm new file mode 100644 index 000000000..96b8eedae --- /dev/null +++ b/include/pdf/doc/setx.htm @@ -0,0 +1,29 @@ + + + +SetX + + + +

    SetX

    +SetX(float x) +

    Version

    +1.2 +

    Description

    +Defines the abscissa of the current position. If the passed value is negative, it is relative +to the right of the page. +

    Parameters

    +x +
    +The value of the abscissa. +
    +

    See also

    +GetX(), +GetY(), +SetY(), +SetXY(). +
    +
    + + + diff --git a/include/pdf/doc/setxy.htm b/include/pdf/doc/setxy.htm new file mode 100644 index 000000000..fd6ec6435 --- /dev/null +++ b/include/pdf/doc/setxy.htm @@ -0,0 +1,31 @@ + + + +SetXY + + + +

    SetXY

    +SetXY(float x, float y) +

    Version

    +1.2 +

    Description

    +Defines the abscissa and ordinate of the current position. If the passed values are negative, +they are relative respectively to the right and bottom of the page. +

    Parameters

    +x +
    +The value of the abscissa. +
    +y +
    +The value of the ordinate. +
    +

    See also

    +SetX(), +SetY(). +
    +
    + + + diff --git a/include/pdf/doc/sety.htm b/include/pdf/doc/sety.htm new file mode 100644 index 000000000..9c3a321ad --- /dev/null +++ b/include/pdf/doc/sety.htm @@ -0,0 +1,29 @@ + + + +SetY + + + +

    SetY

    +SetY(float y) +

    Version

    +1.0 +

    Description

    +Moves the current abscissa back to the left margin and sets the ordinate. If the passed value +is negative, it is relative to the bottom of the page. +

    Parameters

    +y +
    +The value of the ordinate. +
    +

    See also

    +GetX(), +GetY(), +SetY(), +SetXY(). +
    +
    + + + diff --git a/include/pdf/doc/text.htm b/include/pdf/doc/text.htm new file mode 100644 index 000000000..af47881c1 --- /dev/null +++ b/include/pdf/doc/text.htm @@ -0,0 +1,39 @@ + + + +Text + + + +

    Text

    +Text(float x, float y, string txt) +

    Version

    +1.0 +

    Description

    +Prints a character string. The origin is on the left of the first charcter, on the baseline. +This method allows to place a string precisely on the page, but it is usually easier to use +Cell(), MultiCell() or Write() which are the standard methods to print text. +

    Parameters

    +x +
    +Abscissa of the origin. +
    +y +
    +Ordinate of the origin. +
    +txt +
    +String to print. +
    +

    See also

    +SetFont(), +SetTextColor(), +Cell(), +MultiCell(), +Write(). +
    +
    + + + diff --git a/include/pdf/doc/write.htm b/include/pdf/doc/write.htm new file mode 100644 index 000000000..e33c39c17 --- /dev/null +++ b/include/pdf/doc/write.htm @@ -0,0 +1,53 @@ + + + +Write + + + +

    Write

    +Write(float h, string txt [, mixed link]) +

    Version

    +1.5 +

    Description

    +This method prints text from the current position. When the right margin is reached (or the \n +character is met) a line break occurs and text continues from the left margin. Upon method exit, +the current position is left just at the end of the text. +
    +It is possible to put a link on the text. +

    Parameters

    +h +
    +Line height. +
    +txt +
    +String to print. +
    +link +
    +URL or identifier returned by AddLink(). +
    +

    Example

    +
    + +//Begin with regular font
    +$pdf->SetFont('Arial','',14);
    +$pdf->Write(5,'Visit ');
    +//Then put a blue underlined link
    +$pdf->SetTextColor(0,0,255);
    +$pdf->SetFont('','U');
    +$pdf->Write(5,'www.fpdf.org','http://www.fpdf.org'); +
    +

    +

    See also

    +SetFont(), +SetTextColor(), +AddLink(), +MultiCell(), +SetAutoPageBreak(). +
    +
    + + + diff --git a/include/pdf/font/courier.php b/include/pdf/font/courier.php new file mode 100644 index 000000000..913f9a453 --- /dev/null +++ b/include/pdf/font/courier.php @@ -0,0 +1,7 @@ + diff --git a/include/pdf/font/helvetica.php b/include/pdf/font/helvetica.php new file mode 100644 index 000000000..ca94cdf21 --- /dev/null +++ b/include/pdf/font/helvetica.php @@ -0,0 +1,15 @@ +278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278, + chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>278,'"'=>355,'#'=>556,'$'=>556,'%'=>889,'&'=>667,'\''=>191,'('=>333,')'=>333,'*'=>389,'+'=>584, + ','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>278,';'=>278,'<'=>584,'='=>584,'>'=>584,'?'=>556,'@'=>1015,'A'=>667, + 'B'=>667,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>500,'K'=>667,'L'=>556,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944, + 'X'=>667,'Y'=>667,'Z'=>611,'['=>278,'\\'=>278,']'=>278,'^'=>469,'_'=>556,'`'=>333,'a'=>556,'b'=>556,'c'=>500,'d'=>556,'e'=>556,'f'=>278,'g'=>556,'h'=>556,'i'=>222,'j'=>222,'k'=>500,'l'=>222,'m'=>833, + 'n'=>556,'o'=>556,'p'=>556,'q'=>556,'r'=>333,'s'=>500,'t'=>278,'u'=>556,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>500,'{'=>334,'|'=>260,'}'=>334,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>222,chr(131)=>556, + chr(132)=>333,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>222,chr(146)=>222,chr(147)=>333,chr(148)=>333,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>500,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>260,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333, + chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>556,chr(182)=>537,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>667,chr(193)=>667,chr(194)=>667,chr(195)=>667,chr(196)=>667,chr(197)=>667, + chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>500,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>556,chr(241)=>556, + chr(242)=>556,chr(243)=>556,chr(244)=>556,chr(245)=>556,chr(246)=>556,chr(247)=>584,chr(248)=>611,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>500,chr(254)=>556,chr(255)=>500); +?> diff --git a/include/pdf/font/helveticab.php b/include/pdf/font/helveticab.php new file mode 100644 index 000000000..276cfa8cb --- /dev/null +++ b/include/pdf/font/helveticab.php @@ -0,0 +1,15 @@ +278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278, + chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>333,'"'=>474,'#'=>556,'$'=>556,'%'=>889,'&'=>722,'\''=>238,'('=>333,')'=>333,'*'=>389,'+'=>584, + ','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>333,';'=>333,'<'=>584,'='=>584,'>'=>584,'?'=>611,'@'=>975,'A'=>722, + 'B'=>722,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>556,'K'=>722,'L'=>611,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944, + 'X'=>667,'Y'=>667,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>584,'_'=>556,'`'=>333,'a'=>556,'b'=>611,'c'=>556,'d'=>611,'e'=>556,'f'=>333,'g'=>611,'h'=>611,'i'=>278,'j'=>278,'k'=>556,'l'=>278,'m'=>889, + 'n'=>611,'o'=>611,'p'=>611,'q'=>611,'r'=>389,'s'=>556,'t'=>333,'u'=>611,'v'=>556,'w'=>778,'x'=>556,'y'=>556,'z'=>500,'{'=>389,'|'=>280,'}'=>389,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>278,chr(131)=>556, + chr(132)=>500,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>278,chr(146)=>278,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>556,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>280,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333, + chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>611,chr(182)=>556,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722, + chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>556,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>611,chr(241)=>611, + chr(242)=>611,chr(243)=>611,chr(244)=>611,chr(245)=>611,chr(246)=>611,chr(247)=>584,chr(248)=>611,chr(249)=>611,chr(250)=>611,chr(251)=>611,chr(252)=>611,chr(253)=>556,chr(254)=>611,chr(255)=>556); +?> diff --git a/include/pdf/font/helveticabi.php b/include/pdf/font/helveticabi.php new file mode 100644 index 000000000..8d2177432 --- /dev/null +++ b/include/pdf/font/helveticabi.php @@ -0,0 +1,15 @@ +278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278, + chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>333,'"'=>474,'#'=>556,'$'=>556,'%'=>889,'&'=>722,'\''=>238,'('=>333,')'=>333,'*'=>389,'+'=>584, + ','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>333,';'=>333,'<'=>584,'='=>584,'>'=>584,'?'=>611,'@'=>975,'A'=>722, + 'B'=>722,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>556,'K'=>722,'L'=>611,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944, + 'X'=>667,'Y'=>667,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>584,'_'=>556,'`'=>333,'a'=>556,'b'=>611,'c'=>556,'d'=>611,'e'=>556,'f'=>333,'g'=>611,'h'=>611,'i'=>278,'j'=>278,'k'=>556,'l'=>278,'m'=>889, + 'n'=>611,'o'=>611,'p'=>611,'q'=>611,'r'=>389,'s'=>556,'t'=>333,'u'=>611,'v'=>556,'w'=>778,'x'=>556,'y'=>556,'z'=>500,'{'=>389,'|'=>280,'}'=>389,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>278,chr(131)=>556, + chr(132)=>500,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>278,chr(146)=>278,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>556,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>280,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333, + chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>611,chr(182)=>556,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722, + chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>556,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>611,chr(241)=>611, + chr(242)=>611,chr(243)=>611,chr(244)=>611,chr(245)=>611,chr(246)=>611,chr(247)=>584,chr(248)=>611,chr(249)=>611,chr(250)=>611,chr(251)=>611,chr(252)=>611,chr(253)=>556,chr(254)=>611,chr(255)=>556); +?> diff --git a/include/pdf/font/helveticai.php b/include/pdf/font/helveticai.php new file mode 100644 index 000000000..88bf4371b --- /dev/null +++ b/include/pdf/font/helveticai.php @@ -0,0 +1,15 @@ +278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278, + chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>278,'"'=>355,'#'=>556,'$'=>556,'%'=>889,'&'=>667,'\''=>191,'('=>333,')'=>333,'*'=>389,'+'=>584, + ','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>278,';'=>278,'<'=>584,'='=>584,'>'=>584,'?'=>556,'@'=>1015,'A'=>667, + 'B'=>667,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>500,'K'=>667,'L'=>556,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944, + 'X'=>667,'Y'=>667,'Z'=>611,'['=>278,'\\'=>278,']'=>278,'^'=>469,'_'=>556,'`'=>333,'a'=>556,'b'=>556,'c'=>500,'d'=>556,'e'=>556,'f'=>278,'g'=>556,'h'=>556,'i'=>222,'j'=>222,'k'=>500,'l'=>222,'m'=>833, + 'n'=>556,'o'=>556,'p'=>556,'q'=>556,'r'=>333,'s'=>500,'t'=>278,'u'=>556,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>500,'{'=>334,'|'=>260,'}'=>334,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>222,chr(131)=>556, + chr(132)=>333,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>222,chr(146)=>222,chr(147)=>333,chr(148)=>333,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>500,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>260,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333, + chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>556,chr(182)=>537,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>667,chr(193)=>667,chr(194)=>667,chr(195)=>667,chr(196)=>667,chr(197)=>667, + chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>500,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>556,chr(241)=>556, + chr(242)=>556,chr(243)=>556,chr(244)=>556,chr(245)=>556,chr(246)=>556,chr(247)=>584,chr(248)=>611,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>500,chr(254)=>556,chr(255)=>500); +?> diff --git a/include/pdf/font/makefont/cp1250.map b/include/pdf/font/makefont/cp1250.map new file mode 100644 index 000000000..ec110af06 --- /dev/null +++ b/include/pdf/font/makefont/cp1250.map @@ -0,0 +1,251 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+015A Sacute +!8D U+0164 Tcaron +!8E U+017D Zcaron +!8F U+0179 Zacute +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+015B sacute +!9D U+0165 tcaron +!9E U+017E zcaron +!9F U+017A zacute +!A0 U+00A0 space +!A1 U+02C7 caron +!A2 U+02D8 breve +!A3 U+0141 Lslash +!A4 U+00A4 currency +!A5 U+0104 Aogonek +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+015E Scedilla +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+02DB ogonek +!B3 U+0142 lslash +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+0105 aogonek +!BA U+015F scedilla +!BB U+00BB guillemotright +!BC U+013D Lcaron +!BD U+02DD hungarumlaut +!BE U+013E lcaron +!BF U+017C zdotaccent +!C0 U+0154 Racute +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0139 Lacute +!C6 U+0106 Cacute +!C7 U+00C7 Ccedilla +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+011A Ecaron +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+010E Dcaron +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+0147 Ncaron +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0158 Rcaron +!D9 U+016E Uring +!DA U+00DA Uacute +!DB U+0170 Uhungarumlaut +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+0162 Tcommaaccent +!DF U+00DF germandbls +!E0 U+0155 racute +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+013A lacute +!E6 U+0107 cacute +!E7 U+00E7 ccedilla +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+011B ecaron +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+010F dcaron +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+0148 ncaron +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0159 rcaron +!F9 U+016F uring +!FA U+00FA uacute +!FB U+0171 uhungarumlaut +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+0163 tcommaaccent +!FF U+02D9 dotaccent diff --git a/include/pdf/font/makefont/cp1251.map b/include/pdf/font/makefont/cp1251.map new file mode 100644 index 000000000..de6a198d9 --- /dev/null +++ b/include/pdf/font/makefont/cp1251.map @@ -0,0 +1,255 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0402 afii10051 +!81 U+0403 afii10052 +!82 U+201A quotesinglbase +!83 U+0453 afii10100 +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+20AC Euro +!89 U+2030 perthousand +!8A U+0409 afii10058 +!8B U+2039 guilsinglleft +!8C U+040A afii10059 +!8D U+040C afii10061 +!8E U+040B afii10060 +!8F U+040F afii10145 +!90 U+0452 afii10099 +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9A U+0459 afii10106 +!9B U+203A guilsinglright +!9C U+045A afii10107 +!9D U+045C afii10109 +!9E U+045B afii10108 +!9F U+045F afii10193 +!A0 U+00A0 space +!A1 U+040E afii10062 +!A2 U+045E afii10110 +!A3 U+0408 afii10057 +!A4 U+00A4 currency +!A5 U+0490 afii10050 +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+0401 afii10023 +!A9 U+00A9 copyright +!AA U+0404 afii10053 +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+0407 afii10056 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+0406 afii10055 +!B3 U+0456 afii10103 +!B4 U+0491 afii10098 +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+0451 afii10071 +!B9 U+2116 afii61352 +!BA U+0454 afii10101 +!BB U+00BB guillemotright +!BC U+0458 afii10105 +!BD U+0405 afii10054 +!BE U+0455 afii10102 +!BF U+0457 afii10104 +!C0 U+0410 afii10017 +!C1 U+0411 afii10018 +!C2 U+0412 afii10019 +!C3 U+0413 afii10020 +!C4 U+0414 afii10021 +!C5 U+0415 afii10022 +!C6 U+0416 afii10024 +!C7 U+0417 afii10025 +!C8 U+0418 afii10026 +!C9 U+0419 afii10027 +!CA U+041A afii10028 +!CB U+041B afii10029 +!CC U+041C afii10030 +!CD U+041D afii10031 +!CE U+041E afii10032 +!CF U+041F afii10033 +!D0 U+0420 afii10034 +!D1 U+0421 afii10035 +!D2 U+0422 afii10036 +!D3 U+0423 afii10037 +!D4 U+0424 afii10038 +!D5 U+0425 afii10039 +!D6 U+0426 afii10040 +!D7 U+0427 afii10041 +!D8 U+0428 afii10042 +!D9 U+0429 afii10043 +!DA U+042A afii10044 +!DB U+042B afii10045 +!DC U+042C afii10046 +!DD U+042D afii10047 +!DE U+042E afii10048 +!DF U+042F afii10049 +!E0 U+0430 afii10065 +!E1 U+0431 afii10066 +!E2 U+0432 afii10067 +!E3 U+0433 afii10068 +!E4 U+0434 afii10069 +!E5 U+0435 afii10070 +!E6 U+0436 afii10072 +!E7 U+0437 afii10073 +!E8 U+0438 afii10074 +!E9 U+0439 afii10075 +!EA U+043A afii10076 +!EB U+043B afii10077 +!EC U+043C afii10078 +!ED U+043D afii10079 +!EE U+043E afii10080 +!EF U+043F afii10081 +!F0 U+0440 afii10082 +!F1 U+0441 afii10083 +!F2 U+0442 afii10084 +!F3 U+0443 afii10085 +!F4 U+0444 afii10086 +!F5 U+0445 afii10087 +!F6 U+0446 afii10088 +!F7 U+0447 afii10089 +!F8 U+0448 afii10090 +!F9 U+0449 afii10091 +!FA U+044A afii10092 +!FB U+044B afii10093 +!FC U+044C afii10094 +!FD U+044D afii10095 +!FE U+044E afii10096 +!FF U+044F afii10097 diff --git a/include/pdf/font/makefont/cp1252.map b/include/pdf/font/makefont/cp1252.map new file mode 100644 index 000000000..dd490e596 --- /dev/null +++ b/include/pdf/font/makefont/cp1252.map @@ -0,0 +1,251 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+0152 OE +!8E U+017D Zcaron +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+0153 oe +!9E U+017E zcaron +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff --git a/include/pdf/font/makefont/cp1253.map b/include/pdf/font/makefont/cp1253.map new file mode 100644 index 000000000..4bd826fb2 --- /dev/null +++ b/include/pdf/font/makefont/cp1253.map @@ -0,0 +1,239 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9B U+203A guilsinglright +!A0 U+00A0 space +!A1 U+0385 dieresistonos +!A2 U+0386 Alphatonos +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+2015 afii00208 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+0384 tonos +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+0388 Epsilontonos +!B9 U+0389 Etatonos +!BA U+038A Iotatonos +!BB U+00BB guillemotright +!BC U+038C Omicrontonos +!BD U+00BD onehalf +!BE U+038E Upsilontonos +!BF U+038F Omegatonos +!C0 U+0390 iotadieresistonos +!C1 U+0391 Alpha +!C2 U+0392 Beta +!C3 U+0393 Gamma +!C4 U+0394 Delta +!C5 U+0395 Epsilon +!C6 U+0396 Zeta +!C7 U+0397 Eta +!C8 U+0398 Theta +!C9 U+0399 Iota +!CA U+039A Kappa +!CB U+039B Lambda +!CC U+039C Mu +!CD U+039D Nu +!CE U+039E Xi +!CF U+039F Omicron +!D0 U+03A0 Pi +!D1 U+03A1 Rho +!D3 U+03A3 Sigma +!D4 U+03A4 Tau +!D5 U+03A5 Upsilon +!D6 U+03A6 Phi +!D7 U+03A7 Chi +!D8 U+03A8 Psi +!D9 U+03A9 Omega +!DA U+03AA Iotadieresis +!DB U+03AB Upsilondieresis +!DC U+03AC alphatonos +!DD U+03AD epsilontonos +!DE U+03AE etatonos +!DF U+03AF iotatonos +!E0 U+03B0 upsilondieresistonos +!E1 U+03B1 alpha +!E2 U+03B2 beta +!E3 U+03B3 gamma +!E4 U+03B4 delta +!E5 U+03B5 epsilon +!E6 U+03B6 zeta +!E7 U+03B7 eta +!E8 U+03B8 theta +!E9 U+03B9 iota +!EA U+03BA kappa +!EB U+03BB lambda +!EC U+03BC mu +!ED U+03BD nu +!EE U+03BE xi +!EF U+03BF omicron +!F0 U+03C0 pi +!F1 U+03C1 rho +!F2 U+03C2 sigma1 +!F3 U+03C3 sigma +!F4 U+03C4 tau +!F5 U+03C5 upsilon +!F6 U+03C6 phi +!F7 U+03C7 chi +!F8 U+03C8 psi +!F9 U+03C9 omega +!FA U+03CA iotadieresis +!FB U+03CB upsilondieresis +!FC U+03CC omicrontonos +!FD U+03CD upsilontonos +!FE U+03CE omegatonos diff --git a/include/pdf/font/makefont/cp1254.map b/include/pdf/font/makefont/cp1254.map new file mode 100644 index 000000000..829473b28 --- /dev/null +++ b/include/pdf/font/makefont/cp1254.map @@ -0,0 +1,249 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+0152 OE +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+0153 oe +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+011E Gbreve +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0130 Idotaccent +!DE U+015E Scedilla +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+011F gbreve +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0131 dotlessi +!FE U+015F scedilla +!FF U+00FF ydieresis diff --git a/include/pdf/font/makefont/cp1255.map b/include/pdf/font/makefont/cp1255.map new file mode 100644 index 000000000..079e10c61 --- /dev/null +++ b/include/pdf/font/makefont/cp1255.map @@ -0,0 +1,233 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9B U+203A guilsinglright +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+20AA afii57636 +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00D7 multiply +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD sfthyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 middot +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00F7 divide +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+05B0 afii57799 +!C1 U+05B1 afii57801 +!C2 U+05B2 afii57800 +!C3 U+05B3 afii57802 +!C4 U+05B4 afii57793 +!C5 U+05B5 afii57794 +!C6 U+05B6 afii57795 +!C7 U+05B7 afii57798 +!C8 U+05B8 afii57797 +!C9 U+05B9 afii57806 +!CB U+05BB afii57796 +!CC U+05BC afii57807 +!CD U+05BD afii57839 +!CE U+05BE afii57645 +!CF U+05BF afii57841 +!D0 U+05C0 afii57842 +!D1 U+05C1 afii57804 +!D2 U+05C2 afii57803 +!D3 U+05C3 afii57658 +!D4 U+05F0 afii57716 +!D5 U+05F1 afii57717 +!D6 U+05F2 afii57718 +!D7 U+05F3 gereshhebrew +!D8 U+05F4 gershayimhebrew +!E0 U+05D0 afii57664 +!E1 U+05D1 afii57665 +!E2 U+05D2 afii57666 +!E3 U+05D3 afii57667 +!E4 U+05D4 afii57668 +!E5 U+05D5 afii57669 +!E6 U+05D6 afii57670 +!E7 U+05D7 afii57671 +!E8 U+05D8 afii57672 +!E9 U+05D9 afii57673 +!EA U+05DA afii57674 +!EB U+05DB afii57675 +!EC U+05DC afii57676 +!ED U+05DD afii57677 +!EE U+05DE afii57678 +!EF U+05DF afii57679 +!F0 U+05E0 afii57680 +!F1 U+05E1 afii57681 +!F2 U+05E2 afii57682 +!F3 U+05E3 afii57683 +!F4 U+05E4 afii57684 +!F5 U+05E5 afii57685 +!F6 U+05E6 afii57686 +!F7 U+05E7 afii57687 +!F8 U+05E8 afii57688 +!F9 U+05E9 afii57689 +!FA U+05EA afii57690 +!FD U+200E afii299 +!FE U+200F afii300 diff --git a/include/pdf/font/makefont/cp1257.map b/include/pdf/font/makefont/cp1257.map new file mode 100644 index 000000000..2f2ecfa21 --- /dev/null +++ b/include/pdf/font/makefont/cp1257.map @@ -0,0 +1,244 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!8D U+00A8 dieresis +!8E U+02C7 caron +!8F U+00B8 cedilla +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9B U+203A guilsinglright +!9D U+00AF macron +!9E U+02DB ogonek +!A0 U+00A0 space +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00D8 Oslash +!A9 U+00A9 copyright +!AA U+0156 Rcommaaccent +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00C6 AE +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00F8 oslash +!B9 U+00B9 onesuperior +!BA U+0157 rcommaaccent +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00E6 ae +!C0 U+0104 Aogonek +!C1 U+012E Iogonek +!C2 U+0100 Amacron +!C3 U+0106 Cacute +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+0118 Eogonek +!C7 U+0112 Emacron +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0179 Zacute +!CB U+0116 Edotaccent +!CC U+0122 Gcommaaccent +!CD U+0136 Kcommaaccent +!CE U+012A Imacron +!CF U+013B Lcommaaccent +!D0 U+0160 Scaron +!D1 U+0143 Nacute +!D2 U+0145 Ncommaaccent +!D3 U+00D3 Oacute +!D4 U+014C Omacron +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0172 Uogonek +!D9 U+0141 Lslash +!DA U+015A Sacute +!DB U+016A Umacron +!DC U+00DC Udieresis +!DD U+017B Zdotaccent +!DE U+017D Zcaron +!DF U+00DF germandbls +!E0 U+0105 aogonek +!E1 U+012F iogonek +!E2 U+0101 amacron +!E3 U+0107 cacute +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+0119 eogonek +!E7 U+0113 emacron +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+017A zacute +!EB U+0117 edotaccent +!EC U+0123 gcommaaccent +!ED U+0137 kcommaaccent +!EE U+012B imacron +!EF U+013C lcommaaccent +!F0 U+0161 scaron +!F1 U+0144 nacute +!F2 U+0146 ncommaaccent +!F3 U+00F3 oacute +!F4 U+014D omacron +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0173 uogonek +!F9 U+0142 lslash +!FA U+015B sacute +!FB U+016B umacron +!FC U+00FC udieresis +!FD U+017C zdotaccent +!FE U+017E zcaron +!FF U+02D9 dotaccent diff --git a/include/pdf/font/makefont/cp1258.map b/include/pdf/font/makefont/cp1258.map new file mode 100644 index 000000000..fed915f71 --- /dev/null +++ b/include/pdf/font/makefont/cp1258.map @@ -0,0 +1,247 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!8C U+0152 OE +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9B U+203A guilsinglright +!9C U+0153 oe +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+0300 gravecomb +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+0110 Dcroat +!D1 U+00D1 Ntilde +!D2 U+0309 hookabovecomb +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+01A0 Ohorn +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+01AF Uhorn +!DE U+0303 tildecomb +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+0301 acutecomb +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+0111 dcroat +!F1 U+00F1 ntilde +!F2 U+0323 dotbelowcomb +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+01A1 ohorn +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+01B0 uhorn +!FE U+20AB dong +!FF U+00FF ydieresis diff --git a/include/pdf/font/makefont/cp874.map b/include/pdf/font/makefont/cp874.map new file mode 100644 index 000000000..1006e6b17 --- /dev/null +++ b/include/pdf/font/makefont/cp874.map @@ -0,0 +1,225 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!85 U+2026 ellipsis +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!A0 U+00A0 space +!A1 U+0E01 kokaithai +!A2 U+0E02 khokhaithai +!A3 U+0E03 khokhuatthai +!A4 U+0E04 khokhwaithai +!A5 U+0E05 khokhonthai +!A6 U+0E06 khorakhangthai +!A7 U+0E07 ngonguthai +!A8 U+0E08 chochanthai +!A9 U+0E09 chochingthai +!AA U+0E0A chochangthai +!AB U+0E0B sosothai +!AC U+0E0C chochoethai +!AD U+0E0D yoyingthai +!AE U+0E0E dochadathai +!AF U+0E0F topatakthai +!B0 U+0E10 thothanthai +!B1 U+0E11 thonangmonthothai +!B2 U+0E12 thophuthaothai +!B3 U+0E13 nonenthai +!B4 U+0E14 dodekthai +!B5 U+0E15 totaothai +!B6 U+0E16 thothungthai +!B7 U+0E17 thothahanthai +!B8 U+0E18 thothongthai +!B9 U+0E19 nonuthai +!BA U+0E1A bobaimaithai +!BB U+0E1B poplathai +!BC U+0E1C phophungthai +!BD U+0E1D fofathai +!BE U+0E1E phophanthai +!BF U+0E1F fofanthai +!C0 U+0E20 phosamphaothai +!C1 U+0E21 momathai +!C2 U+0E22 yoyakthai +!C3 U+0E23 roruathai +!C4 U+0E24 ruthai +!C5 U+0E25 lolingthai +!C6 U+0E26 luthai +!C7 U+0E27 wowaenthai +!C8 U+0E28 sosalathai +!C9 U+0E29 sorusithai +!CA U+0E2A sosuathai +!CB U+0E2B hohipthai +!CC U+0E2C lochulathai +!CD U+0E2D oangthai +!CE U+0E2E honokhukthai +!CF U+0E2F paiyannoithai +!D0 U+0E30 saraathai +!D1 U+0E31 maihanakatthai +!D2 U+0E32 saraaathai +!D3 U+0E33 saraamthai +!D4 U+0E34 saraithai +!D5 U+0E35 saraiithai +!D6 U+0E36 sarauethai +!D7 U+0E37 saraueethai +!D8 U+0E38 sarauthai +!D9 U+0E39 sarauuthai +!DA U+0E3A phinthuthai +!DF U+0E3F bahtthai +!E0 U+0E40 saraethai +!E1 U+0E41 saraaethai +!E2 U+0E42 saraothai +!E3 U+0E43 saraaimaimuanthai +!E4 U+0E44 saraaimaimalaithai +!E5 U+0E45 lakkhangyaothai +!E6 U+0E46 maiyamokthai +!E7 U+0E47 maitaikhuthai +!E8 U+0E48 maiekthai +!E9 U+0E49 maithothai +!EA U+0E4A maitrithai +!EB U+0E4B maichattawathai +!EC U+0E4C thanthakhatthai +!ED U+0E4D nikhahitthai +!EE U+0E4E yamakkanthai +!EF U+0E4F fongmanthai +!F0 U+0E50 zerothai +!F1 U+0E51 onethai +!F2 U+0E52 twothai +!F3 U+0E53 threethai +!F4 U+0E54 fourthai +!F5 U+0E55 fivethai +!F6 U+0E56 sixthai +!F7 U+0E57 seventhai +!F8 U+0E58 eightthai +!F9 U+0E59 ninethai +!FA U+0E5A angkhankhuthai +!FB U+0E5B khomutthai diff --git a/include/pdf/font/makefont/iso-8859-1.map b/include/pdf/font/makefont/iso-8859-1.map new file mode 100644 index 000000000..61740a38f --- /dev/null +++ b/include/pdf/font/makefont/iso-8859-1.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff --git a/include/pdf/font/makefont/iso-8859-11.map b/include/pdf/font/makefont/iso-8859-11.map new file mode 100644 index 000000000..916881206 --- /dev/null +++ b/include/pdf/font/makefont/iso-8859-11.map @@ -0,0 +1,248 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0E01 kokaithai +!A2 U+0E02 khokhaithai +!A3 U+0E03 khokhuatthai +!A4 U+0E04 khokhwaithai +!A5 U+0E05 khokhonthai +!A6 U+0E06 khorakhangthai +!A7 U+0E07 ngonguthai +!A8 U+0E08 chochanthai +!A9 U+0E09 chochingthai +!AA U+0E0A chochangthai +!AB U+0E0B sosothai +!AC U+0E0C chochoethai +!AD U+0E0D yoyingthai +!AE U+0E0E dochadathai +!AF U+0E0F topatakthai +!B0 U+0E10 thothanthai +!B1 U+0E11 thonangmonthothai +!B2 U+0E12 thophuthaothai +!B3 U+0E13 nonenthai +!B4 U+0E14 dodekthai +!B5 U+0E15 totaothai +!B6 U+0E16 thothungthai +!B7 U+0E17 thothahanthai +!B8 U+0E18 thothongthai +!B9 U+0E19 nonuthai +!BA U+0E1A bobaimaithai +!BB U+0E1B poplathai +!BC U+0E1C phophungthai +!BD U+0E1D fofathai +!BE U+0E1E phophanthai +!BF U+0E1F fofanthai +!C0 U+0E20 phosamphaothai +!C1 U+0E21 momathai +!C2 U+0E22 yoyakthai +!C3 U+0E23 roruathai +!C4 U+0E24 ruthai +!C5 U+0E25 lolingthai +!C6 U+0E26 luthai +!C7 U+0E27 wowaenthai +!C8 U+0E28 sosalathai +!C9 U+0E29 sorusithai +!CA U+0E2A sosuathai +!CB U+0E2B hohipthai +!CC U+0E2C lochulathai +!CD U+0E2D oangthai +!CE U+0E2E honokhukthai +!CF U+0E2F paiyannoithai +!D0 U+0E30 saraathai +!D1 U+0E31 maihanakatthai +!D2 U+0E32 saraaathai +!D3 U+0E33 saraamthai +!D4 U+0E34 saraithai +!D5 U+0E35 saraiithai +!D6 U+0E36 sarauethai +!D7 U+0E37 saraueethai +!D8 U+0E38 sarauthai +!D9 U+0E39 sarauuthai +!DA U+0E3A phinthuthai +!DF U+0E3F bahtthai +!E0 U+0E40 saraethai +!E1 U+0E41 saraaethai +!E2 U+0E42 saraothai +!E3 U+0E43 saraaimaimuanthai +!E4 U+0E44 saraaimaimalaithai +!E5 U+0E45 lakkhangyaothai +!E6 U+0E46 maiyamokthai +!E7 U+0E47 maitaikhuthai +!E8 U+0E48 maiekthai +!E9 U+0E49 maithothai +!EA U+0E4A maitrithai +!EB U+0E4B maichattawathai +!EC U+0E4C thanthakhatthai +!ED U+0E4D nikhahitthai +!EE U+0E4E yamakkanthai +!EF U+0E4F fongmanthai +!F0 U+0E50 zerothai +!F1 U+0E51 onethai +!F2 U+0E52 twothai +!F3 U+0E53 threethai +!F4 U+0E54 fourthai +!F5 U+0E55 fivethai +!F6 U+0E56 sixthai +!F7 U+0E57 seventhai +!F8 U+0E58 eightthai +!F9 U+0E59 ninethai +!FA U+0E5A angkhankhuthai +!FB U+0E5B khomutthai diff --git a/include/pdf/font/makefont/iso-8859-15.map b/include/pdf/font/makefont/iso-8859-15.map new file mode 100644 index 000000000..6c2b57127 --- /dev/null +++ b/include/pdf/font/makefont/iso-8859-15.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+20AC Euro +!A5 U+00A5 yen +!A6 U+0160 Scaron +!A7 U+00A7 section +!A8 U+0161 scaron +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+017D Zcaron +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+017E zcaron +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+0152 OE +!BD U+0153 oe +!BE U+0178 Ydieresis +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff --git a/include/pdf/font/makefont/iso-8859-16.map b/include/pdf/font/makefont/iso-8859-16.map new file mode 100644 index 000000000..202c8fe59 --- /dev/null +++ b/include/pdf/font/makefont/iso-8859-16.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+0105 aogonek +!A3 U+0141 Lslash +!A4 U+20AC Euro +!A5 U+201E quotedblbase +!A6 U+0160 Scaron +!A7 U+00A7 section +!A8 U+0161 scaron +!A9 U+00A9 copyright +!AA U+0218 Scommaaccent +!AB U+00AB guillemotleft +!AC U+0179 Zacute +!AD U+00AD hyphen +!AE U+017A zacute +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+010C Ccaron +!B3 U+0142 lslash +!B4 U+017D Zcaron +!B5 U+201D quotedblright +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+017E zcaron +!B9 U+010D ccaron +!BA U+0219 scommaaccent +!BB U+00BB guillemotright +!BC U+0152 OE +!BD U+0153 oe +!BE U+0178 Ydieresis +!BF U+017C zdotaccent +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0106 Cacute +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+015A Sacute +!D8 U+0170 Uhungarumlaut +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0118 Eogonek +!DE U+021A Tcommaaccent +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+0107 cacute +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+015B sacute +!F8 U+0171 uhungarumlaut +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0119 eogonek +!FE U+021B tcommaaccent +!FF U+00FF ydieresis diff --git a/include/pdf/font/makefont/iso-8859-2.map b/include/pdf/font/makefont/iso-8859-2.map new file mode 100644 index 000000000..65ae09f95 --- /dev/null +++ b/include/pdf/font/makefont/iso-8859-2.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+02D8 breve +!A3 U+0141 Lslash +!A4 U+00A4 currency +!A5 U+013D Lcaron +!A6 U+015A Sacute +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+0160 Scaron +!AA U+015E Scedilla +!AB U+0164 Tcaron +!AC U+0179 Zacute +!AD U+00AD hyphen +!AE U+017D Zcaron +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+0105 aogonek +!B2 U+02DB ogonek +!B3 U+0142 lslash +!B4 U+00B4 acute +!B5 U+013E lcaron +!B6 U+015B sacute +!B7 U+02C7 caron +!B8 U+00B8 cedilla +!B9 U+0161 scaron +!BA U+015F scedilla +!BB U+0165 tcaron +!BC U+017A zacute +!BD U+02DD hungarumlaut +!BE U+017E zcaron +!BF U+017C zdotaccent +!C0 U+0154 Racute +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0139 Lacute +!C6 U+0106 Cacute +!C7 U+00C7 Ccedilla +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+011A Ecaron +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+010E Dcaron +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+0147 Ncaron +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0158 Rcaron +!D9 U+016E Uring +!DA U+00DA Uacute +!DB U+0170 Uhungarumlaut +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+0162 Tcommaaccent +!DF U+00DF germandbls +!E0 U+0155 racute +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+013A lacute +!E6 U+0107 cacute +!E7 U+00E7 ccedilla +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+011B ecaron +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+010F dcaron +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+0148 ncaron +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0159 rcaron +!F9 U+016F uring +!FA U+00FA uacute +!FB U+0171 uhungarumlaut +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+0163 tcommaaccent +!FF U+02D9 dotaccent diff --git a/include/pdf/font/makefont/iso-8859-4.map b/include/pdf/font/makefont/iso-8859-4.map new file mode 100644 index 000000000..a7d87bf3e --- /dev/null +++ b/include/pdf/font/makefont/iso-8859-4.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+0138 kgreenlandic +!A3 U+0156 Rcommaaccent +!A4 U+00A4 currency +!A5 U+0128 Itilde +!A6 U+013B Lcommaaccent +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+0160 Scaron +!AA U+0112 Emacron +!AB U+0122 Gcommaaccent +!AC U+0166 Tbar +!AD U+00AD hyphen +!AE U+017D Zcaron +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+0105 aogonek +!B2 U+02DB ogonek +!B3 U+0157 rcommaaccent +!B4 U+00B4 acute +!B5 U+0129 itilde +!B6 U+013C lcommaaccent +!B7 U+02C7 caron +!B8 U+00B8 cedilla +!B9 U+0161 scaron +!BA U+0113 emacron +!BB U+0123 gcommaaccent +!BC U+0167 tbar +!BD U+014A Eng +!BE U+017E zcaron +!BF U+014B eng +!C0 U+0100 Amacron +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+012E Iogonek +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+0116 Edotaccent +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+012A Imacron +!D0 U+0110 Dcroat +!D1 U+0145 Ncommaaccent +!D2 U+014C Omacron +!D3 U+0136 Kcommaaccent +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+0172 Uogonek +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0168 Utilde +!DE U+016A Umacron +!DF U+00DF germandbls +!E0 U+0101 amacron +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+012F iogonek +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+0117 edotaccent +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+012B imacron +!F0 U+0111 dcroat +!F1 U+0146 ncommaaccent +!F2 U+014D omacron +!F3 U+0137 kcommaaccent +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+0173 uogonek +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0169 utilde +!FE U+016B umacron +!FF U+02D9 dotaccent diff --git a/include/pdf/font/makefont/iso-8859-5.map b/include/pdf/font/makefont/iso-8859-5.map new file mode 100644 index 000000000..f9cd4edcf --- /dev/null +++ b/include/pdf/font/makefont/iso-8859-5.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0401 afii10023 +!A2 U+0402 afii10051 +!A3 U+0403 afii10052 +!A4 U+0404 afii10053 +!A5 U+0405 afii10054 +!A6 U+0406 afii10055 +!A7 U+0407 afii10056 +!A8 U+0408 afii10057 +!A9 U+0409 afii10058 +!AA U+040A afii10059 +!AB U+040B afii10060 +!AC U+040C afii10061 +!AD U+00AD hyphen +!AE U+040E afii10062 +!AF U+040F afii10145 +!B0 U+0410 afii10017 +!B1 U+0411 afii10018 +!B2 U+0412 afii10019 +!B3 U+0413 afii10020 +!B4 U+0414 afii10021 +!B5 U+0415 afii10022 +!B6 U+0416 afii10024 +!B7 U+0417 afii10025 +!B8 U+0418 afii10026 +!B9 U+0419 afii10027 +!BA U+041A afii10028 +!BB U+041B afii10029 +!BC U+041C afii10030 +!BD U+041D afii10031 +!BE U+041E afii10032 +!BF U+041F afii10033 +!C0 U+0420 afii10034 +!C1 U+0421 afii10035 +!C2 U+0422 afii10036 +!C3 U+0423 afii10037 +!C4 U+0424 afii10038 +!C5 U+0425 afii10039 +!C6 U+0426 afii10040 +!C7 U+0427 afii10041 +!C8 U+0428 afii10042 +!C9 U+0429 afii10043 +!CA U+042A afii10044 +!CB U+042B afii10045 +!CC U+042C afii10046 +!CD U+042D afii10047 +!CE U+042E afii10048 +!CF U+042F afii10049 +!D0 U+0430 afii10065 +!D1 U+0431 afii10066 +!D2 U+0432 afii10067 +!D3 U+0433 afii10068 +!D4 U+0434 afii10069 +!D5 U+0435 afii10070 +!D6 U+0436 afii10072 +!D7 U+0437 afii10073 +!D8 U+0438 afii10074 +!D9 U+0439 afii10075 +!DA U+043A afii10076 +!DB U+043B afii10077 +!DC U+043C afii10078 +!DD U+043D afii10079 +!DE U+043E afii10080 +!DF U+043F afii10081 +!E0 U+0440 afii10082 +!E1 U+0441 afii10083 +!E2 U+0442 afii10084 +!E3 U+0443 afii10085 +!E4 U+0444 afii10086 +!E5 U+0445 afii10087 +!E6 U+0446 afii10088 +!E7 U+0447 afii10089 +!E8 U+0448 afii10090 +!E9 U+0449 afii10091 +!EA U+044A afii10092 +!EB U+044B afii10093 +!EC U+044C afii10094 +!ED U+044D afii10095 +!EE U+044E afii10096 +!EF U+044F afii10097 +!F0 U+2116 afii61352 +!F1 U+0451 afii10071 +!F2 U+0452 afii10099 +!F3 U+0453 afii10100 +!F4 U+0454 afii10101 +!F5 U+0455 afii10102 +!F6 U+0456 afii10103 +!F7 U+0457 afii10104 +!F8 U+0458 afii10105 +!F9 U+0459 afii10106 +!FA U+045A afii10107 +!FB U+045B afii10108 +!FC U+045C afii10109 +!FD U+00A7 section +!FE U+045E afii10110 +!FF U+045F afii10193 diff --git a/include/pdf/font/makefont/iso-8859-7.map b/include/pdf/font/makefont/iso-8859-7.map new file mode 100644 index 000000000..e163796b1 --- /dev/null +++ b/include/pdf/font/makefont/iso-8859-7.map @@ -0,0 +1,250 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+2018 quoteleft +!A2 U+2019 quoteright +!A3 U+00A3 sterling +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AF U+2015 afii00208 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+0384 tonos +!B5 U+0385 dieresistonos +!B6 U+0386 Alphatonos +!B7 U+00B7 periodcentered +!B8 U+0388 Epsilontonos +!B9 U+0389 Etatonos +!BA U+038A Iotatonos +!BB U+00BB guillemotright +!BC U+038C Omicrontonos +!BD U+00BD onehalf +!BE U+038E Upsilontonos +!BF U+038F Omegatonos +!C0 U+0390 iotadieresistonos +!C1 U+0391 Alpha +!C2 U+0392 Beta +!C3 U+0393 Gamma +!C4 U+0394 Delta +!C5 U+0395 Epsilon +!C6 U+0396 Zeta +!C7 U+0397 Eta +!C8 U+0398 Theta +!C9 U+0399 Iota +!CA U+039A Kappa +!CB U+039B Lambda +!CC U+039C Mu +!CD U+039D Nu +!CE U+039E Xi +!CF U+039F Omicron +!D0 U+03A0 Pi +!D1 U+03A1 Rho +!D3 U+03A3 Sigma +!D4 U+03A4 Tau +!D5 U+03A5 Upsilon +!D6 U+03A6 Phi +!D7 U+03A7 Chi +!D8 U+03A8 Psi +!D9 U+03A9 Omega +!DA U+03AA Iotadieresis +!DB U+03AB Upsilondieresis +!DC U+03AC alphatonos +!DD U+03AD epsilontonos +!DE U+03AE etatonos +!DF U+03AF iotatonos +!E0 U+03B0 upsilondieresistonos +!E1 U+03B1 alpha +!E2 U+03B2 beta +!E3 U+03B3 gamma +!E4 U+03B4 delta +!E5 U+03B5 epsilon +!E6 U+03B6 zeta +!E7 U+03B7 eta +!E8 U+03B8 theta +!E9 U+03B9 iota +!EA U+03BA kappa +!EB U+03BB lambda +!EC U+03BC mu +!ED U+03BD nu +!EE U+03BE xi +!EF U+03BF omicron +!F0 U+03C0 pi +!F1 U+03C1 rho +!F2 U+03C2 sigma1 +!F3 U+03C3 sigma +!F4 U+03C4 tau +!F5 U+03C5 upsilon +!F6 U+03C6 phi +!F7 U+03C7 chi +!F8 U+03C8 psi +!F9 U+03C9 omega +!FA U+03CA iotadieresis +!FB U+03CB upsilondieresis +!FC U+03CC omicrontonos +!FD U+03CD upsilontonos +!FE U+03CE omegatonos diff --git a/include/pdf/font/makefont/iso-8859-9.map b/include/pdf/font/makefont/iso-8859-9.map new file mode 100644 index 000000000..48c123ae6 --- /dev/null +++ b/include/pdf/font/makefont/iso-8859-9.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+011E Gbreve +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0130 Idotaccent +!DE U+015E Scedilla +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+011F gbreve +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0131 dotlessi +!FE U+015F scedilla +!FF U+00FF ydieresis diff --git a/include/pdf/font/makefont/koi8-r.map b/include/pdf/font/makefont/koi8-r.map new file mode 100644 index 000000000..6ad5d05d0 --- /dev/null +++ b/include/pdf/font/makefont/koi8-r.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+2500 SF100000 +!81 U+2502 SF110000 +!82 U+250C SF010000 +!83 U+2510 SF030000 +!84 U+2514 SF020000 +!85 U+2518 SF040000 +!86 U+251C SF080000 +!87 U+2524 SF090000 +!88 U+252C SF060000 +!89 U+2534 SF070000 +!8A U+253C SF050000 +!8B U+2580 upblock +!8C U+2584 dnblock +!8D U+2588 block +!8E U+258C lfblock +!8F U+2590 rtblock +!90 U+2591 ltshade +!91 U+2592 shade +!92 U+2593 dkshade +!93 U+2320 integraltp +!94 U+25A0 filledbox +!95 U+2219 periodcentered +!96 U+221A radical +!97 U+2248 approxequal +!98 U+2264 lessequal +!99 U+2265 greaterequal +!9A U+00A0 space +!9B U+2321 integralbt +!9C U+00B0 degree +!9D U+00B2 twosuperior +!9E U+00B7 periodcentered +!9F U+00F7 divide +!A0 U+2550 SF430000 +!A1 U+2551 SF240000 +!A2 U+2552 SF510000 +!A3 U+0451 afii10071 +!A4 U+2553 SF520000 +!A5 U+2554 SF390000 +!A6 U+2555 SF220000 +!A7 U+2556 SF210000 +!A8 U+2557 SF250000 +!A9 U+2558 SF500000 +!AA U+2559 SF490000 +!AB U+255A SF380000 +!AC U+255B SF280000 +!AD U+255C SF270000 +!AE U+255D SF260000 +!AF U+255E SF360000 +!B0 U+255F SF370000 +!B1 U+2560 SF420000 +!B2 U+2561 SF190000 +!B3 U+0401 afii10023 +!B4 U+2562 SF200000 +!B5 U+2563 SF230000 +!B6 U+2564 SF470000 +!B7 U+2565 SF480000 +!B8 U+2566 SF410000 +!B9 U+2567 SF450000 +!BA U+2568 SF460000 +!BB U+2569 SF400000 +!BC U+256A SF540000 +!BD U+256B SF530000 +!BE U+256C SF440000 +!BF U+00A9 copyright +!C0 U+044E afii10096 +!C1 U+0430 afii10065 +!C2 U+0431 afii10066 +!C3 U+0446 afii10088 +!C4 U+0434 afii10069 +!C5 U+0435 afii10070 +!C6 U+0444 afii10086 +!C7 U+0433 afii10068 +!C8 U+0445 afii10087 +!C9 U+0438 afii10074 +!CA U+0439 afii10075 +!CB U+043A afii10076 +!CC U+043B afii10077 +!CD U+043C afii10078 +!CE U+043D afii10079 +!CF U+043E afii10080 +!D0 U+043F afii10081 +!D1 U+044F afii10097 +!D2 U+0440 afii10082 +!D3 U+0441 afii10083 +!D4 U+0442 afii10084 +!D5 U+0443 afii10085 +!D6 U+0436 afii10072 +!D7 U+0432 afii10067 +!D8 U+044C afii10094 +!D9 U+044B afii10093 +!DA U+0437 afii10073 +!DB U+0448 afii10090 +!DC U+044D afii10095 +!DD U+0449 afii10091 +!DE U+0447 afii10089 +!DF U+044A afii10092 +!E0 U+042E afii10048 +!E1 U+0410 afii10017 +!E2 U+0411 afii10018 +!E3 U+0426 afii10040 +!E4 U+0414 afii10021 +!E5 U+0415 afii10022 +!E6 U+0424 afii10038 +!E7 U+0413 afii10020 +!E8 U+0425 afii10039 +!E9 U+0418 afii10026 +!EA U+0419 afii10027 +!EB U+041A afii10028 +!EC U+041B afii10029 +!ED U+041C afii10030 +!EE U+041D afii10031 +!EF U+041E afii10032 +!F0 U+041F afii10033 +!F1 U+042F afii10049 +!F2 U+0420 afii10034 +!F3 U+0421 afii10035 +!F4 U+0422 afii10036 +!F5 U+0423 afii10037 +!F6 U+0416 afii10024 +!F7 U+0412 afii10019 +!F8 U+042C afii10046 +!F9 U+042B afii10045 +!FA U+0417 afii10025 +!FB U+0428 afii10042 +!FC U+042D afii10047 +!FD U+0429 afii10043 +!FE U+0427 afii10041 +!FF U+042A afii10044 diff --git a/include/pdf/font/makefont/koi8-u.map b/include/pdf/font/makefont/koi8-u.map new file mode 100644 index 000000000..40a7e4fd7 --- /dev/null +++ b/include/pdf/font/makefont/koi8-u.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+2500 SF100000 +!81 U+2502 SF110000 +!82 U+250C SF010000 +!83 U+2510 SF030000 +!84 U+2514 SF020000 +!85 U+2518 SF040000 +!86 U+251C SF080000 +!87 U+2524 SF090000 +!88 U+252C SF060000 +!89 U+2534 SF070000 +!8A U+253C SF050000 +!8B U+2580 upblock +!8C U+2584 dnblock +!8D U+2588 block +!8E U+258C lfblock +!8F U+2590 rtblock +!90 U+2591 ltshade +!91 U+2592 shade +!92 U+2593 dkshade +!93 U+2320 integraltp +!94 U+25A0 filledbox +!95 U+2022 bullet +!96 U+221A radical +!97 U+2248 approxequal +!98 U+2264 lessequal +!99 U+2265 greaterequal +!9A U+00A0 space +!9B U+2321 integralbt +!9C U+00B0 degree +!9D U+00B2 twosuperior +!9E U+00B7 periodcentered +!9F U+00F7 divide +!A0 U+2550 SF430000 +!A1 U+2551 SF240000 +!A2 U+2552 SF510000 +!A3 U+0451 afii10071 +!A4 U+0454 afii10101 +!A5 U+2554 SF390000 +!A6 U+0456 afii10103 +!A7 U+0457 afii10104 +!A8 U+2557 SF250000 +!A9 U+2558 SF500000 +!AA U+2559 SF490000 +!AB U+255A SF380000 +!AC U+255B SF280000 +!AD U+0491 afii10098 +!AE U+255D SF260000 +!AF U+255E SF360000 +!B0 U+255F SF370000 +!B1 U+2560 SF420000 +!B2 U+2561 SF190000 +!B3 U+0401 afii10023 +!B4 U+0404 afii10053 +!B5 U+2563 SF230000 +!B6 U+0406 afii10055 +!B7 U+0407 afii10056 +!B8 U+2566 SF410000 +!B9 U+2567 SF450000 +!BA U+2568 SF460000 +!BB U+2569 SF400000 +!BC U+256A SF540000 +!BD U+0490 afii10050 +!BE U+256C SF440000 +!BF U+00A9 copyright +!C0 U+044E afii10096 +!C1 U+0430 afii10065 +!C2 U+0431 afii10066 +!C3 U+0446 afii10088 +!C4 U+0434 afii10069 +!C5 U+0435 afii10070 +!C6 U+0444 afii10086 +!C7 U+0433 afii10068 +!C8 U+0445 afii10087 +!C9 U+0438 afii10074 +!CA U+0439 afii10075 +!CB U+043A afii10076 +!CC U+043B afii10077 +!CD U+043C afii10078 +!CE U+043D afii10079 +!CF U+043E afii10080 +!D0 U+043F afii10081 +!D1 U+044F afii10097 +!D2 U+0440 afii10082 +!D3 U+0441 afii10083 +!D4 U+0442 afii10084 +!D5 U+0443 afii10085 +!D6 U+0436 afii10072 +!D7 U+0432 afii10067 +!D8 U+044C afii10094 +!D9 U+044B afii10093 +!DA U+0437 afii10073 +!DB U+0448 afii10090 +!DC U+044D afii10095 +!DD U+0449 afii10091 +!DE U+0447 afii10089 +!DF U+044A afii10092 +!E0 U+042E afii10048 +!E1 U+0410 afii10017 +!E2 U+0411 afii10018 +!E3 U+0426 afii10040 +!E4 U+0414 afii10021 +!E5 U+0415 afii10022 +!E6 U+0424 afii10038 +!E7 U+0413 afii10020 +!E8 U+0425 afii10039 +!E9 U+0418 afii10026 +!EA U+0419 afii10027 +!EB U+041A afii10028 +!EC U+041B afii10029 +!ED U+041C afii10030 +!EE U+041D afii10031 +!EF U+041E afii10032 +!F0 U+041F afii10033 +!F1 U+042F afii10049 +!F2 U+0420 afii10034 +!F3 U+0421 afii10035 +!F4 U+0422 afii10036 +!F5 U+0423 afii10037 +!F6 U+0416 afii10024 +!F7 U+0412 afii10019 +!F8 U+042C afii10046 +!F9 U+042B afii10045 +!FA U+0417 afii10025 +!FB U+0428 afii10042 +!FC U+042D afii10047 +!FD U+0429 afii10043 +!FE U+0427 afii10041 +!FF U+042A afii10044 diff --git a/include/pdf/font/makefont/makefont.php b/include/pdf/font/makefont/makefont.php new file mode 100644 index 000000000..769e8f30f --- /dev/null +++ b/include/pdf/font/makefont/makefont.php @@ -0,0 +1,400 @@ +Error: encoding not found: '.$enc); + $cc2gn=array(); + foreach($a as $l) + { + if($l{0}=='!') + { + $e=preg_split('/[ \\t]+/',chop($l)); + $cc=hexdec(substr($e[0],1)); + $gn=$e[2]; + $cc2gn[$cc]=$gn; + } + } + for($i=0;$i<=255;$i++) + if(!isset($cc2gn[$i])) + $cc2gn[$i]='.notdef'; + return $cc2gn; +} + +function ReadAFM($file,&$map) +{ + //Read a font metric file + $a=file($file); + if(empty($a)) + die('File not found'); + $widths=array(); + $fm=array(); + $fix=array('Edot'=>'Edotaccent','edot'=>'edotaccent','Idot'=>'Idotaccent','Zdot'=>'Zdotaccent','zdot'=>'zdotaccent', + 'Odblacute'=>'Ohungarumlaut','odblacute'=>'ohungarumlaut','Udblacute'=>'Uhungarumlaut','udblacute'=>'uhungarumlaut', + 'Gcedilla'=>'Gcommaaccent','gcedilla'=>'gcommaaccent','Kcedilla'=>'Kcommaaccent','kcedilla'=>'kcommaaccent', + 'Lcedilla'=>'Lcommaaccent','lcedilla'=>'lcommaaccent','Ncedilla'=>'Ncommaaccent','ncedilla'=>'ncommaaccent', + 'Rcedilla'=>'Rcommaaccent','rcedilla'=>'rcommaaccent','Scedilla'=>'Scommaaccent','scedilla'=>'scommaaccent', + 'Tcedilla'=>'Tcommaaccent','tcedilla'=>'tcommaaccent','Dslash'=>'Dcroat','dslash'=>'dcroat','Dmacron'=>'Dcroat','dmacron'=>'dcroat', + 'combininggraveaccent'=>'gravecomb','combininghookabove'=>'hookabovecomb','combiningtildeaccent'=>'tildecomb', + 'combiningacuteaccent'=>'acutecomb','combiningdotbelow'=>'dotbelowcomb','dongsign'=>'dong'); + foreach($a as $l) + { + $e=explode(' ',chop($l)); + if(count($e)<2) + continue; + $code=$e[0]; + $param=$e[1]; + if($code=='C') + { + //Character metrics + $cc=(int)$e[1]; + $w=$e[4]; + $gn=$e[7]; + if(substr($gn,-4)=='20AC') + $gn='Euro'; + if(isset($fix[$gn])) + { + //Fix incorrect glyph name + foreach($map as $c=>$n) + if($n==$fix[$gn]) + $map[$c]=$gn; + } + if(empty($map)) + { + //Symbolic font: use built-in encoding + $widths[$cc]=$w; + } + else + { + $widths[$gn]=$w; + if($gn=='X') + $fm['CapXHeight']=$e[13]; + } + if($gn=='.notdef') + $fm['MissingWidth']=$w; + } + elseif($code=='FontName') + $fm['FontName']=$param; + elseif($code=='Weight') + $fm['Weight']=$param; + elseif($code=='ItalicAngle') + $fm['ItalicAngle']=(double)$param; + elseif($code=='Ascender') + $fm['Ascender']=(int)$param; + elseif($code=='Descender') + $fm['Descender']=(int)$param; + elseif($code=='UnderlineThickness') + $fm['UnderlineThickness']=(int)$param; + elseif($code=='UnderlinePosition') + $fm['UnderlinePosition']=(int)$param; + elseif($code=='IsFixedPitch') + $fm['IsFixedPitch']=($param=='true'); + elseif($code=='FontBBox') + $fm['FontBBox']=array($e[1],$e[2],$e[3],$e[4]); + elseif($code=='CapHeight') + $fm['CapHeight']=(int)$param; + elseif($code=='StdVW') + $fm['StdVW']=(int)$param; + } + if(!isset($fm['FontName'])) + die('FontName not found'); + if(!empty($map)) + { + if(!isset($widths['.notdef'])) + $widths['.notdef']=600; + if(!isset($widths['Delta']) and isset($widths['increment'])) + $widths['Delta']=$widths['increment']; + //Order widths according to map + for($i=0;$i<=255;$i++) + { + if(!isset($widths[$map[$i]])) + { + echo 'Warning: character '.$map[$i].' is missing
    '; + $widths[$i]=$widths['.notdef']; + } + else + $widths[$i]=$widths[$map[$i]]; + } + } + $fm['Widths']=$widths; + return $fm; +} + +function MakeFontDescriptor($fm,$symbolic) +{ + //Ascent + $asc=(isset($fm['Ascender']) ? $fm['Ascender'] : 1000); + $fd="array('Ascent'=>".$asc; + //Descent + $desc=(isset($fm['Descender']) ? $fm['Descender'] : -200); + $fd.=",'Descent'=>".$desc; + //CapHeight + if(isset($fm['CapHeight'])) + $ch=$fm['CapHeight']; + elseif(isset($fm['CapXHeight'])) + $ch=$fm['CapXHeight']; + else + $ch=$asc; + $fd.=",'CapHeight'=>".$ch; + //Flags + $flags=0; + if(isset($fm['IsFixedPitch']) and $fm['IsFixedPitch']) + $flags+=1<<0; + if($symbolic) + $flags+=1<<2; + if(!$symbolic) + $flags+=1<<5; + if(isset($fm['ItalicAngle']) and $fm['ItalicAngle']!=0) + $flags+=1<<6; + $fd.=",'Flags'=>".$flags; + //FontBBox + if(isset($fm['FontBBox'])) + $fbb=$fm['FontBBox']; + else + $fbb=array(0,$des-100,1000,$asc+100); + $fd.=",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'"; + //ItalicAngle + $ia=(isset($fm['ItalicAngle']) ? $fm['ItalicAngle'] : 0); + $fd.=",'ItalicAngle'=>".$ia; + //StemV + if(isset($fm['StdVW'])) + $stemv=$fm['StdVW']; + elseif(isset($fm['Weight']) and eregi('(bold|black)',$fm['Weight'])) + $stemv=120; + else + $stemv=70; + $fd.=",'StemV'=>".$stemv; + //MissingWidth + if(isset($fm['MissingWidth'])) + $fd.=",'MissingWidth'=>".$fm['MissingWidth']; + $fd.=')'; + return $fd; +} + +function MakeWidthArray($fm) +{ + //Make character width array + $s="array(\n\t"; + $cw=$fm['Widths']; + for($i=0;$i<=255;$i++) + { + if(chr($i)=="'") + $s.="'\\''"; + elseif(chr($i)=="\\") + $s.="'\\\\'"; + elseif($i>=32 and $i<=126) + $s.="'".chr($i)."'"; + else + $s.="chr($i)"; + $s.='=>'.$fm['Widths'][$i]; + if($i<255) + $s.=','; + if(($i+1)%22==0) + $s.="\n\t"; + } + $s.=')'; + return $s; +} + +function MakeFontEncoding($map) +{ + //Build differences from reference encoding + $ref=ReadMap('cp1252'); + $s=''; + $last=0; + for($i=32;$i<=255;$i++) + { + if($map[$i]!=$ref[$i]) + { + if($i!=$last+1) + $s.=$i.' '; + $last=$i; + $s.='/'.$map[$i].' '; + } + } + return chop($s); +} + +function SaveToFile($file,$s,$mode='t') +{ + $f=fopen($file,'w'.$mode); + if(!$f) + die('Can\'t write to file '.$file); + fwrite($f,$s,strlen($s)); + fclose($f); +} + +function ReadShort($f) +{ + $a=unpack('n1n',fread($f,2)); + return $a['n']; +} + +function ReadLong($f) +{ + $a=unpack('N1N',fread($f,4)); + return $a['N']; +} + +function CheckTTF($file) +{ + //Check if font license allows embedding + $f=fopen($file,'rb'); + if(!$f) + die('Error: Can\'t open '.$file); + //Extract number of tables + fseek($f,4,SEEK_CUR); + $nb=ReadShort($f); + fseek($f,6,SEEK_CUR); + //Seek OS/2 table + $found=false; + for($i=0;$i<$nb;$i++) + { + if(fread($f,4)=='OS/2') + { + $found=true; + break; + } + fseek($f,12,SEEK_CUR); + } + if(!$found) + { + fclose($f); + return; + } + fseek($f,4,SEEK_CUR); + $offset=ReadLong($f); + fseek($f,$offset,SEEK_SET); + //Extract fsType flags + fseek($f,8,SEEK_CUR); + $fsType=ReadShort($f); + $rl=($fsType & 0x02)!=0; + $pp=($fsType & 0x04)!=0; + $e=($fsType & 0x08)!=0; + fclose($f); + if($rl and !$pp and !$e) + echo 'Warning: font license does not allow embedding'; +} + +/******************************************************************************* +* $fontfile: path to TTF file (or empty string if not to be embedded) * +* $afmfile: path to AFM file * +* $enc: font encoding (or empty string for symbolic fonts) * +* $patch: optional patch for encoding * +* $type : font type if $fontfile is empty * +*******************************************************************************/ +function MakeFont($fontfile,$afmfile,$enc='cp1252',$patch=array(),$type='TrueType') +{ + //Generate a font definition file + set_magic_quotes_runtime(0); + if($enc) + { + $map=ReadMap($enc); + foreach($patch as $cc=>$gn) + $map[$cc]=$gn; + } + else + $map=array(); + if(!file_exists($afmfile)) + die('Error: AFM file not found: '.$afmfile); + $fm=ReadAFM($afmfile,$map); + if($enc) + $diff=MakeFontEncoding($map); + else + $diff=''; + $fd=MakeFontDescriptor($fm,empty($map)); + //Find font type + if($fontfile) + { + $ext=strtolower(substr($fontfile,-3)); + if($ext=='ttf') + $type='TrueType'; + elseif($ext=='pfb') + $type='Type1'; + else + die('Error: unrecognized font file extension: '.$ext); + } + else + { + if($type!='TrueType' and $type!='Type1') + die('Error: incorrect font type: '.$type); + } + //Start generation + $s='Error: font file not found: '.$fontfile); + if($type=='TrueType') + CheckTTF($fontfile); + $f=fopen($fontfile,'rb'); + if(!$f) + die('Error: Can\'t open '.$fontfile); + $file=fread($f,filesize($fontfile)); + fclose($f); + if($type=='Type1') + { + //Find first two sections and discard third one + $pos=strpos($file,'eexec'); + if(!$pos) + die('Error: font file does not seem to be valid Type1'); + $size1=$pos+6; + $pos=strpos($file,'00000000'); + if(!$pos) + die('Error: font file does not seem to be valid Type1'); + $size2=$pos-$size1; + $file=substr($file,0,$size1+$size2); + } + if(function_exists('gzcompress')) + { + $cmp=$basename.'.z'; + SaveToFile($cmp,gzcompress($file),'b'); + $s.='$file=\''.$cmp."';\n"; + echo 'Font file compressed ('.$cmp.')
    '; + } + else + { + $s.='$file=\''.basename($fontfile)."';\n"; + echo 'Notice: font file could not be compressed (gzcompress not available)
    '; + } + if($type=='Type1') + { + $s.='$size1='.$size1.";\n"; + $s.='$size2='.$size2.";\n"; + } + else + $s.='$originalsize='.filesize($fontfile).";\n"; + } + else + { + //Not embedded font + $s.='$file='."'';\n"; + } + $s.="?>\n"; + SaveToFile($basename.'.php',$s); + echo 'Font definition file generated ('.$basename.'.php'.')
    '; +} +?> diff --git a/include/pdf/font/symbol.php b/include/pdf/font/symbol.php new file mode 100644 index 000000000..43b50e451 --- /dev/null +++ b/include/pdf/font/symbol.php @@ -0,0 +1,15 @@ +250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250, + chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>713,'#'=>500,'$'=>549,'%'=>833,'&'=>778,'\''=>439,'('=>333,')'=>333,'*'=>500,'+'=>549, + ','=>250,'-'=>549,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>278,';'=>278,'<'=>549,'='=>549,'>'=>549,'?'=>444,'@'=>549,'A'=>722, + 'B'=>667,'C'=>722,'D'=>612,'E'=>611,'F'=>763,'G'=>603,'H'=>722,'I'=>333,'J'=>631,'K'=>722,'L'=>686,'M'=>889,'N'=>722,'O'=>722,'P'=>768,'Q'=>741,'R'=>556,'S'=>592,'T'=>611,'U'=>690,'V'=>439,'W'=>768, + 'X'=>645,'Y'=>795,'Z'=>611,'['=>333,'\\'=>863,']'=>333,'^'=>658,'_'=>500,'`'=>500,'a'=>631,'b'=>549,'c'=>549,'d'=>494,'e'=>439,'f'=>521,'g'=>411,'h'=>603,'i'=>329,'j'=>603,'k'=>549,'l'=>549,'m'=>576, + 'n'=>521,'o'=>549,'p'=>549,'q'=>521,'r'=>549,'s'=>603,'t'=>439,'u'=>576,'v'=>713,'w'=>686,'x'=>493,'y'=>686,'z'=>494,'{'=>480,'|'=>200,'}'=>480,'~'=>549,chr(127)=>0,chr(128)=>0,chr(129)=>0,chr(130)=>0,chr(131)=>0, + chr(132)=>0,chr(133)=>0,chr(134)=>0,chr(135)=>0,chr(136)=>0,chr(137)=>0,chr(138)=>0,chr(139)=>0,chr(140)=>0,chr(141)=>0,chr(142)=>0,chr(143)=>0,chr(144)=>0,chr(145)=>0,chr(146)=>0,chr(147)=>0,chr(148)=>0,chr(149)=>0,chr(150)=>0,chr(151)=>0,chr(152)=>0,chr(153)=>0, + chr(154)=>0,chr(155)=>0,chr(156)=>0,chr(157)=>0,chr(158)=>0,chr(159)=>0,chr(160)=>750,chr(161)=>620,chr(162)=>247,chr(163)=>549,chr(164)=>167,chr(165)=>713,chr(166)=>500,chr(167)=>753,chr(168)=>753,chr(169)=>753,chr(170)=>753,chr(171)=>1042,chr(172)=>987,chr(173)=>603,chr(174)=>987,chr(175)=>603, + chr(176)=>400,chr(177)=>549,chr(178)=>411,chr(179)=>549,chr(180)=>549,chr(181)=>713,chr(182)=>494,chr(183)=>460,chr(184)=>549,chr(185)=>549,chr(186)=>549,chr(187)=>549,chr(188)=>1000,chr(189)=>603,chr(190)=>1000,chr(191)=>658,chr(192)=>823,chr(193)=>686,chr(194)=>795,chr(195)=>987,chr(196)=>768,chr(197)=>768, + chr(198)=>823,chr(199)=>768,chr(200)=>768,chr(201)=>713,chr(202)=>713,chr(203)=>713,chr(204)=>713,chr(205)=>713,chr(206)=>713,chr(207)=>713,chr(208)=>768,chr(209)=>713,chr(210)=>790,chr(211)=>790,chr(212)=>890,chr(213)=>823,chr(214)=>549,chr(215)=>250,chr(216)=>713,chr(217)=>603,chr(218)=>603,chr(219)=>1042, + chr(220)=>987,chr(221)=>603,chr(222)=>987,chr(223)=>603,chr(224)=>494,chr(225)=>329,chr(226)=>790,chr(227)=>790,chr(228)=>786,chr(229)=>713,chr(230)=>384,chr(231)=>384,chr(232)=>384,chr(233)=>384,chr(234)=>384,chr(235)=>384,chr(236)=>494,chr(237)=>494,chr(238)=>494,chr(239)=>494,chr(240)=>0,chr(241)=>329, + chr(242)=>274,chr(243)=>686,chr(244)=>686,chr(245)=>686,chr(246)=>384,chr(247)=>384,chr(248)=>384,chr(249)=>384,chr(250)=>384,chr(251)=>384,chr(252)=>494,chr(253)=>494,chr(254)=>494,chr(255)=>0); +?> diff --git a/include/pdf/font/times.php b/include/pdf/font/times.php new file mode 100644 index 000000000..837c706e0 --- /dev/null +++ b/include/pdf/font/times.php @@ -0,0 +1,15 @@ +250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250, + chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>408,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>180,'('=>333,')'=>333,'*'=>500,'+'=>564, + ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>278,';'=>278,'<'=>564,'='=>564,'>'=>564,'?'=>444,'@'=>921,'A'=>722, + 'B'=>667,'C'=>667,'D'=>722,'E'=>611,'F'=>556,'G'=>722,'H'=>722,'I'=>333,'J'=>389,'K'=>722,'L'=>611,'M'=>889,'N'=>722,'O'=>722,'P'=>556,'Q'=>722,'R'=>667,'S'=>556,'T'=>611,'U'=>722,'V'=>722,'W'=>944, + 'X'=>722,'Y'=>722,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>469,'_'=>500,'`'=>333,'a'=>444,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>333,'g'=>500,'h'=>500,'i'=>278,'j'=>278,'k'=>500,'l'=>278,'m'=>778, + 'n'=>500,'o'=>500,'p'=>500,'q'=>500,'r'=>333,'s'=>389,'t'=>278,'u'=>500,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>444,'{'=>480,'|'=>200,'}'=>480,'~'=>541,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500, + chr(132)=>444,chr(133)=>1000,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>556,chr(139)=>333,chr(140)=>889,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>444,chr(148)=>444,chr(149)=>350,chr(150)=>500,chr(151)=>1000,chr(152)=>333,chr(153)=>980, + chr(154)=>389,chr(155)=>333,chr(156)=>722,chr(157)=>350,chr(158)=>444,chr(159)=>722,chr(160)=>250,chr(161)=>333,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>200,chr(167)=>500,chr(168)=>333,chr(169)=>760,chr(170)=>276,chr(171)=>500,chr(172)=>564,chr(173)=>333,chr(174)=>760,chr(175)=>333, + chr(176)=>400,chr(177)=>564,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>500,chr(182)=>453,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>310,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>444,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722, + chr(198)=>889,chr(199)=>667,chr(200)=>611,chr(201)=>611,chr(202)=>611,chr(203)=>611,chr(204)=>333,chr(205)=>333,chr(206)=>333,chr(207)=>333,chr(208)=>722,chr(209)=>722,chr(210)=>722,chr(211)=>722,chr(212)=>722,chr(213)=>722,chr(214)=>722,chr(215)=>564,chr(216)=>722,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>722,chr(222)=>556,chr(223)=>500,chr(224)=>444,chr(225)=>444,chr(226)=>444,chr(227)=>444,chr(228)=>444,chr(229)=>444,chr(230)=>667,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>500, + chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>564,chr(248)=>500,chr(249)=>500,chr(250)=>500,chr(251)=>500,chr(252)=>500,chr(253)=>500,chr(254)=>500,chr(255)=>500); +?> diff --git a/include/pdf/font/timesb.php b/include/pdf/font/timesb.php new file mode 100644 index 000000000..09cff86ac --- /dev/null +++ b/include/pdf/font/timesb.php @@ -0,0 +1,15 @@ +250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250, + chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>555,'#'=>500,'$'=>500,'%'=>1000,'&'=>833,'\''=>278,'('=>333,')'=>333,'*'=>500,'+'=>570, + ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>570,'='=>570,'>'=>570,'?'=>500,'@'=>930,'A'=>722, + 'B'=>667,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>778,'I'=>389,'J'=>500,'K'=>778,'L'=>667,'M'=>944,'N'=>722,'O'=>778,'P'=>611,'Q'=>778,'R'=>722,'S'=>556,'T'=>667,'U'=>722,'V'=>722,'W'=>1000, + 'X'=>722,'Y'=>722,'Z'=>667,'['=>333,'\\'=>278,']'=>333,'^'=>581,'_'=>500,'`'=>333,'a'=>500,'b'=>556,'c'=>444,'d'=>556,'e'=>444,'f'=>333,'g'=>500,'h'=>556,'i'=>278,'j'=>333,'k'=>556,'l'=>278,'m'=>833, + 'n'=>556,'o'=>500,'p'=>556,'q'=>556,'r'=>444,'s'=>389,'t'=>333,'u'=>556,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>444,'{'=>394,'|'=>220,'}'=>394,'~'=>520,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500, + chr(132)=>500,chr(133)=>1000,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>556,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>667,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>500,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>389,chr(155)=>333,chr(156)=>722,chr(157)=>350,chr(158)=>444,chr(159)=>722,chr(160)=>250,chr(161)=>333,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>220,chr(167)=>500,chr(168)=>333,chr(169)=>747,chr(170)=>300,chr(171)=>500,chr(172)=>570,chr(173)=>333,chr(174)=>747,chr(175)=>333, + chr(176)=>400,chr(177)=>570,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>556,chr(182)=>540,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>330,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>500,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722, + chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>389,chr(205)=>389,chr(206)=>389,chr(207)=>389,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>570,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>722,chr(222)=>611,chr(223)=>556,chr(224)=>500,chr(225)=>500,chr(226)=>500,chr(227)=>500,chr(228)=>500,chr(229)=>500,chr(230)=>722,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>556, + chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>570,chr(248)=>500,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>500,chr(254)=>556,chr(255)=>500); +?> diff --git a/include/pdf/font/timesbi.php b/include/pdf/font/timesbi.php new file mode 100644 index 000000000..b4e38d763 --- /dev/null +++ b/include/pdf/font/timesbi.php @@ -0,0 +1,15 @@ +250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250, + chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>389,'"'=>555,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>278,'('=>333,')'=>333,'*'=>500,'+'=>570, + ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>570,'='=>570,'>'=>570,'?'=>500,'@'=>832,'A'=>667, + 'B'=>667,'C'=>667,'D'=>722,'E'=>667,'F'=>667,'G'=>722,'H'=>778,'I'=>389,'J'=>500,'K'=>667,'L'=>611,'M'=>889,'N'=>722,'O'=>722,'P'=>611,'Q'=>722,'R'=>667,'S'=>556,'T'=>611,'U'=>722,'V'=>667,'W'=>889, + 'X'=>667,'Y'=>611,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>570,'_'=>500,'`'=>333,'a'=>500,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>333,'g'=>500,'h'=>556,'i'=>278,'j'=>278,'k'=>500,'l'=>278,'m'=>778, + 'n'=>556,'o'=>500,'p'=>500,'q'=>500,'r'=>389,'s'=>389,'t'=>278,'u'=>556,'v'=>444,'w'=>667,'x'=>500,'y'=>444,'z'=>389,'{'=>348,'|'=>220,'}'=>348,'~'=>570,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500, + chr(132)=>500,chr(133)=>1000,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>556,chr(139)=>333,chr(140)=>944,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>500,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>389,chr(155)=>333,chr(156)=>722,chr(157)=>350,chr(158)=>389,chr(159)=>611,chr(160)=>250,chr(161)=>389,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>220,chr(167)=>500,chr(168)=>333,chr(169)=>747,chr(170)=>266,chr(171)=>500,chr(172)=>606,chr(173)=>333,chr(174)=>747,chr(175)=>333, + chr(176)=>400,chr(177)=>570,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>576,chr(182)=>500,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>300,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>500,chr(192)=>667,chr(193)=>667,chr(194)=>667,chr(195)=>667,chr(196)=>667,chr(197)=>667, + chr(198)=>944,chr(199)=>667,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>389,chr(205)=>389,chr(206)=>389,chr(207)=>389,chr(208)=>722,chr(209)=>722,chr(210)=>722,chr(211)=>722,chr(212)=>722,chr(213)=>722,chr(214)=>722,chr(215)=>570,chr(216)=>722,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>611,chr(222)=>611,chr(223)=>500,chr(224)=>500,chr(225)=>500,chr(226)=>500,chr(227)=>500,chr(228)=>500,chr(229)=>500,chr(230)=>722,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>556, + chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>570,chr(248)=>500,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>444,chr(254)=>500,chr(255)=>444); +?> diff --git a/include/pdf/font/timesi.php b/include/pdf/font/timesi.php new file mode 100644 index 000000000..0ba2b7773 --- /dev/null +++ b/include/pdf/font/timesi.php @@ -0,0 +1,15 @@ +250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250, + chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>420,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>214,'('=>333,')'=>333,'*'=>500,'+'=>675, + ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>675,'='=>675,'>'=>675,'?'=>500,'@'=>920,'A'=>611, + 'B'=>611,'C'=>667,'D'=>722,'E'=>611,'F'=>611,'G'=>722,'H'=>722,'I'=>333,'J'=>444,'K'=>667,'L'=>556,'M'=>833,'N'=>667,'O'=>722,'P'=>611,'Q'=>722,'R'=>611,'S'=>500,'T'=>556,'U'=>722,'V'=>611,'W'=>833, + 'X'=>611,'Y'=>556,'Z'=>556,'['=>389,'\\'=>278,']'=>389,'^'=>422,'_'=>500,'`'=>333,'a'=>500,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>278,'g'=>500,'h'=>500,'i'=>278,'j'=>278,'k'=>444,'l'=>278,'m'=>722, + 'n'=>500,'o'=>500,'p'=>500,'q'=>500,'r'=>389,'s'=>389,'t'=>278,'u'=>500,'v'=>444,'w'=>667,'x'=>444,'y'=>444,'z'=>389,'{'=>400,'|'=>275,'}'=>400,'~'=>541,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500, + chr(132)=>556,chr(133)=>889,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>500,chr(139)=>333,chr(140)=>944,chr(141)=>350,chr(142)=>556,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>556,chr(148)=>556,chr(149)=>350,chr(150)=>500,chr(151)=>889,chr(152)=>333,chr(153)=>980, + chr(154)=>389,chr(155)=>333,chr(156)=>667,chr(157)=>350,chr(158)=>389,chr(159)=>556,chr(160)=>250,chr(161)=>389,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>275,chr(167)=>500,chr(168)=>333,chr(169)=>760,chr(170)=>276,chr(171)=>500,chr(172)=>675,chr(173)=>333,chr(174)=>760,chr(175)=>333, + chr(176)=>400,chr(177)=>675,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>500,chr(182)=>523,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>310,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>500,chr(192)=>611,chr(193)=>611,chr(194)=>611,chr(195)=>611,chr(196)=>611,chr(197)=>611, + chr(198)=>889,chr(199)=>667,chr(200)=>611,chr(201)=>611,chr(202)=>611,chr(203)=>611,chr(204)=>333,chr(205)=>333,chr(206)=>333,chr(207)=>333,chr(208)=>722,chr(209)=>667,chr(210)=>722,chr(211)=>722,chr(212)=>722,chr(213)=>722,chr(214)=>722,chr(215)=>675,chr(216)=>722,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>556,chr(222)=>611,chr(223)=>500,chr(224)=>500,chr(225)=>500,chr(226)=>500,chr(227)=>500,chr(228)=>500,chr(229)=>500,chr(230)=>667,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>500, + chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>675,chr(248)=>500,chr(249)=>500,chr(250)=>500,chr(251)=>500,chr(252)=>500,chr(253)=>444,chr(254)=>500,chr(255)=>444); +?> diff --git a/include/pdf/font/zapfdingbats.php b/include/pdf/font/zapfdingbats.php new file mode 100644 index 000000000..1f926a8c3 --- /dev/null +++ b/include/pdf/font/zapfdingbats.php @@ -0,0 +1,15 @@ +0,chr(1)=>0,chr(2)=>0,chr(3)=>0,chr(4)=>0,chr(5)=>0,chr(6)=>0,chr(7)=>0,chr(8)=>0,chr(9)=>0,chr(10)=>0,chr(11)=>0,chr(12)=>0,chr(13)=>0,chr(14)=>0,chr(15)=>0,chr(16)=>0,chr(17)=>0,chr(18)=>0,chr(19)=>0,chr(20)=>0,chr(21)=>0, + chr(22)=>0,chr(23)=>0,chr(24)=>0,chr(25)=>0,chr(26)=>0,chr(27)=>0,chr(28)=>0,chr(29)=>0,chr(30)=>0,chr(31)=>0,' '=>278,'!'=>974,'"'=>961,'#'=>974,'$'=>980,'%'=>719,'&'=>789,'\''=>790,'('=>791,')'=>690,'*'=>960,'+'=>939, + ','=>549,'-'=>855,'.'=>911,'/'=>933,'0'=>911,'1'=>945,'2'=>974,'3'=>755,'4'=>846,'5'=>762,'6'=>761,'7'=>571,'8'=>677,'9'=>763,':'=>760,';'=>759,'<'=>754,'='=>494,'>'=>552,'?'=>537,'@'=>577,'A'=>692, + 'B'=>786,'C'=>788,'D'=>788,'E'=>790,'F'=>793,'G'=>794,'H'=>816,'I'=>823,'J'=>789,'K'=>841,'L'=>823,'M'=>833,'N'=>816,'O'=>831,'P'=>923,'Q'=>744,'R'=>723,'S'=>749,'T'=>790,'U'=>792,'V'=>695,'W'=>776, + 'X'=>768,'Y'=>792,'Z'=>759,'['=>707,'\\'=>708,']'=>682,'^'=>701,'_'=>826,'`'=>815,'a'=>789,'b'=>789,'c'=>707,'d'=>687,'e'=>696,'f'=>689,'g'=>786,'h'=>787,'i'=>713,'j'=>791,'k'=>785,'l'=>791,'m'=>873, + 'n'=>761,'o'=>762,'p'=>762,'q'=>759,'r'=>759,'s'=>892,'t'=>892,'u'=>788,'v'=>784,'w'=>438,'x'=>138,'y'=>277,'z'=>415,'{'=>392,'|'=>392,'}'=>668,'~'=>668,chr(127)=>0,chr(128)=>390,chr(129)=>390,chr(130)=>317,chr(131)=>317, + chr(132)=>276,chr(133)=>276,chr(134)=>509,chr(135)=>509,chr(136)=>410,chr(137)=>410,chr(138)=>234,chr(139)=>234,chr(140)=>334,chr(141)=>334,chr(142)=>0,chr(143)=>0,chr(144)=>0,chr(145)=>0,chr(146)=>0,chr(147)=>0,chr(148)=>0,chr(149)=>0,chr(150)=>0,chr(151)=>0,chr(152)=>0,chr(153)=>0, + chr(154)=>0,chr(155)=>0,chr(156)=>0,chr(157)=>0,chr(158)=>0,chr(159)=>0,chr(160)=>0,chr(161)=>732,chr(162)=>544,chr(163)=>544,chr(164)=>910,chr(165)=>667,chr(166)=>760,chr(167)=>760,chr(168)=>776,chr(169)=>595,chr(170)=>694,chr(171)=>626,chr(172)=>788,chr(173)=>788,chr(174)=>788,chr(175)=>788, + chr(176)=>788,chr(177)=>788,chr(178)=>788,chr(179)=>788,chr(180)=>788,chr(181)=>788,chr(182)=>788,chr(183)=>788,chr(184)=>788,chr(185)=>788,chr(186)=>788,chr(187)=>788,chr(188)=>788,chr(189)=>788,chr(190)=>788,chr(191)=>788,chr(192)=>788,chr(193)=>788,chr(194)=>788,chr(195)=>788,chr(196)=>788,chr(197)=>788, + chr(198)=>788,chr(199)=>788,chr(200)=>788,chr(201)=>788,chr(202)=>788,chr(203)=>788,chr(204)=>788,chr(205)=>788,chr(206)=>788,chr(207)=>788,chr(208)=>788,chr(209)=>788,chr(210)=>788,chr(211)=>788,chr(212)=>894,chr(213)=>838,chr(214)=>1016,chr(215)=>458,chr(216)=>748,chr(217)=>924,chr(218)=>748,chr(219)=>918, + chr(220)=>927,chr(221)=>928,chr(222)=>928,chr(223)=>834,chr(224)=>873,chr(225)=>828,chr(226)=>924,chr(227)=>924,chr(228)=>917,chr(229)=>930,chr(230)=>931,chr(231)=>463,chr(232)=>883,chr(233)=>836,chr(234)=>836,chr(235)=>867,chr(236)=>867,chr(237)=>696,chr(238)=>696,chr(239)=>874,chr(240)=>0,chr(241)=>874, + chr(242)=>760,chr(243)=>946,chr(244)=>771,chr(245)=>865,chr(246)=>771,chr(247)=>888,chr(248)=>967,chr(249)=>888,chr(250)=>831,chr(251)=>873,chr(252)=>927,chr(253)=>970,chr(254)=>918,chr(255)=>0); +?> diff --git a/include/pdf/fpdf.css b/include/pdf/fpdf.css new file mode 100644 index 000000000..045a32e37 --- /dev/null +++ b/include/pdf/fpdf.css @@ -0,0 +1,11 @@ +BODY {font-family:times new roman,serif} +H2 {color:#4000A0} +P.demo {text-align:center; margin-top:-10px} +A.demo {text-decoration:none; font-weight:bold; color:#0000CC} +A.demo:link {text-decoration:none; font-weight:bold; color:#0000CC} +A.demo:hover {text-decoration:none; font-weight:bold; color:#0000FF} +A.demo:active {text-decoration:none; font-weight:bold; color:#0000FF} +.st {font-weight:bold; color:#900000} +.kw {color:#000080; font-weight:bold} +.str {color:#CC0000} +.cmt {color:#008000} diff --git a/include/pdf/fpdf.php b/include/pdf/fpdf.php new file mode 100644 index 000000000..482af32c2 --- /dev/null +++ b/include/pdf/fpdf.php @@ -0,0 +1,1622 @@ +_dochecks(); + //Initialization of properties + $this->page=0; + $this->n=2; + $this->buffer=''; + $this->pages=array(); + $this->OrientationChanges=array(); + $this->state=0; + $this->fonts=array(); + $this->FontFiles=array(); + $this->diffs=array(); + $this->images=array(); + $this->links=array(); + $this->InFooter=false; + $this->lasth=0; + $this->FontFamily=''; + $this->FontStyle=''; + $this->FontSizePt=12; + $this->underline=false; + $this->DrawColor='0 G'; + $this->FillColor='0 g'; + $this->TextColor='0 g'; + $this->ColorFlag=false; + $this->ws=0; + //Standard fonts + $this->CoreFonts=array('courier'=>'Courier','courierB'=>'Courier-Bold','courierI'=>'Courier-Oblique','courierBI'=>'Courier-BoldOblique', + 'helvetica'=>'Helvetica','helveticaB'=>'Helvetica-Bold','helveticaI'=>'Helvetica-Oblique','helveticaBI'=>'Helvetica-BoldOblique', + 'times'=>'Times-Roman','timesB'=>'Times-Bold','timesI'=>'Times-Italic','timesBI'=>'Times-BoldItalic', + 'symbol'=>'Symbol','zapfdingbats'=>'ZapfDingbats'); + //Scale factor + if($unit=='pt') + $this->k=1; + elseif($unit=='mm') + $this->k=72/25.4; + elseif($unit=='cm') + $this->k=72/2.54; + elseif($unit=='in') + $this->k=72; + else + $this->Error('Incorrect unit: '.$unit); + //Page format + if(is_string($format)) + { + $format=strtolower($format); + if($format=='a3') + $format=array(841.89,1190.55); + elseif($format=='a4') + $format=array(595.28,841.89); + elseif($format=='a5') + $format=array(420.94,595.28); + elseif($format=='letter') + $format=array(612,792); + elseif($format=='legal') + $format=array(612,1008); + else + $this->Error('Unknown page format: '.$format); + $this->fwPt=$format[0]; + $this->fhPt=$format[1]; + } + else + { + $this->fwPt=$format[0]*$this->k; + $this->fhPt=$format[1]*$this->k; + } + $this->fw=$this->fwPt/$this->k; + $this->fh=$this->fhPt/$this->k; + //Page orientation + $orientation=strtolower($orientation); + if($orientation=='p' or $orientation=='portrait') + { + $this->DefOrientation='P'; + $this->wPt=$this->fwPt; + $this->hPt=$this->fhPt; + } + elseif($orientation=='l' or $orientation=='landscape') + { + $this->DefOrientation='L'; + $this->wPt=$this->fhPt; + $this->hPt=$this->fwPt; + } + else + $this->Error('Incorrect orientation: '.$orientation); + $this->CurOrientation=$this->DefOrientation; + $this->w=$this->wPt/$this->k; + $this->h=$this->hPt/$this->k; + //Page margins (1 cm) + $margin=28.35/$this->k; + $this->SetMargins($margin,$margin); + //Interior cell margin (1 mm) + $this->cMargin=$margin/10; + //Line width (0.2 mm) + $this->LineWidth=.567/$this->k; + //Automatic page break + $this->SetAutoPageBreak(true,2*$margin); + //Full width display mode + $this->SetDisplayMode('fullwidth'); + //Compression + $this->SetCompression(true); +} + +function SetMargins($left,$top,$right=-1) +{ + //Set left, top and right margins + $this->lMargin=$left; + $this->tMargin=$top; + if($right==-1) + $right=$left; + $this->rMargin=$right; +} + +function SetLeftMargin($margin) +{ + //Set left margin + $this->lMargin=$margin; + if($this->page>0 and $this->x<$margin) + $this->x=$margin; +} + +function SetTopMargin($margin) +{ + //Set top margin + $this->tMargin=$margin; +} + +function SetRightMargin($margin) +{ + //Set right margin + $this->rMargin=$margin; +} + +function SetAutoPageBreak($auto,$margin=0) +{ + //Set auto page break mode and triggering margin + $this->AutoPageBreak=$auto; + $this->bMargin=$margin; + $this->PageBreakTrigger=$this->h-$margin; +} + +function SetDisplayMode($zoom,$layout='continuous') +{ + //Set display mode in viewer + if($zoom=='fullpage' or $zoom=='fullwidth' or $zoom=='real' or $zoom=='default' or !is_string($zoom)) + $this->ZoomMode=$zoom; + else + $this->Error('Incorrect zoom display mode: '.$zoom); + if($layout=='single' or $layout=='continuous' or $layout=='two' or $layout=='default') + $this->LayoutMode=$layout; + else + $this->Error('Incorrect layout display mode: '.$layout); +} + +function SetCompression($compress) +{ + //Set page compression + if(function_exists('gzcompress')) + $this->compress=$compress; + else + $this->compress=false; +} + +function SetTitle($title) +{ + //Title of document + $this->title=$title; +} + +function SetSubject($subject) +{ + //Subject of document + $this->subject=$subject; +} + +function SetAuthor($author) +{ + //Author of document + $this->author=$author; +} + +function SetKeywords($keywords) +{ + //Keywords of document + $this->keywords=$keywords; +} + +function SetCreator($creator) +{ + //Creator of document + $this->creator=$creator; +} + +function AliasNbPages($alias='{nb}') +{ + //Define an alias for total number of pages + $this->AliasNbPages=$alias; +} + +function Error($msg) +{ + //Fatal error + die('FPDF error: '.$msg); +} + +function Open() +{ + //Begin document + if($this->state==0) + $this->_begindoc(); +} + +function Close() +{ + //Terminate document + if($this->state==3) + return; + if($this->page==0) + $this->AddPage(); + //Page footer + $this->InFooter=true; + $this->Footer(); + $this->InFooter=false; + //Close page + $this->_endpage(); + //Close document + $this->_enddoc(); +} + +function AddPage($orientation='') +{ + //Start a new page + if($this->state==0) + $this->Open(); + $family=$this->FontFamily; + $style=$this->FontStyle.($this->underline ? 'U' : ''); + $size=$this->FontSizePt; + $lw=$this->LineWidth; + $dc=$this->DrawColor; + $fc=$this->FillColor; + $tc=$this->TextColor; + $cf=$this->ColorFlag; + if($this->page>0) + { + //Page footer + $this->InFooter=true; + $this->Footer(); + $this->InFooter=false; + //Close page + $this->_endpage(); + } + //Start new page + $this->_beginpage($orientation); + //Set line cap style to square + $this->_out('2 J'); + //Set line width + $this->LineWidth=$lw; + $this->_out(sprintf('%.2f w',$lw*$this->k)); + //Set font + if($family) + $this->SetFont($family,$style,$size); + //Set colors + $this->DrawColor=$dc; + if($dc!='0 G') + $this->_out($dc); + $this->FillColor=$fc; + if($fc!='0 g') + $this->_out($fc); + $this->TextColor=$tc; + $this->ColorFlag=$cf; + //Page header + $this->Header(); + //Restore line width + if($this->LineWidth!=$lw) + { + $this->LineWidth=$lw; + $this->_out(sprintf('%.2f w',$lw*$this->k)); + } + //Restore font + if($family) + $this->SetFont($family,$style,$size); + //Restore colors + if($this->DrawColor!=$dc) + { + $this->DrawColor=$dc; + $this->_out($dc); + } + if($this->FillColor!=$fc) + { + $this->FillColor=$fc; + $this->_out($fc); + } + $this->TextColor=$tc; + $this->ColorFlag=$cf; +} + +function Header() +{ + //To be implemented in your own inherited class +} + +function Footer() +{ + //To be implemented in your own inherited class +} + +function PageNo() +{ + //Get current page number + return $this->page; +} + +function SetDrawColor($r,$g=-1,$b=-1) +{ + //Set color for all stroking operations + if(($r==0 and $g==0 and $b==0) or $g==-1) + $this->DrawColor=sprintf('%.3f G',$r/255); + else + $this->DrawColor=sprintf('%.3f %.3f %.3f RG',$r/255,$g/255,$b/255); + if($this->page>0) + $this->_out($this->DrawColor); +} + +function SetFillColor($r,$g=-1,$b=-1) +{ + //Set color for all filling operations + if(($r==0 and $g==0 and $b==0) or $g==-1) + $this->FillColor=sprintf('%.3f g',$r/255); + else + $this->FillColor=sprintf('%.3f %.3f %.3f rg',$r/255,$g/255,$b/255); + $this->ColorFlag=($this->FillColor!=$this->TextColor); + if($this->page>0) + $this->_out($this->FillColor); +} + +function SetTextColor($r,$g=-1,$b=-1) +{ + //Set color for text + if(($r==0 and $g==0 and $b==0) or $g==-1) + $this->TextColor=sprintf('%.3f g',$r/255); + else + $this->TextColor=sprintf('%.3f %.3f %.3f rg',$r/255,$g/255,$b/255); + $this->ColorFlag=($this->FillColor!=$this->TextColor); +} + +function GetStringWidth($s) +{ + //Get width of a string in the current font + $s=(string)$s; + $cw=&$this->CurrentFont['cw']; + $w=0; + $l=strlen($s); + for($i=0;$i<$l;$i++) + $w+=$cw[$s{$i}]; + return $w*$this->FontSize/1000; +} + +function SetLineWidth($width) +{ + //Set line width + $this->LineWidth=$width; + if($this->page>0) + $this->_out(sprintf('%.2f w',$width*$this->k)); +} + +function Line($x1,$y1,$x2,$y2) +{ + //Draw a line + $this->_out(sprintf('%.2f %.2f m %.2f %.2f l S',$x1*$this->k,($this->h-$y1)*$this->k,$x2*$this->k,($this->h-$y2)*$this->k)); +} + +function Rect($x,$y,$w,$h,$style='') +{ + //Draw a rectangle + if($style=='F') + $op='f'; + elseif($style=='FD' or $style=='DF') + $op='B'; + else + $op='S'; + $this->_out(sprintf('%.2f %.2f %.2f %.2f re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op)); +} + +function AddFont($family,$style='',$file='') +{ + //Add a TrueType or Type1 font + $family=strtolower($family); + if($family=='arial') + $family='helvetica'; + $style=strtoupper($style); + if($style=='IB') + $style='BI'; + if(isset($this->fonts[$family.$style])) + $this->Error('Font already added: '.$family.' '.$style); + if($file=='') + $file=str_replace(' ','',$family).strtolower($style).'.php'; + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$file; + include($file); + if(!isset($name)) + $this->Error('Could not include font definition file'); + $i=count($this->fonts)+1; + $this->fonts[$family.$style]=array('i'=>$i,'type'=>$type,'name'=>$name,'desc'=>$desc,'up'=>$up,'ut'=>$ut,'cw'=>$cw,'enc'=>$enc,'file'=>$file); + if($diff) + { + //Search existing encodings + $d=0; + $nb=count($this->diffs); + for($i=1;$i<=$nb;$i++) + if($this->diffs[$i]==$diff) + { + $d=$i; + break; + } + if($d==0) + { + $d=$nb+1; + $this->diffs[$d]=$diff; + } + $this->fonts[$family.$style]['diff']=$d; + } + if($file) + { + if($type=='TrueType') + $this->FontFiles[$file]=array('length1'=>$originalsize); + else + $this->FontFiles[$file]=array('length1'=>$size1,'length2'=>$size2); + } +} + +function SetFont($family,$style='',$size=0) +{ + //Select a font; size given in points + global $fpdf_charwidths; + + $family=strtolower($family); + if($family=='') + $family=$this->FontFamily; + if($family=='arial') + $family='helvetica'; + elseif($family=='symbol' or $family=='zapfdingbats') + $style=''; + $style=strtoupper($style); + if(is_int(strpos($style,'U'))) + { + $this->underline=true; + $style=str_replace('U','',$style); + } + else + $this->underline=false; + if($style=='IB') + $style='BI'; + if($size==0) + $size=$this->FontSizePt; + //Test if font is already selected + if($this->FontFamily==$family and $this->FontStyle==$style and $this->FontSizePt==$size) + return; + //Test if used for the first time + $fontkey=$family.$style; + if(!isset($this->fonts[$fontkey])) + { + //Check if one of the standard fonts + if(isset($this->CoreFonts[$fontkey])) + { + if(!isset($fpdf_charwidths[$fontkey])) + { + //Load metric file + $file=$family; + if($family=='times' or $family=='helvetica') + $file.=strtolower($style); + $file.='.php'; + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$file; + include($file); + if(!isset($fpdf_charwidths[$fontkey])) + $this->Error('Could not include font metric file'); + } + $i=count($this->fonts)+1; + $this->fonts[$fontkey]=array('i'=>$i,'type'=>'core','name'=>$this->CoreFonts[$fontkey],'up'=>-100,'ut'=>50,'cw'=>$fpdf_charwidths[$fontkey]); + } + else + $this->Error('Undefined font: '.$family.' '.$style); + } + //Select it + $this->FontFamily=$family; + $this->FontStyle=$style; + $this->FontSizePt=$size; + $this->FontSize=$size/$this->k; + $this->CurrentFont=&$this->fonts[$fontkey]; + if($this->page>0) + $this->_out(sprintf('BT /F%d %.2f Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); +} + +function SetFontSize($size) +{ + //Set font size in points + if($this->FontSizePt==$size) + return; + $this->FontSizePt=$size; + $this->FontSize=$size/$this->k; + if($this->page>0) + $this->_out(sprintf('BT /F%d %.2f Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); +} + +function AddLink() +{ + //Create a new internal link + $n=count($this->links)+1; + $this->links[$n]=array(0,0); + return $n; +} + +function SetLink($link,$y=0,$page=-1) +{ + //Set destination of internal link + if($y==-1) + $y=$this->y; + if($page==-1) + $page=$this->page; + $this->links[$link]=array($page,$y); +} + +function Link($x,$y,$w,$h,$link) +{ + //Put a link on the page + $this->PageLinks[$this->page][]=array($x*$this->k,$this->hPt-$y*$this->k,$w*$this->k,$h*$this->k,$link); +} + +function Text($x,$y,$txt) +{ + //Output a string + $s=sprintf('BT %.2f %.2f Td (%s) Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escape($txt)); + if($this->underline and $txt!='') + $s.=' '.$this->_dounderline($x,$y,$txt); + if($this->ColorFlag) + $s='q '.$this->TextColor.' '.$s.' Q'; + $this->_out($s); +} + +function AcceptPageBreak() +{ + //Accept automatic page break or not + return $this->AutoPageBreak; +} + +function Cell($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='') +{ + //Output a cell + $k=$this->k; + if($this->y+$h>$this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak()) + { + //Automatic page break + $x=$this->x; + $ws=$this->ws; + if($ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + $this->AddPage($this->CurOrientation); + $this->x=$x; + if($ws>0) + { + $this->ws=$ws; + $this->_out(sprintf('%.3f Tw',$ws*$k)); + } + } + if($w==0) + $w=$this->w-$this->rMargin-$this->x; + $s=''; + if($fill==1 or $border==1) + { + if($fill==1) + $op=($border==1) ? 'B' : 'f'; + else + $op='S'; + $s=sprintf('%.2f %.2f %.2f %.2f re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op); + } + if(is_string($border)) + { + $x=$this->x; + $y=$this->y; + if(is_int(strpos($border,'L'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k); + if(is_int(strpos($border,'T'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k); + if(is_int(strpos($border,'R'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k); + if(is_int(strpos($border,'B'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k); + } + if($txt!='') + { + if($align=='R') + $dx=$w-$this->cMargin-$this->GetStringWidth($txt); + elseif($align=='C') + $dx=($w-$this->GetStringWidth($txt))/2; + else + $dx=$this->cMargin; + if($this->ColorFlag) + $s.='q '.$this->TextColor.' '; + $txt2=str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$txt))); + $s.=sprintf('BT %.2f %.2f Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txt2); + if($this->underline) + $s.=' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt); + if($this->ColorFlag) + $s.=' Q'; + if($link) + $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link); + } + if($s) + $this->_out($s); + $this->lasth=$h; + if($ln>0) + { + //Go to next line + $this->y+=$h; + if($ln==1) + $this->x=$this->lMargin; + } + else + $this->x+=$w; +} + +function MultiCell($w,$h,$txt,$border=0,$align='J',$fill=0) +{ + //Output text with automatic or explicit line breaks + $cw=&$this->CurrentFont['cw']; + if($w==0) + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + $s=str_replace("\r",'',$txt); + $nb=strlen($s); + if($nb>0 and $s[$nb-1]=="\n") + $nb--; + $b=0; + if($border) + { + if($border==1) + { + $border='LTRB'; + $b='LRT'; + $b2='LR'; + } + else + { + $b2=''; + if(is_int(strpos($border,'L'))) + $b2.='L'; + if(is_int(strpos($border,'R'))) + $b2.='R'; + $b=is_int(strpos($border,'T')) ? $b2.'T' : $b2; + } + } + $sep=-1; + $i=0; + $j=0; + $l=0; + $ns=0; + $nl=1; + while($i<$nb) + { + //Get next character + $c=$s{$i}; + if($c=="\n") + { + //Explicit line break + if($this->ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + $i++; + $sep=-1; + $j=$i; + $l=0; + $ns=0; + $nl++; + if($border and $nl==2) + $b=$b2; + continue; + } + if($c==' ') + { + $sep=$i; + $ls=$l; + $ns++; + } + $l+=$cw[$c]; + if($l>$wmax) + { + //Automatic line break + if($sep==-1) + { + if($i==$j) + $i++; + if($this->ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + } + else + { + if($align=='J') + { + $this->ws=($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0; + $this->_out(sprintf('%.3f Tw',$this->ws*$this->k)); + } + $this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill); + $i=$sep+1; + } + $sep=-1; + $j=$i; + $l=0; + $ns=0; + $nl++; + if($border and $nl==2) + $b=$b2; + } + else + $i++; + } + //Last chunk + if($this->ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + if($border and is_int(strpos($border,'B'))) + $b.='B'; + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + $this->x=$this->lMargin; +} + +function Write($h,$txt,$link='') +{ + //Output text in flowing mode + $cw=&$this->CurrentFont['cw']; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + $s=str_replace("\r",'',$txt); + $nb=strlen($s); + $sep=-1; + $i=0; + $j=0; + $l=0; + $nl=1; + while($i<$nb) + { + //Get next character + $c=$s{$i}; + if($c=="\n") + { + //Explicit line break + $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link); + $i++; + $sep=-1; + $j=$i; + $l=0; + if($nl==1) + { + $this->x=$this->lMargin; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + } + $nl++; + continue; + } + if($c==' ') + $sep=$i; + $l+=$cw[$c]; + if($l>$wmax) + { + //Automatic line break + if($sep==-1) + { + if($this->x>$this->lMargin) + { + //Move to next line + $this->x=$this->lMargin; + $this->y+=$h; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + $i++; + $nl++; + continue; + } + if($i==$j) + $i++; + $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link); + } + else + { + $this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',0,$link); + $i=$sep+1; + } + $sep=-1; + $j=$i; + $l=0; + if($nl==1) + { + $this->x=$this->lMargin; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + } + $nl++; + } + else + $i++; + } + //Last chunk + if($i!=$j) + $this->Cell($l/1000*$this->FontSize,$h,substr($s,$j),0,0,'',0,$link); +} + +function Image($file,$x,$y,$w=0,$h=0,$type='',$link='') +{ + //Put an image on the page + if(!isset($this->images[$file])) + { + //First use of image, get info + if($type=='') + { + $pos=strrpos($file,'.'); + if(!$pos) + $this->Error('Image file has no extension and no type was specified: '.$file); + $type=substr($file,$pos+1); + } + $type=strtolower($type); + $mqr=get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + if($type=='jpg' or $type=='jpeg') + $info=$this->_parsejpg($file); + elseif($type=='png') + $info=$this->_parsepng($file); + else + { + //Allow for additional formats + $mtd='_parse'.$type; + if(!method_exists($this,$mtd)) + $this->Error('Unsupported image type: '.$type); + $info=$this->$mtd($file); + } + set_magic_quotes_runtime($mqr); + $info['i']=count($this->images)+1; + $this->images[$file]=$info; + } + else + $info=$this->images[$file]; + //Automatic width and height calculation if needed + if($w==0 and $h==0) + { + //Put image at 72 dpi + $w=$info['w']/$this->k; + $h=$info['h']/$this->k; + } + if($w==0) + $w=$h*$info['w']/$info['h']; + if($h==0) + $h=$w*$info['h']/$info['w']; + $this->_out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q',$w*$this->k,$h*$this->k,$x*$this->k,($this->h-($y+$h))*$this->k,$info['i'])); + if($link) + $this->Link($x,$y,$w,$h,$link); +} + +function Ln($h='') +{ + //Line feed; default value is last cell height + $this->x=$this->lMargin; + if(is_string($h)) + $this->y+=$this->lasth; + else + $this->y+=$h; +} + +function GetX() +{ + //Get x position + return $this->x; +} + +function SetX($x) +{ + //Set x position + if($x>=0) + $this->x=$x; + else + $this->x=$this->w+$x; +} + +function GetY() +{ + //Get y position + return $this->y; +} + +function SetY($y) +{ + //Set y position and reset x + $this->x=$this->lMargin; + if($y>=0) + $this->y=$y; + else + $this->y=$this->h+$y; +} + +function SetXY($x,$y) +{ + //Set x and y positions + $this->SetY($y); + $this->SetX($x); +} + +function Output($name='',$dest='') +{ + //Output PDF to some destination + global $HTTP_SERVER_VARS; + + //Finish document if necessary + if($this->state<3) + $this->Close(); + //Normalize parameters + if(is_bool($dest)) + $dest=$dest ? 'D' : 'F'; + $dest=strtoupper($dest); + if($dest=='') + { + if($name=='') + { + $name='doc.pdf'; + $dest='I'; + } + else + $dest='F'; + } + switch($dest) + { + case 'I': + //Send to standard output + if(isset($_SERVER['SERVER_NAME'])) + { + //We send to a browser + // ffe, regarding a https pdf download issue, 20050720 + Header('Pragma: '); + Header('Cache-Control: '); + // end of modification + Header('Content-Type: application/pdf'); + if(headers_sent()) + $this->Error('Some data has already been output to browser, can\'t send PDF file'); + Header('Content-Length: '.strlen($this->buffer)); + Header('Content-disposition: inline; filename='.$name); + } + echo $this->buffer; + break; + case 'D': + //Download file + if(isset($_SERVER['HTTP_USER_AGENT']) and strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')) + Header('Content-Type: application/force-download'); + else + Header('Content-Type: application/octet-stream'); + if(headers_sent()) + $this->Error('Some data has already been output to browser, can\'t send PDF file'); + Header('Content-Length: '.strlen($this->buffer)); + Header('Content-disposition: attachment; filename='.$name); + echo $this->buffer; + break; + case 'F': + //Save to local file + $f=fopen($name,'wb'); + if(!$f) + $this->Error('Unable to create output file: '.$name); + fwrite($f,$this->buffer,strlen($this->buffer)); + fclose($f); + break; + case 'S': + //Return as a string + return $this->buffer; + default: + $this->Error('Incorrect output destination: '.$dest); + } + return ''; +} + +/******************************************************************************* +* * +* Protected methods * +* * +*******************************************************************************/ +function _dochecks() +{ + //Check for locale-related bug + if(1.1==1) + $this->Error('Don\'t alter the locale before including class file'); + //Check for decimal separator + if(sprintf('%.1f',1.0)!='1.0') + setlocale(LC_NUMERIC,'C'); +} + +function _begindoc() +{ + //Start document + $this->state=1; + $this->_out('%PDF-1.3'); +} + +function _putpages() +{ + $nb=$this->page; + if(!empty($this->AliasNbPages)) + { + //Replace number of pages + for($n=1;$n<=$nb;$n++) + $this->pages[$n]=str_replace($this->AliasNbPages,$nb,$this->pages[$n]); + } + if($this->DefOrientation=='P') + { + $wPt=$this->fwPt; + $hPt=$this->fhPt; + } + else + { + $wPt=$this->fhPt; + $hPt=$this->fwPt; + } + $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; + for($n=1;$n<=$nb;$n++) + { + //Page + $this->_newobj(); + $this->_out('<_out('/Parent 1 0 R'); + if(isset($this->OrientationChanges[$n])) + $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$hPt,$wPt)); + $this->_out('/Resources 2 0 R'); + if(isset($this->PageLinks[$n])) + { + //Links + $annots='/Annots ['; + foreach($this->PageLinks[$n] as $pl) + { + $rect=sprintf('%.2f %.2f %.2f %.2f',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]); + $annots.='<_textstring($pl[4]).'>>>>'; + else + { + $l=$this->links[$pl[4]]; + $h=isset($this->OrientationChanges[$l[0]]) ? $wPt : $hPt; + $annots.=sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+2*$l[0],$h-$l[1]*$this->k); + } + } + $this->_out($annots.']'); + } + $this->_out('/Contents '.($this->n+1).' 0 R>>'); + $this->_out('endobj'); + //Page content + $p=($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n]; + $this->_newobj(); + $this->_out('<<'.$filter.'/Length '.strlen($p).'>>'); + $this->_putstream($p); + $this->_out('endobj'); + } + //Pages root + $this->offsets[1]=strlen($this->buffer); + $this->_out('1 0 obj'); + $this->_out('<_out($kids.']'); + $this->_out('/Count '.$nb); + $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$wPt,$hPt)); + $this->_out('>>'); + $this->_out('endobj'); +} + +function _putfonts() +{ + $nf=$this->n; + foreach($this->diffs as $diff) + { + //Encodings + $this->_newobj(); + $this->_out('<>'); + $this->_out('endobj'); + } + $mqr=get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + foreach($this->FontFiles as $file=>$info) + { + //Font file embedding + $this->_newobj(); + $this->FontFiles[$file]['n']=$this->n; + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$file; + $size=filesize($file); + if(!$size) + $this->Error('Font file not found'); + $this->_out('<_out('/Filter /FlateDecode'); + $this->_out('/Length1 '.$info['length1']); + if(isset($info['length2'])) + $this->_out('/Length2 '.$info['length2'].' /Length3 0'); + $this->_out('>>'); + $f=fopen($file,'rb'); + $this->_putstream(fread($f,$size)); + fclose($f); + $this->_out('endobj'); + } + set_magic_quotes_runtime($mqr); + foreach($this->fonts as $k=>$font) + { + //Font objects + $this->fonts[$k]['n']=$this->n+1; + $type=$font['type']; + $name=$font['name']; + if($type=='core') + { + //Standard font + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$name); + $this->_out('/Subtype /Type1'); + if($name!='Symbol' and $name!='ZapfDingbats') + $this->_out('/Encoding /WinAnsiEncoding'); + $this->_out('>>'); + $this->_out('endobj'); + } + elseif($type=='Type1' or $type=='TrueType') + { + //Additional Type1 or TrueType font + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$name); + $this->_out('/Subtype /'.$type); + $this->_out('/FirstChar 32 /LastChar 255'); + $this->_out('/Widths '.($this->n+1).' 0 R'); + $this->_out('/FontDescriptor '.($this->n+2).' 0 R'); + if($font['enc']) + { + if(isset($font['diff'])) + $this->_out('/Encoding '.($nf+$font['diff']).' 0 R'); + else + $this->_out('/Encoding /WinAnsiEncoding'); + } + $this->_out('>>'); + $this->_out('endobj'); + //Widths + $this->_newobj(); + $cw=&$font['cw']; + $s='['; + for($i=32;$i<=255;$i++) + $s.=$cw[chr($i)].' '; + $this->_out($s.']'); + $this->_out('endobj'); + //Descriptor + $this->_newobj(); + $s='<$v) + $s.=' /'.$k.' '.$v; + $file=$font['file']; + if($file) + $s.=' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$file]['n'].' 0 R'; + $this->_out($s.'>>'); + $this->_out('endobj'); + } + else + { + //Allow for additional types + $mtd='_put'.strtolower($type); + if(!method_exists($this,$mtd)) + $this->Error('Unsupported font type: '.$type); + $this->$mtd($font); + } + } +} + +function _putimages() +{ + $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; + reset($this->images); + while(list($file,$info)=each($this->images)) + { + $this->_newobj(); + $this->images[$file]['n']=$this->n; + $this->_out('<_out('/Subtype /Image'); + $this->_out('/Width '.$info['w']); + $this->_out('/Height '.$info['h']); + if($info['cs']=='Indexed') + $this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]'); + else + { + $this->_out('/ColorSpace /'.$info['cs']); + if($info['cs']=='DeviceCMYK') + $this->_out('/Decode [1 0 1 0 1 0 1 0]'); + } + $this->_out('/BitsPerComponent '.$info['bpc']); + $this->_out('/Filter /'.$info['f']); + if(isset($info['parms'])) + $this->_out($info['parms']); + if(isset($info['trns']) and is_array($info['trns'])) + { + $trns=''; + for($i=0;$i_out('/Mask ['.$trns.']'); + } + $this->_out('/Length '.strlen($info['data']).'>>'); + $this->_putstream($info['data']); + unset($this->images[$file]['data']); + $this->_out('endobj'); + //Palette + if($info['cs']=='Indexed') + { + $this->_newobj(); + $pal=($this->compress) ? gzcompress($info['pal']) : $info['pal']; + $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>'); + $this->_putstream($pal); + $this->_out('endobj'); + } + } +} + +function _putresources() +{ + $this->_putfonts(); + $this->_putimages(); + //Resource dictionary + $this->offsets[2]=strlen($this->buffer); + $this->_out('2 0 obj'); + $this->_out('<_out('/Font <<'); + foreach($this->fonts as $font) + $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R'); + $this->_out('>>'); + if(count($this->images)) + { + $this->_out('/XObject <<'); + foreach($this->images as $image) + $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); + $this->_out('>>'); + } + $this->_out('>>'); + $this->_out('endobj'); +} + +function _putinfo() +{ + $this->_out('/Producer '.$this->_textstring('FPDF '.FPDF_VERSION)); + if(!empty($this->title)) + $this->_out('/Title '.$this->_textstring($this->title)); + if(!empty($this->subject)) + $this->_out('/Subject '.$this->_textstring($this->subject)); + if(!empty($this->author)) + $this->_out('/Author '.$this->_textstring($this->author)); + if(!empty($this->keywords)) + $this->_out('/Keywords '.$this->_textstring($this->keywords)); + if(!empty($this->creator)) + $this->_out('/Creator '.$this->_textstring($this->creator)); + $this->_out('/CreationDate '.$this->_textstring('D:'.date('YmdHis'))); +} + +function _putcatalog() +{ + $this->_out('/Type /Catalog'); + $this->_out('/Pages 1 0 R'); + if($this->ZoomMode=='fullpage') + $this->_out('/OpenAction [3 0 R /Fit]'); + elseif($this->ZoomMode=='fullwidth') + $this->_out('/OpenAction [3 0 R /FitH null]'); + elseif($this->ZoomMode=='real') + $this->_out('/OpenAction [3 0 R /XYZ null null 1]'); + elseif(!is_string($this->ZoomMode)) + $this->_out('/OpenAction [3 0 R /XYZ null null '.($this->ZoomMode/100).']'); + if($this->LayoutMode=='single') + $this->_out('/PageLayout /SinglePage'); + elseif($this->LayoutMode=='continuous') + $this->_out('/PageLayout /OneColumn'); + elseif($this->LayoutMode=='two') + $this->_out('/PageLayout /TwoColumnLeft'); +} + +function _puttrailer() +{ + $this->_out('/Size '.($this->n+1)); + $this->_out('/Root '.$this->n.' 0 R'); + $this->_out('/Info '.($this->n-1).' 0 R'); +} + +function _enddoc() +{ + $this->_putpages(); + $this->_putresources(); + //Info + $this->_newobj(); + $this->_out('<<'); + $this->_putinfo(); + $this->_out('>>'); + $this->_out('endobj'); + //Catalog + $this->_newobj(); + $this->_out('<<'); + $this->_putcatalog(); + $this->_out('>>'); + $this->_out('endobj'); + //Cross-ref + $o=strlen($this->buffer); + $this->_out('xref'); + $this->_out('0 '.($this->n+1)); + $this->_out('0000000000 65535 f '); + for($i=1;$i<=$this->n;$i++) + $this->_out(sprintf('%010d 00000 n ',$this->offsets[$i])); + //Trailer + $this->_out('trailer'); + $this->_out('<<'); + $this->_puttrailer(); + $this->_out('>>'); + $this->_out('startxref'); + $this->_out($o); + $this->_out('%%EOF'); + $this->state=3; +} + +function _beginpage($orientation) +{ + $this->page++; + $this->pages[$this->page]=''; + $this->state=2; + $this->x=$this->lMargin; + $this->y=$this->tMargin; + $this->FontFamily=''; + //Page orientation + if(!$orientation) + $orientation=$this->DefOrientation; + else + { + $orientation=strtoupper($orientation{0}); + if($orientation!=$this->DefOrientation) + $this->OrientationChanges[$this->page]=true; + } + if($orientation!=$this->CurOrientation) + { + //Change orientation + if($orientation=='P') + { + $this->wPt=$this->fwPt; + $this->hPt=$this->fhPt; + $this->w=$this->fw; + $this->h=$this->fh; + } + else + { + $this->wPt=$this->fhPt; + $this->hPt=$this->fwPt; + $this->w=$this->fh; + $this->h=$this->fw; + } + $this->PageBreakTrigger=$this->h-$this->bMargin; + $this->CurOrientation=$orientation; + } +} + +function _endpage() +{ + //End of page contents + $this->state=1; +} + +function _newobj() +{ + //Begin a new object + $this->n++; + $this->offsets[$this->n]=strlen($this->buffer); + $this->_out($this->n.' 0 obj'); +} + +function _dounderline($x,$y,$txt) +{ + //Underline text + $up=$this->CurrentFont['up']; + $ut=$this->CurrentFont['ut']; + $w=$this->GetStringWidth($txt)+$this->ws*substr_count($txt,' '); + return sprintf('%.2f %.2f %.2f %.2f re f',$x*$this->k,($this->h-($y-$up/1000*$this->FontSize))*$this->k,$w*$this->k,-$ut/1000*$this->FontSizePt); +} + +function _parsejpg($file) +{ + //Extract info from a JPEG file + $a=GetImageSize($file); + if(!$a) + $this->Error('Missing or incorrect image file: '.$file); + if($a[2]!=2) + $this->Error('Not a JPEG file: '.$file); + if(!isset($a['channels']) or $a['channels']==3) + $colspace='DeviceRGB'; + elseif($a['channels']==4) + $colspace='DeviceCMYK'; + else + $colspace='DeviceGray'; + $bpc=isset($a['bits']) ? $a['bits'] : 8; + //Read whole file + $f=fopen($file,'rb'); + $data=''; + while(!feof($f)) + $data.=fread($f,4096); + fclose($f); + return array('w'=>$a[0],'h'=>$a[1],'cs'=>$colspace,'bpc'=>$bpc,'f'=>'DCTDecode','data'=>$data); +} + +function _parsepng($file) +{ + //Extract info from a PNG file + $f=fopen($file,'rb'); + if(!$f) + $this->Error('Can\'t open image file: '.$file); + //Check signature + if(fread($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) + $this->Error('Not a PNG file: '.$file); + //Read header chunk + fread($f,4); + if(fread($f,4)!='IHDR') + $this->Error('Incorrect PNG file: '.$file); + $w=$this->_freadint($f); + $h=$this->_freadint($f); + $bpc=ord(fread($f,1)); + if($bpc>8) + $this->Error('16-bit depth not supported: '.$file); + $ct=ord(fread($f,1)); + if($ct==0) + $colspace='DeviceGray'; + elseif($ct==2) + $colspace='DeviceRGB'; + elseif($ct==3) + $colspace='Indexed'; + else + $this->Error('Alpha channel not supported: '.$file); + if(ord(fread($f,1))!=0) + $this->Error('Unknown compression method: '.$file); + if(ord(fread($f,1))!=0) + $this->Error('Unknown filter method: '.$file); + if(ord(fread($f,1))!=0) + $this->Error('Interlacing not supported: '.$file); + fread($f,4); + $parms='/DecodeParms <>'; + //Scan chunks looking for palette, transparency and image data + $pal=''; + $trns=''; + $data=''; + do + { + $n=$this->_freadint($f); + $type=fread($f,4); + if($type=='PLTE') + { + //Read palette + $pal=fread($f,$n); + fread($f,4); + } + elseif($type=='tRNS') + { + //Read transparency info + $t=fread($f,$n); + if($ct==0) + $trns=array(ord(substr($t,1,1))); + elseif($ct==2) + $trns=array(ord(substr($t,1,1)),ord(substr($t,3,1)),ord(substr($t,5,1))); + else + { + $pos=strpos($t,chr(0)); + if(is_int($pos)) + $trns=array($pos); + } + fread($f,4); + } + elseif($type=='IDAT') + { + //Read image data block + $data.=fread($f,$n); + fread($f,4); + } + elseif($type=='IEND') + break; + else + fread($f,$n+4); + } + while($n); + if($colspace=='Indexed' and empty($pal)) + $this->Error('Missing palette in '.$file); + fclose($f); + return array('w'=>$w,'h'=>$h,'cs'=>$colspace,'bpc'=>$bpc,'f'=>'FlateDecode','parms'=>$parms,'pal'=>$pal,'trns'=>$trns,'data'=>$data); +} + +function _freadint($f) +{ + //Read a 4-byte integer from file + $i=ord(fread($f,1))<<24; + $i+=ord(fread($f,1))<<16; + $i+=ord(fread($f,1))<<8; + $i+=ord(fread($f,1)); + return $i; +} + +function _textstring($s) +{ + //Format a text string + return '('.$this->_escape($s).')'; +} + +function _escape($s) +{ + //Add \ before \, ( and ) + return str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$s))); +} + +function _putstream($s) +{ + $this->_out('stream'); + $this->_out($s); + $this->_out('endstream'); +} + +function _out($s) +{ + //Add a line to the document + if($this->state==2) + $this->pages[$this->page].=$s."\n"; + else + $this->buffer.=$s."\n"; +} +//End of class +} + +//Handle special IE contype request +if(isset($_SERVER['HTTP_USER_AGENT']) and $_SERVER['HTTP_USER_AGENT']=='contype') +{ + Header('Content-Type: application/pdf'); + exit; +} + +} +?> diff --git a/include/pdf/fpdf.php.ie b/include/pdf/fpdf.php.ie new file mode 100644 index 000000000..631ab7f1e --- /dev/null +++ b/include/pdf/fpdf.php.ie @@ -0,0 +1,1618 @@ +_dochecks(); + //Initialization of properties + $this->page=0; + $this->n=2; + $this->buffer=''; + $this->pages=array(); + $this->OrientationChanges=array(); + $this->state=0; + $this->fonts=array(); + $this->FontFiles=array(); + $this->diffs=array(); + $this->images=array(); + $this->links=array(); + $this->InFooter=false; + $this->lasth=0; + $this->FontFamily=''; + $this->FontStyle=''; + $this->FontSizePt=12; + $this->underline=false; + $this->DrawColor='0 G'; + $this->FillColor='0 g'; + $this->TextColor='0 g'; + $this->ColorFlag=false; + $this->ws=0; + //Standard fonts + $this->CoreFonts=array('courier'=>'Courier','courierB'=>'Courier-Bold','courierI'=>'Courier-Oblique','courierBI'=>'Courier-BoldOblique', + 'helvetica'=>'Helvetica','helveticaB'=>'Helvetica-Bold','helveticaI'=>'Helvetica-Oblique','helveticaBI'=>'Helvetica-BoldOblique', + 'times'=>'Times-Roman','timesB'=>'Times-Bold','timesI'=>'Times-Italic','timesBI'=>'Times-BoldItalic', + 'symbol'=>'Symbol','zapfdingbats'=>'ZapfDingbats'); + //Scale factor + if($unit=='pt') + $this->k=1; + elseif($unit=='mm') + $this->k=72/25.4; + elseif($unit=='cm') + $this->k=72/2.54; + elseif($unit=='in') + $this->k=72; + else + $this->Error('Incorrect unit: '.$unit); + //Page format + if(is_string($format)) + { + $format=strtolower($format); + if($format=='a3') + $format=array(841.89,1190.55); + elseif($format=='a4') + $format=array(595.28,841.89); + elseif($format=='a5') + $format=array(420.94,595.28); + elseif($format=='letter') + $format=array(612,792); + elseif($format=='legal') + $format=array(612,1008); + else + $this->Error('Unknown page format: '.$format); + $this->fwPt=$format[0]; + $this->fhPt=$format[1]; + } + else + { + $this->fwPt=$format[0]*$this->k; + $this->fhPt=$format[1]*$this->k; + } + $this->fw=$this->fwPt/$this->k; + $this->fh=$this->fhPt/$this->k; + //Page orientation + $orientation=strtolower($orientation); + if($orientation=='p' or $orientation=='portrait') + { + $this->DefOrientation='P'; + $this->wPt=$this->fwPt; + $this->hPt=$this->fhPt; + } + elseif($orientation=='l' or $orientation=='landscape') + { + $this->DefOrientation='L'; + $this->wPt=$this->fhPt; + $this->hPt=$this->fwPt; + } + else + $this->Error('Incorrect orientation: '.$orientation); + $this->CurOrientation=$this->DefOrientation; + $this->w=$this->wPt/$this->k; + $this->h=$this->hPt/$this->k; + //Page margins (1 cm) + $margin=28.35/$this->k; + $this->SetMargins($margin,$margin); + //Interior cell margin (1 mm) + $this->cMargin=$margin/10; + //Line width (0.2 mm) + $this->LineWidth=.567/$this->k; + //Automatic page break + $this->SetAutoPageBreak(true,2*$margin); + //Full width display mode + $this->SetDisplayMode('fullwidth'); + //Compression + $this->SetCompression(true); +} + +function SetMargins($left,$top,$right=-1) +{ + //Set left, top and right margins + $this->lMargin=$left; + $this->tMargin=$top; + if($right==-1) + $right=$left; + $this->rMargin=$right; +} + +function SetLeftMargin($margin) +{ + //Set left margin + $this->lMargin=$margin; + if($this->page>0 and $this->x<$margin) + $this->x=$margin; +} + +function SetTopMargin($margin) +{ + //Set top margin + $this->tMargin=$margin; +} + +function SetRightMargin($margin) +{ + //Set right margin + $this->rMargin=$margin; +} + +function SetAutoPageBreak($auto,$margin=0) +{ + //Set auto page break mode and triggering margin + $this->AutoPageBreak=$auto; + $this->bMargin=$margin; + $this->PageBreakTrigger=$this->h-$margin; +} + +function SetDisplayMode($zoom,$layout='continuous') +{ + //Set display mode in viewer + if($zoom=='fullpage' or $zoom=='fullwidth' or $zoom=='real' or $zoom=='default' or !is_string($zoom)) + $this->ZoomMode=$zoom; + else + $this->Error('Incorrect zoom display mode: '.$zoom); + if($layout=='single' or $layout=='continuous' or $layout=='two' or $layout=='default') + $this->LayoutMode=$layout; + else + $this->Error('Incorrect layout display mode: '.$layout); +} + +function SetCompression($compress) +{ + //Set page compression + if(function_exists('gzcompress')) + $this->compress=$compress; + else + $this->compress=false; +} + +function SetTitle($title) +{ + //Title of document + $this->title=$title; +} + +function SetSubject($subject) +{ + //Subject of document + $this->subject=$subject; +} + +function SetAuthor($author) +{ + //Author of document + $this->author=$author; +} + +function SetKeywords($keywords) +{ + //Keywords of document + $this->keywords=$keywords; +} + +function SetCreator($creator) +{ + //Creator of document + $this->creator=$creator; +} + +function AliasNbPages($alias='{nb}') +{ + //Define an alias for total number of pages + $this->AliasNbPages=$alias; +} + +function Error($msg) +{ + //Fatal error + die('FPDF error: '.$msg); +} + +function Open() +{ + //Begin document + if($this->state==0) + $this->_begindoc(); +} + +function Close() +{ + //Terminate document + if($this->state==3) + return; + if($this->page==0) + $this->AddPage(); + //Page footer + $this->InFooter=true; + $this->Footer(); + $this->InFooter=false; + //Close page + $this->_endpage(); + //Close document + $this->_enddoc(); +} + +function AddPage($orientation='') +{ + //Start a new page + if($this->state==0) + $this->Open(); + $family=$this->FontFamily; + $style=$this->FontStyle.($this->underline ? 'U' : ''); + $size=$this->FontSizePt; + $lw=$this->LineWidth; + $dc=$this->DrawColor; + $fc=$this->FillColor; + $tc=$this->TextColor; + $cf=$this->ColorFlag; + if($this->page>0) + { + //Page footer + $this->InFooter=true; + $this->Footer(); + $this->InFooter=false; + //Close page + $this->_endpage(); + } + //Start new page + $this->_beginpage($orientation); + //Set line cap style to square + $this->_out('2 J'); + //Set line width + $this->LineWidth=$lw; + $this->_out(sprintf('%.2f w',$lw*$this->k)); + //Set font + if($family) + $this->SetFont($family,$style,$size); + //Set colors + $this->DrawColor=$dc; + if($dc!='0 G') + $this->_out($dc); + $this->FillColor=$fc; + if($fc!='0 g') + $this->_out($fc); + $this->TextColor=$tc; + $this->ColorFlag=$cf; + //Page header + $this->Header(); + //Restore line width + if($this->LineWidth!=$lw) + { + $this->LineWidth=$lw; + $this->_out(sprintf('%.2f w',$lw*$this->k)); + } + //Restore font + if($family) + $this->SetFont($family,$style,$size); + //Restore colors + if($this->DrawColor!=$dc) + { + $this->DrawColor=$dc; + $this->_out($dc); + } + if($this->FillColor!=$fc) + { + $this->FillColor=$fc; + $this->_out($fc); + } + $this->TextColor=$tc; + $this->ColorFlag=$cf; +} + +function Header() +{ + //To be implemented in your own inherited class +} + +function Footer() +{ + //To be implemented in your own inherited class +} + +function PageNo() +{ + //Get current page number + return $this->page; +} + +function SetDrawColor($r,$g=-1,$b=-1) +{ + //Set color for all stroking operations + if(($r==0 and $g==0 and $b==0) or $g==-1) + $this->DrawColor=sprintf('%.3f G',$r/255); + else + $this->DrawColor=sprintf('%.3f %.3f %.3f RG',$r/255,$g/255,$b/255); + if($this->page>0) + $this->_out($this->DrawColor); +} + +function SetFillColor($r,$g=-1,$b=-1) +{ + //Set color for all filling operations + if(($r==0 and $g==0 and $b==0) or $g==-1) + $this->FillColor=sprintf('%.3f g',$r/255); + else + $this->FillColor=sprintf('%.3f %.3f %.3f rg',$r/255,$g/255,$b/255); + $this->ColorFlag=($this->FillColor!=$this->TextColor); + if($this->page>0) + $this->_out($this->FillColor); +} + +function SetTextColor($r,$g=-1,$b=-1) +{ + //Set color for text + if(($r==0 and $g==0 and $b==0) or $g==-1) + $this->TextColor=sprintf('%.3f g',$r/255); + else + $this->TextColor=sprintf('%.3f %.3f %.3f rg',$r/255,$g/255,$b/255); + $this->ColorFlag=($this->FillColor!=$this->TextColor); +} + +function GetStringWidth($s) +{ + //Get width of a string in the current font + $s=(string)$s; + $cw=&$this->CurrentFont['cw']; + $w=0; + $l=strlen($s); + for($i=0;$i<$l;$i++) + $w+=$cw[$s{$i}]; + return $w*$this->FontSize/1000; +} + +function SetLineWidth($width) +{ + //Set line width + $this->LineWidth=$width; + if($this->page>0) + $this->_out(sprintf('%.2f w',$width*$this->k)); +} + +function Line($x1,$y1,$x2,$y2) +{ + //Draw a line + $this->_out(sprintf('%.2f %.2f m %.2f %.2f l S',$x1*$this->k,($this->h-$y1)*$this->k,$x2*$this->k,($this->h-$y2)*$this->k)); +} + +function Rect($x,$y,$w,$h,$style='') +{ + //Draw a rectangle + if($style=='F') + $op='f'; + elseif($style=='FD' or $style=='DF') + $op='B'; + else + $op='S'; + $this->_out(sprintf('%.2f %.2f %.2f %.2f re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op)); +} + +function AddFont($family,$style='',$file='') +{ + //Add a TrueType or Type1 font + $family=strtolower($family); + if($family=='arial') + $family='helvetica'; + $style=strtoupper($style); + if($style=='IB') + $style='BI'; + if(isset($this->fonts[$family.$style])) + $this->Error('Font already added: '.$family.' '.$style); + if($file=='') + $file=str_replace(' ','',$family).strtolower($style).'.php'; + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$file; + include($file); + if(!isset($name)) + $this->Error('Could not include font definition file'); + $i=count($this->fonts)+1; + $this->fonts[$family.$style]=array('i'=>$i,'type'=>$type,'name'=>$name,'desc'=>$desc,'up'=>$up,'ut'=>$ut,'cw'=>$cw,'enc'=>$enc,'file'=>$file); + if($diff) + { + //Search existing encodings + $d=0; + $nb=count($this->diffs); + for($i=1;$i<=$nb;$i++) + if($this->diffs[$i]==$diff) + { + $d=$i; + break; + } + if($d==0) + { + $d=$nb+1; + $this->diffs[$d]=$diff; + } + $this->fonts[$family.$style]['diff']=$d; + } + if($file) + { + if($type=='TrueType') + $this->FontFiles[$file]=array('length1'=>$originalsize); + else + $this->FontFiles[$file]=array('length1'=>$size1,'length2'=>$size2); + } +} + +function SetFont($family,$style='',$size=0) +{ + //Select a font; size given in points + global $fpdf_charwidths; + + $family=strtolower($family); + if($family=='') + $family=$this->FontFamily; + if($family=='arial') + $family='helvetica'; + elseif($family=='symbol' or $family=='zapfdingbats') + $style=''; + $style=strtoupper($style); + if(is_int(strpos($style,'U'))) + { + $this->underline=true; + $style=str_replace('U','',$style); + } + else + $this->underline=false; + if($style=='IB') + $style='BI'; + if($size==0) + $size=$this->FontSizePt; + //Test if font is already selected + if($this->FontFamily==$family and $this->FontStyle==$style and $this->FontSizePt==$size) + return; + //Test if used for the first time + $fontkey=$family.$style; + if(!isset($this->fonts[$fontkey])) + { + //Check if one of the standard fonts + if(isset($this->CoreFonts[$fontkey])) + { + if(!isset($fpdf_charwidths[$fontkey])) + { + //Load metric file + $file=$family; + if($family=='times' or $family=='helvetica') + $file.=strtolower($style); + $file.='.php'; + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$file; + include($file); + if(!isset($fpdf_charwidths[$fontkey])) + $this->Error('Could not include font metric file'); + } + $i=count($this->fonts)+1; + $this->fonts[$fontkey]=array('i'=>$i,'type'=>'core','name'=>$this->CoreFonts[$fontkey],'up'=>-100,'ut'=>50,'cw'=>$fpdf_charwidths[$fontkey]); + } + else + $this->Error('Undefined font: '.$family.' '.$style); + } + //Select it + $this->FontFamily=$family; + $this->FontStyle=$style; + $this->FontSizePt=$size; + $this->FontSize=$size/$this->k; + $this->CurrentFont=&$this->fonts[$fontkey]; + if($this->page>0) + $this->_out(sprintf('BT /F%d %.2f Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); +} + +function SetFontSize($size) +{ + //Set font size in points + if($this->FontSizePt==$size) + return; + $this->FontSizePt=$size; + $this->FontSize=$size/$this->k; + if($this->page>0) + $this->_out(sprintf('BT /F%d %.2f Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); +} + +function AddLink() +{ + //Create a new internal link + $n=count($this->links)+1; + $this->links[$n]=array(0,0); + return $n; +} + +function SetLink($link,$y=0,$page=-1) +{ + //Set destination of internal link + if($y==-1) + $y=$this->y; + if($page==-1) + $page=$this->page; + $this->links[$link]=array($page,$y); +} + +function Link($x,$y,$w,$h,$link) +{ + //Put a link on the page + $this->PageLinks[$this->page][]=array($x*$this->k,$this->hPt-$y*$this->k,$w*$this->k,$h*$this->k,$link); +} + +function Text($x,$y,$txt) +{ + //Output a string + $s=sprintf('BT %.2f %.2f Td (%s) Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escape($txt)); + if($this->underline and $txt!='') + $s.=' '.$this->_dounderline($x,$y,$txt); + if($this->ColorFlag) + $s='q '.$this->TextColor.' '.$s.' Q'; + $this->_out($s); +} + +function AcceptPageBreak() +{ + //Accept automatic page break or not + return $this->AutoPageBreak; +} + +function Cell($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='') +{ + //Output a cell + $k=$this->k; + if($this->y+$h>$this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak()) + { + //Automatic page break + $x=$this->x; + $ws=$this->ws; + if($ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + $this->AddPage($this->CurOrientation); + $this->x=$x; + if($ws>0) + { + $this->ws=$ws; + $this->_out(sprintf('%.3f Tw',$ws*$k)); + } + } + if($w==0) + $w=$this->w-$this->rMargin-$this->x; + $s=''; + if($fill==1 or $border==1) + { + if($fill==1) + $op=($border==1) ? 'B' : 'f'; + else + $op='S'; + $s=sprintf('%.2f %.2f %.2f %.2f re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op); + } + if(is_string($border)) + { + $x=$this->x; + $y=$this->y; + if(is_int(strpos($border,'L'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k); + if(is_int(strpos($border,'T'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k); + if(is_int(strpos($border,'R'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k); + if(is_int(strpos($border,'B'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k); + } + if($txt!='') + { + if($align=='R') + $dx=$w-$this->cMargin-$this->GetStringWidth($txt); + elseif($align=='C') + $dx=($w-$this->GetStringWidth($txt))/2; + else + $dx=$this->cMargin; + if($this->ColorFlag) + $s.='q '.$this->TextColor.' '; + $txt2=str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$txt))); + $s.=sprintf('BT %.2f %.2f Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txt2); + if($this->underline) + $s.=' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt); + if($this->ColorFlag) + $s.=' Q'; + if($link) + $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link); + } + if($s) + $this->_out($s); + $this->lasth=$h; + if($ln>0) + { + //Go to next line + $this->y+=$h; + if($ln==1) + $this->x=$this->lMargin; + } + else + $this->x+=$w; +} + +function MultiCell($w,$h,$txt,$border=0,$align='J',$fill=0) +{ + //Output text with automatic or explicit line breaks + $cw=&$this->CurrentFont['cw']; + if($w==0) + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + $s=str_replace("\r",'',$txt); + $nb=strlen($s); + if($nb>0 and $s[$nb-1]=="\n") + $nb--; + $b=0; + if($border) + { + if($border==1) + { + $border='LTRB'; + $b='LRT'; + $b2='LR'; + } + else + { + $b2=''; + if(is_int(strpos($border,'L'))) + $b2.='L'; + if(is_int(strpos($border,'R'))) + $b2.='R'; + $b=is_int(strpos($border,'T')) ? $b2.'T' : $b2; + } + } + $sep=-1; + $i=0; + $j=0; + $l=0; + $ns=0; + $nl=1; + while($i<$nb) + { + //Get next character + $c=$s{$i}; + if($c=="\n") + { + //Explicit line break + if($this->ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + $i++; + $sep=-1; + $j=$i; + $l=0; + $ns=0; + $nl++; + if($border and $nl==2) + $b=$b2; + continue; + } + if($c==' ') + { + $sep=$i; + $ls=$l; + $ns++; + } + $l+=$cw[$c]; + if($l>$wmax) + { + //Automatic line break + if($sep==-1) + { + if($i==$j) + $i++; + if($this->ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + } + else + { + if($align=='J') + { + $this->ws=($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0; + $this->_out(sprintf('%.3f Tw',$this->ws*$this->k)); + } + $this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill); + $i=$sep+1; + } + $sep=-1; + $j=$i; + $l=0; + $ns=0; + $nl++; + if($border and $nl==2) + $b=$b2; + } + else + $i++; + } + //Last chunk + if($this->ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + if($border and is_int(strpos($border,'B'))) + $b.='B'; + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + $this->x=$this->lMargin; +} + +function Write($h,$txt,$link='') +{ + //Output text in flowing mode + $cw=&$this->CurrentFont['cw']; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + $s=str_replace("\r",'',$txt); + $nb=strlen($s); + $sep=-1; + $i=0; + $j=0; + $l=0; + $nl=1; + while($i<$nb) + { + //Get next character + $c=$s{$i}; + if($c=="\n") + { + //Explicit line break + $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link); + $i++; + $sep=-1; + $j=$i; + $l=0; + if($nl==1) + { + $this->x=$this->lMargin; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + } + $nl++; + continue; + } + if($c==' ') + $sep=$i; + $l+=$cw[$c]; + if($l>$wmax) + { + //Automatic line break + if($sep==-1) + { + if($this->x>$this->lMargin) + { + //Move to next line + $this->x=$this->lMargin; + $this->y+=$h; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + $i++; + $nl++; + continue; + } + if($i==$j) + $i++; + $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link); + } + else + { + $this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',0,$link); + $i=$sep+1; + } + $sep=-1; + $j=$i; + $l=0; + if($nl==1) + { + $this->x=$this->lMargin; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + } + $nl++; + } + else + $i++; + } + //Last chunk + if($i!=$j) + $this->Cell($l/1000*$this->FontSize,$h,substr($s,$j),0,0,'',0,$link); +} + +function Image($file,$x,$y,$w=0,$h=0,$type='',$link='') +{ + //Put an image on the page + if(!isset($this->images[$file])) + { + //First use of image, get info + if($type=='') + { + $pos=strrpos($file,'.'); + if(!$pos) + $this->Error('Image file has no extension and no type was specified: '.$file); + $type=substr($file,$pos+1); + } + $type=strtolower($type); + $mqr=get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + if($type=='jpg' or $type=='jpeg') + $info=$this->_parsejpg($file); + elseif($type=='png') + $info=$this->_parsepng($file); + else + { + //Allow for additional formats + $mtd='_parse'.$type; + if(!method_exists($this,$mtd)) + $this->Error('Unsupported image type: '.$type); + $info=$this->$mtd($file); + } + set_magic_quotes_runtime($mqr); + $info['i']=count($this->images)+1; + $this->images[$file]=$info; + } + else + $info=$this->images[$file]; + //Automatic width and height calculation if needed + if($w==0 and $h==0) + { + //Put image at 72 dpi + $w=$info['w']/$this->k; + $h=$info['h']/$this->k; + } + if($w==0) + $w=$h*$info['w']/$info['h']; + if($h==0) + $h=$w*$info['h']/$info['w']; + $this->_out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q',$w*$this->k,$h*$this->k,$x*$this->k,($this->h-($y+$h))*$this->k,$info['i'])); + if($link) + $this->Link($x,$y,$w,$h,$link); +} + +function Ln($h='') +{ + //Line feed; default value is last cell height + $this->x=$this->lMargin; + if(is_string($h)) + $this->y+=$this->lasth; + else + $this->y+=$h; +} + +function GetX() +{ + //Get x position + return $this->x; +} + +function SetX($x) +{ + //Set x position + if($x>=0) + $this->x=$x; + else + $this->x=$this->w+$x; +} + +function GetY() +{ + //Get y position + return $this->y; +} + +function SetY($y) +{ + //Set y position and reset x + $this->x=$this->lMargin; + if($y>=0) + $this->y=$y; + else + $this->y=$this->h+$y; +} + +function SetXY($x,$y) +{ + //Set x and y positions + $this->SetY($y); + $this->SetX($x); +} + +function Output($name='',$dest='') +{ + //Output PDF to some destination + global $HTTP_SERVER_VARS; + + //Finish document if necessary + if($this->state<3) + $this->Close(); + //Normalize parameters + if(is_bool($dest)) + $dest=$dest ? 'D' : 'F'; + $dest=strtoupper($dest); + if($dest=='') + { + if($name=='') + { + $name='doc.pdf'; + $dest='I'; + } + else + $dest='F'; + } + switch($dest) + { + case 'I': + //Send to standard output + if(isset($HTTP_SERVER_VARS['SERVER_NAME'])) + { + //We send to a browser + Header('Content-Type: application/pdf'); + if(headers_sent()) + $this->Error('Some data has already been output to browser, can\'t send PDF file'); + Header('Content-Length: '.strlen($this->buffer)); + Header('Content-disposition: inline; filename='.$name); + } + echo $this->buffer; + break; + case 'D': + //Download file + if(isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']) and strpos($HTTP_SERVER_VARS['HTTP_USER_AGENT'],'MSIE')) + Header('Content-Type: application/force-download'); + else + Header('Content-Type: application/octet-stream'); + if(headers_sent()) + $this->Error('Some data has already been output to browser, can\'t send PDF file'); + Header('Content-Length: '.strlen($this->buffer)); + Header('Content-disposition: attachment; filename='.$name); + echo $this->buffer; + break; + case 'F': + //Save to local file + $f=fopen($name,'wb'); + if(!$f) + $this->Error('Unable to create output file: '.$name); + fwrite($f,$this->buffer,strlen($this->buffer)); + fclose($f); + break; + case 'S': + //Return as a string + return $this->buffer; + default: + $this->Error('Incorrect output destination: '.$dest); + } + return ''; +} + +/******************************************************************************* +* * +* Protected methods * +* * +*******************************************************************************/ +function _dochecks() +{ + //Check for locale-related bug + if(1.1==1) + $this->Error('Don\'t alter the locale before including class file'); + //Check for decimal separator + if(sprintf('%.1f',1.0)!='1.0') + setlocale(LC_NUMERIC,'C'); +} + +function _begindoc() +{ + //Start document + $this->state=1; + $this->_out('%PDF-1.3'); +} + +function _putpages() +{ + $nb=$this->page; + if(!empty($this->AliasNbPages)) + { + //Replace number of pages + for($n=1;$n<=$nb;$n++) + $this->pages[$n]=str_replace($this->AliasNbPages,$nb,$this->pages[$n]); + } + if($this->DefOrientation=='P') + { + $wPt=$this->fwPt; + $hPt=$this->fhPt; + } + else + { + $wPt=$this->fhPt; + $hPt=$this->fwPt; + } + $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; + for($n=1;$n<=$nb;$n++) + { + //Page + $this->_newobj(); + $this->_out('<_out('/Parent 1 0 R'); + if(isset($this->OrientationChanges[$n])) + $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$hPt,$wPt)); + $this->_out('/Resources 2 0 R'); + if(isset($this->PageLinks[$n])) + { + //Links + $annots='/Annots ['; + foreach($this->PageLinks[$n] as $pl) + { + $rect=sprintf('%.2f %.2f %.2f %.2f',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]); + $annots.='<_textstring($pl[4]).'>>>>'; + else + { + $l=$this->links[$pl[4]]; + $h=isset($this->OrientationChanges[$l[0]]) ? $wPt : $hPt; + $annots.=sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+2*$l[0],$h-$l[1]*$this->k); + } + } + $this->_out($annots.']'); + } + $this->_out('/Contents '.($this->n+1).' 0 R>>'); + $this->_out('endobj'); + //Page content + $p=($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n]; + $this->_newobj(); + $this->_out('<<'.$filter.'/Length '.strlen($p).'>>'); + $this->_putstream($p); + $this->_out('endobj'); + } + //Pages root + $this->offsets[1]=strlen($this->buffer); + $this->_out('1 0 obj'); + $this->_out('<_out($kids.']'); + $this->_out('/Count '.$nb); + $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$wPt,$hPt)); + $this->_out('>>'); + $this->_out('endobj'); +} + +function _putfonts() +{ + $nf=$this->n; + foreach($this->diffs as $diff) + { + //Encodings + $this->_newobj(); + $this->_out('<>'); + $this->_out('endobj'); + } + $mqr=get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + foreach($this->FontFiles as $file=>$info) + { + //Font file embedding + $this->_newobj(); + $this->FontFiles[$file]['n']=$this->n; + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$file; + $size=filesize($file); + if(!$size) + $this->Error('Font file not found'); + $this->_out('<_out('/Filter /FlateDecode'); + $this->_out('/Length1 '.$info['length1']); + if(isset($info['length2'])) + $this->_out('/Length2 '.$info['length2'].' /Length3 0'); + $this->_out('>>'); + $f=fopen($file,'rb'); + $this->_putstream(fread($f,$size)); + fclose($f); + $this->_out('endobj'); + } + set_magic_quotes_runtime($mqr); + foreach($this->fonts as $k=>$font) + { + //Font objects + $this->fonts[$k]['n']=$this->n+1; + $type=$font['type']; + $name=$font['name']; + if($type=='core') + { + //Standard font + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$name); + $this->_out('/Subtype /Type1'); + if($name!='Symbol' and $name!='ZapfDingbats') + $this->_out('/Encoding /WinAnsiEncoding'); + $this->_out('>>'); + $this->_out('endobj'); + } + elseif($type=='Type1' or $type=='TrueType') + { + //Additional Type1 or TrueType font + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$name); + $this->_out('/Subtype /'.$type); + $this->_out('/FirstChar 32 /LastChar 255'); + $this->_out('/Widths '.($this->n+1).' 0 R'); + $this->_out('/FontDescriptor '.($this->n+2).' 0 R'); + if($font['enc']) + { + if(isset($font['diff'])) + $this->_out('/Encoding '.($nf+$font['diff']).' 0 R'); + else + $this->_out('/Encoding /WinAnsiEncoding'); + } + $this->_out('>>'); + $this->_out('endobj'); + //Widths + $this->_newobj(); + $cw=&$font['cw']; + $s='['; + for($i=32;$i<=255;$i++) + $s.=$cw[chr($i)].' '; + $this->_out($s.']'); + $this->_out('endobj'); + //Descriptor + $this->_newobj(); + $s='<$v) + $s.=' /'.$k.' '.$v; + $file=$font['file']; + if($file) + $s.=' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$file]['n'].' 0 R'; + $this->_out($s.'>>'); + $this->_out('endobj'); + } + else + { + //Allow for additional types + $mtd='_put'.strtolower($type); + if(!method_exists($this,$mtd)) + $this->Error('Unsupported font type: '.$type); + $this->$mtd($font); + } + } +} + +function _putimages() +{ + $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; + reset($this->images); + while(list($file,$info)=each($this->images)) + { + $this->_newobj(); + $this->images[$file]['n']=$this->n; + $this->_out('<_out('/Subtype /Image'); + $this->_out('/Width '.$info['w']); + $this->_out('/Height '.$info['h']); + if($info['cs']=='Indexed') + $this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]'); + else + { + $this->_out('/ColorSpace /'.$info['cs']); + if($info['cs']=='DeviceCMYK') + $this->_out('/Decode [1 0 1 0 1 0 1 0]'); + } + $this->_out('/BitsPerComponent '.$info['bpc']); + $this->_out('/Filter /'.$info['f']); + if(isset($info['parms'])) + $this->_out($info['parms']); + if(isset($info['trns']) and is_array($info['trns'])) + { + $trns=''; + for($i=0;$i_out('/Mask ['.$trns.']'); + } + $this->_out('/Length '.strlen($info['data']).'>>'); + $this->_putstream($info['data']); + unset($this->images[$file]['data']); + $this->_out('endobj'); + //Palette + if($info['cs']=='Indexed') + { + $this->_newobj(); + $pal=($this->compress) ? gzcompress($info['pal']) : $info['pal']; + $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>'); + $this->_putstream($pal); + $this->_out('endobj'); + } + } +} + +function _putresources() +{ + $this->_putfonts(); + $this->_putimages(); + //Resource dictionary + $this->offsets[2]=strlen($this->buffer); + $this->_out('2 0 obj'); + $this->_out('<_out('/Font <<'); + foreach($this->fonts as $font) + $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R'); + $this->_out('>>'); + if(count($this->images)) + { + $this->_out('/XObject <<'); + foreach($this->images as $image) + $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); + $this->_out('>>'); + } + $this->_out('>>'); + $this->_out('endobj'); +} + +function _putinfo() +{ + $this->_out('/Producer '.$this->_textstring('FPDF '.FPDF_VERSION)); + if(!empty($this->title)) + $this->_out('/Title '.$this->_textstring($this->title)); + if(!empty($this->subject)) + $this->_out('/Subject '.$this->_textstring($this->subject)); + if(!empty($this->author)) + $this->_out('/Author '.$this->_textstring($this->author)); + if(!empty($this->keywords)) + $this->_out('/Keywords '.$this->_textstring($this->keywords)); + if(!empty($this->creator)) + $this->_out('/Creator '.$this->_textstring($this->creator)); + $this->_out('/CreationDate '.$this->_textstring('D:'.date('YmdHis'))); +} + +function _putcatalog() +{ + $this->_out('/Type /Catalog'); + $this->_out('/Pages 1 0 R'); + if($this->ZoomMode=='fullpage') + $this->_out('/OpenAction [3 0 R /Fit]'); + elseif($this->ZoomMode=='fullwidth') + $this->_out('/OpenAction [3 0 R /FitH null]'); + elseif($this->ZoomMode=='real') + $this->_out('/OpenAction [3 0 R /XYZ null null 1]'); + elseif(!is_string($this->ZoomMode)) + $this->_out('/OpenAction [3 0 R /XYZ null null '.($this->ZoomMode/100).']'); + if($this->LayoutMode=='single') + $this->_out('/PageLayout /SinglePage'); + elseif($this->LayoutMode=='continuous') + $this->_out('/PageLayout /OneColumn'); + elseif($this->LayoutMode=='two') + $this->_out('/PageLayout /TwoColumnLeft'); +} + +function _puttrailer() +{ + $this->_out('/Size '.($this->n+1)); + $this->_out('/Root '.$this->n.' 0 R'); + $this->_out('/Info '.($this->n-1).' 0 R'); +} + +function _enddoc() +{ + $this->_putpages(); + $this->_putresources(); + //Info + $this->_newobj(); + $this->_out('<<'); + $this->_putinfo(); + $this->_out('>>'); + $this->_out('endobj'); + //Catalog + $this->_newobj(); + $this->_out('<<'); + $this->_putcatalog(); + $this->_out('>>'); + $this->_out('endobj'); + //Cross-ref + $o=strlen($this->buffer); + $this->_out('xref'); + $this->_out('0 '.($this->n+1)); + $this->_out('0000000000 65535 f '); + for($i=1;$i<=$this->n;$i++) + $this->_out(sprintf('%010d 00000 n ',$this->offsets[$i])); + //Trailer + $this->_out('trailer'); + $this->_out('<<'); + $this->_puttrailer(); + $this->_out('>>'); + $this->_out('startxref'); + $this->_out($o); + $this->_out('%%EOF'); + $this->state=3; +} + +function _beginpage($orientation) +{ + $this->page++; + $this->pages[$this->page]=''; + $this->state=2; + $this->x=$this->lMargin; + $this->y=$this->tMargin; + $this->FontFamily=''; + //Page orientation + if(!$orientation) + $orientation=$this->DefOrientation; + else + { + $orientation=strtoupper($orientation{0}); + if($orientation!=$this->DefOrientation) + $this->OrientationChanges[$this->page]=true; + } + if($orientation!=$this->CurOrientation) + { + //Change orientation + if($orientation=='P') + { + $this->wPt=$this->fwPt; + $this->hPt=$this->fhPt; + $this->w=$this->fw; + $this->h=$this->fh; + } + else + { + $this->wPt=$this->fhPt; + $this->hPt=$this->fwPt; + $this->w=$this->fh; + $this->h=$this->fw; + } + $this->PageBreakTrigger=$this->h-$this->bMargin; + $this->CurOrientation=$orientation; + } +} + +function _endpage() +{ + //End of page contents + $this->state=1; +} + +function _newobj() +{ + //Begin a new object + $this->n++; + $this->offsets[$this->n]=strlen($this->buffer); + $this->_out($this->n.' 0 obj'); +} + +function _dounderline($x,$y,$txt) +{ + //Underline text + $up=$this->CurrentFont['up']; + $ut=$this->CurrentFont['ut']; + $w=$this->GetStringWidth($txt)+$this->ws*substr_count($txt,' '); + return sprintf('%.2f %.2f %.2f %.2f re f',$x*$this->k,($this->h-($y-$up/1000*$this->FontSize))*$this->k,$w*$this->k,-$ut/1000*$this->FontSizePt); +} + +function _parsejpg($file) +{ + //Extract info from a JPEG file + $a=GetImageSize($file); + if(!$a) + $this->Error('Missing or incorrect image file: '.$file); + if($a[2]!=2) + $this->Error('Not a JPEG file: '.$file); + if(!isset($a['channels']) or $a['channels']==3) + $colspace='DeviceRGB'; + elseif($a['channels']==4) + $colspace='DeviceCMYK'; + else + $colspace='DeviceGray'; + $bpc=isset($a['bits']) ? $a['bits'] : 8; + //Read whole file + $f=fopen($file,'rb'); + $data=''; + while(!feof($f)) + $data.=fread($f,4096); + fclose($f); + return array('w'=>$a[0],'h'=>$a[1],'cs'=>$colspace,'bpc'=>$bpc,'f'=>'DCTDecode','data'=>$data); +} + +function _parsepng($file) +{ + //Extract info from a PNG file + $f=fopen($file,'rb'); + if(!$f) + $this->Error('Can\'t open image file: '.$file); + //Check signature + if(fread($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) + $this->Error('Not a PNG file: '.$file); + //Read header chunk + fread($f,4); + if(fread($f,4)!='IHDR') + $this->Error('Incorrect PNG file: '.$file); + $w=$this->_freadint($f); + $h=$this->_freadint($f); + $bpc=ord(fread($f,1)); + if($bpc>8) + $this->Error('16-bit depth not supported: '.$file); + $ct=ord(fread($f,1)); + if($ct==0) + $colspace='DeviceGray'; + elseif($ct==2) + $colspace='DeviceRGB'; + elseif($ct==3) + $colspace='Indexed'; + else + $this->Error('Alpha channel not supported: '.$file); + if(ord(fread($f,1))!=0) + $this->Error('Unknown compression method: '.$file); + if(ord(fread($f,1))!=0) + $this->Error('Unknown filter method: '.$file); + if(ord(fread($f,1))!=0) + $this->Error('Interlacing not supported: '.$file); + fread($f,4); + $parms='/DecodeParms <>'; + //Scan chunks looking for palette, transparency and image data + $pal=''; + $trns=''; + $data=''; + do + { + $n=$this->_freadint($f); + $type=fread($f,4); + if($type=='PLTE') + { + //Read palette + $pal=fread($f,$n); + fread($f,4); + } + elseif($type=='tRNS') + { + //Read transparency info + $t=fread($f,$n); + if($ct==0) + $trns=array(ord(substr($t,1,1))); + elseif($ct==2) + $trns=array(ord(substr($t,1,1)),ord(substr($t,3,1)),ord(substr($t,5,1))); + else + { + $pos=strpos($t,chr(0)); + if(is_int($pos)) + $trns=array($pos); + } + fread($f,4); + } + elseif($type=='IDAT') + { + //Read image data block + $data.=fread($f,$n); + fread($f,4); + } + elseif($type=='IEND') + break; + else + fread($f,$n+4); + } + while($n); + if($colspace=='Indexed' and empty($pal)) + $this->Error('Missing palette in '.$file); + fclose($f); + return array('w'=>$w,'h'=>$h,'cs'=>$colspace,'bpc'=>$bpc,'f'=>'FlateDecode','parms'=>$parms,'pal'=>$pal,'trns'=>$trns,'data'=>$data); +} + +function _freadint($f) +{ + //Read a 4-byte integer from file + $i=ord(fread($f,1))<<24; + $i+=ord(fread($f,1))<<16; + $i+=ord(fread($f,1))<<8; + $i+=ord(fread($f,1)); + return $i; +} + +function _textstring($s) +{ + //Format a text string + return '('.$this->_escape($s).')'; +} + +function _escape($s) +{ + //Add \ before \, ( and ) + return str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$s))); +} + +function _putstream($s) +{ + $this->_out('stream'); + $this->_out($s); + $this->_out('endstream'); +} + +function _out($s) +{ + //Add a line to the document + if($this->state==2) + $this->pages[$this->page].=$s."\n"; + else + $this->buffer.=$s."\n"; +} +//End of class +} + +//Handle special IE contype request +if(isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']) and $HTTP_SERVER_VARS['HTTP_USER_AGENT']=='contype') +{ + Header('Content-Type: application/pdf'); + exit; +} + +} +?> diff --git a/include/pdf/histo.htm b/include/pdf/histo.htm new file mode 100644 index 000000000..7f261bf8b --- /dev/null +++ b/include/pdf/histo.htm @@ -0,0 +1,103 @@ + + + +History + + + +

    History

    +v1.52 (2003-12-30) +
    +- Image() now displays the image at 72 dpi if no dimension is given.
    +- Output() takes a string as second parameter to indicate destination.
    +- Open() is now called automatically by AddPage().
    +- Inserting remote JPEG images doesn't generate an error any longer.
    +- Decimal separator is forced to dot in the constructor.
    +- Added several encodings (Turkish, Thai, Hebrew, Ukrainian and Vietnamese).
    +- The last line of a right-aligned MultiCell() was not correctly aligned if it was terminated by a carriage return.
    +- No more error message about already sent headers when outputting the PDF to the standard output from the command line.
    +- The underlining was going too far for text containing characters \, ( or ).
    +- $HTTP_ENV_VARS has been replaced by $HTTP_SERVER_VARS.
    +
    +v1.51 (2002-08-03) +
    +- Type1 font support.
    +- Added Baltic encoding.
    +- The class now works internally in points with the origin at the bottom in order to avoid two bugs occurring with Acrobat 5 :
      * The line thickness was too large when printed under Windows 98 SE and ME.
      * TrueType fonts didn't appear immediately inside the plug-in (a substitution font was used), one had to cause a window refresh to make them show up.
    +- It is no longer necessary to set the decimal separator as dot to produce valid documents.
    +- The clickable area in a cell was always on the left independently from the text alignment.
    +- JPEG images in CMYK mode appeared in inverted colors.
    +- Transparent PNG images in grayscale or true color mode were incorrectly handled.
    +- Adding new fonts now works correctly even with the magic_quotes_runtime option set to on.
    +
    +v1.5 (2002-05-28) +
    +- TrueType font (AddFont()) and encoding support (Western and Eastern Europe, Cyrillic and Greek).
    +- Added Write() method.
    +- Added underlined style.
    +- Internal and external link support (AddLink(), SetLink(), Link()).
    +- Added right margin management and methods SetRightMargin(), SetTopMargin().
    +- Modification of SetDisplayMode() to select page layout.
    +- The border parameter of MultiCell() now lets choose borders to draw as Cell().
    +- When a document contains no page, Close() now calls AddPage() instead of causing a fatal error.
    +
    +v1.41 (2002-03-13) +
    +- Fixed SetDisplayMode() which no longer worked (the PDF viewer used its default display).
    +
    +v1.4 (2002-03-02) +
    +- PHP3 is no longer supported.
    +- Page compression (SetCompression()).
    +- Choice of page format and possibility to change orientation inside document.
    +- Added AcceptPageBreak() method.
    +- Ability to print the total number of pages (AliasNbPages()).
    +- Choice of cell borders to draw.
    +- New mode for Cell(): the current position can now move under the cell.
    +- Ability to include an image by specifying height only (width is calculated automatically).
    +- Fixed a bug: when a justified line triggered a page break, the footer inherited the corresponding word spacing.
    +
    +v1.31 (2002-01-12) +
    +- Fixed a bug in drawing frame with MultiCell(): the last line always started from the left margin.
    +- Removed Expires HTTP header (gives trouble in some situations).
    +- Added Content-disposition HTTP header (seems to help in some situations).
    +
    +v1.3 (2001-12-03) +
    +- Line break and text justification support (MultiCell()).
    +- Color support (SetDrawColor(), SetFillColor(), SetTextColor()). Possibility to draw filled rectangles and paint cell background.
    +- A cell whose width is declared null extends up to the right margin of the page.
    +- Line width is now retained from page to page and defaults to 0.2 mm.
    +- Added SetXY() method.
    +- Fixed a passing by reference done in a deprecated manner for PHP4.
    +
    +v1.2 (2001-11-11) +
    +- Added font metric files and GetStringWidth() method.
    +- Centering and right-aligning text in cells.
    +- Display mode control (SetDisplayMode()).
    +- Added methods to set document properties (SetAuthor(), SetCreator(), SetKeywords(), SetSubject(), SetTitle()).
    +- Possibility to force PDF download by browser.
    +- Added SetX() and GetX() methods.
    +- During automatic page break, current abscissa is now retained.
    +
    +v1.11 (2001-10-20) +
    +- PNG support doesn't require PHP4/Zlib any more. Data are now put directly into PDF without any decompression/recompression stage.
    +- Image insertion now works correctly even with magic_quotes_runtime option set to on.
    +
    +v1.1 (2001-10-07) +
    +- JPEG and PNG image support.
    +
    +v1.01 (2001-10-03) +
    +- Fixed a bug involving page break: in case when Header() doesn't specify a font, the one from previous page was not restored and produced an incorrect document.
    +
    +v1.0 (2001-09-17) +
    +- First version.
    +
    + + diff --git a/include/pdf/install.txt b/include/pdf/install.txt new file mode 100644 index 000000000..494fcf784 --- /dev/null +++ b/include/pdf/install.txt @@ -0,0 +1,29 @@ +The FPDF library is made up of the following elements: + +- the main file, fpdf.php, which contains the class +- the font metric files (located in the font directory of this archive) + +The metric files are necessary as soon as you want to output text in a document. +They can be accessed from three different locations: + +- the current directory (the one where the running script lies) +- one of the directories defined by the include_path parameter +- the directory defined by the FPDF_FONTPATH constant + +Here is an example for the last case (note the mandatory final slash): + +define('FPDF_FONTPATH','/home/www/font/'); +require('fpdf.php'); + +If the files are not accessible, the SetFont() method will produce the following error: + +FPDF error: Could not include font metric file + +If so, check if you have correctly defined the constant. + +Remarks: + +- You can also define FPDF_FONTPATH directly at the beginning of fpdf.php +- Only the files corresponding to the fonts actually used are necessary + +The tutorials provided in this package are ready to be executed. diff --git a/include/pdf/tutorial/20k_c1.txt b/include/pdf/tutorial/20k_c1.txt new file mode 100644 index 000000000..0b09f265f --- /dev/null +++ b/include/pdf/tutorial/20k_c1.txt @@ -0,0 +1,10 @@ +The year 1866 was marked by a bizarre development, an unexplained and downright inexplicable phenomenon that surely no one has forgotten. Without getting into those rumors that upset civilians in the seaports and deranged the public mind even far inland, it must be said that professional seamen were especially alarmed. Traders, shipowners, captains of vessels, skippers, and master mariners from Europe and America, naval officers from every country, and at their heels the various national governments on these two continents, were all extremely disturbed by the business. +In essence, over a period of time several ships had encountered "an enormous thing" at sea, a long spindle-shaped object, sometimes giving off a phosphorescent glow, infinitely bigger and faster than any whale. +The relevant data on this apparition, as recorded in various logbooks, agreed pretty closely as to the structure of the object or creature in question, its unprecedented speed of movement, its startling locomotive power, and the unique vitality with which it seemed to be gifted. If it was a cetacean, it exceeded in bulk any whale previously classified by science. No naturalist, neither Cuvier nor Lacépède, neither Professor Dumeril nor Professor de Quatrefages, would have accepted the existence of such a monster sight unseen -- specifically, unseen by their own scientific eyes. +Striking an average of observations taken at different times -- rejecting those timid estimates that gave the object a length of 200 feet, and ignoring those exaggerated views that saw it as a mile wide and three long--you could still assert that this phenomenal creature greatly exceeded the dimensions of anything then known to ichthyologists, if it existed at all. +Now then, it did exist, this was an undeniable fact; and since the human mind dotes on objects of wonder, you can understand the worldwide excitement caused by this unearthly apparition. As for relegating it to the realm of fiction, that charge had to be dropped. +In essence, on July 20, 1866, the steamer Governor Higginson, from the Calcutta & Burnach Steam Navigation Co., encountered this moving mass five miles off the eastern shores of Australia. Captain Baker at first thought he was in the presence of an unknown reef; he was even about to fix its exact position when two waterspouts shot out of this inexplicable object and sprang hissing into the air some 150 feet. So, unless this reef was subject to the intermittent eruptions of a geyser, the Governor Higginson had fair and honest dealings with some aquatic mammal, until then unknown, that could spurt from its blowholes waterspouts mixed with air and steam. +Similar events were likewise observed in Pacific seas, on July 23 of the same year, by the Christopher Columbus from the West India & Pacific Steam Navigation Co. Consequently, this extraordinary cetacean could transfer itself from one locality to another with startling swiftness, since within an interval of just three days, the Governor Higginson and the Christopher Columbus had observed it at two positions on the charts separated by a distance of more than 700 nautical leagues. +Fifteen days later and 2,000 leagues farther, the Helvetia from the Compagnie Nationale and the Shannon from the Royal Mail line, running on opposite tacks in that part of the Atlantic lying between the United States and Europe, respectively signaled each other that the monster had been sighted in latitude 42 degrees 15' north and longitude 60 degrees 35' west of the meridian of Greenwich. From their simultaneous observations, they were able to estimate the mammal's minimum length at more than 350 English feet; this was because both the Shannon and the Helvetia were of smaller dimensions, although each measured 100 meters stem to stern. Now then, the biggest whales, those rorqual whales that frequent the waterways of the Aleutian Islands, have never exceeded a length of 56 meters--if they reach even that. +One after another, reports arrived that would profoundly affect public opinion: new observations taken by the transatlantic liner Pereire, the Inman line's Etna running afoul of the monster, an official report drawn up by officers on the French frigate Normandy, dead-earnest reckonings obtained by the general staff of Commodore Fitz-James aboard the Lord Clyde. In lighthearted countries, people joked about this phenomenon, but such serious, practical countries as England, America, and Germany were deeply concerned. +In every big city the monster was the latest rage; they sang about it in the coffee houses, they ridiculed it in the newspapers, they dramatized it in the theaters. The tabloids found it a fine opportunity for hatching all sorts of hoaxes. In those newspapers short of copy, you saw the reappearance of every gigantic imaginary creature, from "Moby Dick," that dreadful white whale from the High Arctic regions, to the stupendous kraken whose tentacles could entwine a 500-ton craft and drag it into the ocean depths. They even reprinted reports from ancient times: the views of Aristotle and Pliny accepting the existence of such monsters, then the Norwegian stories of Bishop Pontoppidan, the narratives of Paul Egede, and finally the reports of Captain Harrington -- whose good faith is above suspicion--in which he claims he saw, while aboard the Castilian in 1857, one of those enormous serpents that, until then, had frequented only the seas of France's old extremist newspaper, The Constitutionalist. diff --git a/include/pdf/tutorial/20k_c2.txt b/include/pdf/tutorial/20k_c2.txt new file mode 100644 index 000000000..096dbd193 --- /dev/null +++ b/include/pdf/tutorial/20k_c2.txt @@ -0,0 +1,23 @@ +During the period in which these developments were occurring, I had returned from a scientific undertaking organized to explore the Nebraska badlands in the United States. In my capacity as Assistant Professor at the Paris Museum of Natural History, I had been attached to this expedition by the French government. After spending six months in Nebraska, I arrived in New York laden with valuable collections near the end of March. My departure for France was set for early May. In the meantime, then, I was busy classifying my mineralogical, botanical, and zoological treasures when that incident took place with the Scotia. +I was perfectly abreast of this question, which was the big news of the day, and how could I not have been? I had read and reread every American and European newspaper without being any farther along. This mystery puzzled me. Finding it impossible to form any views, I drifted from one extreme to the other. Something was out there, that much was certain, and any doubting Thomas was invited to place his finger on the Scotia's wound. +When I arrived in New York, the question was at the boiling point. The hypothesis of a drifting islet or an elusive reef, put forward by people not quite in their right minds, was completely eliminated. And indeed, unless this reef had an engine in its belly, how could it move about with such prodigious speed? +Also discredited was the idea of a floating hull or some other enormous wreckage, and again because of this speed of movement. +So only two possible solutions to the question were left, creating two very distinct groups of supporters: on one side, those favoring a monster of colossal strength; on the other, those favoring an "underwater boat" of tremendous motor power. +Now then, although the latter hypothesis was completely admissible, it couldn't stand up to inquiries conducted in both the New World and the Old. That a private individual had such a mechanism at his disposal was less than probable. Where and when had he built it, and how could he have built it in secret? +Only some government could own such an engine of destruction, and in these disaster-filled times, when men tax their ingenuity to build increasingly powerful aggressive weapons, it was possible that, unknown to the rest of the world, some nation could have been testing such a fearsome machine. The Chassepot rifle led to the torpedo, and the torpedo has led to this underwater battering ram, which in turn will lead to the world putting its foot down. At least I hope it will. +But this hypothesis of a war machine collapsed in the face of formal denials from the various governments. Since the public interest was at stake and transoceanic travel was suffering, the sincerity of these governments could not be doubted. Besides, how could the assembly of this underwater boat have escaped public notice? Keeping a secret under such circumstances would be difficult enough for an individual, and certainly impossible for a nation whose every move is under constant surveillance by rival powers. +So, after inquiries conducted in England, France, Russia, Prussia, Spain, Italy, America, and even Turkey, the hypothesis of an underwater Monitor was ultimately rejected. +After I arrived in New York, several people did me the honor of consulting me on the phenomenon in question. In France I had published a two-volume work, in quarto, entitled The Mysteries of the Great Ocean Depths. Well received in scholarly circles, this book had established me as a specialist in this pretty obscure field of natural history. My views were in demand. As long as I could deny the reality of the business, I confined myself to a flat "no comment." But soon, pinned to the wall, I had to explain myself straight out. And in this vein, "the honorable Pierre Aronnax, Professor at the Paris Museum," was summoned by The New York Herald to formulate his views no matter what. +I complied. Since I could no longer hold my tongue, I let it wag. I discussed the question in its every aspect, both political and scientific, and this is an excerpt from the well-padded article I published in the issue of April 30. + +"Therefore," I wrote, "after examining these different hypotheses one by one, we are forced, every other supposition having been refuted, to accept the existence of an extremely powerful marine animal. +"The deepest parts of the ocean are totally unknown to us. No soundings have been able to reach them. What goes on in those distant depths? What creatures inhabit, or could inhabit, those regions twelve or fifteen miles beneath the surface of the water? What is the constitution of these animals? It's almost beyond conjecture. +"However, the solution to this problem submitted to me can take the form of a choice between two alternatives. +"Either we know every variety of creature populating our planet, or we do not. +"If we do not know every one of them, if nature still keeps ichthyological secrets from us, nothing is more admissible than to accept the existence of fish or cetaceans of new species or even new genera, animals with a basically 'cast-iron' constitution that inhabit strata beyond the reach of our soundings, and which some development or other, an urge or a whim if you prefer, can bring to the upper level of the ocean for long intervals. +"If, on the other hand, we do know every living species, we must look for the animal in question among those marine creatures already cataloged, and in this event I would be inclined to accept the existence of a giant narwhale. +"The common narwhale, or sea unicorn, often reaches a length of sixty feet. Increase its dimensions fivefold or even tenfold, then give this cetacean a strength in proportion to its size while enlarging its offensive weapons, and you have the animal we're looking for. It would have the proportions determined by the officers of the Shannon, the instrument needed to perforate the Scotia, and the power to pierce a steamer's hull. +"In essence, the narwhale is armed with a sort of ivory sword, or lance, as certain naturalists have expressed it. It's a king-sized tooth as hard as steel. Some of these teeth have been found buried in the bodies of baleen whales, which the narwhale attacks with invariable success. Others have been wrenched, not without difficulty, from the undersides of vessels that narwhales have pierced clean through, as a gimlet pierces a wine barrel. The museum at the Faculty of Medicine in Paris owns one of these tusks with a length of 2.25 meters and a width at its base of forty-eight centimeters! +"All right then! Imagine this weapon to be ten times stronger and the animal ten times more powerful, launch it at a speed of twenty miles per hour, multiply its mass times its velocity, and you get just the collision we need to cause the specified catastrophe. +"So, until information becomes more abundant, I plump for a sea unicorn of colossal dimensions, no longer armed with a mere lance but with an actual spur, like ironclad frigates or those warships called 'rams,' whose mass and motor power it would possess simultaneously. +"This inexplicable phenomenon is thus explained away--unless it's something else entirely, which, despite everything that has been sighted, studied, explored and experienced, is still possible!" diff --git a/include/pdf/tutorial/calligra.afm b/include/pdf/tutorial/calligra.afm new file mode 100644 index 000000000..806685eae --- /dev/null +++ b/include/pdf/tutorial/calligra.afm @@ -0,0 +1,275 @@ +StartFontMetrics 4.1 +FontName Calligrapher-Regular +FullName Calligrapher Regular +Notice Generated by Fontographer 3.5 +EncodingScheme FontSpecific +FamilyName Calligrapher +Weight Regular +Version (Altsys Fontographer 3.5 5/26/92) +Characters 215 +ItalicAngle 0.0 +Ascender 899 +Descender -234 +UnderlineThickness 20 +UnderlinePosition -200 +IsFixedPitch false +FontBBox -50 -234 1328 899 +StartCharMetrics 256 +C 0 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 1 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 2 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 3 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 4 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 5 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 6 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 7 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 8 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 9 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 10 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 11 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 12 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 13 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 14 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 15 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 16 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 17 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 18 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 19 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 20 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 21 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 22 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 23 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 24 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 25 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 26 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 27 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 28 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 29 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 30 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 31 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 32 ; WX 282 ; N space ; B 67 -16 251 718 ; +C 33 ; WX 324 ; N exclam ; B 67 -16 251 718 ; +C 34 ; WX 405 ; N quotedbl ; B 60 460 353 718 ; +C 35 ; WX 584 ; N numbersign ; B 35 0 549 701 ; +C 36 ; WX 632 ; N dollar ; B 32 -126 595 814 ; +C 37 ; WX 980 ; N percent ; B 35 -16 945 703 ; +C 38 ; WX 776 ; N ampersand ; B 41 -17 811 670 ; +C 39 ; WX 259 ; N quotesingle ; B 72 460 206 718 ; +C 40 ; WX 299 ; N parenleft ; B 57 -119 299 785 ; +C 41 ; WX 299 ; N parenright ; B 0 -119 242 785 ; +C 42 ; WX 377 ; N asterisk ; B 35 407 342 714 ; +C 43 ; WX 600 ; N plus ; B 47 0 553 506 ; +C 44 ; WX 259 ; N comma ; B 35 -67 224 162 ; +C 45 ; WX 432 ; N hyphen ; B 28 249 404 377 ; +C 46 ; WX 254 ; N period ; B 43 -16 227 162 ; +C 47 ; WX 597 ; N slash ; B 7 -14 591 714 ; +C 48 ; WX 529 ; N zero ; B 21 -18 508 583 ; +C 49 ; WX 298 ; N one ; B 8 -15 233 582 ; +C 50 ; WX 451 ; N two ; B 17 -8 430 588 ; +C 51 ; WX 359 ; N three ; B 11 -54 337 582 ; +C 52 ; WX 525 ; N four ; B 18 -20 519 602 ; +C 53 ; WX 423 ; N five ; B 10 -55 420 582 ; +C 54 ; WX 464 ; N six ; B 23 -14 447 589 ; +C 55 ; WX 417 ; N seven ; B 8 -18 415 589 ; +C 56 ; WX 457 ; N eight ; B 19 -16 432 583 ; +C 57 ; WX 479 ; N nine ; B 26 -16 450 588 ; +C 58 ; WX 275 ; N colon ; B 59 -16 242 491 ; +C 59 ; WX 282 ; N semicolon ; B 54 -67 245 491 ; +C 60 ; WX 600 ; N less ; B 47 -8 553 514 ; +C 61 ; WX 600 ; N equal ; B 47 98 553 408 ; +C 62 ; WX 600 ; N greater ; B 47 -8 553 514 ; +C 63 ; WX 501 ; N question ; B 21 -16 473 721 ; +C 64 ; WX 800 ; N at ; B 29 -12 771 730 ; +C 65 ; WX 743 ; N A ; B -23 -14 754 723 ; +C 66 ; WX 636 ; N B ; B -42 -7 608 706 ; +C 67 ; WX 598 ; N C ; B 27 -12 572 712 ; +C 68 ; WX 712 ; N D ; B -42 -11 684 705 ; +C 69 ; WX 608 ; N E ; B -21 0 608 708 ; +C 70 ; WX 562 ; N F ; B -21 -18 584 716 ; +C 71 ; WX 680 ; N G ; B 29 -8 668 714 ; +C 72 ; WX 756 ; N H ; B 70 -17 777 728 ; +C 73 ; WX 308 ; N I ; B 14 -15 238 718 ; +C 74 ; WX 314 ; N J ; B 7 -223 244 727 ; +C 75 ; WX 676 ; N K ; B 14 -16 683 725 ; +C 76 ; WX 552 ; N L ; B 14 -8 580 713 ; +C 77 ; WX 1041 ; N M ; B 42 -17 1017 739 ; +C 78 ; WX 817 ; N N ; B -42 -17 747 736 ; +C 79 ; WX 729 ; N O ; B 32 -16 698 709 ; +C 80 ; WX 569 ; N P ; B -35 -15 570 716 ; +C 81 ; WX 698 ; N Q ; B 27 -201 1328 715 ; +C 82 ; WX 674 ; N R ; B -35 -20 696 712 ; +C 83 ; WX 618 ; N S ; B 31 -16 589 709 ; +C 84 ; WX 673 ; N T ; B -21 -20 702 714 ; +C 85 ; WX 805 ; N U ; B 0 -19 804 722 ; +C 86 ; WX 753 ; N V ; B -28 -20 788 729 ; +C 87 ; WX 1238 ; N W ; B -28 -17 1273 736 ; +C 88 ; WX 716 ; N X ; B 7 -38 709 731 ; +C 89 ; WX 754 ; N Y ; B -35 -17 789 747 ; +C 90 ; WX 599 ; N Z ; B 30 -5 584 748 ; +C 91 ; WX 315 ; N bracketleft ; B 93 -124 322 718 ; +C 92 ; WX 463 ; N backslash ; B -21 -18 484 736 ; +C 93 ; WX 315 ; N bracketright ; B -7 -124 222 718 ; +C 94 ; WX 600 ; N asciicircum ; B 63 266 537 658 ; +C 95 ; WX 547 ; N underscore ; B -7 -198 554 -163 ; +C 96 ; WX 278 ; N grave ; B -1 541 214 693 ; +C 97 ; WX 581 ; N a ; B 21 -16 581 494 ; +C 98 ; WX 564 ; N b ; B -24 -17 543 793 ; +C 99 ; WX 440 ; N c ; B 21 -17 422 490 ; +C 100 ; WX 571 ; N d ; B 0 -15 550 659 ; +C 101 ; WX 450 ; N e ; B 28 -23 428 493 ; +C 102 ; WX 347 ; N f ; B -35 -14 474 785 ; +C 103 ; WX 628 ; N g ; B 19 -219 612 496 ; +C 104 ; WX 611 ; N h ; B -29 -18 569 785 ; +C 105 ; WX 283 ; N i ; B -14 -15 241 679 ; +C 106 ; WX 283 ; N j ; B -14 -234 241 679 ; +C 107 ; WX 560 ; N k ; B -24 -15 582 789 ; +C 108 ; WX 252 ; N l ; B -28 -15 210 789 ; +C 109 ; WX 976 ; N m ; B -21 -16 927 494 ; +C 110 ; WX 595 ; N n ; B -28 -15 574 493 ; +C 111 ; WX 508 ; N o ; B 27 -17 485 490 ; +C 112 ; WX 549 ; N p ; B -28 -216 526 496 ; +C 113 ; WX 540 ; N q ; B 28 -219 491 493 ; +C 114 ; WX 395 ; N r ; B -21 -19 430 492 ; +C 115 ; WX 441 ; N s ; B 34 -15 413 493 ; +C 116 ; WX 307 ; N t ; B -21 -16 378 621 ; +C 117 ; WX 614 ; N u ; B -14 -18 558 501 ; +C 118 ; WX 556 ; N v ; B -28 -20 569 483 ; +C 119 ; WX 915 ; N w ; B -28 -17 928 495 ; +C 120 ; WX 559 ; N x ; B 14 -17 546 500 ; +C 121 ; WX 597 ; N y ; B -21 -227 541 500 ; +C 122 ; WX 452 ; N z ; B 28 -5 442 515 ; +C 123 ; WX 315 ; N braceleft ; B 6 -118 309 718 ; +C 124 ; WX 222 ; N bar ; B 63 -18 159 730 ; +C 125 ; WX 315 ; N braceright ; B 6 -118 309 718 ; +C 126 ; WX 600 ; N asciitilde ; B 69 166 531 340 ; +C 127 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 128 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 129 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 130 ; WX 0 ; N quotesinglbase ; B -23 -14 754 877 ; +C 131 ; WX 0 ; N florin ; B 0 -19 804 854 ; +C 132 ; WX 0 ; N quotedblbase ; B -23 -14 754 877 ; +C 133 ; WX 780 ; N ellipsis ; B 43 -16 747 162 ; +C 134 ; WX 0 ; N dagger ; B 27 -122 437 592 ; +C 135 ; WX 0 ; N daggerdbl ; B 43 278 227 456 ; +C 136 ; WX 278 ; N circumflex ; B -14 557 292 677 ; +C 137 ; WX 0 ; N perthousand ; B -23 -14 754 877 ; +C 138 ; WX 0 ; N Scaron ; B 0 0 0 100 ; +C 139 ; WX 0 ; N guilsinglleft ; B 43 278 227 456 ; +C 140 ; WX 1064 ; N OE ; B 32 -16 1055 709 ; +C 141 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 142 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 143 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 144 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 145 ; WX 259 ; N quoteleft ; B 35 489 224 717 ; +C 146 ; WX 259 ; N quoteright ; B 35 489 224 717 ; +C 147 ; WX 470 ; N quotedblleft ; B 35 489 443 717 ; +C 148 ; WX 470 ; N quotedblright ; B 35 487 443 717 ; +C 149 ; WX 500 ; N bullet ; B 70 179 430 539 ; +C 150 ; WX 300 ; N endash ; B 0 245 300 350 ; +C 151 ; WX 600 ; N emdash ; B 0 245 600 350 ; +C 152 ; WX 278 ; N tilde ; B -44 563 326 689 ; +C 153 ; WX 990 ; N trademark ; B 62 306 928 718 ; +C 154 ; WX 0 ; N scaron ; B 0 0 0 100 ; +C 155 ; WX 0 ; N guilsinglright ; B 43 278 227 456 ; +C 156 ; WX 790 ; N oe ; B 27 -23 764 493 ; +C 157 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 158 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C 159 ; WX 754 ; N Ydieresis ; B -35 -17 789 882 ; +C 160 ; WX 282 ; N nbspace ; B -23 -14 754 893 ; +C 161 ; WX 324 ; N exclamdown ; B 69 -203 253 531 ; +C 162 ; WX 450 ; N cent ; B 27 -122 437 592 ; +C 163 ; WX 640 ; N sterling ; B 0 -9 619 716 ; +C 164 ; WX 518 ; N currency ; B 3 72 515 586 ; +C 165 ; WX 603 ; N yen ; B -28 -65 631 747 ; +C 166 ; WX 0 ; N brokenbar ; B 0 0 0 100 ; +C 167 ; WX 519 ; N section ; B -50 -216 524 762 ; +C 168 ; WX 254 ; N dieresis ; B -20 554 308 682 ; +C 169 ; WX 800 ; N copyright ; B 29 -12 771 730 ; +C 170 ; WX 349 ; N ordfeminine ; B 13 385 349 717 ; +C 171 ; WX 0 ; N guillemotleft ; B 43 -16 747 162 ; +C 172 ; WX 0 ; N logicalnot ; B 30 0 730 700 ; +C 173 ; WX 432 ; N hyphen ; B 28 249 404 377 ; +C 174 ; WX 800 ; N registered ; B 29 -12 771 730 ; +C 175 ; WX 278 ; N macron ; B -47 584 325 665 ; +C 176 ; WX 0 ; N degree ; B 27 -122 437 592 ; +C 177 ; WX 0 ; N plusminus ; B 29 -8 668 877 ; +C 178 ; WX 0 ; N twosuperior ; B 0 0 0 100 ; +C 179 ; WX 0 ; N threesuperior ; B 0 0 0 100 ; +C 180 ; WX 278 ; N acute ; B 49 536 279 693 ; +C 181 ; WX 614 ; N mu ; B -14 -231 558 501 ; +C 182 ; WX 0 ; N paragraph ; B -35 -15 668 785 ; +C 183 ; WX 254 ; N periodcentered ; B 43 278 227 456 ; +C 184 ; WX 278 ; N cedilla ; B -8 -216 231 6 ; +C 185 ; WX 0 ; N onesuperior ; B 0 0 0 100 ; +C 186 ; WX 305 ; N ordmasculine ; B 16 373 291 702 ; +C 187 ; WX 0 ; N guillemotright ; B 43 -16 747 162 ; +C 188 ; WX 0 ; N onequarter ; B 0 0 0 100 ; +C 189 ; WX 0 ; N onehalf ; B 0 0 0 100 ; +C 190 ; WX 0 ; N threequarters ; B 0 0 0 100 ; +C 191 ; WX 501 ; N questiondown ; B 15 -196 467 541 ; +C 192 ; WX 743 ; N Agrave ; B -23 -14 754 893 ; +C 193 ; WX 743 ; N Aacute ; B -23 -14 754 893 ; +C 194 ; WX 743 ; N Acircumflex ; B -23 -14 754 877 ; +C 195 ; WX 743 ; N Atilde ; B -23 -14 754 889 ; +C 196 ; WX 743 ; N Adieresis ; B -23 -14 754 882 ; +C 197 ; WX 743 ; N Aring ; B -23 -14 754 899 ; +C 198 ; WX 1060 ; N AE ; B -29 -14 1053 708 ; +C 199 ; WX 598 ; N Ccedilla ; B 27 -183 572 712 ; +C 200 ; WX 608 ; N Egrave ; B -21 0 608 893 ; +C 201 ; WX 608 ; N Eacute ; B -21 0 608 893 ; +C 202 ; WX 608 ; N Ecircumflex ; B -21 0 608 877 ; +C 203 ; WX 608 ; N Edieresis ; B -21 0 608 882 ; +C 204 ; WX 308 ; N Igrave ; B 14 -15 264 893 ; +C 205 ; WX 308 ; N Iacute ; B 14 -15 274 893 ; +C 206 ; WX 308 ; N Icircumflex ; B 1 -15 307 877 ; +C 207 ; WX 308 ; N Idieresis ; B -15 -15 313 882 ; +C 208 ; WX 0 ; N Eth ; B 0 0 0 100 ; +C 209 ; WX 817 ; N Ntilde ; B -42 -17 747 889 ; +C 210 ; WX 729 ; N Ograve ; B 32 -16 698 893 ; +C 211 ; WX 729 ; N Oacute ; B 32 -16 698 893 ; +C 212 ; WX 729 ; N Ocircumflex ; B 32 -16 698 877 ; +C 213 ; WX 729 ; N Otilde ; B 32 -16 698 889 ; +C 214 ; WX 729 ; N Odieresis ; B 32 -16 698 882 ; +C 215 ; WX 0 ; N multiply ; B 0 0 0 100 ; +C 216 ; WX 729 ; N Oslash ; B 14 -24 724 709 ; +C 217 ; WX 805 ; N Ugrave ; B 0 -19 804 893 ; +C 218 ; WX 805 ; N Uacute ; B 0 -19 804 893 ; +C 219 ; WX 805 ; N Ucircumflex ; B 0 -19 804 877 ; +C 220 ; WX 805 ; N Udieresis ; B 0 -19 804 882 ; +C 221 ; WX 0 ; N _235 ; B 0 0 0 100 ; +C 222 ; WX 0 ; N Thorn ; B 0 0 0 100 ; +C 223 ; WX 688 ; N germandbls ; B -35 -15 668 785 ; +C 224 ; WX 581 ; N agrave ; B 21 -16 581 693 ; +C 225 ; WX 581 ; N aacute ; B 21 -16 581 693 ; +C 226 ; WX 581 ; N acircumflex ; B 21 -16 581 677 ; +C 227 ; WX 581 ; N atilde ; B 21 -16 581 689 ; +C 228 ; WX 581 ; N adieresis ; B 21 -16 581 682 ; +C 229 ; WX 581 ; N aring ; B 21 -16 581 734 ; +C 230 ; WX 792 ; N ae ; B 21 -23 773 494 ; +C 231 ; WX 440 ; N ccedilla ; B 21 -183 422 490 ; +C 232 ; WX 450 ; N egrave ; B 28 -23 428 693 ; +C 233 ; WX 450 ; N eacute ; B 28 -23 428 693 ; +C 234 ; WX 450 ; N ecircumflex ; B 28 -23 432 677 ; +C 235 ; WX 450 ; N edieresis ; B 28 -23 428 682 ; +C 236 ; WX 283 ; N igrave ; B -14 -15 244 693 ; +C 237 ; WX 283 ; N iacute ; B -14 -15 269 693 ; +C 238 ; WX 283 ; N icircumflex ; B -14 -15 297 677 ; +C 239 ; WX 283 ; N idieresis ; B -25 -15 303 682 ; +C 240 ; WX 0 ; N Yacute ; B 0 0 0 100 ; +C 241 ; WX 595 ; N ntilde ; B -28 -15 574 689 ; +C 242 ; WX 508 ; N ograve ; B 27 -17 485 693 ; +C 243 ; WX 508 ; N oacute ; B 27 -17 485 693 ; +C 244 ; WX 508 ; N ocircumflex ; B 27 -17 485 677 ; +C 245 ; WX 508 ; N otilde ; B 27 -17 485 689 ; +C 246 ; WX 508 ; N odieresis ; B 27 -17 485 682 ; +C 247 ; WX 0 ; N divide ; B 35 0 760 727 ; +C 248 ; WX 508 ; N oslash ; B -8 -54 496 589 ; +C 249 ; WX 614 ; N ugrave ; B -14 -18 558 693 ; +C 250 ; WX 614 ; N uacute ; B -14 -18 558 693 ; +C 251 ; WX 614 ; N ucircumflex ; B -14 -18 558 677 ; +C 252 ; WX 614 ; N udieresis ; B -14 -18 558 682 ; +C 253 ; WX 0 ; N yacute ; B 0 0 0 100 ; +C 254 ; WX 0 ; N thorn ; B 0 0 0 100 ; +C 255 ; WX 597 ; N ydieresis ; B -21 -227 541 682 ; +EndCharMetrics +EndFontMetrics diff --git a/include/pdf/tutorial/calligra.php b/include/pdf/tutorial/calligra.php new file mode 100644 index 000000000..1af82ac82 --- /dev/null +++ b/include/pdf/tutorial/calligra.php @@ -0,0 +1,24 @@ +899,'Descent'=>-234,'CapHeight'=>731,'Flags'=>32,'FontBBox'=>'[-50 -234 1328 899]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>800); +$up=-200; +$ut=20; +$cw=array( + chr(0)=>800,chr(1)=>800,chr(2)=>800,chr(3)=>800,chr(4)=>800,chr(5)=>800,chr(6)=>800,chr(7)=>800,chr(8)=>800,chr(9)=>800,chr(10)=>800,chr(11)=>800,chr(12)=>800,chr(13)=>800,chr(14)=>800,chr(15)=>800,chr(16)=>800,chr(17)=>800,chr(18)=>800,chr(19)=>800,chr(20)=>800,chr(21)=>800, + chr(22)=>800,chr(23)=>800,chr(24)=>800,chr(25)=>800,chr(26)=>800,chr(27)=>800,chr(28)=>800,chr(29)=>800,chr(30)=>800,chr(31)=>800,' '=>282,'!'=>324,'"'=>405,'#'=>584,'$'=>632,'%'=>980,'&'=>776,'\''=>259,'('=>299,')'=>299,'*'=>377,'+'=>600, + ','=>259,'-'=>432,'.'=>254,'/'=>597,'0'=>529,'1'=>298,'2'=>451,'3'=>359,'4'=>525,'5'=>423,'6'=>464,'7'=>417,'8'=>457,'9'=>479,':'=>275,';'=>282,'<'=>600,'='=>600,'>'=>600,'?'=>501,'@'=>800,'A'=>743, + 'B'=>636,'C'=>598,'D'=>712,'E'=>608,'F'=>562,'G'=>680,'H'=>756,'I'=>308,'J'=>314,'K'=>676,'L'=>552,'M'=>1041,'N'=>817,'O'=>729,'P'=>569,'Q'=>698,'R'=>674,'S'=>618,'T'=>673,'U'=>805,'V'=>753,'W'=>1238, + 'X'=>716,'Y'=>754,'Z'=>599,'['=>315,'\\'=>463,']'=>315,'^'=>600,'_'=>547,'`'=>278,'a'=>581,'b'=>564,'c'=>440,'d'=>571,'e'=>450,'f'=>347,'g'=>628,'h'=>611,'i'=>283,'j'=>283,'k'=>560,'l'=>252,'m'=>976, + 'n'=>595,'o'=>508,'p'=>549,'q'=>540,'r'=>395,'s'=>441,'t'=>307,'u'=>614,'v'=>556,'w'=>915,'x'=>559,'y'=>597,'z'=>452,'{'=>315,'|'=>222,'}'=>315,'~'=>600,chr(127)=>800,chr(128)=>800,chr(129)=>800,chr(130)=>0,chr(131)=>0, + chr(132)=>0,chr(133)=>780,chr(134)=>0,chr(135)=>0,chr(136)=>278,chr(137)=>0,chr(138)=>0,chr(139)=>0,chr(140)=>1064,chr(141)=>800,chr(142)=>800,chr(143)=>800,chr(144)=>800,chr(145)=>259,chr(146)=>259,chr(147)=>470,chr(148)=>470,chr(149)=>500,chr(150)=>300,chr(151)=>600,chr(152)=>278,chr(153)=>990, + chr(154)=>0,chr(155)=>0,chr(156)=>790,chr(157)=>800,chr(158)=>800,chr(159)=>754,chr(160)=>282,chr(161)=>324,chr(162)=>450,chr(163)=>640,chr(164)=>518,chr(165)=>603,chr(166)=>0,chr(167)=>519,chr(168)=>254,chr(169)=>800,chr(170)=>349,chr(171)=>0,chr(172)=>0,chr(173)=>432,chr(174)=>800,chr(175)=>278, + chr(176)=>0,chr(177)=>0,chr(178)=>0,chr(179)=>0,chr(180)=>278,chr(181)=>614,chr(182)=>0,chr(183)=>254,chr(184)=>278,chr(185)=>0,chr(186)=>305,chr(187)=>0,chr(188)=>0,chr(189)=>0,chr(190)=>0,chr(191)=>501,chr(192)=>743,chr(193)=>743,chr(194)=>743,chr(195)=>743,chr(196)=>743,chr(197)=>743, + chr(198)=>1060,chr(199)=>598,chr(200)=>608,chr(201)=>608,chr(202)=>608,chr(203)=>608,chr(204)=>308,chr(205)=>308,chr(206)=>308,chr(207)=>308,chr(208)=>0,chr(209)=>817,chr(210)=>729,chr(211)=>729,chr(212)=>729,chr(213)=>729,chr(214)=>729,chr(215)=>0,chr(216)=>729,chr(217)=>805,chr(218)=>805,chr(219)=>805, + chr(220)=>805,chr(221)=>0,chr(222)=>0,chr(223)=>688,chr(224)=>581,chr(225)=>581,chr(226)=>581,chr(227)=>581,chr(228)=>581,chr(229)=>581,chr(230)=>792,chr(231)=>440,chr(232)=>450,chr(233)=>450,chr(234)=>450,chr(235)=>450,chr(236)=>283,chr(237)=>283,chr(238)=>283,chr(239)=>283,chr(240)=>800,chr(241)=>595, + chr(242)=>508,chr(243)=>508,chr(244)=>508,chr(245)=>508,chr(246)=>508,chr(247)=>0,chr(248)=>508,chr(249)=>614,chr(250)=>614,chr(251)=>614,chr(252)=>614,chr(253)=>0,chr(254)=>0,chr(255)=>597); +$enc='cp1252'; +$diff=''; +$file='calligra.z'; +$originalsize=40120; +?> diff --git a/include/pdf/tutorial/calligra.ttf b/include/pdf/tutorial/calligra.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9713c468ca29f5bfcecb65d96e52711aaa5f50e7 GIT binary patch literal 40120 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 EJEXL@qyPW_ literal 0 HcmV?d00001 diff --git a/include/pdf/tutorial/calligra.z b/include/pdf/tutorial/calligra.z new file mode 100644 index 0000000000000000000000000000000000000000..1c0bebd20b3f68fe84a44520cc93c7cee39f2792 GIT binary patch literal 25604 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 jkH^DoB9A@c#fz}Vaf2UWPe| + + +Tutorials + + + +

    Tutorials

    +The different examples rapidly show how to use FPDF. You will find all main features explained.

    +
    Tutorial 1: Minimal example
    +Tutorial 2: Header, footer, page break and image
    +Tutorial 3: Line breaks and colors
    +Tutorial 4: Multi-columns
    +Tutorial 5: Tables
    +Tutorial 6: Links and flowing text
    +Tutorial 7: Adding new fonts and encoding support
    + + diff --git a/include/pdf/tutorial/logo.png b/include/pdf/tutorial/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..284a0071c850b5a2f1ba86f16775c5c0da9fe082 GIT binary patch literal 2373 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 IayK9PFK}2WsQ>@~ literal 0 HcmV?d00001 diff --git a/include/pdf/tutorial/makefont.php b/include/pdf/tutorial/makefont.php new file mode 100644 index 000000000..3773429bd --- /dev/null +++ b/include/pdf/tutorial/makefont.php @@ -0,0 +1,6 @@ + diff --git a/include/pdf/tutorial/tuto1.htm b/include/pdf/tutorial/tuto1.htm new file mode 100644 index 000000000..34f0480b7 --- /dev/null +++ b/include/pdf/tutorial/tuto1.htm @@ -0,0 +1,92 @@ + + + +Minimal example + + + +

    Minimal example

    +Let's start with the classic example: +
    +
    +
    + +<?php
    define('FPDF_FONTPATH','font/');
    require(
    'fpdf.php');

    $pdf=new FPDF();
    $pdf->AddPage();
    $pdf->SetFont('Arial','B',16);
    $pdf->Cell(40,10,'Hello World!');
    $pdf->Output();
    ?> +
    +

    + +The first line defines where the font directory resides, relative to the current directory.
    +Then, after including the library file, we create an FPDF object. +The FPDF() constructor is used here with the default values: pages are in A4 portrait and +the measure unit is millimeter. It could have been specified explicitly with: +
    +
    +
    + +$pdf=new FPDF('P','mm','A4');
    +
    +

    +It is possible to use landscape (L), other page formats (such as Letter and +Legal) and measure units (pt, cm, in). +
    +
    +There is no page for the moment, so we have to add one with AddPage(). The origin +is at the upper-left corner and the current position is by default placed at 1 cm from the +borders; the margins can be changed with SetMargins(). +
    +
    +Before we can print text, it is mandatory to select a font with SetFont(), otherwise the +document would be invalid. We choose Arial bold 16: +
    +
    +
    + +$pdf->SetFont('Arial','B',16);
    +
    +

    +We could have specified italics with I, underlined with U or a regular font with an empty string +(or any combination). Note that the font size is given in points, not millimeters (or another +user unit); it is the only exception. The other standard fonts are Times, Courier, Symbol and +ZapfDingbats. +
    +
    +We can now print a cell with Cell(). A cell is a rectangular area, possibly framed, +which contains some text. It is output at the current position. We specify its dimensions, +its text (centered or aligned), if borders should be drawn, and where the current position +moves after it (to the right, below or to the beginning of the next line). To add a frame, we would do this: +
    +
    +
    + +$pdf->Cell(40,10,'Hello World !',1);
    +
    +

    +To add a new cell next to it with centered text and go to the next line, we would do: +
    +
    +
    + +$pdf->Cell(60,10,'Powered by FPDF.',0,1,'C');
    +
    +

    +Remark : the line break can also be done with Ln(). This method allows to specify +in addition the height of the break. +
    +
    +Finally, the document is closed and sent to the browser with Output(). We could have saved +it in a file by passing the desired file name. +
    +
    +Caution: in case when the PDF is sent to the browser, nothing else must be output, not before +nor after (the least space or carriage return matters). If you send some data before, you will +get the error message: "Some data has already been output to browser, can't send PDF file". If +you send after, your browser may display a blank page. + + diff --git a/include/pdf/tutorial/tuto1.php b/include/pdf/tutorial/tuto1.php new file mode 100644 index 000000000..14b836242 --- /dev/null +++ b/include/pdf/tutorial/tuto1.php @@ -0,0 +1,10 @@ +AddPage(); +$pdf->SetFont('Arial','B',16); +$pdf->Cell(40,10,'Hello World!'); +$pdf->Output(); +?> diff --git a/include/pdf/tutorial/tuto2.htm b/include/pdf/tutorial/tuto2.htm new file mode 100644 index 000000000..22e052d00 --- /dev/null +++ b/include/pdf/tutorial/tuto2.htm @@ -0,0 +1,50 @@ + + + +Header, footer, page break and image + + + +

    Header, footer, page break and image

    +Here is a two page example with header, footer and logo: +
    +
    +
    + +<?php
    define('FPDF_FONTPATH','font/');
    require(
    'fpdf.php');

    class
    PDF extends FPDF
    {
    //Page header
    function Header()
    {
        
    //Logo
        
    $this->Image('logo_pb.png',10,8,33);
        
    //Arial bold 15
        
    $this->SetFont('Arial','B',15);
        
    //Move to the right
        
    $this->Cell(80);
        
    //Title
        
    $this->Cell(30,10,'Title',1,0,'C');
        
    //Line break
        
    $this->Ln(20);
    }

    //Page footer
    function Footer()
    {
        
    //Position at 1.5 cm from bottom
        
    $this->SetY(-15);
        
    //Arial italic 8
        
    $this->SetFont('Arial','I',8);
        
    //Page number
        
    $this->Cell(0,10,'Page '.$this->PageNo().'/{nb}',0,0,'C');
    }
    }

    //Instanciation of inherited class
    $pdf=new PDF();
    $pdf->AliasNbPages();
    $pdf->AddPage();
    $pdf->SetFont('Times','',12);
    for(
    $i=1;$i<=40;$i++)
        
    $pdf->Cell(0,10,'Printing line number '.$i,0,1);
    $pdf->Output();
    ?> +
    +

    + +This example makes use of the Header() and Footer() methods to process page headers and +footers. They are called automatically. They already exist in the FPDF class but do nothing, +therefore we have to extend the class and override them. +
    +
    +The logo is printed with the Image() method by specifying its upper-left corner and +its width. The height is calculated automatically to respect the image proportions. +
    +
    +To print the page number, a null value is passed as the cell width. It means that the cell +should extend up to the right margin of the page; it is handy to center text. The current page +number is returned by the PageNo() method; as for the total number of pages, it is obtained +by means of the special value {nb} which will be substituted on document closure +(provided you first called AliasNbPages()). +
    +Note the use of the SetY() method which allows to set position at an absolute location in +the page, starting from the top or the bottom. +
    +
    +Another interesting feature is used here: the automatic page breaking. As soon as a cell would +cross a limit in the page (at 2 centimeters from the bottom by default), a break is performed +and the font restored. Although the header and footer select their own font (Arial), the body +continues with Times. This mechanism of automatic restoration also applies to colors and line +width. The limit which triggers page breaks can be set with SetAutoPageBreak(). + + diff --git a/include/pdf/tutorial/tuto2.php b/include/pdf/tutorial/tuto2.php new file mode 100644 index 000000000..1bb8ddd05 --- /dev/null +++ b/include/pdf/tutorial/tuto2.php @@ -0,0 +1,42 @@ +Image('logo_pb.png',10,8,33); + //Arial bold 15 + $this->SetFont('Arial','B',15); + //Move to the right + $this->Cell(80); + //Title + $this->Cell(30,10,'Title',1,0,'C'); + //Line break + $this->Ln(20); +} + +//Page footer +function Footer() +{ + //Position at 1.5 cm from bottom + $this->SetY(-15); + //Arial italic 8 + $this->SetFont('Arial','I',8); + //Page number + $this->Cell(0,10,'Page '.$this->PageNo().'/{nb}',0,0,'C'); +} +} + +//Instanciation of inherited class +$pdf=new PDF(); +$pdf->AliasNbPages(); +$pdf->AddPage(); +$pdf->SetFont('Times','',12); +for($i=1;$i<=40;$i++) + $pdf->Cell(0,10,'Printing line number '.$i,0,1); +$pdf->Output(); +?> diff --git a/include/pdf/tutorial/tuto3.htm b/include/pdf/tutorial/tuto3.htm new file mode 100644 index 000000000..41e434c17 --- /dev/null +++ b/include/pdf/tutorial/tuto3.htm @@ -0,0 +1,43 @@ + + + +Line breaks and colors + + + +

    Line breaks and colors

    +Let's continue with an example which prints justified paragraphs. It also illustrates the use +of colors. +
    +
    +
    + +<?php
    define('FPDF_FONTPATH','font/');
    require(
    'fpdf.php');

    class
    PDF extends FPDF
    {
    function
    Header()
    {
        global
    $title;

        
    //Arial bold 15
        
    $this->SetFont('Arial','B',15);
        
    //Calculate width of title and position
        
    $w=$this->GetStringWidth($title)+6;
        
    $this->SetX((210-$w)/2);
        
    //Colors of frame, background and text
        
    $this->SetDrawColor(0,80,180);
        
    $this->SetFillColor(230,230,0);
        
    $this->SetTextColor(220,50,50);
        
    //Thickness of frame (1 mm)
        
    $this->SetLineWidth(1);
        
    //Title
        
    $this->Cell($w,9,$title,1,1,'C',1);
        
    //Line break
        
    $this->Ln(10);
    }

    function
    Footer()
    {
        
    //Position at 1.5 cm from bottom
        
    $this->SetY(-15);
        
    //Arial italic 8
        
    $this->SetFont('Arial','I',8);
        
    //Text color in gray
        
    $this->SetTextColor(128);
        
    //Page number
        
    $this->Cell(0,10,'Page '.$this->PageNo(),0,0,'C');
    }

    function
    ChapterTitle($num,$label)
    {
        
    //Arial 12
        
    $this->SetFont('Arial','',12);
        
    //Background color
        
    $this->SetFillColor(200,220,255);
        
    //Title
        
    $this->Cell(0,6,"Chapter $num : $label",0,1,'L',1);
        
    //Line break
        
    $this->Ln(4);
    }

    function
    ChapterBody($file)
    {
        
    //Read text file
        
    $f=fopen($file,'r');
        
    $txt=fread($f,filesize($file));
        
    fclose($f);
        
    //Times 12
        
    $this->SetFont('Times','',12);
        
    //Output justified text
        
    $this->MultiCell(0,5,$txt);
        
    //Line break
        
    $this->Ln();
        
    //Mention in italics
        
    $this->SetFont('','I');
        
    $this->Cell(0,5,'(end of excerpt)');
    }

    function
    PrintChapter($num,$title,$file)
    {
        
    $this->AddPage();
        
    $this->ChapterTitle($num,$title);
        
    $this->ChapterBody($file);
    }
    }

    $pdf=new PDF();
    $title='20000 Leagues Under the Seas';
    $pdf->SetTitle($title);
    $pdf->SetAuthor('Jules Verne');
    $pdf->PrintChapter(1,'A RUNAWAY REEF','20k_c1.txt');
    $pdf->PrintChapter(2,'THE PROS AND CONS','20k_c2.txt');
    $pdf->Output();
    ?> +
    +

    + +The GetStringWidth() method allows to determine the length of a string in the current font, +which is used here to calculate the position and the width of the frame surrounding the title. +Then colors are set (via SetDrawColor(), SetFillColor() and SetTextColor()) and the +thickness of the line is set to 1 mm (against 0.2 by default) with SetLineWidth(). Finally, +we output the cell (the last parameter to 1 indicates that the background must be filled). +
    +
    +The method used to print the paragraphs is MultiCell(). Each time a line reaches the +right extremity of the cell or a carriage-return character is met, a line break is issued +and a new cell automatically created under the current one. Text is justified by default. +
    +
    +Two document properties are defined: title (SetTitle()) and author (SetAuthor()). +Properties can be viewed by two means. First is open the document directly with Acrobat Reader, +go to the File menu, Document info, General. Second, also available from the plug-in, is click +on the triangle just above the right scrollbar and choose Document info. + + diff --git a/include/pdf/tutorial/tuto3.php b/include/pdf/tutorial/tuto3.php new file mode 100644 index 000000000..f2c38ff99 --- /dev/null +++ b/include/pdf/tutorial/tuto3.php @@ -0,0 +1,84 @@ +SetFont('Arial','B',15); + //Calculate width of title and position + $w=$this->GetStringWidth($title)+6; + $this->SetX((210-$w)/2); + //Colors of frame, background and text + $this->SetDrawColor(0,80,180); + $this->SetFillColor(230,230,0); + $this->SetTextColor(220,50,50); + //Thickness of frame (1 mm) + $this->SetLineWidth(1); + //Title + $this->Cell($w,9,$title,1,1,'C',1); + //Line break + $this->Ln(10); +} + +function Footer() +{ + //Position at 1.5 cm from bottom + $this->SetY(-15); + //Arial italic 8 + $this->SetFont('Arial','I',8); + //Text color in gray + $this->SetTextColor(128); + //Page number + $this->Cell(0,10,'Page '.$this->PageNo(),0,0,'C'); +} + +function ChapterTitle($num,$label) +{ + //Arial 12 + $this->SetFont('Arial','',12); + //Background color + $this->SetFillColor(200,220,255); + //Title + $this->Cell(0,6,"Chapter $num : $label",0,1,'L',1); + //Line break + $this->Ln(4); +} + +function ChapterBody($file) +{ + //Read text file + $f=fopen($file,'r'); + $txt=fread($f,filesize($file)); + fclose($f); + //Times 12 + $this->SetFont('Times','',12); + //Output justified text + $this->MultiCell(0,5,$txt); + //Line break + $this->Ln(); + //Mention in italics + $this->SetFont('','I'); + $this->Cell(0,5,'(end of excerpt)'); +} + +function PrintChapter($num,$title,$file) +{ + $this->AddPage(); + $this->ChapterTitle($num,$title); + $this->ChapterBody($file); +} +} + +$pdf=new PDF(); +$title='20000 Leagues Under the Seas'; +$pdf->SetTitle($title); +$pdf->SetAuthor('Jules Verne'); +$pdf->PrintChapter(1,'A RUNAWAY REEF','20k_c1.txt'); +$pdf->PrintChapter(2,'THE PROS AND CONS','20k_c2.txt'); +$pdf->Output(); +?> diff --git a/include/pdf/tutorial/tuto4.htm b/include/pdf/tutorial/tuto4.htm new file mode 100644 index 000000000..5d7ae86eb --- /dev/null +++ b/include/pdf/tutorial/tuto4.htm @@ -0,0 +1,34 @@ + + + +Multi-columns + + + +

    Multi-columns

    +This example is a variant of the previous one showing how to lay the text across multiple +columns. +
    +
    +
    + +<?php
    define('FPDF_FONTPATH','font/');
    require(
    'fpdf.php');

    class
    PDF extends FPDF
    {
    //Current column
    var $col=0;
    //Ordinate of column start
    var $y0;

    function
    Header()
    {
        
    //Page header
        
    global $title;

        
    $this->SetFont('Arial','B',15);
        
    $w=$this->GetStringWidth($title)+6;
        
    $this->SetX((210-$w)/2);
        
    $this->SetDrawColor(0,80,180);
        
    $this->SetFillColor(230,230,0);
        
    $this->SetTextColor(220,50,50);
        
    $this->SetLineWidth(1);
        
    $this->Cell($w,9,$title,1,1,'C',1);
        
    $this->Ln(10);
        
    //Save ordinate
        
    $this->y0=$this->GetY();
    }

    function
    Footer()
    {
        
    //Page footer
        
    $this->SetY(-15);
        
    $this->SetFont('Arial','I',8);
        
    $this->SetTextColor(128);
        
    $this->Cell(0,10,'Page '.$this->PageNo(),0,0,'C');
    }

    function
    SetCol($col)
    {
        
    //Set position at a given column
        
    $this->col=$col;
        
    $x=10+$col*65;
        
    $this->SetLeftMargin($x);
        
    $this->SetX($x);
    }

    function
    AcceptPageBreak()
    {
        
    //Method accepting or not automatic page break
        
    if($this->col<2)
        {
            
    //Go to next column
            
    $this->SetCol($this->col+1);
            
    //Set ordinate to top
            
    $this->SetY($this->y0);
            
    //Keep on page
            
    return false;
        }
        else
        {
            
    //Go back to first column
            
    $this->SetCol(0);
            
    //Page break
            
    return true;
        }
    }

    function
    ChapterTitle($num,$label)
    {
        
    //Title
        
    $this->SetFont('Arial','',12);
        
    $this->SetFillColor(200,220,255);
        
    $this->Cell(0,6,"Chapter  $num : $label",0,1,'L',1);
        
    $this->Ln(4);
        
    //Save ordinate
        
    $this->y0=$this->GetY();
    }

    function
    ChapterBody($fichier)
    {
        
    //Read text file
        
    $f=fopen($fichier,'r');
        
    $txt=fread($f,filesize($fichier));
        
    fclose($f);
        
    //Font
        
    $this->SetFont('Times','',12);
        
    //Output text in a 6 cm width column
        
    $this->MultiCell(60,5,$txt);
        
    $this->Ln();
        
    //Mention
        
    $this->SetFont('','I');
        
    $this->Cell(0,5,'(end of excerpt)');
        
    //Go back to first column
        
    $this->SetCol(0);
    }

    function
    PrintChapter($num,$title,$file)
    {
        
    //Add chapter
        
    $this->AddPage();
        
    $this->ChapterTitle($num,$title);
        
    $this->ChapterBody($file);
    }
    }

    $pdf=new PDF();
    $title='20000 Leagues Under the Seas';
    $pdf->SetTitle($title);
    $pdf->SetAuthor('Jules Verne');
    $pdf->PrintChapter(1,'A RUNAWAY REEF','20k_c1.txt');
    $pdf->PrintChapter(2,'THE PROS AND CONS','20k_c2.txt');
    $pdf->Output();
    ?> +
    +

    + +The key method used is AcceptPageBreak(). It allows to accept or not an automatic page +break. By refusing it and altering the margin and current position, the desired column layout +is achieved. +
    +For the rest, not much change; two properties have been added to the class to save the current +column number and the position where columns begin, and the MultiCell() call specifies a +6 centimeter width. + + diff --git a/include/pdf/tutorial/tuto4.php b/include/pdf/tutorial/tuto4.php new file mode 100644 index 000000000..41d6ff6fb --- /dev/null +++ b/include/pdf/tutorial/tuto4.php @@ -0,0 +1,114 @@ +SetFont('Arial','B',15); + $w=$this->GetStringWidth($title)+6; + $this->SetX((210-$w)/2); + $this->SetDrawColor(0,80,180); + $this->SetFillColor(230,230,0); + $this->SetTextColor(220,50,50); + $this->SetLineWidth(1); + $this->Cell($w,9,$title,1,1,'C',1); + $this->Ln(10); + //Save ordinate + $this->y0=$this->GetY(); +} + +function Footer() +{ + //Page footer + $this->SetY(-15); + $this->SetFont('Arial','I',8); + $this->SetTextColor(128); + $this->Cell(0,10,'Page '.$this->PageNo(),0,0,'C'); +} + +function SetCol($col) +{ + //Set position at a given column + $this->col=$col; + $x=10+$col*65; + $this->SetLeftMargin($x); + $this->SetX($x); +} + +function AcceptPageBreak() +{ + //Method accepting or not automatic page break + if($this->col<2) + { + //Go to next column + $this->SetCol($this->col+1); + //Set ordinate to top + $this->SetY($this->y0); + //Keep on page + return false; + } + else + { + //Go back to first column + $this->SetCol(0); + //Page break + return true; + } +} + +function ChapterTitle($num,$label) +{ + //Title + $this->SetFont('Arial','',12); + $this->SetFillColor(200,220,255); + $this->Cell(0,6,"Chapter $num : $label",0,1,'L',1); + $this->Ln(4); + //Save ordinate + $this->y0=$this->GetY(); +} + +function ChapterBody($fichier) +{ + //Read text file + $f=fopen($fichier,'r'); + $txt=fread($f,filesize($fichier)); + fclose($f); + //Font + $this->SetFont('Times','',12); + //Output text in a 6 cm width column + $this->MultiCell(60,5,$txt); + $this->Ln(); + //Mention + $this->SetFont('','I'); + $this->Cell(0,5,'(end of excerpt)'); + //Go back to first column + $this->SetCol(0); +} + +function PrintChapter($num,$title,$file) +{ + //Add chapter + $this->AddPage(); + $this->ChapterTitle($num,$title); + $this->ChapterBody($file); +} +} + +$pdf=new PDF(); +$title='20000 Leagues Under the Seas'; +$pdf->SetTitle($title); +$pdf->SetAuthor('Jules Verne'); +$pdf->PrintChapter(1,'A RUNAWAY REEF','20k_c1.txt'); +$pdf->PrintChapter(2,'THE PROS AND CONS','20k_c2.txt'); +$pdf->Output(); +?> diff --git a/include/pdf/tutorial/tuto5.htm b/include/pdf/tutorial/tuto5.htm new file mode 100644 index 000000000..b0263003e --- /dev/null +++ b/include/pdf/tutorial/tuto5.htm @@ -0,0 +1,43 @@ + + + +Tables + + + +

    Tables

    +This tutorial shows how to make tables easily. +
    +
    +
    + +<?php
    define('FPDF_FONTPATH','font/');
    require(
    'fpdf.php');

    class
    PDF extends FPDF
    {
    //Load data
    function LoadData($file)
    {
        
    //Read file lines
        
    $lines=file($file);
        
    $data=array();
        foreach(
    $lines as $line)
            
    $data[]=explode(';',chop($line));
        return
    $data;
    }

    //Simple table
    function BasicTable($header,$data)
    {
        
    //Header
        
    foreach($header as $col)
            
    $this->Cell(40,7,$col,1);
        
    $this->Ln();
        
    //Data
        
    foreach($data as $row)
        {
            foreach(
    $row as $col)
                
    $this->Cell(40,6,$col,1);
            
    $this->Ln();
        }
    }

    //Better table
    function ImprovedTable($header,$data)
    {
        
    //Column widths
        
    $w=array(40,35,40,45);
        
    //Header
        
    for($i=0;$i<count($header);$i++)
            
    $this->Cell($w[$i],7,$header[$i],1,0,'C');
        
    $this->Ln();
        
    //Data
        
    foreach($data as $row)
        {
            
    $this->Cell($w[0],6,$row[0],'LR');
            
    $this->Cell($w[1],6,$row[1],'LR');
            
    $this->Cell($w[2],6,number_format($row[2]),'LR',0,'R');
            
    $this->Cell($w[3],6,number_format($row[3]),'LR',0,'R');
            
    $this->Ln();
        }
        
    //Closure line
        
    $this->Cell(array_sum($w),0,'','T');
    }

    //Colored table
    function FancyTable($header,$data)
    {
        
    //Colors, line width and bold font
        
    $this->SetFillColor(255,0,0);
        
    $this->SetTextColor(255);
        
    $this->SetDrawColor(128,0,0);
        
    $this->SetLineWidth(.3);
        
    $this->SetFont('','B');
        
    //Header
        
    $w=array(40,35,40,45);
        for(
    $i=0;$i<count($header);$i++)
            
    $this->Cell($w[$i],7,$header[$i],1,0,'C',1);
        
    $this->Ln();
        
    //Color and font restoration
        
    $this->SetFillColor(224,235,255);
        
    $this->SetTextColor(0);
        
    $this->SetFont('');
        
    //Data
        
    $fill=0;
        foreach(
    $data as $row)
        {
            
    $this->Cell($w[0],6,$row[0],'LR',0,'L',$fill);
            
    $this->Cell($w[1],6,$row[1],'LR',0,'L',$fill);
            
    $this->Cell($w[2],6,number_format($row[2]),'LR',0,'R',$fill);
            
    $this->Cell($w[3],6,number_format($row[3]),'LR',0,'R',$fill);
            
    $this->Ln();
            
    $fill=!$fill;
        }
        
    $this->Cell(array_sum($w),0,'','T');
    }
    }

    $pdf=new PDF();
    //Column titles
    $header=array('Country','Capital','Area (sq km)','Pop. (thousands)');
    //Data loading
    $data=$pdf->LoadData('countries.txt');
    $pdf->SetFont('Arial','',14);
    $pdf->AddPage();
    $pdf->BasicTable($header,$data);
    $pdf->AddPage();
    $pdf->ImprovedTable($header,$data);
    $pdf->AddPage();
    $pdf->FancyTable($header,$data);
    $pdf->Output();
    ?> +
    +

    + +A table being just a collection of cells, it is natural to build one from them. The first +example is achieved in the most basic way possible: simple framed cells, all of the same size +and left aligned. The result is rudimentary but very quick to obtain. +
    +
    +The second table brings some improvements: each column has its own width, titles are centered +and figures right aligned. Moreover, horizontal lines have been removed. This is done by means +of the border parameter of the Cell() method, which specifies which sides of the +cell must be drawn. Here we want the left (L) and right (R) ones. It remains +the problem of the horizontal line to finish the table. There are two possibilities: either +check for the last line in the loop, in which case we use LRB for the border +parameter; or, as done here, add the line once the loop is over. +
    +
    +The third table is similar to the second one but uses colors. Fill, text and line colors are +simply specified. Alternate coloring for rows is obtained by using alternatively transparent +and filled cells. + + diff --git a/include/pdf/tutorial/tuto5.php b/include/pdf/tutorial/tuto5.php new file mode 100644 index 000000000..4b6c4535b --- /dev/null +++ b/include/pdf/tutorial/tuto5.php @@ -0,0 +1,102 @@ +Cell(40,7,$col,1); + $this->Ln(); + //Data + foreach($data as $row) + { + foreach($row as $col) + $this->Cell(40,6,$col,1); + $this->Ln(); + } +} + +//Better table +function ImprovedTable($header,$data) +{ + //Column widths + $w=array(40,35,40,45); + //Header + for($i=0;$iCell($w[$i],7,$header[$i],1,0,'C'); + $this->Ln(); + //Data + foreach($data as $row) + { + $this->Cell($w[0],6,$row[0],'LR'); + $this->Cell($w[1],6,$row[1],'LR'); + $this->Cell($w[2],6,number_format($row[2]),'LR',0,'R'); + $this->Cell($w[3],6,number_format($row[3]),'LR',0,'R'); + $this->Ln(); + } + //Closure line + $this->Cell(array_sum($w),0,'','T'); +} + +//Colored table +function FancyTable($header,$data) +{ + //Colors, line width and bold font + $this->SetFillColor(255,0,0); + $this->SetTextColor(255); + $this->SetDrawColor(128,0,0); + $this->SetLineWidth(.3); + $this->SetFont('','B'); + //Header + $w=array(40,35,40,45); + for($i=0;$iCell($w[$i],7,$header[$i],1,0,'C',1); + $this->Ln(); + //Color and font restoration + $this->SetFillColor(224,235,255); + $this->SetTextColor(0); + $this->SetFont(''); + //Data + $fill=0; + foreach($data as $row) + { + $this->Cell($w[0],6,$row[0],'LR',0,'L',$fill); + $this->Cell($w[1],6,$row[1],'LR',0,'L',$fill); + $this->Cell($w[2],6,number_format($row[2]),'LR',0,'R',$fill); + $this->Cell($w[3],6,number_format($row[3]),'LR',0,'R',$fill); + $this->Ln(); + $fill=!$fill; + } + $this->Cell(array_sum($w),0,'','T'); +} +} + +$pdf=new PDF(); +//Column titles +$header=array('Country','Capital','Area (sq km)','Pop. (thousands)'); +//Data loading +$data=$pdf->LoadData('countries.txt'); +$pdf->SetFont('Arial','',14); +$pdf->AddPage(); +$pdf->BasicTable($header,$data); +$pdf->AddPage(); +$pdf->ImprovedTable($header,$data); +$pdf->AddPage(); +$pdf->FancyTable($header,$data); +$pdf->Output(); +?> diff --git a/include/pdf/tutorial/tuto6.htm b/include/pdf/tutorial/tuto6.htm new file mode 100644 index 000000000..e94043ddc --- /dev/null +++ b/include/pdf/tutorial/tuto6.htm @@ -0,0 +1,68 @@ + + + +Links and flowing text + + + +

    Links and flowing text

    +This tutorial explains how to insert links (internal and external) and shows a new text writing +mode. It also contains a rudimentary HTML parser. +
    +
    +
    + +<?php
    define('FPDF_FONTPATH','font/');
    require(
    'fpdf.php');

    class
    PDF extends FPDF
    {
    var
    $B;
    var
    $I;
    var
    $U;
    var
    $HREF;

    function
    PDF($orientation='P',$unit='mm',$format='A4')
    {
        
    //Call parent constructor
        
    $this->FPDF($orientation,$unit,$format);
        
    //Initialization
        
    $this->B=0;
        
    $this->I=0;
        
    $this->U=0;
        
    $this->HREF='';
    }

    function
    WriteHTML($html)
    {
        
    //HTML parser
        
    $html=str_replace("\n",' ',$html);
        
    $a=preg_split('/<(.*)>/U',$html,-1,PREG_SPLIT_DELIM_CAPTURE);
        foreach(
    $a as $i=>$e)
        {
            if(
    $i%2==0)
            {
                
    //Text
                
    if($this->HREF)
                    
    $this->PutLink($this->HREF,$e);
                else
                    
    $this->Write(5,$e);
            }
            else
            {
                
    //Tag
                
    if($e{0}=='/')
                    
    $this->CloseTag(strtoupper(substr($e,1)));
                else
                {
                    
    //Extract attributes
                    
    $a2=explode(' ',$e);
                    
    $tag=strtoupper(array_shift($a2));
                    
    $attr=array();
                    foreach(
    $a2 as $v)
                        if(
    ereg('^([^=]*)=["\']?([^"\']*)["\']?$',$v,$a3))
                            
    $attr[strtoupper($a3[1])]=$a3[2];
                    
    $this->OpenTag($tag,$attr);
                }
            }
        }
    }

    function
    OpenTag($tag,$attr)
    {
        
    //Opening tag
        
    if($tag=='B' or $tag=='I' or $tag=='U')
            
    $this->SetStyle($tag,true);
        if(
    $tag=='A')
            
    $this->HREF=$attr['HREF'];
        if(
    $tag=='BR')
            
    $this->Ln(5);
    }

    function
    CloseTag($tag)
    {
        
    //Closing tag
        
    if($tag=='B' or $tag=='I' or $tag=='U')
            
    $this->SetStyle($tag,false);
        if(
    $tag=='A')
            
    $this->HREF='';
    }

    function
    SetStyle($tag,$enable)
    {
        
    //Modify style and select corresponding font
        
    $this->$tag+=($enable ? 1 : -1);
        
    $style='';
        foreach(array(
    'B','I','U') as $s)
            if(
    $this->$s>0)
                
    $style.=$s;
        
    $this->SetFont('',$style);
    }

    function
    PutLink($URL,$txt)
    {
        
    //Put a hyperlink
        
    $this->SetTextColor(0,0,255);
        
    $this->SetStyle('U',true);
        
    $this->Write(5,$txt,$URL);
        
    $this->SetStyle('U',false);
        
    $this->SetTextColor(0);
    }
    }

    $html='You can now easily print text mixing different
    styles : <B>bold</B>, <I>italic</I>, <U>underlined</U>, or
    <B><I><U>all at once</U></I></B>!<BR>You can also insert links
    on text, such as <A HREF="http://www.fpdf.org">www.fpdf.org</A>,
    or on an image: click on the logo.'
    ;

    $pdf=new PDF();
    //First page
    $pdf->AddPage();
    $pdf->SetFont('Arial','',20);
    $pdf->Write(5,'To find out what\'s new in this tutorial, click ');
    $pdf->SetFont('','U');
    $link=$pdf->AddLink();
    $pdf->Write(5,'here',$link);
    $pdf->SetFont('');
    //Second page
    $pdf->AddPage();
    $pdf->SetLink($link);
    $pdf->Image('logo.png',10,10,30,0,'','http://www.fpdf.org');
    $pdf->SetLeftMargin(45);
    $pdf->SetFontSize(14);
    $pdf->WriteHTML($html);
    $pdf->Output();
    ?> +
    +

    + +The new method to print text is Write(). It is very close to MultiCell(); the differences +are: +
      +
    • The end of line is at the right margin and the next line begins at the left one +
    • The current position moves at the end of the text +
    +So it allows to write a chunk of text, alter the font style, then continue from the exact +place we left it. On the other hand, you cannot full justify it. +
    +
    +The method is used on the first page to put a link pointing to the second one. The beginning of +the sentence is written in regular style, then we switch to underline and finish it. The link +is created with AddLink(), which returns a link identifier. The identifier is +passed as third parameter of Write(). Once the second page is created, we use SetLink() to +make the link point to the beginning of the current page. +
    +
    +Then we put an image with a link on it. An external link points to an URL (HTTP, mailto...). +The URL is simply passed as last parameter of Image(). +Note that external links do not work when the PDF is displayed inside Netscape's plug-in. +
    +
    +Finally, the left margin is moved after the image with SetLeftMargin() and some text in +HTML format is output. An HTML parser is used for this, based on the regular expression splitting +function preg_split() and the option PREG_SPLIT_DELIM_CAPTURE (introduced in PHP 4.0.5) which +allows to fetch the separators as well (in this case the tags). If you use an older version of +PHP, replace the line with this one: +
    +
    +
    + +$a=preg_split('/[<>]/',$html);
    +
    +

    +which is less strict but gives the same results with valid HTML. +
    +Recognized tags are <B>, <I>, <U>, <A> and <BR>; the others are +ignored. The parser also makes use of the Write() method. An external link is put the same way as +an internal one (third parameter of Write()). +
    +Note that Cell() also allows to put links. + + diff --git a/include/pdf/tutorial/tuto6.php b/include/pdf/tutorial/tuto6.php new file mode 100644 index 000000000..5d9436c31 --- /dev/null +++ b/include/pdf/tutorial/tuto6.php @@ -0,0 +1,123 @@ +FPDF($orientation,$unit,$format); + //Initialization + $this->B=0; + $this->I=0; + $this->U=0; + $this->HREF=''; +} + +function WriteHTML($html) +{ + //HTML parser + $html=str_replace("\n",' ',$html); + $a=preg_split('/<(.*)>/U',$html,-1,PREG_SPLIT_DELIM_CAPTURE); + foreach($a as $i=>$e) + { + if($i%2==0) + { + //Text + if($this->HREF) + $this->PutLink($this->HREF,$e); + else + $this->Write(5,$e); + } + else + { + //Tag + if($e{0}=='/') + $this->CloseTag(strtoupper(substr($e,1))); + else + { + //Extract attributes + $a2=explode(' ',$e); + $tag=strtoupper(array_shift($a2)); + $attr=array(); + foreach($a2 as $v) + if(ereg('^([^=]*)=["\']?([^"\']*)["\']?$',$v,$a3)) + $attr[strtoupper($a3[1])]=$a3[2]; + $this->OpenTag($tag,$attr); + } + } + } +} + +function OpenTag($tag,$attr) +{ + //Opening tag + if($tag=='B' or $tag=='I' or $tag=='U') + $this->SetStyle($tag,true); + if($tag=='A') + $this->HREF=$attr['HREF']; + if($tag=='BR') + $this->Ln(5); +} + +function CloseTag($tag) +{ + //Closing tag + if($tag=='B' or $tag=='I' or $tag=='U') + $this->SetStyle($tag,false); + if($tag=='A') + $this->HREF=''; +} + +function SetStyle($tag,$enable) +{ + //Modify style and select corresponding font + $this->$tag+=($enable ? 1 : -1); + $style=''; + foreach(array('B','I','U') as $s) + if($this->$s>0) + $style.=$s; + $this->SetFont('',$style); +} + +function PutLink($URL,$txt) +{ + //Put a hyperlink + $this->SetTextColor(0,0,255); + $this->SetStyle('U',true); + $this->Write(5,$txt,$URL); + $this->SetStyle('U',false); + $this->SetTextColor(0); +} +} + +$html='You can now easily print text mixing different +styles : bold, italic, underlined, or +all at once!
    You can also insert links +on text, such as www.fpdf.org, +or on an image: click on the logo.'; + +$pdf=new PDF(); +//First page +$pdf->AddPage(); +$pdf->SetFont('Arial','',20); +$pdf->Write(5,'To find out what\'s new in this tutorial, click '); +$pdf->SetFont('','U'); +$link=$pdf->AddLink(); +$pdf->Write(5,'here',$link); +$pdf->SetFont(''); +//Second page +$pdf->AddPage(); +$pdf->SetLink($link); +$pdf->Image('logo.png',10,10,30,0,'','http://www.fpdf.org'); +$pdf->SetLeftMargin(45); +$pdf->SetFontSize(14); +$pdf->WriteHTML($html); +$pdf->Output(); +?> diff --git a/include/pdf/tutorial/tuto7.htm b/include/pdf/tutorial/tuto7.htm new file mode 100644 index 000000000..69aef60fb --- /dev/null +++ b/include/pdf/tutorial/tuto7.htm @@ -0,0 +1,316 @@ + + + +Adding new fonts and encoding support + + + +

    Adding new fonts and encoding support

    +This tutorial explains how to use TrueType or Type1 fonts so that you are not limited to the standard +fonts any more. The other interest is that you can choose the font encoding, which allows you to +use other languages than the Western ones (the standard fonts having too few available characters). +
    +
    +There are two ways to use a new font: embedding it in the PDF or not. When a font is not +embedded, it is sought in the system. The advantage is that the PDF file is lighter; on the other +hand, if it is not available, a substitution font is used. So it is preferable to ensure that the +needed font is installed on the client systems. If the file is to be viewed by a large audience, +it is better to embed. +
    +
    +Adding a new font requires three steps for TrueTypes: +
      +
    • Generation of the metric file (.afm) +
    • Generation of the font definition file (.php) +
    • Declaration of the font in the script +
    +For Type1, the first one is theoretically not necessary because the AFM file is usually shipped +with the font. In case you have only a metric file in PFM format, use the convertor available +here. +

    Generation of the metric file

    +The first step for a TrueType consists in generating the AFM file. A utility exists to do this +task: ttf2pt1. The Windows binary +is available here. The command line to use is +the following: +
    +
    +ttf2pt1 -a font.ttf font +
    +
    +For example, for Comic Sans MS Regular: +
    +
    +ttf2pt1 -a c:\windows\fonts\comic.ttf comic +
    +
    +Two files are created; the one we are interested in is comic.afm. +

    Generation of the font definition file

    +The second step consists in generating a PHP file containing all the information needed by FPDF; +in addition, the font file is compressed. To do this, a helper script is provided in the font/makefont/ +directory of the package: makefont.php. It contains the following function: +
    +
    +MakeFont(string fontfile, string afmfile [, string enc [, array patch [, string type]]]) +
    +
    +fontfile +
    +Path to the .ttf or .pfb file. +
    +afmfile +
    +Path to the .afm file. +
    +enc +
    +Name of the encoding to use. Default value: cp1252. +
    +patch +
    +Optional modification of the encoding. Empty by default. +
    +type +
    +Type of the font (TrueType or Type1). Default value: TrueType. +
    +
    +The first parameter is the name of the font file. The extension must be either .ttf or .pfb and +determines the font type. If you own a Type1 font in ASCII format (.pfa), you can convert it to +binary format with t1utils. +
    +If you don't want to embed the font, pass an empty string. In this case, type is given by the +type parameter. +
    +Note: in the case of a font with the same name as a standard one, for instance arial.ttf, it is +mandatory to embed. If you don't, Acrobat will use its own font. +
    +
    +The AFM file is the one previously generated. +
    +
    +The encoding defines the association between a code (from 0 to 255) and a character. The first +128 are fixed and correspond to ASCII; the following are variable. The encodings are stored in +.map files. Those available are: +
      +
    • cp1250 (Central Europe) +
    • cp1251 (Cyrillic) +
    • cp1252 (Western Europe) +
    • cp1253 (Greek) +
    • cp1254 (Turkish) +
    • cp1255 (Hebrew) +
    • cp1257 (Baltic) +
    • cp1258 (Vietnamese) +
    • cp874 (Thai) +
    • ISO-8859-1 (Western Europe) +
    • ISO-8859-2 (Central Europe) +
    • ISO-8859-4 (Baltic) +
    • ISO-8859-5 (Cyrillic) +
    • ISO-8859-7 (Greek) +
    • ISO-8859-9 (Turkish) +
    • ISO-8859-11 (Thai) +
    • ISO-8859-15 (Western Europe) +
    • ISO-8859-16 (Central Europe) +
    • KOI8-R (Russian) +
    • KOI8-U (Ukrainian) +
    +Of course, the font must contain the characters corresponding to the chosen encoding. +
    +In the particular case of a symbolic font (that is to say which does not contain letters, such +as Symbol or ZapfDingbats), pass an empty string. +
    +The encodings which begin with cp are those used by Windows; Linux systems usually use ISO. +
    +Remark: the standard fonts use cp1252. +
    +
    +The fourth parameter gives the possibility to alter the encoding. Sometimes you may want to add +some characters. For instance, ISO-8859-1 does not contain the euro symbol. To add it at position +164, pass array(164=>'Euro'). +
    +
    +The last parameter is used to give the type of the font in case it is not embedded (that is to +say the first parameter is empty). +
    +
    +After you have called the function (create a new file for this and include makefont.php, or +simply add the call directly inside), a .php file is created, with the same name as the .afm one. +You may rename it if you wish. If the case of embedding, the font file is compressed and gives a +second file with .z as extension (except if the compression function is not available, it +requires Zlib). You may rename it too, but in this case you have to alter the variable $file +in the .php file accordingly. +
    +
    +Example: +
    +
    +MakeFont('c:\\windows\\fonts\\comic.ttf','comic.afm','cp1252'); +
    +
    +which gives the files comic.php and comic.z. +
    +
    +Then you have to copy the generated file(s) either in the directory of the script which will use +the font, or in the directory given by FPDF_FONTPATH if the constant is defined. If the font file +could not be compressed, copy the .ttf or .pfb instead of the .z. +

    Declaration of the font in the script

    +The last step is the most simple. You just need to call the AddFont() method. For instance: +
    +
    +
    + +$pdf->AddFont('Comic','','comic.php');
    +
    +

    +or simply: +
    +
    +
    + +$pdf->AddFont('Comic');
    +
    +

    +And the font is now available (in regular and underlined styles), usable like the others. If we +had worked with Comic Sans MS Bold (comicbd.ttf), we would have put: +
    +
    +
    + +$pdf->AddFont('Comic','B','comicbd.php');
    +
    +

    +

    Example

    +Let's now see a small complete example. The font used is Calligrapher, available at +www.abstractfonts.com (a site +offering numerous free TrueType fonts). The first step is the generation of the AFM file: +
    +
    +ttf2pt1 -a calligra.ttf calligra +
    +
    +which gives calligra.afm (and calligra.t1a that we can delete). Then we generate the definition +file: +
    +
    +
    + +<?php
    require('../font/makefont/makefont.php');

    MakeFont('calligra.ttf','calligra.afm');
    ?> +
    +

    +The function call gives the following report: +
    +
    +Warning: character Euro is missing
    +Warning: character Zcaron is missing
    +Warning: character zcaron is missing
    +Warning: character eth is missing
    +Font file compressed (calligra.z)
    +Font definition file generated (calligra.php)
    +
    +The euro character is not present in the font (it is too old). Three other characters are missing +too, but we are not interested in them anyway. +
    +We can now copy the two files in the font directory and write the script: +
    +
    +
    + +<?php
    define('FPDF_FONTPATH','font/');
    require(
    'fpdf.php');

    $pdf=new FPDF();
    $pdf->AddFont('Calligrapher','','calligra.php');
    $pdf->AddPage();
    $pdf->SetFont('Calligrapher','',35);
    $pdf->Cell(0,10,'Enjoy new fonts with FPDF!');
    $pdf->Output();
    ?> +
    +

    + +

    About the euro symbol

    +The euro character is not present in all encodings, and is not always placed at the same position: +
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    EncodingPosition
    cp1250128
    cp1251136
    cp1252128
    cp1253128
    cp1254128
    cp1255128
    cp1257128
    cp1258128
    cp874128
    ISO-8859-1absent
    ISO-8859-2absent
    ISO-8859-4absent
    ISO-8859-5absent
    ISO-8859-7absent
    ISO-8859-9absent
    ISO-8859-11absent
    ISO-8859-15164
    ISO-8859-16164
    KOI8-Rabsent
    KOI8-Uabsent
    +
    +ISO-8859-1 is widespread but does not include the euro sign. If you need it, the simplest thing +to do is using cp1252 or ISO-8859-15 instead, which are nearly identical but contain the precious +symbol. +
    +As for ISO-8859-2, it is possible to use ISO-8859-16 instead, but it contains many differences. +It is therefore simpler to patch the encoding to add the symbol to it, as explained above. The +same is true for the other encodings. +

    Font synthesis under Windows

    +When a TrueType font is not available in a given style, Windows is able to synthesize it from the +regular version. For instance, there is no Comic Sans MS Italic, but it can be built from Comic +Sans MS Regular. This feature can be used in a PDF file, but unfortunately requires that the +regular font be present in the system (you must not embed it). Here is how to do it: +
      +
    • Generate the definition file for the regular font without embedding (you may rename it to +reflect the desired style) +
    • Open it and append to the variable $name a comma followed by the desired style +(Italic, Bold or BoldItalic) +
    +For instance, for the file comici.php: +
    +
    +$name='ComicSansMS,Italic'; +
    +
    +It can then be used normally: +
    +
    +
    + +$pdf->AddFont('Comic','I','comici.php');
    +
    +

    +

    Reducing the size of TrueType fonts

    +Font files are often quite voluminous (more than 100, even 200KB); this is due to the fact that +they contain the characters corresponding to many encodings. Zlib compression reduces them but +they remain fairly big. A technique exists to reduce them further. It consists in converting the +font to the Type1 format with ttf2pt1 by specifying the encoding you are interested in; all other +characters will be discarded. +
    +For instance, the arial.ttf font shipped with Windows 98 is 267KB (it contains 1296 characters). +After compression it gives 147. Let's convert it to Type1 by keeping only cp1250 characters: +
    +
    +ttf2pt1 -b -L cp1250.map c:\windows\fonts\arial.ttf arial +
    +
    +The .map files are located in the font/makefont/ directory of the package. The command produces +arial.pfb and arial.afm. The arial.pfb file is only 35KB, and 30KB after compression. +
    +
    +It is possible to go even further. If you are interested only by a subset of the encoding (you +probably don't need all 217 characters), you can open the .map file and remove the lines you are +not interested in. This will reduce the file size accordingly. + + diff --git a/include/pdf/tutorial/tuto7.php b/include/pdf/tutorial/tuto7.php new file mode 100644 index 000000000..38caf9394 --- /dev/null +++ b/include/pdf/tutorial/tuto7.php @@ -0,0 +1,10 @@ +AddFont('Calligrapher','','calligra.php'); +$pdf->AddPage(); +$pdf->SetFont('Calligrapher','',35); +$pdf->Cell(0,10,'Enjoy new fonts with FPDF!'); +$pdf->Output(); +?> diff --git a/include/person.class.php b/include/person.class.php new file mode 100644 index 000000000..3440df800 --- /dev/null +++ b/include/person.class.php @@ -0,0 +1,194 @@ +false wenn Fehler auftritt und schreiben + * die Fehlermeldung in diese Variable + * @var string enthält Fehlermeldung + */ + var $errormsg; + /** + * @var boolean true=Person neu anlegen (INSERT), false=UPDATE + */ + var $new=true; + /** + * @var person Person (todo: wozu?) + */ + var $person; + /** + * @var resource + */ + var $conn; + var $updateamum; + var $updatevon; + + function person($conn) + { + $this->conn = $conn; + } + + + /** + * Verbindung zur Datenbank herstellen + * @return PostgreSQL-Connection oder NULL + */ + function getConnection() { + return $this->conn; + } + + /** + * Speichert die Person in die Datenbank. INSERT oder DELETE wird durch 'new' + * bestimmt. + * @return boolean false, wenn's nicht funtkioniert hat (Fehlermeldung steht + * in errormsg) + */ + function save() + { + if (is_null($conn=$this->getConnection())) { + return false; + } + if (strlen($this->uid)==0) + { + $this->errormsg="uid nicht gesetzt"; + return false; + } + if ($this->new) + { + $qry="insert into tbl_person(uid,titel,vornamen,nachname,gebdatum,". + "gebort,gebzeit,anmerkungen,aktiv,". + "email,alias,homepage) ". + "values('".$this->uid."','".$this->titel."',". + "'".$this->vornamen."','".$this->nachname."',". + (strlen($this->gebdatum)>0?"'".$this->gebdatum."'":'NULL'). + ",'".$this->gebort."',". + (strlen($this->gebzeit)>0?"'".$this->gebzeit."'":'NULL'). + ",'".$this->anmerkungen."',".($this->aktiv?'true':'false').",". + "'".$this->email."',".($this->alias==''?'null':"'$this->alias'").",'".$this->homepage."'". + ")"; + } + else + { + $qry="update tbl_person set ". + "titel='".$this->titel."',". + "vornamen='".$this->vornamen."',". + "nachname='".$this->nachname."',". + "gebdatum=".(strlen($this->gebdatum)>0?"'".$this->gebdatum."'":'NULL').",". + "gebort='".$this->gebort."',". + "gebzeit=".(strlen($this->gebzeit)>0?"'".$this->gebzeit."'":'NULL').",". + "anmerkungen='".$this->anmerkungen."',". + "aktiv=".($this->aktiv?'true':'false').",". + "email='".$this->email."',alias=".($this->alias==''?'null':"'$this->alias'").",". + "homepage='".$this->homepage."' ". + "where uid='".$this->uid."'"; + } + $qry="set datestyle to german;".$qry; + //echo $qry; + if(!($erg=pg_exec($conn, $qry))) + { + $this->errormsg=pg_errormessage($conn); + return false; + } + return true; + } + + /** + * Ladet die Attribute der Person aus der Datenbank. Bei Fehler ist der + * Rueckgabewert 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true, wenn's funktioniert hat; false bei Fehler + */ + function load($uid='') + { + // optional: uid setzen + if (strlen($uid)>0) + $this->uid=$uid; + // uid vorhanden? + if (strlen($this->uid)==0) { + $this->errormsg='uid nicht gesetzt'; + return false; + } + if (is_null($conn=$this->getConnection())) { + return false; + } + $sql_query="set datestyle to german;SELECT tbl_person.* ". + "FROM tbl_person ". + "WHERE uid='".addslashes($this->uid)."'"; + if(!($erg=pg_exec($conn, $sql_query))) { + $this->errormsg=pg_errormessage($conn); + return false; + } + $num_rows=pg_numrows($erg); + if($num_rows!=1) + { + $this->errormsg="Zuwenige oder zuviele Ergebnisse (Anzahl: $num_rows)!"; + return false; + } + $row=pg_fetch_object($erg,0); + + $this->titel=$row->titel; + $this->vornamen=$row->vornamen; + $this->nachname=$row->nachname; + $this->gebdatum=$row->gebdatum; + $this->gebort=$row->gebort; + $this->gebzeit=$row->gebzeit; + $this->foto=$row->foto; + $this->anmerkungen=$row->anmerkungen; + $this->aktiv=$row->aktiv=='t'?true:false; + $this->email=$row->email; + $this->alias=$row->alias; + $this->homepage=$row->homepage; + $this->updateamum=$row->updateamum; + $this->updatevon=$row->updatevon; + $this->new=false; + return true; + } + + /** + * Löscht die Person aus der Datenbank. Bei Fehler ist der Rueckgabewert 'false' + * und die Fehlermeldung steht in 'errormsg'. + * @return boolean true bei Erfolg, false bei Fehler + */ + function delete() + { + if (is_null($conn=$this->getConnection())) + { + return false; + } + $qry="delete from tbl_person where uid='".$this->uid."'"; + if(!($erg=pg_exec($conn, $sql_query))) + { + $this->errormsg=pg_errormessage($conn); + return false; + } + return true; + } + + + +} +?> \ No newline at end of file diff --git a/include/pgRS.class.php b/include/pgRS.class.php new file mode 100644 index 000000000..f8adfffea --- /dev/null +++ b/include/pgRS.class.php @@ -0,0 +1,62 @@ + + * date: 2004-06-26 + * date-modified: 2004-10-28 + * title: pgRS.class.php +*/ + +class pgRS +{ + var $arr = array(); + var $num = 0; + var $CONN = 0; + var $iid = 0; + + function pgRS($conn,$sql) + { + //echo $sql; + $this->CONN=$conn; + return $this->query($sql); + } + +/* function pgRS($sql, $dbname = "vilesci") { + if (!$this->CONN) + $this->CONN = ConnectDB($dbname); + return $this->query($sql); + } + + function pgRS($sql, $dbname = "vilesci", $user = "", $pw = "") + { + if (!$this->CONN) + $this->CONN = ConnectDB($dbname, $user, $pw); + return $this->query($sql); + } +*/ + function query($sql) + { + static $selects = 0; + //echo $sql; + $result = pg_exec($this->CONN, $sql); + if (strtolower(substr($sql,0,6))=="select") + { + $arr = array(); + ++$selects; + $row = 0; + if (($num = pg_numrows($result)) > 0) + $this->num = $num; + + while ($row < $this->num) + $arr[] = pg_fetch_array($result,$row++, + PGSQL_ASSOC); + + $this->arr = $arr; + + } + //else if (strtolower(substr($sql,0,6))=="insert"){ + $this->iid = pg_last_oid($result); + //} + } +} + +?> diff --git a/include/raumtyp.class.php b/include/raumtyp.class.php new file mode 100644 index 000000000..4fcb26ebf --- /dev/null +++ b/include/raumtyp.class.php @@ -0,0 +1,69 @@ +conn = $conn; + } + + + /** + * Alle Raumtypen zurückgeben + * @return array mit Raumtypen oder false=fehler + */ + function getAll() + { + if (is_null($this->conn)) + { + return false; + } + $qry = "select raumtyp_kurzbz,beschreibung from tbl_raumtyp order by raumtyp_kurzbz"; + //echo $qry; + if (!($erg = pg_exec($this->conn, $qry))) + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + $result = array(); + $num_rows = pg_numrows($erg); + for ($i = 0; $i < $num_rows; $i ++) + { + // Record holen + $row = pg_fetch_object($erg, $i); + // Instanz erzeugen + $rt = new raumtyp($this->conn); + $rt->kurzbz = $row->raumtyp_kurzbz; + $rt->beschreibung = $row->beschreibung; + // in array speichern + $result[] = $rt; + } + return $result; + } + + function test() + { + $bla= new test(); + } +} +?> \ No newline at end of file diff --git a/include/reservierung.class.php b/include/reservierung.class.php new file mode 100644 index 000000000..0a4e96758 --- /dev/null +++ b/include/reservierung.class.php @@ -0,0 +1,354 @@ +conn = $conn; + if (strlen($id)>0) { + $this->id=$id; + $this->load(); + } + } + + /** + * Verbindung zur Datenbank herstellen + * @return PostgreSQL-Connection oder NULL + + function getConnection() { + if (!$conn = @pg_pconnect(CONN_STRING)) { + $this->errormsg="Es konnte keine Verbindung zum Server ". + "aufgebaut werden."; + return null; + } + return $conn; + } */ + + function load($id='') + { + if (is_null($this->conn)) + { + return false; + } + $sql_query="select * from tbl_reservierung where reservierung_id=".$this->id; + if(!($erg=@pg_exec($this->conn, $sql_query))) { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + if($num_rows!=1) { + $this->errormsg="Zuwenige oder zuviele Ergebnisse (Anzahl: $num_rows)!"; + return false; + } + $row=pg_fetch_object($erg,0); + + $this->new=false; + $this->id=$row->reservierung_id; + $this->ort_kurzbz=$row->ort_kurzbz; + $this->studiengang_kz=$row->studiengang_kz; + $this->uid=$row->uid; + $this->stunde=$row->stunde; + $this->datum=$this->unixDate($row->datum); + $this->titel=$row->titel; + $this->beschreibung=$row->beschreibung; + $this->semester=$row->semester; + $this->verband=$row->verband; + $this->gruppe=$row->gruppe; + $this->einheit_kurzbz=$row->einheit_kurzbz; + return true; + } + + function save() + { + if (is_null($this->conn)) + { + return false; + } + if ($this->new) + { + // Kollision-Check + $r=$this->exists($this->datum,$this->stunde,$this->ort_kurzbz); + if ($r!==false) + { + $this->errormsg("Kollision mit bereits bestehender Reservierung: ".$r->titel." (".$r->uid.")"); + return false; + } + // Stundenplan-Kollision? + $kollisionen=$this->collisionStundenplan($this->datum,$this->stunde,$this->ort_kurzbz); + if ($kollisionen>0) + { + $this->errormsg="Kollisionen mit Stundenplan: $kollisionen"; + return false; + } + $qry="insert into tbl_reservierung(ort_kurzbz,studiengang_kz,uid,stunde,datum,titel,beschreibung,semester,verband,gruppe,einheit_kurzbz)". + "values('".$this->ort_kurzbz."',". + $this->studiengang_kz.",'". + $this->uid."',".$this->stunde.",'". + date("d.m.Y",$this->datum)."','". + $this->titel."','".$this->beschreibung."',". + (ctype_digit($this->semester)?$this->semester:'NULL').",". + (strlen($this->verband)>0?"'".$this->verband."'":'NULL').",". + (strlen($this->gruppe)>0?"'".$this->gruppe."'":'NULL').",". + (strlen($this->einheit_kurzbz)>0?"'".$this->einheit_kurzbz."'":'NULL'). + ")"; + } else + { + $qry="update tbl_reservierung set ". + "ort_kurzbz='".$this->ort_kurzbz."',". + "studiengang_kz='".$this->studiengang_kz."',". + "uid='".$this->uid."',". + "stunde=".$this->stunde.",". + "datum='".date("d.m.Y",$this->datum)."',". + "titel='".$this->titel."',". + "beschreibung='".$this->beschreibung."',". + "semester=".(ctype_digit($this->semester)?$this->semester:'NULL').",". + "verband=".(strlen($this->verband)>0?"'".$this->verband."'":'NULL').",". + "gruppe=".(strlen($this->gruppe)>0?"'".$this->gruppe."'":'NULL').",". + "einheit_kurzbz=".(strlen($this->einheit_kurzbz)>0?"'".$this->einheit_kurzbz."'":'NULL'). + "WHERE reservierung_id=".$this->reservierung_id; + + } + $qry="set datestyle to german;".$qry; + //echo $qry; + if(!($erg=pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + return true; + } + + /** + * Überprüfen ob eine Kollision mit dem Stundenplan besteht + * @param integer $datum datum im unix-format + * @param integer $stunde id der stunde + * @param string $ort_kurzbz ort-ID + * @return integer anzahl der Kollisionen, -1 bei fehler + */ + function collisionStundenplan($datum,$stunde,$ort_kurzbz) + { + if (is_null($this->conn)) { + return -1; + } + $qry="SELECT uid, lehrfach_nr, studiengang_kz, stundenplan_id, unr, datum, stunde, ort_kurzbz, semester, verband, gruppe, einheit_kurzbz, titel, anmerkung, fix, stg_kurzbz, stg_kurzbzlang, stg_bezeichnung, fachbereich_id, lehrfach, farbe, lehrform, aktiv, lektor, fixangestellt ". + "FROM vw_stundenplan ". + "WHERE datum='".date('d.m.Y',$datum)."' ". + "AND stunde=".$stunde." ". + "AND ort_kurzbz='".$ort_kurzbz."' ". + "order by semester,verband,gruppe"; + if(!($erg=pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return -1; + } + $num_rows=pg_numrows($erg); + return $num_rows; + } + + /** + * Überprüfen, ob bereits eine Reservierung existiert + * @param integer $datum datum im unix-format + * @param integer $stunde id der stunde + * @param string $ort_kurzbz ort-ID + * @return reservierung reservierung die bereits existiert + */ + function exists($datum,$stunde,$ort_kurzbz) + { + if (is_null($this->conn)) { + return false; + } + $qry="SELECT reservierung_id from tbl_reservierung ". + "WHERE datum='".date('d.m.Y',$datum)."' ". + "AND stunde=".$stunde." ". + "AND ort_kurzbz='".$ort_kurzbz."' ". + "ORDER BY semester,verband,gruppe"; + if(!($erg=pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + $row=pg_fetch_object($erg,0); + $id=$row->reservierung_id; + $r=new reservierung($id); + // bereits vorhandene reservierung zurückgeben + if ($r!==false) return $r; + // reservierung konnte nicht geladen werden + $this->errormsg='Reservierung konnte nicht geladen werden'; + return false; + } + + + + /** + * reservierung löschen + */ + function delete() + { + if (is_null($conn=$this->getConnection())) { + return false; + } + $sql_query="DELETE FROM tbl_reservierung WHERE reservierung_id=".$this->id; + $result=pg_exec($this->conn, $sql_query); + $num_rows=pg_numrows($result); + if ($result) + { + print_r($result); + return true; + } + $this->errormsg=pg_errormessage($this->conn); + return false; + } + + /** + * Alle mehrfach Reservierungen holen + * @return array(datum,stunde,ort) + */ + function getAllMehrfach() + { + if (is_null($this->conn)) + { + return false; + } + $sql_query="set datestyle to german;". + "SELECT count(reservierung_id), datum, stunde, ort_kurzbz ". + "FROM tbl_reservierung GROUP BY datum, stunde, ort_kurzbz ". + "HAVING (count(reservierung_id)>1) ". + "ORDER BY datum, stunde, ort_kurzbz"; + if(!($erg=@pg_exec($this->conn, $sql_query))) { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + $result=array(); + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + $result[]=array('datum'=>$this->unixDate($row->datum), + 'stunde'=>$row->stunde, + 'ort'=>$row->ort_kurzbz); + + } + return $result; + } + + /** + * mehrfach vorkommende Reservierungen laden + * @param string $datum + * @param integer $stunde + * @return array + */ + function getMehrfach($datum,$stunde,$ort_kurzbz) { + if (is_null($this->conn)) { + return false; + } + $sql_query="set datestyle to german;". + "SELECT tbl_reservierung.*, tbl_ort.ort_kurzbz AS ortkurzbz, tbl_mitarbeiter.kurzbz AS lektorkurzbz ". + "FROM tbl_reservierung, tbl_ort, tbl_person,tbl_mitarbeiter ". + "WHERE datum='$datum' AND tbl_reservierung.stunde=$stunde ". + "AND tbl_reservierung.ort_kurzbz='$ort_kurzbz' AND ". + "tbl_reservierung.ort_kurzbz=tbl_ort.ort_kurzbz ". + "AND tbl_person.uid=tbl_mitarbeiter.uid ". + "and tbl_mitarbeiter.lektor=true;"; + if(!($erg=@pg_exec($this->conn, $sql_query))) { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $num_rows=pg_numrows($erg); + $result=array(); + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + $l=new reservierung(); + $l->new=false; + $l->id=$row->reservierung_id; + $l->ort_kurzbz=$row->ort_kurzbz; + $l->studiengang_kz=$row->studiengang_kz; + $l->uid=$row->uid; + $l->stunde=$row->stunde; + $l->datum=$this->unixDate($row->datum); + $l->titel=$row->titel; + $l->beschreibung=$row->beschreibung; + $l->semester=$row->semester; + $l->verband=$row->verband; + $l->gruppe=$row->gruppe; + $l->einheit_kurzbz=$row->einheit_kurzbz; + $result[]=$l; + } + return $result; + } + + function unixDate($date) + { + if (strlen($date)>0) + { + $_d1 = explode(".", $date); + $d1 = $_d1[0]; + $m1 = $_d1[1]; + $y1 = $_d1[2]; + $unixDate=mktime(0,0,0,$d1,$m1,$y1); + } else + { + return null; + } + return $unixDate; + } + +} + +?> \ No newline at end of file diff --git a/include/student.class.php b/include/student.class.php new file mode 100644 index 000000000..928d7b2c8 --- /dev/null +++ b/include/student.class.php @@ -0,0 +1,345 @@ +conn = $conn; + if (strlen($uid)>0) { + $this->uid=$uid; + $this->load(); + } + } + + + /** + * Speichert den Studenten in die Datenbank. Bei Fehler ist der Rueckgabewert + * 'false' und die Fehlermeldung steht in 'errormsg'. INSERT oder DELETE wird + * durch 'new' bestimmt. + * @return boolean true=ok, false=fehler + */ + function save() + { + // uid vorhanden? + if (strlen($this->uid)==0) { + $this->errormsg='uid nicht gesetzt.'; + return false; + } + // Connection holen + if (is_null($conn=person::getConnection())) { + return false; + } + // Daten zur Person speichern + + if (!person::save()) { + $this->errormsg.="
    Daten zur Person konnten nicht gespeichert werden."; + return false; + } + if ($this->new) { + $qry="INSERT INTO tbl_student(uid,studiengang_kz,matrikelnr,". + "semester,verband,gruppe,updateamum,updatevon)". + "values(". + "'".$this->uid."',". + (ctype_digit($this->studiengang_kz)?$this->studiengang_kz:'NULL').",". + "'".$this->matrikelnr."',". + (ctype_digit($this->semester)?$this->semester:'NULL').",". + "'".$this->verband."','".$this->gruppe."',". + "now(),'".$_SERVER['PHP_AUTH_USER']."'". + ")"; + } else + { + $qry="UPDATE tbl_student ". + "SET studiengang_kz=".$this->studiengang_kz.",". + "matrikelnr='".$this->matrikelnr."',". + "semester=".(ctype_digit($this->semester)?$this->semester:'NULL').",". + "verband='".$this->verband."',". + "gruppe='".$this->gruppe."',". + "updateamum=now(),updatevon='".$_SERVER['PHP_AUTH_USER']."' ". + "WHERE uid='".$this->uid."'"; + } + //echo "
    ".$qry; + if(!($erg=pg_exec($conn, $qry))) + { + $this->errormsg=pg_errormessage($conn); + return false; + } + return true; + } + + /** + * Ladet die Attribute des Studenten aus der Datenbank. Bei Fehler ist der + * Rueckgabewert 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true=ok, false=fehler + */ + function load($uid='') + { + // optional: uid setzen + if (strlen($uid)>0) + $this->uid=$uid; + // uid vorhanden? + if (strlen($this->uid)==0) { + $this->errormsg='uid nicht gesetzt.'; + return false; + } + // Connection holen + if (is_null($conn=person::getConnection())) { + return false; + } + // Daten zur Person laden + if (!person::load()) { + $this->errormsg.="
    Daten zur Person konnten nicht geladen werden."; + return false; + } + // Studentendaten holen + $sql_query="SELECT s.studiengang_kz,s.matrikelnr,s.semester,s.verband,s.gruppe ". + "FROM tbl_student as s ". + "WHERE uid='".$this->uid."'"; + $sql_query="set datestyle to german; + SELECT tbl_person.*, m.studiengang_kz,m.matrikelnr,m.semester,m.verband,m.gruppe, + tbl_studiengang.studiengang_kz,tbl_studiengang.bezeichnung + FROM tbl_person join tbl_student as m using(uid) join + tbl_studiengang on (m.studiengang_kz=tbl_studiengang.studiengang_kz) + WHERE uid='".$this->uid."'"; + if(!($erg=pg_exec($conn, $sql_query))) + die(pg_errormessage($conn)); + $num_rows=pg_numrows($erg); + if($num_rows!=1) + { + $this->errormsg="Zuwenige oder zuviele Ergebnisse (Anzahl: $num_rows)!"; + return false; + } + $row=pg_fetch_object($erg,0); + + $this->studiengang_kz=$row->studiengang_kz; + $this->matrikelnr=$row->matrikelnr; + $this->semester=$row->semester; + $this->verband=$row->verband; + $this->gruppe=$row->gruppe; + $this->uid=$row->uid; + $this->titel=$row->titel; + $this->vornamen=$row->vornamen; + $this->nachname=$row->nachname; + $this->gebdatum=$row->gebdatum; + $this->gebort=$row->gebort; + $this->gebzeit=$row->gebzeit; + $this->foto=$row->foto; + $this->anmerkungen=$row->anmerkungen; + $this->aktiv=$row->aktiv=='t'?true:false; + $this->email=$row->email; + $this->homepage=$row->homepage; + $this->updateamum=$row->updateamum; + $this->updatevon=$row->updatevon; + $this->stg_bezeichnung=$row->bezeichnung; + + // todo: einheit + + $result[]=$this; + return $result; + //return true; + } + + /** + * Loescht den Studenten aus der Datenbank. Bei Fehler ist der Rueckgabewert + * 'false' und die Fehlermeldung steht in 'errormsg'. + * @return boolean true=ok, false=fehler + */ + function delete() + { + return false; + } + + /** + * Rueckgabewert ist die Anzahl der Ergebnisse. Bei Fehler negativ und die + * Fehlermeldung liegt in errormsg. + * Wenn der Parameter stg_kz NULL ist tritt einheit_kurzbzb in Kraft. + * @param string $einheit_kurzbz Einheit + * @param string grp Gruppe + * @param string ver Verband + * @param integer sem Semester + * @param integer stg_kz Kennzahl des Studiengangs + * @return integer Anzahl der gefundenen Einträge; negativ bei Fehler + */ + function getStudents($einheit_kurzbz, $grp, $ver, $sem, $stg_kz) + { + if (is_null($conn=person::getConnection())) { + return false; + } + $join = ''; + $where = ''; + if (strlen($einheit_kurzbz)>0) + { + // einheit? + $join=" join tbl_einheitstudent on (m.uid=tbl_einheitstudent.uid) "; + $where=" tbl_einheitstudent.einheit_kurzbz='".$einheit_kurzbz."'"; + } else + { + if (strlen($grp)>0) + { + // Gruppe + $where.=(strlen($where)>0?' and ':'')." m.gruppe='".$grp."' "; + } + if (strlen($ver)>0) + { + // Verband + $where.=(strlen($where)>0?' and ':'')." m.verband='".$ver."' "; + } + if (strlen($sem)>0) + { + // Semester + $where.=(strlen($where)>0?' and ':'')." m.semester=".$sem." "; + } + if (strlen($stg_kz)>0) + { + // Studiengang + $where.=(strlen($where)>0?' and ':'')." m.studiengang_kz='".$stg_kz."' "; + } + } + + + $sql_query="set datestyle to german;SELECT tbl_person.*,". + "m.studiengang_kz,m.matrikelnr,m.semester,m.verband,m.gruppe, ". + "tbl_studiengang.studiengang_kz,tbl_studiengang.bezeichnung ". + "FROM tbl_person join tbl_student as m using(uid) join ". + "tbl_studiengang on (m.studiengang_kz=tbl_studiengang.studiengang_kz) $join ". + (strlen($where)>1?'WHERE '.$where:''). + "ORDER by upper(tbl_person.nachname),upper(tbl_person.vornamen)"; + //echo $sql_query; + if(!($erg=@pg_exec($conn, $sql_query))) { + $this->errormsg=pg_errormessage($conn); + return false; + } + $num_rows=pg_numrows($erg); + $result=array(); + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + $l=new student($conn); + // Personendaten + $l->uid=$row->uid; + $l->titel=$row->titel; + $l->vornamen=$row->vornamen; + $l->nachname=$row->nachname; + $l->gebdatum=$row->gebdatum; + $l->gebort=$row->gebort; + $l->gebzeit=$row->gebzeit; + $l->foto=$row->foto; + $l->anmerkungen=$row->anmerkungen; + $l->aktiv=$row->aktiv=='t'?true:false; + $l->email=$row->email; + $l->homepage=$row->homepage; + $l->updateamum=(isset($row->updateamum)?$row->updateamum:''); + $l->updatevon=(isset($row->updatevon)?$row->updatevon:''); + // Studentendaten + $l->matrikelnr=$row->matrikelnr; + $l->gruppe=$row->gruppe; + $l->verband=$row->verband; + $l->semester=$row->semester; + $l->studiengang_kz=$row->studiengang_kz; + $l->stg_bezeichnung=$row->bezeichnung; + // student in Array speichern + $result[]=$l; + } + return $result; + } + + /** + * gibt array mit allen Studenten zurück + * @return array Studenten + */ + function getAll() { + if (is_null($conn=person::getConnection())) { + return false; + } + $sql_query="set datestyle to german;SELECT tbl_person.*,". + "m.matrikelnr,m.semester,m.verband,m.gruppe, ". + "tbl_studiengang.studiengang_kz,tbl_studiengang.bezeichnung ". + "FROM tbl_person join tbl_student as m using(uid) ". + " join tbl_studiengang on (m.studiengang_kz=tbl_studiengang.studiengang_kz) ". + "ORDER by upper(tbl_person.nachname),upper(tbl_person.vornamen)"; + //echo $sql_query; + if(!($erg=@pg_exec($conn, $sql_query))) { + $this->errormsg=pg_errormessage($conn); + return false; + } + $num_rows=pg_numrows($erg); + $result=array(); + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + $l=new student($conn); + // Personendaten + $l->uid=$row->uid; + $l->titel=$row->titel; + $l->vornamen=$row->vornamen; + $l->nachname=$row->nachname; + $l->gebdatum=$row->gebdatum; + $l->gebort=$row->gebort; + $l->gebzeit=$row->gebzeit; + $l->foto=$row->foto; + $l->anmerkungen=$row->anmerkungen; + $l->aktiv=$row->aktiv=='t'?true:false; + $l->email=$row->email; + $l->homepage=$row->homepage; + $l->updateamum=$row->updateamum; + $l->updatevon=$row->updatevon; + // Studentendaten + $l->matrikelnummer=$row->matrikelnummer; + $l->gruppe=$row->gruppe; + $l->verband=$row->verband; + $l->semester=$row->semester; + $l->studiengang_kz=$row->studiengang_kz; + $l->stg_bezeichnung=$row->bezeichnung; + // student in Array speichern + $result[]=$l; + } + return $result; + } + + + + +} + +?> \ No newline at end of file diff --git a/include/studiengang.class.php b/include/studiengang.class.php new file mode 100644 index 000000000..e0b63b912 --- /dev/null +++ b/include/studiengang.class.php @@ -0,0 +1,152 @@ +conn = $conn; + } + + /** + * Verbindung zur Datenbank herstellen + * @return PostgreSQL-Connection oder NULL + + function getConnection() + { + if (!$conn = @pg_pconnect(CONN_STRING)) { + $this->errormsg="Es konnte keine Verbindung zum Server ". + "aufgebaut werden."; + return null; + } + return $conn; + }*/ + + + /** + * @return array Array mit allen Studiengängen, oder false bei Fehler + */ + function getAll($order='kurzbz') + { + if (is_null($this->conn)) { + $this->errormsg = "Connection failed"; + return false; + } + $qry="select * from tbl_studiengang order by $order"; + if(!($erg=pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + $result=array(); + $num_rows=pg_numrows($erg); + for ($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($erg,$i); + $p=new studiengang($this->conn); + $p->studiengang_kz=$row->studiengang_kz; + $p->kurzbz=$row->kurzbz; + $p->kurzbzlang=$row->kurzbzlang; + $p->bezeichnung=$row->bezeichnung; + $p->max_semester=$row->max_semester; + $p->typ=$row->typ; + $p->farbe=$row->farbe; + $p->email=$row->email; + $result[]=$p; + } + return $result; + } + + function load($stgkz) + { + if (is_null($this->conn)) { + $this->errormsg = "Connection failed"; + return false; + } + $qry="select * from tbl_studiengang where studiengang_kz=$stgkz"; + if(!($erg=pg_exec($this->conn, $qry))) + { + $this->errormsg=pg_errormessage($this->conn); + return false; + } + else + { + if(pg_num_rows($erg)>0) + { + $row=pg_fetch_object($erg); + $this->studiengang_kz = $row->studiengang_kz; + $this->kurzbz = $row->kurzbz; + $this->kurzbzlang = $row->kurzbzlang; + $this->bezeichnung = $row->bezeichnung; + $this->typ = $row->typ; + $this->farbe = $row->farbe; + $this->email = $row->email; + $this->max_semester = $row->max_semester; + $this->max_verband = $row->max_verband; + $this->max_gruppe = $row->max_gruppe; + return true; + } + else + { + $this->errormsg = "Studiengang konnte nicht aufgeloest werden"; + return false; + } + } + } + +} +?> \ No newline at end of file diff --git a/include/studiensemester.class.php b/include/studiensemester.class.php new file mode 100644 index 000000000..38302fa80 --- /dev/null +++ b/include/studiensemester.class.php @@ -0,0 +1,154 @@ +conn=$conn; + } + + /** + * Verbindung zur Datenbank herstellen + * @return PostgreSQL-Connection oder NULL + + function getConnection() + { + if (!$conn = @ pg_pconnect(CONN_STRING)) + { + $this->errormsg = "Es konnte keine Verbindung zum Server "."aufgebaut werden."; + return null; + } + return $conn; + }*/ + + function load() + { + + } + + /** + * Alle Studiensemester zurückgeben + * @return array mit Studiensemester oder false=fehler + */ + function getAll($order='studiensemester_kurzbz') + { + if (is_null($this->conn)) + { + return false; + } + $qry = "select * from tbl_studiensemester ". + "order by $order"; + //echo $qry; + if (!($erg = pg_exec($this->conn, $qry))) + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + $result = array(); + $num_rows = pg_numrows($erg); + for ($i = 0; $i < $num_rows; $i ++) + { + // Record holen + $row = pg_fetch_object($erg, $i); + // Instanz erzeugen + $lf = new studiensemester($this->conn); + $lf->kurzbz = $row->studiensemester_kurzbz; + $lf->start = $row->start; + $lf->ende = $row->ende; + // in array speichern + $result[] = $lf; + } + return $result; + } + + /** + * Liefert das Aktuelle Studiensemester + * @return aktuelles Studiensemester oder false wenn es keines gibt + */ + function getakt() + { + $qry = "Select studiensemester_kurzbz from tbl_studiensemester where start <= now() and ende >= now()"; + if(!$res=pg_exec($this->conn,$qry)) + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + + if(pg_num_rows($res)>0) + { + $erg = pg_fetch_object($res); + return $erg->studiensemester_kurzbz; + } + else + { + $this->errormsg = "Kein aktuelles Studiensemester vorhanden"; + return false; + } + } + + /** + * Liefert das Aktuelle Studiensemester oder das darauffolgende + * @return Studiensemester oder false wenn es keines gibt + */ + function getaktorNext() + { + if($stsem=$this->getakt()) + return $stsem; + else + { + $qry = "Select studiensemester_kurzbz from tbl_studiensemester where ende >= now() ORDER BY ende"; + if(!$res=pg_exec($this->conn,$qry)) + { + $this->errormsg = pg_errormessage($this->conn); + return false; + } + + if(pg_num_rows($res)>0) + { + $erg = pg_fetch_object($res); + return $erg->studiensemester_kurzbz; + } + else + { + $this->errormsg = "Kein aktuelles Studiensemester vorhanden"; + return false; + } + } + } + + function save() + { + + } + + function delete() + { + + } + +} +?> \ No newline at end of file diff --git a/include/stundenplan.class.php b/include/stundenplan.class.php new file mode 100644 index 000000000..58973d83a --- /dev/null +++ b/include/stundenplan.class.php @@ -0,0 +1,1567 @@ +type=$type; + $this->conn=$conn; + $this->link='stpl_week.php?type='.$type; + $this->kal_link='stpl_kalender.php?type='.$type; + $this->datum=mktime(); + $this->init_stdplan(); + } + + function init_stdplan() + { + //Stundenplan Array initialisieren (Anzahl auf 0 setzten) + unset($this->std_plan); + for ($i=1; $i<7; $i++) + for ($j=0; $j<20; $j++) + { + $this->std_plan[$i][$j][0]->anz=0; + $this->std_plan[$i][$j][0]->unr=0; + } + } + + /************************************************************************** + * @brief Funktion load_data ladet alle Zusatzinformationen fuer die Darstellung + * und ueberprueft die Daten + * + * @param datum Datum eines Tages in der angeforderten Woche + * + * @return einheit_kurzbz + * + */ + function load_data($type, $uid, $ort_kurzbz=NULL, $studiengang_kz=NULL, $sem=NULL, $ver=NULL, $grp=NULL, $einheit_kurzbz=NULL) + { + /////////////////////////////////////////////////////////////////////// + // Parameter Checken + // Typ des Stundenplans + if ($type=='student' || $type=='lektor' || $type=='verband' || $type=='einheit' || $type=='ort') + $this->type=$type; + else + { + $this->errormsg='Error: type is not defined!'; + return false; + } + // Person + if (($type=='student' || $type=='lektor') && ($uid==NULL || $uid=='')) + { + $this->errormsg='Fehler: uid der Person ist nicht gesetzt'; + return false; + } + else + $this->pers_uid=$uid; + + // Ort + if ($type=='ort' && $ort_kurzbz==NULL) + { + $this->errormsg='Fehler: Kurzbezeichnung des Orts ist nicht gesetzt'; + return false; + } + elseif ($type=='ort') + $this->ort_kurzbz=$ort_kurzbz; + else + $this->ort_kurzbz=''; + + // Lehrverband + if ($type=='verband' && $studiengang_kz==NULL) + { + $this->errormsg='Fehler: Kennzahl des Studiengangs ist nicht gesetzt'; + return false; + } + elseif($type=='verband') + { + $this->stg_kz=$studiengang_kz; + $this->sem=$sem; + $this->ver=$ver; + $this->grp=$grp; + } + + // Einheit + if ($type=='einheit' && $einheit_kurzbz==NULL) + { + $this->errormsg='Fehler: Kurzbezeichnung der Einheit ist nicht gesetzt'; + return false; + } + elseif ($type=='einheit') + $this->einheit_kurzbz=$einheit_kurzbz; + + + /////////////////////////////////////////////////////////////////////// + // Zusaetzliche Daten ermitteln + //personendaten + if ($this->type=='student' || $this->type=='lektor') + { + $this->link.='&pers_uid='.$this->pers_uid; //Link erweitern + if ($this->type=='student') + $sql_query="SELECT uid, titel, nachname, vornamen, studiengang_kz, semester, verband, gruppe FROM vw_student WHERE uid='$this->pers_uid'"; + else + $sql_query="SELECT uid, titel, nachname, vornamen FROM vw_lektor WHERE uid='$this->pers_uid'"; + //echo $sql_query; + if (!($result=pg_exec($this->conn, $sql_query))) + { + $this->errormsg=pg_last_error($this->conn); + return false; + } + if (pg_num_rows($result)!=1) + { + $this->errormsg='Error: Cannot identify UID "'.$this->pers_uid.'"!'; + return false; + } + $this->pers_uid=pg_result($result,0,'"uid"'); + $this->pers_titel=pg_result($result,0,'"titel"'); + $this->pers_nachname=pg_result($result,0,'"nachname"'); + $this->pers_vornamen=pg_result($result,0,'"vornamen"'); + if ($this->type=='student') + { + $this->stg_kz=pg_result($result,0,'"studiengang_kz"'); + $this->sem=pg_result($result,0,'"semester"'); + $this->ver=pg_result($result,0,'"verband"'); + $this->grp=pg_result($result,0,'"gruppe"'); + } + } + + //ortdaten ermitteln + if ($this->type=='ort') + { + $sql_query="SELECT bezeichnung, ort_kurzbz FROM tbl_ort WHERE ort_kurzbz='$this->ort_kurzbz'"; + //echo $sql_query; + if (!$result=pg_query($this->conn, $sql_query)) + $this->errormsg=pg_last_error($this->conn); + $this->ort_bezeichnung=pg_result($result,0,'"bezeichnung"'); + $this->ort_kurzbz=pg_result($result,0,'"ort_kurzbz"'); + $this->link.='&ort_kurzbz='.$this->ort_kurzbz; //Link erweitern + } + + // Studiengangsdaten ermitteln + if ($this->type=='student' || $this->type=='verband') + { + $sql_query="SELECT bezeichnung, kurzbz, kurzbzlang FROM tbl_studiengang WHERE studiengang_kz=$this->stg_kz"; + //echo $sql_query; + if(!($result=pg_exec($this->conn, $sql_query))) + die(pg_last_error($this->conn)); + $this->stg_bez=pg_result($result,0,'"bezeichnung"'); + $this->stg_kurzbz=pg_result($result,0,'"kurzbz"'); + $this->stg_kurzbzlang=pg_result($result,0,'"kurzbzlang"'); + } + + // Stundentafel abfragen + $sql_query="SELECT stunde, beginn, ende FROM tbl_stunde ORDER BY stunde"; + if(!$this->stunde=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + + // Studiensemesterdaten ermitteln + $sql_query="SELECT * FROM tbl_studiensemester WHERE now()conn, $sql_query)) + die(pg_last_error($this->conn)); + else + { + $row=pg_fetch_object($result); + $this->studiensemester_now->name=$row->studiensemester_kurzbz; + $this->studiensemester_now->start=mktime(0,0,0,substr($row->start,5,2),substr($row->start,8,2),substr($row->start,0,4)); + $this->studiensemester_now->ende=mktime(0,0,0,substr($row->ende,5,2),substr($row->ende,8,2),substr($row->ende,0,4)); + $row=pg_fetch_object($result); + $this->studiensemester_next->name=$row->studiensemester_kurzbz; + $this->studiensemester_next->start=mktime(0,0,0,substr($row->start,5,2),substr($row->start,8,2),substr($row->start,0,4)); + $this->studiensemester_next->ende=mktime(0,0,0,substr($row->ende,5,2),substr($row->ende,8,2),substr($row->ende,0,4)); + } + return true; + } + + /************************************************************************** + * @brief Funktion load_week ladet die Stundenplandaten einer Woche + * + * @param datum Datum eines Tages in der angeforderten Woche + * + * @return true oder false + * + */ + function load_week($datum, $stpl_view='stundenplan') + { + // Pruefung der Attribute + if (!isset($this->type)) + { + $this->errormsg='$type is not set in stundenplan.load_week!'; + return false; + } + + //Kalenderdaten setzen + $this->datum=montag($datum); + $this->datum_begin=$this->datum; + $this->datum_end=jump_week($this->datum_begin, 1); + $this->datum_nextweek=$this->datum_end; + $this->datum_prevweek=jump_week($this->datum_begin, -1); + $this->datum_next4week=jump_week($this->datum_begin, 4); + $this->datum_prev4week=jump_week($this->datum_begin, -4); + // Formatieren fuer Datenbankabfragen + $this->datum_begin=date("Y-m-d",$this->datum_begin); + $this->datum_end=date("Y-m-d",$this->datum_end); + $this->kalenderwoche=kalenderwoche($this->datum); + + // Stundenplandaten ermittlen + $this->wochenplan=new lehrstunde($this->conn); + $anz=$this->wochenplan->load_lehrstunden($this->type,$this->datum_begin,$this->datum_end,$this->pers_uid,$this->ort_kurzbz,$this->stg_kz,$this->sem,$this->ver,$this->grp,$this->einheit_kurzbz, $stpl_view); + if ($anz<0) + { + $this->errormsg=$this->wochenplan->errormsg; + return false; + } + + // Stundenplandaten aufbereiten + for($i=0;$i<$anz;$i++) + { + $idx=0; + $mtag=substr($this->wochenplan->lehrstunden[$i]->datum, 8,2); + $month=substr($this->wochenplan->lehrstunden[$i]->datum, 5,2); + $jahr=substr($this->wochenplan->lehrstunden[$i]->datum, 0,4); + $tag=date("w",mktime(12,0,0,$month,$mtag,$jahr)); + //echo $tag.':'.$this->wochenplan->lehrstunden[$i]->datum.'
    '; + $stunde=$this->wochenplan->lehrstunden[$i]->stunde; + // naechste freie Stelle im Array suchen + while (isset($this->std_plan[$tag][$stunde][$idx]->lektor_uid)) + $idx++; + //echo $idx.'
    '; + $this->std_plan[$tag][$stunde][$idx]->unr=$this->wochenplan->lehrstunden[$i]->unr; + if ($this->wochenplan->lehrstunden[$idx]->reservierung) + $this->std_plan[$tag][$stunde][$idx]->lehrfach=$this->wochenplan->lehrstunden[$i]->titel; + else + { + $this->std_plan[$tag][$stunde][$idx]->lehrfach=$this->wochenplan->lehrstunden[$i]->lehrfach; + $this->std_plan[$tag][$stunde][$idx]->lehrform=$this->wochenplan->lehrstunden[$i]->lehrform; + $this->std_plan[$tag][$stunde][$idx]->lehrfach_nr=$this->wochenplan->lehrstunden[$i]->lehrfach_nr; + $this->std_plan[$tag][$stunde][$idx]->farbe=$this->wochenplan->lehrstunden[$i]->farbe; + $this->std_plan[$tag][$stunde][$idx]->titel=$this->wochenplan->lehrstunden[$i]->titel; + } + $this->std_plan[$tag][$stunde][$idx]->stundenplan_id=$this->wochenplan->lehrstunden[$i]->stundenplan_id; + $this->std_plan[$tag][$stunde][$idx]->lektor_uid=$this->wochenplan->lehrstunden[$i]->lektor_uid; + $this->std_plan[$tag][$stunde][$idx]->lektor=$this->wochenplan->lehrstunden[$i]->lektor_kurzbz; + $this->std_plan[$tag][$stunde][$idx]->ort=$this->wochenplan->lehrstunden[$i]->ort_kurzbz; + $this->std_plan[$tag][$stunde][$idx]->stg=$this->wochenplan->lehrstunden[$i]->studiengang; + $this->std_plan[$tag][$stunde][$idx]->stg_kz=$this->wochenplan->lehrstunden[$i]->studiengang_kz; + $this->std_plan[$tag][$stunde][$idx]->sem=$this->wochenplan->lehrstunden[$i]->sem; + $this->std_plan[$tag][$stunde][$idx]->ver=$this->wochenplan->lehrstunden[$i]->ver; + $this->std_plan[$tag][$stunde][$idx]->grp=$this->wochenplan->lehrstunden[$i]->grp; + $this->std_plan[$tag][$stunde][$idx]->einheit_kurzbz=$this->wochenplan->lehrstunden[$i]->einheit_kurzbz; + $this->std_plan[$tag][$stunde][$idx]->anmerkung=$this->wochenplan->lehrstunden[$i]->anmerkung; + $this->std_plan[$tag][$stunde][$idx]->updateamum=$this->wochenplan->lehrstunden[$i]->updateamum; + $this->std_plan[$tag][$stunde][$idx]->updatevon=$this->wochenplan->lehrstunden[$i]->updatevon; + //echo $tag.' '.$stunde.' '.$this->std_plan[$tag][$stunde][$idx]->lektor_uid.'
    '; + } + unset($this->wochenplan); + return true; + } + + function draw_header() + { + echo ''; + echo ''; + echo ''; + + // Kalenderjump + echo ''; + echo ''; + echo '

    '; + if ($this->type=='student' || $this->type=='lektor') + echo 'Person: '.$this->pers_titel.' '.$this->pers_vornamen.' '.$this->pers_nachname.' - '.$this->pers_uid.'
    '; + if ($this->type=='student' || $this->type=='verband') + { + echo 'Studiengang: '.$this->stg_kurzbzlang.' - '.$this->stg_bez.'
    '; + echo 'Semester: '.$this->sem.'
    '; + if ($this->ver!='0' && $this->ver!='' && $this->ver!=null) + echo 'Verband: '.$this->ver.'
    '; + if ($this->grp!='0' && $this->grp!='' && $this->grp!=null) + echo 'Gruppe: '.$this->grp.'
    '; + $this->link.='&stg_kz='.$this->stg_kz.'&sem='.$this->sem.'&ver='.$this->ver.'&grp='.$this->grp; + } + if ($this->type=='ort') + echo 'Ort: '.$this->ort_kurzbz.' - '.$this->ort_bezeichnung.'
    '; + echo '

    '; + + //Kalender + $this->kal_link.='&pers_uid='.$this->pers_uid.'&ort_kurzbz='.$this->ort_kurzbz.'&stg_kz='.$this->stg_kz.'&sem='.$this->sem.'&ver='.$this->ver.'&grp='.$this->grp.'&einheit_kurzbz='.$this->einheit_kurzbz; + //global $kalender_begin_ws, $kalender_ende_ws, $kalender_begin_ss, $kalender_ende_ss; + $kal_link_ws=$this->kal_link.'&begin='.$this->studiensemester_now->start.'&ende='.$this->studiensemester_now->ende; + $kal_link_ss=$this->kal_link.'&begin='.$this->studiensemester_next->start.'&ende='.$this->studiensemester_next->ende; + echo '       Kalender:    '; + echo ''.$this->studiensemester_now->name.' '; + echo ' + HTML'; + echo ' + CSV'; + echo ' + CSV-Outlook'; + echo ' + vCal Version 1.0'; + echo ' + vCal Version 2.0'; + echo '    '.$this->studiensemester_next->name.' '; + echo ' + HTML'; + echo ' + CSV'; + echo ' + CSV-Outlook'; + echo ' + iCal Version 1.0'; + echo ' + iCal Version 2.0'; + echo '
    '; + jahreskalenderjump($this->link); + echo '

    '; + + // Jump Wochenweise + if ($this->type=='verband') + $link_parameter='&stg_kz='.$this->stg_kz.'&sem='.$this->sem.'&ver='.$this->ver.'&grp='.$this->grp; + if ($this->type=='student' || $this->type=='lektor') + $link_parameter='&pers_uid='.$this->pers_uid; + + // Ort Jump + if ($this->type=='ort') + { + // Orte abfragen + $sql_query="SELECT * FROM tbl_ort WHERE aktiv AND lehre ORDER BY ort_kurzbz"; + if(!$result_ort=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + $num_rows_ort=pg_numrows($result_ort); + + // vorigen Ort bestimmen + for ($i=0;$i<($num_rows_ort-1);$i++) + if (pg_result($result_ort,$i+1,'"ort_kurzbz"')==$this->ort_kurzbz) + $prev_ort=pg_fetch_object($result_ort,$i); + // naechsten Ort bestimmen + for ($i=1;$i<$num_rows_ort;$i++) + if (pg_result($result_ort,$i-1,'"ort_kurzbz"')==$this->ort_kurzbz) + $next_ort=pg_fetch_object($result_ort,$i); + + // Ort Jump + echo '

    '; + //$datum=mktime($this->datum[hours], $this->datum[minutes], $this->datum[seconds], $this->datum[mon], $this->datum[mday], $this->datum[year]); + if (isset($prev_ort)) + { + echo ''; + } + echo "'; + if (isset($next_ort)) + { + echo ''; + } + echo '

    '; + $link_parameter='&ort_kurzbz='.$this->ort_kurzbz; + } + echo '

    '; + // 4 Wochen zurueck + echo ''; + // 1 Woche zurueck + echo ' KW '.$this->kalenderwoche; + // 1 Woche nach vor + echo ''; + // 4 Wochen nach vor + echo ''; + echo '

    '; + return true; + } + + /************************************************************************** + * Zeichnen der Stundenplanwoche in HTML + */ + function draw_week($user_uid='pam') + { + // Stundentafel abfragen + $sql_query="SELECT stunde, beginn, ende FROM tbl_stunde ORDER BY stunde"; + if(!$result_stunde=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + $num_rows_stunde=pg_numrows($result_stunde); + + // Formularbeginn wenn Lektor + if ($this->user=='lektor' && $this->type=='ort') + echo ''; + + //Tabelle zeichnen + echo ''; + // Kopfzeile darstellen + echo ''; + echo ''; + for ($i=0;$i<$num_rows_stunde; $i++) + { + $beginn=pg_result($result_stunde,$i,'"beginn"'); + $beginn=substr($beginn,0,5); + $ende=pg_result($result_stunde,$i,'"ende"'); + $ende=substr($ende,0,5); + $stunde=pg_result($result_stunde,$i,'"stunde"'); + echo ''; + } + echo ''; + // Von Montag bis Samstag + $datum_now=mktime(); + $datum_res_lektor_start=jump_day($datum_now,RES_TAGE_LEKTOR_MIN); + $datum_res_lektor_ende=jump_day($datum_now,RES_TAGE_LEKTOR_MAX); + if (!date("w",$this->datum)) + $this->datum=jump_day($this->datum,1); + $datum=$this->datum; + for ($i=1; $i<7; $i++) + { + echo ''; //.strftime("%A %d %B %Y",$this->datum) + for ($k=0; $k<$num_rows_stunde; $k++) + { + $j=pg_result($result_stunde,$k,'"stunde"'); + // Stunde aufbereiten + if (isset($this->std_plan[$i][$j][0]->lehrfach)) + { + // Anzahl der Felder + + // Daten aufbereiten + $kollision=-1; + unset($unr); + unset($lektor); + unset($lehrverband); + unset($lehrfach); + foreach ($this->std_plan[$i][$j] as $lehrstunde) + { + $unr[]=$lehrstunde->unr; + // Lektoren + $lektor[]=$lehrstunde->lektor; + // Lehrverband + $lvb=$lehrstunde->stg.'-'.$lehrstunde->sem; + if ($lehrstunde->ver!=null && $lehrstunde->ver!='0' && $lehrstunde->ver!='') + { + $lvb.=$lehrstunde->ver; + if ($lehrstunde->grp!=null && $lehrstunde->grp!='0' && $lehrstunde->grp!='') + $lvb.=$lehrstunde->grp; + } + if (count($lehrstunde->einheit_kurzbz)>0) + $lvb=$lehrstunde->einheit_kurzbz; + $lehrverband[]=$lvb; + // Lehrfach + $lf=$lehrstunde->lehrfach; + if (isset($lehrstunde->lehrform)) + $lf.='-'.$lehrstunde->lehrform; + $lehrfach[]=$lf; + $titel=$lehrstunde->titel; + $anmerkung=$lehrstunde->anmerkung; + } + + + // Unterrichtsnummer (Kollision?) + $unr=array_unique($unr); + $kollision+=count($unr); + + // Lektoren + if ($this->type!='lektor') + { + $lektor=array_unique($lektor); + sort($lektor); + $lkt=''; + foreach ($lektor as $l) + $lkt.=$l.'
    '; + } + else + $lkt=$lektor[0].'
    '; + //echo $lkt; + + // Lehrverband + if ($this->type!='verband') + { + $lehrverband=array_unique($lehrverband); + sort($lehrverband); + $lvb=''; + foreach ($lehrverband as $l) + $lvb.=$l.'
    '; + } + else + $lvb=$lehrverband[0].'
    '; + + // Lehrfach + if ($this->type=='verband') + { + $lehrfach=array_unique($lehrfach); + sort($lehrfach); + $lf=''; + foreach ($lehrfach as $l) + $lf.=$l.'
    '; + } + else + $lf=$lehrfach[0].'
    '; + + //$lkt=$this->std_plan[$i][$j][0]->lektor.'
    '; + //$lvb=$this->std_plan[$i][$j][0]->stg.'-'.$this->std_plan[$i][$j][0]->sem.$this->std_plan[$i][$j][0]->ver.$this->std_plan[$i][$j][0]->grp.'
    '; + + + // Blinken oder nicht ? + if ($kollision) + { + $blink_ein=''.$kollision; + $blink_aus=''; + } + else + { + $blink_ein=''; + $blink_aus=''; + } + + // Ausgabe einer Stunde im Raster (HTML) + echo ''; + } + else + { + echo ''; + } + } + echo ""; + $datum=jump_day($datum, 1); + } + echo '
    Stunde 
    Beginn 
    Ende 
    '.$stunde.'
     '.$beginn .' 
     '.$ende.' 
    '.date("l",$datum).'
    '.date("j. M y",$datum).'
    std_plan[$i][$j][0]->farbe)) + echo 'style="background-color: #'.$this->std_plan[$i][$j][0]->farbe.';"'; + echo '>'.$blink_ein.''.$blink_aus.'
    '; + if ($this->user=='lektor' && $this->type=='ort' && (($datum>$datum_res_lektor_start && $datum<=$datum_res_lektor_ende) || $user_uid=='wagner')) + echo ''; //&& $datum>=$datum_now + echo '
    '; + if ($this->user=='lektor' && $this->type=='ort' && (($datum>=$datum_now && $datum>$datum_res_lektor_start && $datum<=$datum_res_lektor_ende) || $user_uid=='wagner' )) + { + echo '
    Titel: '; + echo ' Beschreibung: '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo '
    '; + } + } + + /************************************************************************** + * @brief Funktion draw_week_xul Stundenplan im XUL-Format + * + * @param datum Datum eines Tages in der angeforderten Woche + * + * @return true oder false + * + */ + function draw_week_xul($semesterplan,$uid, $wunsch=null) + { + echo $wunsch; + global $cfgStdBgcolor; + $count=0; + $berechtigung=new berechtigung($this->conn); + $berechtigung->getBerechtigungen($uid); + // Stundentafel abfragen + $sql_query="SELECT * FROM tbl_stunde ORDER BY stunde"; + if(!$result_stunde=pg_query($this->conn, $sql_query)) + $this->errormsg=pg_last_error($this->conn); + $num_rows_stunde=pg_numrows($result_stunde); + + // Kontext Menue + echo ' + + + + + '; + + //Tabelle zeichnen + echo ''; + echo ''; + echo ' '; + for ($i=0;$i<$num_rows_stunde; $i++) + echo ' '; + echo ''; + echo ''; + + // Kopfzeile darstellen + echo ''.$this->crlf; + echo ' + + + '.$this->crlf; //BeginnEnde + for ($i=0;$i<$num_rows_stunde; $i++) + { + $row=pg_fetch_object($result_stunde,$i); + $beginn=substr($row->beginn,0,5); + $ende=substr($row->ende,0,5); + $stunde=$row->stunde; + echo ' + '.$this->crlf; + } + echo ''; + + // Von Montag bis Samstag + if (!date("w",$this->datum)) + $this->datum=jump_day($this->datum,1); + $datum=$this->datum; + + // Ferien holen + $ferien=new ferien($this->conn); + if ($this->type=='verband') + $ferien->getAll($this->stg_kz); + else + $ferien->getAll(0); + for ($i=1; $i<7; $i++) + { + $isferien=$ferien->isferien($datum); + echo ''; + echo ''.date("l",$datum).''.date("j.m y",$datum).''; + echo ''; + for ($k=0; $k<$num_rows_stunde; $k++) + { + $j=pg_result($result_stunde,$k,'"stunde"'); + if (isset($wunsch[$i][$j])) + $index=$wunsch[$i][$j]; + else + $index=1; + if ($index=='') + $index=1; + $bgcolor=$cfgStdBgcolor[$index+3]; + if ($isferien) + $bgcolor='#FFFF55'; + echo ''; + + if (isset($this->std_plan[$i][$j][0]->lehrfach)) + { + // Daten aufbereiten + $kollision=-1; + unset($a_unr); + foreach ($this->std_plan[$i][$j] as $lehrstunde) + { + $a_unr[]=$lehrstunde->unr; + $a_lvb[$lehrstunde->unr][]=$lehrstunde->sem.$lehrstunde->ver.$lehrstunde->grp; + } + // Unterrichtsnummer (Kollision?) + $a_unr=array_unique($a_unr); + $kollision+=count($a_unr); + // Ist es bei LVB-Ansicht wirklich eine Kollision? + if ($kollision>0 && $this->type=='verband') + { + $kollision=0; + $a=0; + foreach ($a_unr as $unr) + { + array_unique($a_lvb[$unr]); + $lvb[$a++]=$a_lvb[$unr]; + } + for ($a=0;$astd_plan[$i][$j] as $lehrstunde) + if ($lehrstunde->unr==$unr) + { + // Lektoren + $lektor[]=$lehrstunde->lektor; + // Lehrverband + $lvb=$lehrstunde->stg.'-'.$lehrstunde->sem; + if ($lehrstunde->ver!=null && $lehrstunde->ver!='0' && $lehrstunde->ver!='') + { + $lvb.=$lehrstunde->ver; + if ($lehrstunde->grp!=null && $lehrstunde->grp!='0' && $lehrstunde->grp!='') + $lvb.=$lehrstunde->grp; + } + if (count($lehrstunde->einheit_kurzbz)>0) + $lvb=$lehrstunde->einheit_kurzbz; + $lehrverband[]=$lvb; + // Lehrfach + $lf=$lehrstunde->lehrfach; + if (isset($lehrstunde->lehrform)) + $lf.='-'.$lehrstunde->lehrform; + $lehrfach[]=$lf; + $ort[]=$lehrstunde->ort; + $stg_kz=$lehrstunde->stg_kz; + $updateamum[]=substr($lehrstunde->updateamum,0,16); + $updatevon[]=$lehrstunde->updatevon; + $paramList.='&stundenplan_id'.$z++.'='.$lehrstunde->stundenplan_id; + $farbe=$lehrstunde->farbe; + $titel=$lehrstunde->titel; + $anmerkung=$lehrstunde->anmerkung; + } + + // Lektoren + //if ($this->type!='lektor') + $lektor=array_unique($lektor); + sort($lektor); + $lkt=''; + foreach ($lektor as $l) + $lkt.=$l.''; + + // Lehrverband + //if ($this->type!='verband') + $lehrverband=array_unique($lehrverband); + sort($lehrverband); + $lvb=''; + foreach ($lehrverband as $l) + $lvb.=$l.''; + + // Lehrfach + //if ($this->type=='verband') + $lehrfach=array_unique($lehrfach); + sort($lehrfach); + $lf=''; + foreach ($lehrfach as $l) + $lf.=$l.''; + + // Ort + //if ($this->type=='verband') + $ort=array_unique($ort); + sort($ort); + $orte=''; + foreach ($ort as $o) + $orte.=$o.''; + + // Update Von + $updatevon=array_unique($updatevon); + sort($updatevon); + $updatevonam='Ge??ndert von '; + foreach ($updatevon as $u) + $updatevonam.=$u.', '; + + // Update Am + $updateamum=array_unique($updateamum); + sort($updateamum); + $updatevonam.='am '; + foreach ($updateamum as $u) + $updatevonam.=$u.' '; + //$updatevonam='Ge??ndert von '.$updatevon.', am '.$updateamum; + + // Blinken oder nicht ? + if ($kollision) + { + $blink_ein='';// .$kollision; + $blink_aus=''; + } + else + { + $blink_ein=''; + $blink_aus=''; + } + + // Ausgabe + echo ''; + } + } + if (isset($this->std_plan[$i][$j][0]->frei_orte)) + foreach ($this->std_plan[$i][$j][0]->frei_orte as $f_ort) + { + echo ''.$this->crlf; + } + echo ""; + $datum=jump_day($datum, 1); + } + + // Fuszzeile darstellen + if (!$semesterplan) + { + echo ''.$this->crlf; + echo ' + + + '.$this->crlf; //BeginnEnde + for ($i=0;$i<$num_rows_stunde; $i++) + { + $row=pg_fetch_object($result_stunde,$i); + $beginn=substr($row->beginn,0,5); + $ende=substr($row->ende,0,5); + $stunde=$row->stunde; + echo ' + '.$this->crlf; + } + echo ''; + } + echo ''; + echo ''; + } + + + + /************************************************************************** + * @brief Funktion load_stpl_search sucht Vorschlag fuer Stundenverschiebung + * + * @param datum der Aktuellen Woche + * @param stpl_id Array der stundenplan_id's + * @param db_stpl_table Name der DB-Tabelle + * + * @return true oder false + * + */ + function load_stpl_search($datum,$stpl_id,$db_stpl_table, $block=1) + { + // Name der View + $stpl_view=VIEW_BEGIN.$db_stpl_table; + $stpl_view_id=$db_stpl_table.TABLE_ID; + //Kalenderdaten setzen + $this->datum=montag($datum); + $this->datum_begin=$this->datum; + $this->datum_end=jump_week($this->datum_begin, 1); + // Formatieren fuer Datenbankabfragen + $this->datum_begin=date("Y-m-d",$this->datum_begin); + $this->datum_end=date("Y-m-d",$this->datum_end); + // Stundentafel abfragen + $sql_query='SELECT min(stunde),max(stunde)FROM tbl_stunde'; + if(!$result_stunde=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + $min_stunde=pg_result($result_stunde,0,'min'); + $max_stunde=pg_result($result_stunde,0,'max'); + // Stundenplaneintraege holen + $sql_query="SELECT * FROM $stpl_view WHERE"; + $stplids=''; + foreach ($stpl_id as $id) + $stplids.=" OR $stpl_view_id=$id"; + $stplids=substr($stplids,3); + $sql_query.=$stplids; + //echo $sql_query; + if(!$result_stpl=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + $num_rows_stpl=pg_numrows($result_stpl); + // Daten aufbereiten + for ($i=0;$i<$num_rows_stpl;$i++) + { + $row=pg_fetch_object($result_stpl,$i); + //$block=$row->stundenblockung; + //$raumtyp[$i]=$row->raumtyp; + //$raumtypalt[$i]=$row->raumtypalternativ; + if ($row->einheit_kurzbz!=null) + $einheit[]=$row->einheit_kurzbz; + else + $einheit[]=''; + $lehrverband[$i]->stg_kz=$row->studiengang_kz; + $lehrverband[$i]->sem=$row->semester; + $lehrverband[$i]->ver=$row->verband; + $lehrverband[$i]->grp=$row->gruppe; + $lektor[$i]=$row->uid; + $unr=$row->unr; + } + // Raumtypen + //$raumtyp=array_unique($raumtyp); + //$rtype=''; + //foreach ($raumtyp as $r) + // $rtype.=" OR raumtyp_kurzbz='$r'"; + //$raumtypalt=array_unique($raumtypalt); + //foreach ($raumtypalt as $r) + // $rtype.=" OR raumtyp_kurzbz='$r'"; + //$rtype=substr($rtype,3); + //Lektor + $lektor=array_unique($lektor); + $lkt=''; + foreach ($lektor as $l) + $lkt.=" OR uid='$l'"; + $lkt=substr($lkt,3); + // Einheiten + $einheit=array_unique($einheit); + $einheiten=''; + foreach ($einheit as $e) + if ($e!='') + $einheiten.=" OR einheit_kurzbz='$e'"; + //$einheiten=substr($einheiten,3); + //Lehrverband + //$lehrverband=array_unique($lehrverband); + $lvb=''; + foreach ($lehrverband as $l) + { + $lvb.=' OR (studiengang_kz='.$l->stg_kz.' AND semester='.$l->sem; + if ($l->ver!='' && $l->ver!=' ' && $l->ver!=null) + { + $lvb.=" AND (verband='$l->ver' OR verband IS NULL OR verband='')"; + if ($l->grp!='' && $l->grp!=' ' && $l->grp!=null) + $lvb.=" AND (gruppe='$l->grp' OR gruppe IS NULL OR gruppe='')"; + } + //if ($einheiten=='') + // $lvb.=' AND einheit_kurzbz IS NULL'; + $lvb.=')'; + } + $lvb=substr($lvb,3); + + // Raeume die in Frage kommen, aufgrund der Raumtypen + $sql_query="SELECT DISTINCT ort_kurzbz FROM tbl_ort + WHERE aktiv AND ort_kurzbz NOT LIKE '\\\\_%' ORDER BY ort_kurzbz"; // NATURAL JOIN tbl_ortraumtyp WHERE $rtype hierarchie + //echo $sql_query; + if(!$result=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + $num_orte=pg_numrows($result); + for ($i=0;$i<$num_orte;$i++) + $orte[]=pg_fetch_result($result,$i,"ort_kurzbz"); + + // Raster vorbereiten + for ($t=1;$t<7;$t++) + for ($s=$min_stunde;$s<=$max_stunde;$s++) + { + $raster[$t][$s]->ort=array(); + $raster[$t][$s]->kollision=false; + } + + // Stundenplanabfrage bauen (Wo ist Kollision?) + $sql_query="SELECT DISTINCT datum, stunde FROM $stpl_view + WHERE datum>='$this->datum_begin' AND datum<'$this->datum_end' AND + ($lkt $einheiten OR ($lvb) ) AND unr!=$unr"; //AND unr!=$unr" + //echo $sql_query; + if(!$result_kollision=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + $num_k=pg_numrows($result_kollision); + for ($i=0;$i<$num_k;$i++) + { + $row=pg_fetch_object($result_kollision,$i); + $mtag=substr($row->datum, 8,2); + $month=substr($row->datum, 5,2); + $jahr=substr($row->datum, 0,4); + $tag=date("w",mktime(12,0,0,$month,$mtag,$jahr)); + $raster[$tag][$row->stunde]->kollision=true; + } + + // Stundenplanabfrage bauen (Wo ist besetzt?) + $sql_query="SELECT DISTINCT datum, stunde, ort_kurzbz FROM $stpl_view + WHERE datum>='$this->datum_begin' AND datum<'$this->datum_end' AND unr!=$unr"; + //echo $sql_query; NATURAL JOIN tbl_ortraumtyp AND ($rtype) " + if(!$result_besetzt=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + $num_b=pg_numrows($result_besetzt); + for ($i=0;$i<$num_b;$i++) + { + $row=pg_fetch_object($result_besetzt,$i); + $mtag=substr($row->datum, 8,2); + $month=substr($row->datum, 5,2); + $jahr=substr($row->datum, 0,4); + $tag=date("w",mktime(12,0,0,$month,$mtag,$jahr)); + $raster[$tag][$row->stunde]->ort[]=$row->ort_kurzbz; + } + + // freie Plaetze in den Stundenplan eintragen. + for ($t=1;$t<7;$t++) + for ($s=1;$s<=$max_stunde;$s++) + if (!$raster[$t][$s]->kollision && ($s+$block)<=($max_stunde+1)) + { + if (count($raster[$t][$s]->ort)>0) + $this->std_plan[$t][$s][0]->frei_orte=array_diff($orte,$raster[$t][$s]->ort); + else + $this->std_plan[$t][$s][0]->frei_orte=$orte; + for ($b=1;$b<$block && ($s+$block)<=($max_stunde+1);$b++) + $this->std_plan[$t][$s][0]->frei_orte=array_diff($this->std_plan[$t][$s][0]->frei_orte,$raster[$t][$s+$b]->ort); + } + return true; + } + + /************************************************************************** + * @brief Funktion load_lva_search sucht Vorschlag fuer LVAs + * + * @param datum der Aktuellen Woche + * @param lva_id Array der lvaIDs + * @param db_stpl_table Name der DB-Tabelle + * + * @return true oder false + * + */ + function load_lva_search($datum,$lva_id,$db_stpl_table,$type) + { + // Name der View + $stpl_view=VIEW_BEGIN.$db_stpl_table; + $lva_stpl_view=VIEW_BEGIN.'lva_'.$db_stpl_table; + $stpl_table=TABLE_BEGIN.$db_stpl_table; + //Kalenderdaten setzen + $this->datum=montag($datum); + $this->datum_begin=$this->datum; + $this->datum_end=jump_week($this->datum_begin, 1); + // Formatieren fuer Datenbankabfragen + $this->datum_begin=date("Y-m-d",$this->datum_begin); + $this->datum_end=date("Y-m-d",$this->datum_end); + // Stundentafel abfragen + $sql_query='SELECT min(stunde),max(stunde) FROM tbl_stunde'; + if(!$result_stunde=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + $min_stunde=pg_result($result_stunde,0,'min'); + $max_stunde=pg_result($result_stunde,0,'max'); + + // LVAs holen + $sql_query='SELECT *, (semesterstunden-verplant::smallint) AS offenestunden FROM '.$lva_stpl_view.' WHERE'; + $lvas=''; + foreach ($lva_id as $id) + $lvas.=' OR lehrveranstaltung_id='.$id; + $lvas=substr($lvas,3); + $sql_query.=$lvas; + //$this->errormsg.=$sql_query; + //return false; + if(!$result_lva=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + $num_rows_lva=pg_numrows($result_lva); + // Arrays setzen + //$wochenrythmus=array(); + $verplant=array(); + $block=array(); + $semesterstunden=array(); + $offenestunden=array(); + // Daten aufbereiten + for ($i=0;$i<$num_rows_lva;$i++) + { + $row=pg_fetch_object($result_lva,$i); + $raumtyp[$i]=$row->raumtyp; + $raumtypalt[$i]=$row->raumtypalternativ; + if ($row->einheit_kurzbz!=null && $row->einheit_kurzbz!='') + $einheit[$i]=$row->einheit_kurzbz; + $lehrverband[$i]->stg_kz=$row->studiengang_kz; + $lehrverband[$i]->sem=$row->semester; + $lehrverband[$i]->ver=$row->verband; + $lehrverband[$i]->grp=$row->gruppe; + $lektor[$i]=$row->lektor_uid; + $verplant[$i]=$row->verplant; + $offenestunden[]=$row->offenestunden; + $unr=$row->unr; + $block[$i]=$row->stundenblockung; + $wochenrythmus[$i]=$row->wochenrythmus; + $semesterstunden[$i]=(integer)$row->semesterstunden; + //$this->errormsg.='SS:'.$semesterstunden[$i]; + } + /*// verplante Stunden eindeutig? + $verpl=$verplant[0]; + $verplant=array_unique($verplant); + if (count($verplant)==1) + $verplant=$verpl; //verplant[0]; + else + { + $this->errormsg.='Verplante Stunden sind nicht eindeutig!'; + return false; + } + //$this->errormsg.='Verplant:'.$verplant; + // Semesterstunden eindeutig? + $semstd=$semesterstunden[0]; + $semesterstunden=array_unique($semesterstunden); + //$this->errormsg.='SS:'.$semesterstunden[0]; + if (count($semesterstunden)==1) + $semesterstunden=$semstd;//semesterstunden[0]; + else + { + $this->errormsg.='Semesterstunden sind nicht eindeutig!'; + return false; + } + //$this->errormsg.='SS:'.$semesterstunden;*/ + // Blockung eindeutig? + $blck=$block[0]; + $block=array_unique($block); + if (count($block)==1) + $block=$blck; //block[0]; + else + { + $this->errormsg.='Blockung ist nicht eindeutig!'; + return false; + } + //$this->errormsg.='Block:'.$block; + // Offene Stunden eindeutig? + $os=$offenestunden[0]; + $offenestunden=array_unique($offenestunden); + if ($type=='lva_single_search') + $offenestunden=$block; + elseif (count($offenestunden)==1) + $offenestunden=$os; + else + { + $this->errormsg.='Offene Stunden sind nicht eindeutig!'; + return false; + } + // Wochenrythmus eindeutig? + $wr=$wochenrythmus[0]; + $wochenrythmus=array_unique($wochenrythmus); + if (count($wochenrythmus)==1) + $wr=$wr; + else + { + $this->errormsg.='Wochenrythmus ist nicht eindeutig!'; + return false; + } + // Raumtypen + $raumtyp=array_unique($raumtyp); + $rtype=''; + foreach ($raumtyp as $r) + $rtype.=" OR raumtyp_kurzbz='$r'"; + $raumtypalt=array_unique($raumtypalt); + foreach ($raumtypalt as $r) + $rtype.=" OR raumtyp_kurzbz='$r'"; + $rtype=substr($rtype,3); + //Lektor + $lektor=array_unique($lektor); + $lkt=''; + foreach ($lektor as $l) + $lkt.=" OR uid='$l'"; + $lkt=substr($lkt,3); + //Dummy Lektor kollidiert nicht + $lkt='(('.$lkt.") AND uid!='_DummyLektor')"; + // Einheiten + $einheit=array_unique($einheit); + $einheiten=''; + foreach ($einheit as $e) + $einheiten.=" OR einheit_kurzbz='$e'"; + //$einheiten=substr($einheiten,3); + //Lehrverband + //$lehrverband=array_unique($lehrverband); + $lvb=''; + foreach ($lehrverband as $l) + { + $lvb.=' OR (studiengang_kz='.$l->stg_kz.' AND semester='.$l->sem; + if ($l->ver!='' && $l->ver!=' ' && $l->ver!=null) + { + $lvb.=" AND (verband='$l->ver' OR verband IS NULL OR verband='' OR verband=' ')"; + if ($l->grp!='' && $l->grp!=' ' && $l->grp!=null) + $lvb.=" AND (gruppe='$l->grp' OR gruppe IS NULL OR gruppe='' OR gruppe=' ')"; + } + if ($einheiten=='') + $lvb.=' AND einheit_kurzbz IS NULL'; + $lvb.=')'; + } + $lvb=substr($lvb,3); + + // Raeume die in Frage kommen aufgrund der Raumtypen + $sql_query="SELECT DISTINCT ort_kurzbz, hierarchie FROM tbl_ort + NATURAL JOIN tbl_ortraumtyp WHERE ($rtype) AND aktiv AND ort_kurzbz NOT LIKE '\\\\_%' ORDER BY hierarchie,ort_kurzbz"; // + //echo $sql_query; + if(!$result=pg_exec($this->conn, $sql_query)) + die(pg_last_error($this->conn)); + $num_orte=pg_numrows($result); + for ($i=0;$i<$num_orte;$i++) + $orte[]=pg_fetch_result($result,$i,"ort_kurzbz"); + + // Suche nach freien Orten. Bei 'lva_multi_search' wird die Schleife (do) aktiv + $count=0; + $rest=$offenestunden; + if ($rest<=0 && $type=='lva_multi_search') + { + $this->errormsg.='Es sind bereits alle Stunden verplant!'; + return false; + } + $datum=$this->datum; + $datum_begin=$this->datum_begin; + $datum_end=$this->datum_end; + do + { + // Raster vorbereiten + for ($t=1;$t<7;$t++) + for ($s=$min_stunde;$s<=$max_stunde;$s++) + { + unset($raster[$t][$s]); + $raster[$t][$s]->ort=array(); + $raster[$t][$s]->kollision=false; + } + + // Stundenplanabfrage bauen (Wo ist Kollision?) + $sql_query="SELECT DISTINCT datum, stunde FROM $stpl_table + WHERE datum>='$datum_begin' AND datum<'$datum_end' AND + ($lkt $einheiten OR ($lvb) ) AND unr!=$unr"; + //$this->errormsg.=htmlspecialchars($sql_query); + //return false; + if(!$result_kollision=pg_exec($this->conn, $sql_query)) + { + $this->errormsg=pg_last_error($this->conn); + return false; + } + $num_k=pg_numrows($result_kollision); + // Kollisionen ins Raster eintragen + for ($i=0;$i<$num_k;$i++) + { + $row=pg_fetch_object($result_kollision,$i); + $mtag=substr($row->datum, 8,2); + $month=substr($row->datum, 5,2); + $jahr=substr($row->datum, 0,4); + $tag=date("w",mktime(12,0,0,$month,$mtag,$jahr)); + $raster[$tag][$row->stunde]->kollision=true; + } + + // Stundenplanabfrage bauen (Wo ist besetzt?) + $sql_query="SELECT DISTINCT datum, stunde, ort_kurzbz FROM $stpl_view + NATURAL JOIN tbl_ortraumtyp + WHERE datum>='$datum_begin' AND datum<'$datum_end' AND + ($rtype) AND unr!=$unr"; // + //echo $sql_query; + if(!$result_besetzt=pg_query($this->conn, $sql_query)) + { + $this->errormsg=pg_last_error($this->conn); + return false; + } + $num_b=pg_numrows($result_besetzt); + + // Besetzte Orte ins Raster eintragen + for ($i=0;$i<$num_b;$i++) + { + $row=pg_fetch_object($result_besetzt,$i); + $mtag=substr($row->datum, 8,2); + $month=substr($row->datum, 5,2); + $jahr=substr($row->datum, 0,4); + $tag=date("w",mktime(12,0,0,$month,$mtag,$jahr)); + $raster[$tag][$row->stunde]->ort[]=$row->ort_kurzbz; + //if ($row->ort_kurzbz=='EDV6.10' && $tag==2 && $row->stunde==8) + // $this->errormsg.=htmlspecialchars($row->ort_kurzbz).'/'.$mtag.'/'.$month; + } + + // freie Plaetze in den Stundenplan eintragen. + for ($t=1;$t<7;$t++) + for ($s=1;$s<=$max_stunde;$s++) + if (!$raster[$t][$s]->kollision && ($s+$block)<=($max_stunde+1)) + { + // Besetzte Orte von den freien abziehen + if (count($raster[$t][$s]->ort)>0 && $count==0) + $this->std_plan[$t][$s][0]->frei_orte=array_diff($orte,$raster[$t][$s]->ort); + elseif ($count==0) + $this->std_plan[$t][$s][0]->frei_orte=$orte; + elseif (count($raster[$t][$s]->ort)>0) + $this->std_plan[$t][$s][0]->frei_orte=array_diff($this->std_plan[$t][$s][0]->frei_orte,$raster[$t][$s]->ort); + // Blockung beruecksichtigen + for ($b=1;$b<$block && ($s+$block)<=($max_stunde+1);$b++) + if (!$raster[$t][$s+$b]->kollision) + $this->std_plan[$t][$s][0]->frei_orte=array_diff($this->std_plan[$t][$s][0]->frei_orte,$raster[$t][$s+$b]->ort); + else + $this->std_plan[$t][$s][0]->frei_orte=array(); + } + elseif($raster[$t][$s]->kollision) + $this->std_plan[$t][$s][0]->frei_orte=array(); + + // Variablen abgleichen + $rest-=$block; + if ($block>$rest) + $block=$rest; + $datum=jump_week($datum,$wr); + $datum_begin=$datum; + $datum_end=jump_week($datum_begin, 1); + // Formatieren fuer Datenbankabfragen + $datum_begin=date("Y-m-d",$datum_begin); + $datum_end=date("Y-m-d",$datum_end); + $count++; + } while($type=='lva_multi_search' && $rest>0); + return true; + } + + + /************************************************************************** + * @brief Funktion draw_week_csv Stundenplan im XUL-Format + * + * @param target Ziel-System zB Outlook + * + * @return true oder false + * + */ + function draw_week_csv($target) + { + if (!date("w",$this->datum)) + $this->datum=jump_day($this->datum,1); + $num_rows_stunde=pg_numrows($this->stunde); + for ($i=1; $i<7; $i++) + { + for ($k=0; $k<$num_rows_stunde; $k++) + { + $j=pg_result($this->stunde,$k,'"stunde"'); // get id of hour + if (isset($this->std_plan[$i][$j][0]->lehrfach)) + { + // Daten aufbereiten + unset($unr); + unset($lektor); + unset($lehrverband); + unset($lehrfach); + foreach ($this->std_plan[$i][$j] as $lehrstunde) + { + $unr[]=$lehrstunde->unr; + // Lektoren + $lektor[]=$lehrstunde->lektor; + // Lehrverband + $lvb=$lehrstunde->stg.'-'.$lehrstunde->sem; + if ($lehrstunde->ver!=null && $lehrstunde->ver!='0' && $lehrstunde->ver!='') + { + $lvb.=$lehrstunde->ver; + if ($lehrstunde->grp!=null && $lehrstunde->grp!='0' && $lehrstunde->grp!='') + $lvb.=$lehrstunde->grp; + } + if (count($lehrstunde->einheit_kurzbz)>0) + $lvb=$lehrstunde->einheit_kurzbz; + $lehrverband[]=$lvb; + // Lehrfach + $lf=$lehrstunde->lehrfach; + if (isset($lehrstunde->lehrform)) + $lf.='-'.$lehrstunde->lehrform; + $lehrfach[]=$lf; + $titel=$lehrstunde->titel; + $anmerkung=$lehrstunde->anmerkung; + } + + // Unterrichtsnummer (Kollision?) + $unr=array_unique($unr); + if(!isset($kollision)) + $kollision=0; + $kollision+=count($unr); + + // Lektoren + if ($this->type!='lektor') + { + $lektor=array_unique($lektor); + sort($lektor); + $lkt=''; + foreach ($lektor as $l) + $lkt.=$l.' '; + } + else + $lkt=$lektor[0]; + //echo $lkt; + + // Lehrverband + if ($this->type!='verband') + { + $lehrverband=array_unique($lehrverband); + sort($lehrverband); + $lvb=''; + foreach ($lehrverband as $l) + $lvb.=$l.' '; + } + else + $lvb=$lehrverband[0]; + + + $start_time=pg_result($this->stunde,$k,'"beginn"'); + // Blockungen erkennen + if (($this->std_plan[$i][$j][0]->unr == $this->std_plan[$i][$j+1][0]->unr) && $this->std_plan[$i][$j][0]!=0 && $k<($num_rows_stunde-1)) + { + $end_time=pg_result($this->stunde,++$k,'"ende"'); + if (($this->std_plan[$i][$j][0]->unr == $this->std_plan[$i][$j+2][0]->unr) && $k<($num_rows_stunde-2)) + { + $end_time=pg_result($this->stunde,++$k,'"ende"'); + if (($this->std_plan[$i][$j][0]->unr == $this->std_plan[$i][$j+3][0]->unr) && $k<($num_rows_stunde-3)) + $end_time=pg_result($this->stunde,++$k,'"ende"'); + } + } + else + $end_time=pg_result($this->stunde,$k,'"ende"'); + //$start_time=substr($start_time,0,5); + //$end_time=substr($end_time,0,5); + //$start_date=$this->datum[year].'/'.$this->datum[mon].'/'.$this->datum[mday]; + + $start_date=date("d.m.Y",$this->datum); + $end_date=$start_date; + if ($target=='outlook') + { + echo $this->crlf.'"'.$this->std_plan[$i][$j][0]->lehrfach.'","'.$start_date.'","'.$start_time.'","'.$end_date.'","'.$end_time.'","Aus","Aus",,,,,,,,"Stundenplan'; + echo $this->crlf.$this->std_plan[$i][$j][0]->lehrfach.$this->crlf.$this->std_plan[$i][$j][0]->lektor.$this->crlf.$lvb.$this->crlf.$this->std_plan[$i][$j][0]->ort.'","StundenplanFH","'.$this->std_plan[$i][$j][0]->ort.'","Normal","Aus",,"Normal","2"'; + } + else if ($target=='ical') + { + $sda = explode(".",$start_date); //sda start date array + $sta = explode(":",$start_time); //sta start time array + $eda = explode(".",$end_date); //eda end date array + $eta = explode(":",$end_time); //eta end time array + + $start_date_time_ical = $sda[2].$sda[1].$sda[0].'T'.$sta[0].$sta[1].$sta[2]; //.'Z'; //neu gruppieren der Startzeit und des Startdatums + $end_date_time_ical = $eda[2].$eda[1].$eda[0].'T'.$eta[0].$eta[1].$eta[2]; //.'Z'; //neu gruppieren der Startzeit und des Startdatums + + echo $this->crlf.'BEGIN:VEVENT'.$this->crlf + .'UID:'.'TW'.$lvb.$this->std_plan[$i][$j][0]->ort.$this->std_plan[$i][$j][0]->lektor.$lehrfach[0].$start_date_time_ical.$this->crlf + .'SUMMARY:'.$lehrfach[0].' '.$this->std_plan[$i][$j][0]->ort.' - '.$lvb.$this->crlf + .'DESCRIPTION:'.$lehrfach[0].'\n'.$this->std_plan[$i][$j][0]->lektor.'\n'.$lvb.'\n'.$this->std_plan[$i][$j][0]->ort.$this->crlf + .'LOCATION:'.$this->std_plan[$i][$j][0]->ort.$this->crlf + .'CATEGORIES:StundenplanTW'.$this->crlf + .'DTSTART:'.$start_date_time_ical.$this->crlf + .'DTEND:'.$end_date_time_ical.$this->crlf + .'END:VEVENT'; + } + else + { + echo $this->crlf.'"'.$lehrfach[0].'","StundenplanTW","'.$this->std_plan[$i][$j][0]->ort.'","Stundenplan'.$this->crlf.$this->std_plan[$i][$j][0]->lehrfach.$this->crlf; + echo $this->std_plan[$i][$j][0]->lektor.$this->crlf.$lvb.$this->crlf.$this->std_plan[$i][$j][0]->ort.'","Stundenplan",'; + echo '"'.$start_date.'","'.$start_time.'","'.$end_date.'","'.$end_time.'",,,,,'; + } + } + } + $this->datum=jump_day($this->datum, 1); + } + return true; + } + +} + +?> \ No newline at end of file diff --git a/include/test.php b/include/test.php new file mode 100644 index 000000000..ecfa68b70 --- /dev/null +++ b/include/test.php @@ -0,0 +1,9 @@ + diff --git a/include/zeitwunsch.class.php b/include/zeitwunsch.class.php new file mode 100644 index 000000000..f5483d79e --- /dev/null +++ b/include/zeitwunsch.class.php @@ -0,0 +1,96 @@ +conn=$conn; + } + + /** + * Zeitwunsch einer Person laden + * @return boolean Ergebnis steht in Array $zeitwunsch wenn true + */ + function loadPerson($uid) + { + // Zeitwuensche abfragen + if(!$result=@pg_query($this->conn, "SELECT * FROM tbl_zeitwunsch WHERE uid='$uid'")) + { + $this->errormsg=pg_last_error($this->conn); + return false; + } + else + { + while ($row=@pg_fetch_object($result)) + $this->zeitwunsch[$row->tag][$row->stunde]=$row->gewicht; + return true; + } + } + + + /** + * Zeitwunsch der Personen in Lehrveranstaltungen laden + * @return array mit Fachbereichen oder false=fehler + */ + function loadLVA($lva_id) + { + // SUB-Select fuer LVAs + $sql_query_lva='SELECT DISTINCT lektor FROM tbl_lehrveranstaltung WHERE '; + for ($i=0;$iconn, $sql_query)) + { + $this->errormsg=pg_last_error($this->conn); + return false; + } + else + { + while ($row=@pg_fetch_object($result)) + $this->zeitwunsch[$row->tag][$row->stunde]=$row->gewicht; + return true; + } + } + +} +?> \ No newline at end of file diff --git a/index.cis.html b/index.cis.html new file mode 100644 index 000000000..229e853d1 --- /dev/null +++ b/index.cis.html @@ -0,0 +1,23 @@ + + + + CIS - FH Technikum Wien + + + + + + + + + + + + + + <body> + <p>Diese Seite verwendet Frames. Frames werden von Ihrem Browser aber nicht unterstützt.</p> + </body> + + + diff --git a/index.cis2.html b/index.cis2.html new file mode 100644 index 000000000..c64d5567c --- /dev/null +++ b/index.cis2.html @@ -0,0 +1,22 @@ + + + + CIS - FH Technikum Wien + + + + + + + + + + + + + <body> + <p>Diese Seite verwendet Frames. Frames werden von Ihrem Browser aber nicht unterstützt.</p> + </body> + + + diff --git a/index.vilesci.html b/index.vilesci.html new file mode 100644 index 000000000..7e2e57415 --- /dev/null +++ b/index.vilesci.html @@ -0,0 +1,17 @@ + + + +VileSci + + + + + + + +<body bgcolor="#FFFFFF"> + +</body> + + diff --git a/locale/contents.rdf b/locale/contents.rdf new file mode 100644 index 000000000..b4d9f650d --- /dev/null +++ b/locale/contents.rdf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/locale/de-AT/contents.rdf b/locale/de-AT/contents.rdf new file mode 100644 index 000000000..b4d9f650d --- /dev/null +++ b/locale/de-AT/contents.rdf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/locale/de-AT/fas.dtd b/locale/de-AT/fas.dtd new file mode 100644 index 000000000..509add4b3 --- /dev/null +++ b/locale/de-AT/fas.dtd @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/locale/de-AT/tempus.dtd b/locale/de-AT/tempus.dtd new file mode 100644 index 000000000..33d99ba68 --- /dev/null +++ b/locale/de-AT/tempus.dtd @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/locale/en-US/contents.rdf b/locale/en-US/contents.rdf new file mode 100644 index 000000000..a5fd2e813 --- /dev/null +++ b/locale/en-US/contents.rdf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/locale/en-US/tempus.dtd b/locale/en-US/tempus.dtd new file mode 100644 index 000000000..bddf5465f --- /dev/null +++ b/locale/en-US/tempus.dtd @@ -0,0 +1,7 @@ + + + + + + + diff --git a/locale/tempus.dtd b/locale/tempus.dtd new file mode 100644 index 000000000..05fae9f44 --- /dev/null +++ b/locale/tempus.dtd @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/phpinfo.php b/phpinfo.php new file mode 100644 index 000000000..c18f4c6d5 --- /dev/null +++ b/phpinfo.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/rdf/einheiten.rdf.php b/rdf/einheiten.rdf.php new file mode 100644 index 000000000..382ee5c93 --- /dev/null +++ b/rdf/einheiten.rdf.php @@ -0,0 +1,65 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/einheit.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + + +// Einheiten holen +$einheitenDAO=new einheit($conn); +$einheiten=$einheitenDAO->getAll(); + + + +$rdf_url='http://www.technikum-wien.at/tempus/einheiten'; + +?> + + + + + + + + + + kurzbz ?> + stg_kz ?> + stg_kurzbz ?> + bezeichnung ?> + semester ?> + typ ?> + + + + + + + + \ No newline at end of file diff --git a/rdf/fachbereich.rdf.php b/rdf/fachbereich.rdf.php new file mode 100644 index 000000000..79f692e9c --- /dev/null +++ b/rdf/fachbereich.rdf.php @@ -0,0 +1,83 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/fachbereich.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + + +// test + +$einheit_kurzbz=''; +$grp='1'; +//$ver='A'; +$sem=5; +$stg_kz=145; + + +/* +$einheit_kurzbz=''; +$grp=$_GET['grp']; +$ver=$_GET['ver']; +$sem=$_GET['sem']; +$stg_kz=$_GET['stg_kz']; */ + +// fachbereiche holen +$fachbereichDAO=new fachbereich($conn); +$fachbereiche=$fachbereichDAO->getAll(); + + + +$rdf_url='http://www.technikum-wien.at/tempus/fachbereich'; + +?> + + + + + + + + + id ?> + kurzbz ?> + bezeichnung ?> + farbe ?> + studiengang_kz ?> + studiengang_kurzbz ?> + + + + + + + \ No newline at end of file diff --git a/rdf/fas/adressen.rdf.php b/rdf/fas/adressen.rdf.php new file mode 100644 index 000000000..d42553ef3 --- /dev/null +++ b/rdf/fas/adressen.rdf.php @@ -0,0 +1,100 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include_once('../../include/fas/adresse.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$rdf_url='http://www.technikum-wien.at/adressen'; + +?> + + + + + +load_pers($pers_id); + + + foreach ($adressenDAO->result as $adressen) + { + ?> + + + adresse_id; ?> + bismeldeadresse?'Ja':'Nein'); ?> + gemeinde; ?> + name; ?> + nation; ?> + ort; ?> + person_id; ?> + plz; ?> + strasse; ?> + typ; ?> + zustelladresse?'Ja':'Nein'); ?> + + + load($adress_id) + + ?> + + + adresse_id; ?> + bismeldeadresse?'Ja':'Nein'); ?> + gemeinde; ?> + name; ?> + nation; ?> + ort; ?> + person_id; ?> + plz; ?> + strasse; ?> + typ; ?> + zustelladresse?'Ja':'Nein'); ?> + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/ausbildung.rdf.php b/rdf/fas/ausbildung.rdf.php new file mode 100644 index 000000000..ac2abcd52 --- /dev/null +++ b/rdf/fas/ausbildung.rdf.php @@ -0,0 +1,90 @@ +'; + +$rdf_url='http://www.technikum-wien.at/ausbildung'; +?> + + + + + + 1 + Universitätsabschluss mit Doktorat als Zweit- oder Dritt- oder PhD-Abschluss + + + + + 2 + Universitäts- oder Hochschulabschluss auf Diplom oder Magisterebene, Doktor als Erstabschluss + + + + + 3 + Fachhochschulabschluss auf Diplom- oder Magisterebene + + + + + 4 + Universitätsabschluss auf Bakkalaureatsebene + + + + + 5 + Fachhochschulabschluss auf Bakkalaureatsebene + + + + + 6 + Diplom einer Akademie + + + + + 7 + Anderer tertiärer Bildungsabschluss + + + + + 8 + Reifeprüfung einer allgemeinbildenden höheren Schule + + + + + 9 + Reifeprüfung einer berufsbildenden höheren Schule + + + + + 10 + Lehrabschlussprüfung + + + + + 11 + Pflichtschule + + + + \ No newline at end of file diff --git a/rdf/fas/ausbildungssemester.rdf.php b/rdf/fas/ausbildungssemester.rdf.php new file mode 100644 index 000000000..808f4baab --- /dev/null +++ b/rdf/fas/ausbildungssemester.rdf.php @@ -0,0 +1,61 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include_once('../../include/fas/ausbildungssemester.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$rdf_url='http://www.technikum-wien.at/ausbildungssemester'; + +?> + + + + + +load_stg($_GET['stg']); + + foreach ($ausbsem_obj->result as $ausbsem) + { + ?> + + + ausbildungssemester_id; ?> + studiengang_id; ?> + semester; ?> + name; ?> + + + + + + + \ No newline at end of file diff --git a/rdf/fas/ausmass.rdf.php b/rdf/fas/ausmass.rdf.php new file mode 100644 index 000000000..325549f52 --- /dev/null +++ b/rdf/fas/ausmass.rdf.php @@ -0,0 +1,61 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); + +$rdf_url='http://www.technikum-wien.at/ausmass'; + +?> + + + + + + + + 1 + Vollzeit + + + + + 2 + + + + + + 3 + 16 - 25 Wochenstunden + + + + + 4 + 26 - 35 Wochenstunden + + + + + 5 + Karenz + + + + \ No newline at end of file diff --git a/rdf/fas/bankverbindungen.rdf.php b/rdf/fas/bankverbindungen.rdf.php new file mode 100644 index 000000000..1f8d80e61 --- /dev/null +++ b/rdf/fas/bankverbindungen.rdf.php @@ -0,0 +1,98 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include_once('../../include/fas/bankverbindung.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$rdf_url='http://www.technikum-wien.at/bankverbindungen'; + +?> + + + + + +load_pers($pers_id); + + + foreach ($bankverbindungenDAO->result as $bankverbindungen) + { + ?> + + + bankverbindung_id; ?> + person_id; ?> + name; ?>]]> + anschrift; ?>]]> + blz; ?> + bic; ?> + kontonr; ?> + iban; ?> + typ,10); ?> + getTypBezeichnung(fmod($bankverbindungen->typ,10)); ?> + typ>10?'Ja':'Nein'); ?> + + + load($bankverbindung_id); + ?> + + + bankverbindung_id; ?> + person_id; ?> + name; ?>]]> + anschrift; ?>]]> + blz; ?> + bic; ?> + kontonr; ?> + iban; ?> + typ,10); ?> + typ>10?'Ja':'Nein'); ?> + + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/beschaeftigungsart1.rdf.php b/rdf/fas/beschaeftigungsart1.rdf.php new file mode 100644 index 000000000..0d14bb547 --- /dev/null +++ b/rdf/fas/beschaeftigungsart1.rdf.php @@ -0,0 +1,70 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); + +$rdf_url='http://www.technikum-wien.at/beschaeftigungsart1'; + +?> + + + + + + + + 1 + Dienstverhältnis zum Bund + + + + + 2 + Dienstverhältnis zu einer anderen Gebietskörperschaft + + + + + 3 + Dienstverhältnis zur Bildungseinrichtung oder deren Träger ("Echter" Dienstvertrag) + + + + + 4 + Dienstverhältnis zur Bildungseinrichtung oder deren Träger (Freier Dienstvertrag) + + + + + 5 + Lehr- oder Ausbildungsverhältnis + + + + + 6 + Sonstiges Beschäftigungsverhältnis + + + + + + + \ No newline at end of file diff --git a/rdf/fas/db_dml.rdf.php b/rdf/fas/db_dml.rdf.php new file mode 100644 index 000000000..23e70b04a --- /dev/null +++ b/rdf/fas/db_dml.rdf.php @@ -0,0 +1,1156 @@ +'; + $rdf_url='http://www.technikum-wien.at/dbdml'; + $error=false; + $errormsg = 'Funktion noch nicht implementiert'; + $return = 'false'; + + //UID holen + $user=get_uid(); + + //Sollte eigentlich nie vorkommen + if($user=='') + { + $error = true; + $return = 'false'; + $errormsg = 'User konnte nicht ermittelt werden'; + } + + //VILESCI Datenbankverbindung herstellen + if(!$conn = pg_pconnect(CONN_STRING)) + { + $error = true; + $return = 'false'; + $errormsg = 'Verbindung zur Datenbank fehlgeschlagen'; + } + + //FAS Datenbankverbindung herstellen + if(!$conn_fas = pg_pconnect(CONN_STRING_FAS)) + { + $error = true; + $return = 'false'; + $errormsg = 'Verbindung zur Datenbank fehlgeschlagen'; + } + $rechte = new berechtigung($conn); + $rechte->getBerechtigungen($user); + $benutzer = new benutzer($conn); + $benutzer->loadVariables($user); +?> + + + + +isBerechtigt('admin', 0, 'i') + || $rechte->isBerechtigt('admin', 0, 'u') + || $rechte->isBerechtigt('mitarbeiter', 0, 'i') + || $rechte->isBerechtigt('mitarbeiter', 0, 'u')) + { + $mitarbeiter = new mitarbeiter($conn_fas); + //Werte holen und zuweisen + $mitarbeiter->new = ($_POST['new']=='true'?true:false); + $mitarbeiter->person_id = $_POST['person_id']; + $mitarbeiter->mitarbeiter_id = $_POST['mitarbeiter_id']; + $mitarbeiter->anrede = $_POST['anrede']; + $mitarbeiter->titelpre = $_POST['titelpre']; + $mitarbeiter->titelpost = $_POST['titelpost']; + $mitarbeiter->familienname = $_POST['nachname']; + $mitarbeiter->vorname = $_POST['vorname']; + $mitarbeiter->vornamen = $_POST['vornamen']; + $mitarbeiter->uid = $_POST['uid']; + $mitarbeiter->svnr = $_POST['svnr']; + $mitarbeiter->ersatzkennzeichen = $_POST['ersatzkennzeichen']; + $mitarbeiter->gebort = $_POST['geburtsort']; + if($_POST['geburtsdatum']!='') + $mitarbeiter->gebdat = convertdate($_POST['geburtsdatum']); + else + $mitarbeiter->gebdat = ''; + $mitarbeiter->bemerkung = $_POST['bemerkung']; + $mitarbeiter->anzahlderkinder = $_POST['anzahlderkinder']; + $mitarbeiter->geschlecht = $_POST['geschlecht']; + $mitarbeiter->bismelden = ($_POST['bismelden']=='true'?true:false); + $mitarbeiter->familienstand = $_POST['familienstand']; + $mitarbeiter->staatsbuergerschaft = $_POST['staatsbuergerschaft']; + $mitarbeiter->gebnation = $_POST['geburtsnation']; + $mitarbeiter->persnr = $_POST['personal_nr']; + $mitarbeiter->kurzbez = $_POST['kurzbezeichnung']; + if($_POST['beginndatum']!='') + $mitarbeiter->beginndatum = convertdate($_POST['beginndatum']); + else + $mitarbeiter->beginndatum = ''; + $mitarbeiter->stundensatz = $_POST['stundensatz']; + $mitarbeiter->habilitation = ($_POST['habilitation']=='true'?true:false); + $mitarbeiter->ausgeschieden = ($_POST['ausgeschieden']=='true'?true:false); + if($_POST['beendigungsdatum']!='') + $mitarbeiter->beendigungsdatum = convertdate($_POST['beendigungsdatum']); + else + $mitarbeiter->beendigungsdatum = ''; + $mitarbeiter->ausbildung = $_POST['ausbildung']; + $mitarbeiter->aktstatus = $_POST['aktstatus']; + $mitarbeiter->aktiv = $_POST['aktiv']; + $mitarbeiter->updatevon = $benutzer->variable->fas_id; + + if($mitarbeiter->save()) //Datensatz speichern + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich gespeichert'; + } + else + { + $return = 'false'; + $errormsg = $mitarbeiter->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum Speichern'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='delmitarbeiter') //Person und Mitarbeiter loeschen + { + /** + * Beim loeschen wird eine variable Anzahl an IDs uebergeben die Anzahl wird + * in $_POST['anz'] gespeichert die einzelnen IDS heissen dann x1, x2, x3, ... + */ + if($rechte->isBerechtigt('admin', 0, 'd') + || $rechte->isBerechtigt('mitarbeiter', 0, 'd')) + { + $errormsg = ''; + $mitarbeiter = new mitarbeiter($conn_fas); + $mitarbeiter->updatevon = $benutzer->variable->fas_id; + for($i=0;$i<$_POST['anz'];$i++) + { + if(!$mitarbeiter->delete($_POST['x'.$i])) + { + $var = 'x'.$i; + $errormsg .= "\n\rFehler beim loeschen des Datensatzes mit der ID ".$_POST[$var]." Meldung: ".$mitarbeiter->errormsg; + $return = 'false'; + } + } + if($errormsg=='') + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich gespeichert'; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum Löschen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='newmitarbeiter') //Neuen,leeren Mitarbeiterdatensatz anlegen + { + if($rechte->isBerechtigt('admin', 0, 'i') + || $rechte->isBerechtigt('mitarbeiter', 0, 'i')) + { + $mitarbeiter = new mitarbeiter($conn_fas); + $mitarbeiter->new=true; + $mitarbeiter->aktstatus=100; + $mitarbeiter->aktiv=true; + $mitarbeiter->staatsbuergerschaft ='A'; + $mitarbeiter->gebnation = 'A'; + $mitarbeiter->bismelden = true; + $mitarbeiter->ausbildung = 1; + $mitarbeiter->svnr = '0000000000'; + $mitarbeiter->updatevon = $benutzer->variable->fas_id; + $mitarbeiter->persnr = $mitarbeiter->getNextPersonalnr(); + + if($mitarbeiter->save()) + { + $return = 'true'; + $errormsg = $mitarbeiter->mitarbeiter_id; + //Funktion anlegen falls noetig + if(isset($_POST['art']) && $_POST['art']=='fix') //Fixangestellt - Echter Dienstvertrag + { + $fkt_obj = new funktion($conn_fas); + $fkt_obj->new=true; + $fkt_obj->mitarbeiter_id = $mitarbeiter->mitarbeiter_id; + $fkt_obj->studiensemester_id = $_POST['studiensemester_id']; + $fkt_obj->erhalter_id = 1; + $fkt_obj->studiengang_id = null; + $fkt_obj->fachbereich_id = null; + $fkt_obj->name = null; + $fkt_obj->funktion = null; + $fkt_obj->beschart1 = 3; + $fkt_obj->beschart2 = null; + $fkt_obj->verwendung = null; + $fkt_obj->hauptberuf = null; + $fkt_obj->hauptberuflich = true; + $fkt_obj->entwicklungsteam = false; + $fkt_obj->besonderequalifikation = 0; + $fkt_obj->ausmass = 0; + $fkt_obj->updatevon = $benutzer->variable->fas_id; + if($fkt_obj->save()) + { + $return = 'true'; + $errormsg = $mitarbeiter->mitarbeiter_id; + } + else + { + $return = 'false'; + $errormsg = 'funktion konnte nicht angelegt werden:'.$fkt_obj->errormsg; + } + } + elseif(isset($_POST['art']) && $_POST['art']=='frei') //Freier Mitarbeiter - Freier Dienstvertrag + { + $fkt_obj = new funktion($conn_fas); + $fkt_obj->new=true; + $fkt_obj->mitarbeiter_id = $mitarbeiter->mitarbeiter_id; + $fkt_obj->studiensemester_id = $_POST['studiensemester_id']; + $fkt_obj->erhalter_id = 1; + $fkt_obj->studiengang_id = null; + $fkt_obj->fachbereich_id = null; + $fkt_obj->name = null; + $fkt_obj->funktion = null; + $fkt_obj->beschart1 = 4; + $fkt_obj->beschart2 = null; + $fkt_obj->verwendung = null; + $fkt_obj->hauptberuf = null; + $fkt_obj->hauptberuflich = true; + $fkt_obj->entwicklungsteam = false; + $fkt_obj->besonderequalifikation = 0; + $fkt_obj->ausmass = 0; + $fkt_obj->updatevon = $benutzer->variable->fas_id; + if($fkt_obj->save()) + { + $return = 'true'; + $errormsg = $mitarbeiter->mitarbeiter_id; + } + else + { + $return = 'false'; + $errormsg = 'funktion konnte nicht angelegt werden:'.$fkt_obj->errormsg; + } + } + + } + else + { + $return = 'false'; + $errormsg = 'Datensatz konnte nicht angelegt werden: '.$mitarbeiter->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum einfuegen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='funktion') /***********FUNKTIONEN***********/ + { + //Speichert eine Funktion + if($rechte->isBerechtigt('admin', 0, 'i') + || $rechte->isBerechtigt('mitarbeiter', 0, 'i')) + { + //Parameter holen und zuweisen + $funktion_obj = new funktion($conn_fas); + $funktion_obj->new = ($_POST['new']=='true'?true:false); + $funktion_obj->funktion_id = $_POST['funktion_id']; + $funktion_obj->mitarbeiter_id = $_POST['mitarbeiter_id']; + $funktion_obj->studiensemester_id = $_POST['studiensemester_id']; + $funktion_obj->erhalter_id = $_POST['erhalter_id']; + $funktion_obj->studiengang_id = $_POST['studiengang_id']; + $funktion_obj->fachbereich_id = $_POST['fachbereich_id']; + $funktion_obj->name = $_POST['name']; + $funktion_obj->funktion = $_POST['funktion']; + $funktion_obj->beschart1 = $_POST['beschart1']; + $funktion_obj->beschart2 = $_POST['beschart2']; + $funktion_obj->verwendung = $_POST['verwendung']; + $funktion_obj->hauptberuf = $_POST['hauptberuf']; + $funktion_obj->hauptberuflich = ($_POST['hauptberuflich']=='true'?true:false); + $funktion_obj->entwicklungsteam = ($_POST['entwicklungsteam']=='true'?true:false); + $funktion_obj->besonderequalifikation = $_POST['qualifikation']; + $funktion_obj->ausmass = $_POST['ausmass']; + $funktion_obj->updatevon = $benutzer->variable->fas_id; + + if($funktion_obj->save()) //Funktion Speichern + { + $return = 'true'; + $errormsg = $funktion_obj->status; // aktstatus der Person nach dem Speichern + } + else + { + $return = 'false'; + $errormsg = $funktion_obj->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum einfuegen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='delfunktion') + { + /** + * Beim loeschen wird eine variable Anzahl an IDs uebergeben die Anzahl wird + * in $_POST['anz'] gespeichert die einzelnen IDS heissen dann x1, x2, x3, ... + */ + if($rechte->isBerechtigt('admin', 0, 'd') + || $rechte->isBerechtigt('mitarbeiter', 0, 'd')) + { + $errormsg = ''; + $funktion_obj = new funktion($conn_fas); + $funktion_obj->updatevon = $benutzer->variable->fas_id; + for($i=0;$i<$_POST['anz'];$i++) + { + if(!$funktion_obj->delete($_POST['x'.$i])) + { + $var = 'x'.$i; + $errormsg .= "\n\rFehler beim loeschen des Datensatzes mit der ID ".$_POST[$var]." Meldung: ".$funktion_obj->errormsg; + $return = 'false'; + } + } + if($errormsg=='') + { + $return = 'true'; + $errormsg = $funktion_obj->status; //aktstatus der Person nach dem loeschen + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum Löschen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='adresse') /***********Adressen***********/ + { + //Speichern eines Adressdatensatzes + if($rechte->isBerechtigt('admin', 0, 'i') + || $rechte->isBerechtigt('mitarbeiter', 0, 'i')) + { + $adresse = new adresse($conn_fas); + $adresse->adresse_id = $_POST['adress_id']; + $adresse->person_id = $_POST['person_id']; + $adresse->typ = $_POST['adresstyp']; + $adresse->name = $_POST['name']; + $adresse->nation = $_POST['nation']; + $adresse->new = ($_POST['new']=='true'?true:false); + $adresse->strasse = $_POST['strasse']; + $adresse->plz = $_POST['plz']; + $adresse->ort = $_POST['ort']; + $adresse->gemeinde = $_POST['gemeinde']; + $adresse->bismeldeadresse = ($_POST['bismeldeadresse']=='true'?true:false); + $adresse->zustelladresse = ($_POST['zustelladresse']=='true'?true:false); + $adresse->updatevon = $benutzer->variable->fas_id; + + if($adresse->save()) + { + $return = 'true'; + $errormsg = 'Datensatz wurde erfolgreich gespeichert'; + } + else + { + $return = 'false'; + $errormsg = $adresse->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum einfuegen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='deladresse') //Loescht Adressen + { + /** + * Beim loeschen wird eine variable Anzahl an IDs uebergeben die Anzahl wird + * in $_POST['anz'] gespeichert die einzelnen IDS heissen dann x1, x2, x3, ... + */ + if($rechte->isBerechtigt('admin', 0, 'd') + || $rechte->isBerechtigt('mitarbeiter', 0, 'd')) + { + $errormsg = ''; + $adresse = new adresse($conn_fas); + $adresse->updatevon = $benutzer->variable->fas_id; + for($i=0;$i<$_POST['anz'];$i++) + { + if(!$adresse->delete($_POST['x'.$i])) + { + $var = 'x'.$i; + $errormsg .= "\n\rFehler beim loeschen des Datensatzes mit der ID ".$_POST[$var]." Meldung: ".$adresse->errormsg; + $return = 'false'; + } + } + if($errormsg=='') + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich gespeichert'; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum Löschen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='email') /***********EMAIL***********/ + { + //Speichert eine Email + if($rechte->isBerechtigt('admin', 0, 'i') + || $rechte->isBerechtigt('mitarbeiter', 0, 'i')) + { + $email = new email($conn_fas); + $email->email_id = $_POST['email_id']; + $email->person_id = $_POST['person_id']; + $email->name = $_POST['name']; + $email->email = $_POST['email']; + $email->typ = $_POST['typ']; + $email->new = ($_POST['new']=='true'?true:false); + $email->zustelladresse = ($_POST['zustelladresse']=='true'?true:false); + $email->updatevon = $benutzer->variable->fas_id; + + if($email->save()) + { + $return = 'true'; + $errormsg = 'Datensatz wurde erfolgreich gespeichert'; + } + else + { + $return = 'false'; + $errormsg = $email->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum einfuegen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='delemail') //Loescht Emails + { + /** + * Beim loeschen wird eine variable Anzahl an IDs uebergeben die Anzahl wird + * in $_POST['anz'] gespeichert die einzelnen IDS heissen dann x1, x2, x3, ... + */ + if($rechte->isBerechtigt('admin', 0, 'd') + || $rechte->isBerechtigt('mitarbeiter', 0, 'd')) + { + $errormsg = ''; + $email = new email($conn_fas); + $email->updatevon = $benutzer->variable->fas_id; + for($i=0;$i<$_POST['anz'];$i++) + { + if(!$email->delete($_POST['x'.$i])) + { + $var = 'x'.$i; + $errormsg .= "\n\rFehler beim loeschen des Datensatzes mit der ID ".$_POST[$var]." Meldung: ".$email->errormsg; + $return = 'false'; + } + } + if($errormsg=='') + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich gespeichert'; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum Loeschen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='telefonnummer') /***********TELEFONNUMMER***********/ + { + //Speichert eine Telefonnummer + if($rechte->isBerechtigt('admin', 0, 'i') + || $rechte->isBerechtigt('mitarbeiter', 0, 'i')) + { + $telefon = new telefonnummer($conn_fas); + $telefon->telefonnummer_id = $_POST['telefonnummer_id']; + $telefon->person_id = $_POST['person_id']; + $telefon->name = $_POST['name']; + $telefon->nummer = $_POST['nummer']; + $telefon->typ = $_POST['typ']; + $telefon->new = ($_POST['new']=='true'?true:false); + $telefon->updatevon = $benutzer->variable->fas_id; + + if($telefon->save()) + { + $return = 'true'; + $errormsg = 'Datensatz wurde erfolgreich gespeichert'; + } + else + { + $return = 'false'; + $errormsg = $telefon->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum einfuegen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='deltelefonnummer') + { + /** + * Beim loeschen wird eine variable Anzahl an IDs uebergeben die Anzahl wird + * in $_POST['anz'] gespeichert die einzelnen IDS heissen dann x1, x2, x3, ... + */ + if($rechte->isBerechtigt('admin', 0, 'd') + || $rechte->isBerechtigt('mitarbeiter', 0, 'd')) + { + $errormsg = ''; + $telefon = new telefonnummer($conn_fas); + $telefon->updatevon = $benutzer->variable->fas_id; + for($i=0;$i<$_POST['anz'];$i++) + { + if(!$telefon->delete($_POST['x'.$i])) + { + $var = 'x'.$i; + $errormsg .= "\n\rFehler beim loeschen des Datensatzes mit der ID ".$_POST[$var]." Meldung: ".$telefon->errormsg; + $return = 'false'; + } + } + if($errormsg=='') + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich gespeichert'; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum Löschen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='bankverbindung') /***********BANKVERBINDUNG***********/ + { + //Speichert eine Bankverbindung + if($rechte->isBerechtigt('admin', 0, 'i') + || $rechte->isBerechtigt('mitarbeiter', 0, 'i')) + { + $bankverbindung = new bankverbindung($conn_fas); + $bankverbindung->bankverbindung_id = $_POST['bankverbindung_id']; + $bankverbindung->person_id = $_POST['person_id']; + $bankverbindung->name = $_POST['name']; + $bankverbindung->anschrift = $_POST['anschrift']; + $bankverbindung->blz = $_POST['blz']; + $bankverbindung->bic = $_POST['bic']; + $bankverbindung->kontonr = $_POST['kontonr']; + $bankverbindung->iban = $_POST['iban']; + $typ = ($_POST['verrechnungskonto']=='true'?10:0) + $_POST['typ']; + $bankverbindung->typ = $typ; + $bankverbindung->new = ($_POST['new']=='true'?true:false); + $bankverbindung->updatevon = $benutzer->variable->fas_id; + + if($bankverbindung->save()) + { + $return = 'true'; + $errormsg = 'Datensatz wurde erfolgreich gespeichert'; + } + else + { + $return = 'false'; + $errormsg = $bankverbindung->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum einfuegen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='delbankverbindung') + { + /** + * Beim loeschen wird eine variable Anzahl an IDs uebergeben die Anzahl wird + * in $_POST['anz'] gespeichert die einzelnen IDS heissen dann x1, x2, x3, ... + */ + if($rechte->isBerechtigt('admin', 0, 'd') + || $rechte->isBerechtigt('mitarbeiter', 0, 'd')) + { + $errormsg = ''; + $bankverbindung = new bankverbindung($conn_fas); + $bankverbindung->updatevon = $benutzer->variable->fas_id; + for($i=0;$i<$_POST['anz'];$i++) + { + if(!$bankverbindung->delete($_POST['x'.$i])) + { + $var = 'x'.$i; + $errormsg .= "\n\rFehler beim loeschen des Datensatzes mit der ID ".$_POST[$var]." Meldung: ".$bankverbindung->errormsg; + $return = 'false'; + } + } + if($errormsg=='') + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich gespeichert'; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung zum Löschen'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='lva_save') /*********** LEHRVERANSTALTUNGEN ***********/ + { + /** + * Speichert eine Lehreinheit + */ + + if(isset($_POST['studiengang_id']) && is_numeric($_POST['studiengang_id'])) + { + $qry = "SELECT kennzahl FROM studiengang WHERE studiengang_pk=".$_POST['studiengang_id']; + if($row=pg_fetch_object(pg_query($conn_fas,$qry))) + { + $studiengang = $row->kennzahl; + //Ueberpruefen der Berechtigung fuer diesen Studiengang + if($rechte->isBerechtigt('admin', $studiengang, 'u') + || $rechte->isBerechtigt('lva-verwaltung', $studiengang, 'u')) + { + $lva = new lehreinheit($conn_fas); + //Werte zuweisen + $lva->new=false; + $lva->lehreinheit_id = (isset($_POST['lehreinheit_id'])?urldecode($_POST['lehreinheit_id']):''); + $lva->studiengang_id = (isset($_POST['studiengang_id'])?urldecode($_POST['studiengang_id']):''); + $lva->studiensemester_id = (isset($_POST['studiensemester_id'])?urldecode($_POST['studiensemester_id']):''); + $lva->lehrveranstaltung_id = (isset($_POST['lehrveranstaltung_id'])?urldecode($_POST['lehrveranstaltung_id']):''); + $lva->fachbereich_id = (isset($_POST['fachbereich_id'])?urldecode($_POST['fachbereich_id']):''); + $lva->ausbildungssemester_id = (isset($_POST['ausbildungssemester_id'])?urldecode($_POST['ausbildungssemester_id']):''); + $lva->lehreinheit_fk = (isset($_POST['lehreinheit_fk'])?urldecode($_POST['lehreinheit_fk']):''); + $lva->lehrform_id = (isset($_POST['lehrform_id'])?urldecode($_POST['lehrform_id']):''); + $lva->gruppe_id = (isset($_POST['gruppe_id'])?urldecode($_POST['gruppe_id']):''); + $lva->nummer = (isset($_POST['nummer'])?urldecode($_POST['nummer']):''); + $lva->bezeichnung = (isset($_POST['bezeichnung'])?urldecode($_POST['bezeichnung']):''); + $lva->kurzbezeichnung = (isset($_POST['kurzbezeichnung'])?urldecode($_POST['kurzbezeichnung']):''); + $lva->semesterwochenstunden = (isset($_POST['semesterwochenstunden'])?urldecode($_POST['semesterwochenstunden']):''); + $lva->gesamtstunden = (isset($_POST['gesamtstunden'])?urldecode($_POST['gesamtstunden']):''); + $lva->wochenrythmus = (isset($_POST['wochenrythmus'])?urldecode($_POST['wochenrythmus']):''); + $lva->start_kw = (isset($_POST['kalenderwoche'])?urldecode($_POST['kalenderwoche']):''); + $lva->stundenblockung = (isset($_POST['stundenblockung'])?urldecode($_POST['stundenblockung']):''); + $lva->koordinator_id = (isset($_POST['koordinator_id'])?urldecode($_POST['koordinator_id']):''); + $lva->plankostenprolektor = (isset($_POST['plankostenprolektor'])?urldecode($_POST['plankostenprolektor']):''); + $lva->planfaktor = (isset($_POST['planfaktor'])?urldecode($_POST['planfaktor']):''); + $lva->planlektoren = (isset($_POST['planlektoren'])?urldecode($_POST['planlektoren']):''); + $lva->raumtyp_id = (isset($_POST['raumtyp_id'])?urldecode($_POST['raumtyp_id']):''); + $lva->raumtypalternativ_id = (isset($_POST['raumtypalternativ_id'])?urldecode($_POST['raumtypalternativ_id']):''); + $lva->bemerkungen = (isset($_POST['bemerkungen'])?urldecode($_POST['bemerkungen']):''); + + //Speichern + if($lva->save()) + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich gespeichert'; + } + else + { + $return = 'false'; + $errormsg = $lva->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung um diesen Datensatz zu ändern'; + } + } + else + { + $return = 'false'; + $errormsg = 'Studiengang konnte nicht ermittelt werden'; + } + } + else + { + $return = 'false'; + $errormsg = 'Fehlerhafte Parameteruebergabe'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='lva_delete') + { + /** + * Loescht eine Lehreinheit + */ + + if(isset($_POST['lehreinheit_id']) && is_numeric($_POST['lehreinheit_id'])) + { + $qry = "SELECT kennzahl FROM studiengang WHERE studiengang_pk = (SELECT studiengang_fk FROM lehreinheit WHERE lehreinheit_pk='".$_POST['lehreinheit_id']."')"; + if($row=pg_fetch_object(pg_query($conn_fas,$qry))) + { + $studiengang = $row->kennzahl; + //Ueberpruefen der Berechtigung fuer diesen Studiengang + if($rechte->isBerechtigt('admin', $studiengang, 'd') + || $rechte->isBerechtigt('lva-verwaltung', $studiengang, 'd')) + { + $lva = new lehreinheit($conn_fas); + + //Loeschen + if($lva->delete($_POST['lehreinheit_id'])) + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich gespeichert'; + } + else + { + $return = 'false'; + $errormsg = $lva->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung um diesen Datensatz zu loeschen'; + } + } + else + { + $return = 'false'; + $errormsg = 'Studiengang konnte nicht ermittelt werden'; + } + } + else + { + $return = 'false'; + $errormsg = 'Fehlerhafte Parameteruebergabe'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='lva_neu') + { + /** + * Loescht eine Lehreinheit + */ + + if(isset($_POST['lehrveranstaltung_id']) && is_numeric($_POST['lehrveranstaltung_id'])) + { + $qry = "SELECT kennzahl FROM studiengang WHERE studiengang_pk = (SELECT studiengang_fk FROM lehrveranstaltung WHERE lehrveranstaltung_pk='".$_POST['lehrveranstaltung_id']."')"; + if($row=pg_fetch_object(pg_query($conn_fas,$qry))) + { + $studiengang = $row->kennzahl; + //Ueberpruefen der Berechtigung fuer diesen Studiengang + if($rechte->isBerechtigt('admin', $studiengang, 'i') + || $rechte->isBerechtigt('lva-verwaltung', $studiengang, 'i')) + { + //LVA Laden + $lva = new lehrveranstaltung($conn_fas); + $lva->load($_POST['lehrveranstaltung_id']); + + //Daten Übernehmen + $lehreinheit = new lehreinheit($conn_fas); + $lehreinheit->new=true; + $lehreinheit->lehrveranstaltung_id = $_POST['lehrveranstaltung_id']; + $lehreinheit->studiengang_id = $lva->studiengang_id; + $lehreinheit->fachbereich_id = $lva->fachbereich_id; + $lehreinheit->ausbildungssemester_id = $lva->ausbildungssemester_id; + $lehreinheit->kurzbezeichnung = $lva->kurzbezeichnung; + $lehreinheit->bezeichnung = $lva->name; + $lehreinheit->studiensemester_id = $lva->studiensemester_id; + $lehreinheit->lehrform_id = 2; + $lehreinheit->gesamtstunden = 0; + $lehreinheit->faktor = 0; + $lehreinheit->wochenrythmus = 1; + $lehreinheit->start_kw = 0; + $lehreinheit->stundenblockung = 0; + $lehreinheit->planlektoren = 1; + + $lehreinheit->updatevon = $benutzer->variable->fas_id; + + //Speichern + if($lehreinheit->save()) + { + $return = 'true'; + $errormsg = $lehreinheit->lehreinheit_id; + } + else + { + $return = 'false'; + $errormsg = $lehreinheit->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung um diesen Datensatz zu loeschen'; + } + } + else + { + $return = 'false'; + $errormsg = 'Studiengang konnte nicht ermittelt werden'; + } + } + else + { + $return = 'false'; + $errormsg = 'Fehlerhafte Parameteruebergabe'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='lva_partizipierung') + { + /** + * Teilt eine Partizipierung zu + */ + + if(isset($_POST['quell_lehreinheit_id']) && is_numeric($_POST['quell_lehreinheit_id']) + && isset($_POST['ziel_lehreinheit_id']) && is_numeric($_POST['ziel_lehreinheit_id'])) + { + + $qry = "SELECT kennzahl FROM studiengang WHERE studiengang_pk = (SELECT studiengang_fk FROM lehreinheit WHERE lehreinheit_pk='".$_POST['quell_lehreinheit_id']."')"; + if($row=pg_fetch_object(pg_query($conn_fas,$qry))) + { + $studiengang = $row->kennzahl; + //Ueberpruefen der Berechtigung fuer diesen Studiengang + if($rechte->isBerechtigt('admin', $studiengang, 'u') + || $rechte->isBerechtigt('lva-verwaltung', $studiengang, 'u')) + { + $lva = new lehreinheit($conn_fas); + + if($lva->setPartizipierung($_POST['quell_lehreinheit_id'], $_POST['ziel_lehreinheit_id'])) + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich gespeichert'; + } + else + { + $return = 'false'; + $errormsg = $lva->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung und diese Aktion durchzufuehren'; + } + } + else + { + $return = 'false'; + $errormsg = 'Studiengang konnte nicht ermittelt werden'; + } + } + else + { + $return = 'false'; + $errormsg = 'Fehlerhafte Parameteruebergabe'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='lva_mitarbeiter_lehreinheit_zuteilung') + { + /** + * Speichert die Zuteilung eines Mitarbeiters zu einer Lehreinheit + */ + + //Ermitteln des Studienganges zu dem diese Zuteilung gehoert + if(isset($_POST['mitarbeiter_lehreinheit_id']) && is_numeric($_POST['mitarbeiter_lehreinheit_id'])) + { + $qry = "SELECT kennzahl FROM studiengang WHERE studiengang_pk = (SELECT studiengang_fk FROM mitarbeiter_lehreinheit JOIN lehreinheit ON (mitarbeiter_lehreinheit.lehreinheit_fk=lehreinheit_pk) WHERE mitarbeiter_lehreinheit_pk='".$_POST['mitarbeiter_lehreinheit_id']."')"; + if($row=pg_fetch_object(pg_query($conn_fas,$qry))) + { + $studiengang = $row->kennzahl; + //Ueberpruefen der Berechtigung fuer diesen Studiengang + if($rechte->isBerechtigt('admin', $studiengang, 'u') + || $rechte->isBerechtigt('lva-verwaltung', $studiengang, 'u')) + { + $lva = new lehreinheit($conn_fas); + //Werte zuweisen + $lva->new=false; + $lva->mitarbeiter_id = isset($_POST['mitarbeiter_id'])?$_POST['mitarbeiter_id']:''; + $lva->faktor = isset($_POST['faktor'])?$_POST['faktor']:''; + $lva->gesamtstunden_mitarbeiter = isset($_POST['gesamtstunden'])?$_POST['gesamtstunden']:''; + $lva->kosten = isset($_POST['kosten'])?$_POST['kosten']:''; + $lva->lehrfunktion_id = isset($_POST['lehrfunktion_id'])?$_POST['lehrfunktion_id']:''; + $lva->lehreinheit_fk = isset($_POST['lehreinheit_id'])?$_POST['lehreinheit_id']:''; + $lva->updatevon = $benutzer->variable->fas_id; + $lva->mitarbeiter_lehreinheit_id = isset($_POST['mitarbeiter_lehreinheit_id'])?$_POST['mitarbeiter_lehreinheit_id']:''; + + //Speichern + if($lva->save_zuteilung()) + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich gespeichert'; + } + else + { + $return = 'false'; + $errormsg = $lva->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung um diesen Datensatz zu ändern'; + } + } + else + { + $return = 'false'; + $errormsg = 'Studiengang konnte nicht ermittelt werden'.$qry; + } + } + else + { + $return = 'false'; + $errormsg = 'Fehlerhafte Parameteruebergabe'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='lva_mitarbeiter_lehreinheit_add') + { + /** + * Fuegt einen Dummy Lektor zu einer Lehreinheit hinzu + */ + + //Ermitteln des Studienganges zu dem diese Zuteilung gehoert + if(isset($_POST['lehreinheit_id']) && is_numeric($_POST['lehreinheit_id'])) + { + $qry = "SELECT kennzahl FROM studiengang WHERE studiengang_pk = (SELECT studiengang_fk FROM lehreinheit WHERE lehreinheit_pk='".$_POST['lehreinheit_id']."')"; + if($row=pg_fetch_object(pg_query($conn_fas,$qry))) + { + $studiengang = $row->kennzahl; + //Ueberpruefen der Berechtigung fuer diesen Studiengang + if($rechte->isBerechtigt('admin', $studiengang, 'i') + || $rechte->isBerechtigt('lva-verwaltung', $studiengang, 'i')) + { + $lva = new lehreinheit($conn_fas); + //Werte zuweisen + $lva->new=true; + $lva->mitarbeiter_id = 2701; //= Dr. Dieter Dummy + $lva->faktor = 1; + $lva->kosten = 0; + $lva->gesamtstunden_mitarbeiter = 0; + $lva->lehrfunktion_id = 2; + $lva->lehreinheit_fk = isset($_POST['lehreinheit_id'])?$_POST['lehreinheit_id']:''; + $lva->updatevon = $benutzer->variable->fas_id; + + //Speichern + if($lva->save_zuteilung()) + { + $return = 'true'; + $errormsg = $lva->mitarbeiter_lehreinheit_id; + } + else + { + $return = 'false'; + $errormsg = $lva->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung um diesen Datensatz zu ändern'; + } + } + else + { + $return = 'false'; + $errormsg = 'Studiengang konnte nicht ermittelt werden'; + } + } + else + { + $return = 'false'; + $errormsg = 'Fehlerhafte Parameteruebergabe'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='lva_mitarbeiter_lehreinheit_del') + { + /** + * Loescht die zuteilung eines Lektors zu einer Lehrveranstaltung + */ + + //Ermitteln des Studienganges zu dem diese Zuteilung gehoert + if(isset($_POST['mitarbeiter_lehreinheit_id']) && is_numeric($_POST['mitarbeiter_lehreinheit_id'])) + { + $qry = "SELECT kennzahl FROM studiengang WHERE studiengang_pk = (SELECT studiengang_fk FROM mitarbeiter_lehreinheit JOIN lehreinheit ON (mitarbeiter_lehreinheit.lehreinheit_fk=lehreinheit_pk) WHERE mitarbeiter_lehreinheit_pk='".$_POST['mitarbeiter_lehreinheit_id']."')"; + if($row=pg_fetch_object(pg_query($conn_fas,$qry))) + { + $studiengang = $row->kennzahl; + //Ueberpruefen der Berechtigung fuer diesen Studiengang + if($rechte->isBerechtigt('admin', $studiengang, 'u') + || $rechte->isBerechtigt('lva-verwaltung', $studiengang, 'u')) + { + $lva = new lehreinheit($conn_fas); + + //Loeschen des DS + if($lva->delete_zuteilung($_POST['mitarbeiter_lehreinheit_id'])) + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich gespeichert'; + } + else + { + $return = 'false'; + $errormsg = $lva->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung um diesen Datensatz zu ändern'; + } + } + else + { + $return = 'false'; + $errormsg = 'Studiengang konnte nicht ermittelt werden'; + } + } + else + { + $return = 'false'; + $errormsg = 'Fehlerhafte Parameteruebergabe'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='lva_mitarbeiter_lehreinheit_auswahladd') + { + /** + * Fuegt eine Funktion zu einem Mitarbeiter hinzu + */ + + //Ermitteln des Studienganges zu dem diese Zuteilung gehoert + if(isset($_POST['lehreinheit_id']) && is_numeric($_POST['lehreinheit_id']) + && isset($_POST['mitarbeiter_id']) && is_numeric($_POST['mitarbeiter_id']) ) + { + $qry = "SELECT kennzahl, studiengang_pk, fachbereich_fk FROM studiengang JOIN lehreinheit ON (studiengang_fk=studiengang_pk) WHERE lehreinheit_pk = '".$_POST['lehreinheit_id']."'"; + if($row=pg_fetch_object(pg_query($conn_fas,$qry))) + { + $studiengang_kz = $row->kennzahl; + $studiengang_id = $row->studiengang_pk; + $fachbereich_id = $row->fachbereich_fk; + $studiensemester_id = getStudiensemesterIdFromName($conn_fas, $benutzer->variable->semester_aktuell); + //Ueberpruefen der Berechtigung fuer diesen Studiengang + if($rechte->isBerechtigt('admin', $studiengang_kz, 'u') + || $rechte->isBerechtigt('lva-verwaltung', $studiengang_kz, 'u')) + { + $fkt = new funktion($conn_fas); + //Nachschauen ob diese Funktion bereits existiert + if($fkt->FunktionExists($_POST['mitarbeiter_id'], $studiengang_id, $fachbereich_id, $studiensemester_id, 1)) + { + $return = 'false'; + $errormsg = 'Dieser Lektor befindet sich bereits in der Liste'; + } + else + { + if($fkt->errormsg!='') //Falls ein Fehler aufgetreten ist + { + $return = 'false'; + $errormsg = $fkt->errormsg; + } + else + { + //Funktion anlegen + $fkt->new = true; + $fkt->mitarbeiter_id = $_POST['mitarbeiter_id']; + $fkt->studiensemester_id = $studiensemester_id; + $fkt->studiengang_id = $studiengang_id; + $fkt->fachbereich_id = $fachbereich_id; + $fkt->funktion = 1; //Lektor + $fkt->erhalter_id = 1; //TW + + if($fkt->save()) + { + $return = 'true'; + $errormsg = 'Datensatz erfolgreich angelegt'; + } + else + { + $return = 'false'; + $errormsg = $fkt->errormsg; + } + + } + } + } + else + { + $return = 'false'; + $errormsg = 'Sie haben keine Berechtigung um diesen Datensatz zu ändern'; + } + } + else + { + $return = 'false'; + $errormsg = 'Studiengang konnte nicht ermittelt werden'; + } + } + else + { + $return = 'false'; + $errormsg = 'Fehlerhafte Parameteruebergabe'; + } + } + elseif(isset($_POST['type']) && $_POST['type']=='variablechange') /**********************SONSTIGES*****************/ + { + /** + * Aendert die Variable Studiensemester + */ + if(isset($_POST['stsem'])) + { + if($benutzer->setVariableStudiensemester($user,$_POST['stsem'])) + { + $return = 'true'; + $errormsg = getStudiensemesterIdFromName($conn_fas, $_POST['stsem']); + } + else + { + $return = 'false'; + $errormsg = $benutzer->errormsg; + } + } + else + { + $return = 'false'; + $errormsg = 'Falsche Paramenteruebergabe'; + } + } + } +?> + + + + ]]> + + + + \ No newline at end of file diff --git a/rdf/fas/email.rdf.php b/rdf/fas/email.rdf.php new file mode 100644 index 000000000..ea9f5bb8d --- /dev/null +++ b/rdf/fas/email.rdf.php @@ -0,0 +1,86 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include_once('../../include/fas/email.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$rdf_url='http://www.technikum-wien.at/email'; + +?> + + + + + +load_pers($pers_id); + + + foreach ($emailDAO->result as $email) + { + ?> + + + email_id; ?> + person_id; ?> + email; ?>]]> + name; ?> + typ; ?> + zustelladresse?'Ja':'Nein'); ?> + + + load($email_id); +?> + + + email_id; ?> + person_id; ?> + email; ?>]]> + name; ?> + typ; ?> + zustelladresse?'Ja':'Nein'); ?> + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/fachbereich.rdf.php b/rdf/fas/fachbereich.rdf.php new file mode 100644 index 000000000..c6db9030c --- /dev/null +++ b/rdf/fas/fachbereich.rdf.php @@ -0,0 +1,54 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include('../../include/fas/fachbereich.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$rdf_url='http://www.technikum-wien.at/fachbereich'; + +?> + + + + + +getAll(); + + foreach ($fachbereichDAO->result as $fachbereich) + { + ?> + + + fachbereich_id; ?> + name; ?> + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/funktion_id.rdf.php b/rdf/fas/funktion_id.rdf.php new file mode 100644 index 000000000..8061da81d --- /dev/null +++ b/rdf/fas/funktion_id.rdf.php @@ -0,0 +1,80 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include('../../include/fas/studiensemester.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$rdf_url='http://www.technikum-wien.at/funktion_id'; + +?> + + + + + + + + + 0 + Mitarbeiter + + + + + 1 + Lektor + + + + + 2 + Fachbereichskoordinator + + + + + 3 + Assistenz + + + + + 4 + Rektor + + + + + 5 + Studiengangsleiter + + + + + 6 + Fachbereichsleiter + + + + + + \ No newline at end of file diff --git a/rdf/fas/funktionen.rdf.php b/rdf/fas/funktionen.rdf.php new file mode 100644 index 000000000..95b4f08ef --- /dev/null +++ b/rdf/fas/funktionen.rdf.php @@ -0,0 +1,255 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include('../../include/functions.inc.php'); +include('../../include/fas/funktion.class.php'); +include('../../include/fas/studiensemester.class.php'); +include('../../include/fas/studiengang.class.php'); +include('../../include/fas/fachbereich.class.php'); +include('../../include/fas/benutzer.class.php'); + + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +if (!$conn_calva = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$user = get_uid(); + +$rdf_url='http://www.technikum-wien.at/funktionen'; + +function addCDATA($str) +{ + return ($str==' '?' ':''); +} +?> + + + + + +loadVariables($user)) + die("error:".$benutzer->errormsg); + + $stsem = $benutzer->variable->semester_aktuell; + + $qry = "SELECT studiensemester_pk from studiensemester where art="; + if(substr($stsem,0,2)=='WS') + $qry .="1"; + else + $qry .="2"; + $qry .= " AND jahr="; + $qry .= substr($stsem,2,4); + $stsem_id=''; + + if($result=pg_query($conn,$qry)) + if($row=pg_fetch_object($result)) + $stsem_id=$row->studiensemester_pk; + } + else + $stsem_id=''; + + // Funktionen holen + $funktionenDAO=new funktion($conn); + $funktionenDAO->load_pers($mitarbeiter_id, $stsem_id); + + foreach ($funktionenDAO->result as $funktionen) + { + + if($leerzeichencodierung) + { + if ($funktion->studiensemester_id=='') $funktion->studiensemester_id=' '; + if ($funktion->studiengang_id=='') $funktion->studiengang_id=' '; + if ($funktion->studiengang_id=='') $funktion->studiengang_id=' '; + if ($funktion->fachbereich_id=='') $funktion->fachbereich_id=' '; + if ($funktion->name=='') $funktion->name=' '; + if ($funktion->funktion=='') $funktion->funktion=' '; + if ($funktion->beschart1=='') $funktion->beschart1=' '; + if ($funktion->beschart2='') $funktion->beschart2=' '; + if ($funktion->verwendung='') $funktion->verwendung=' '; + if ($funktion->hauptberuf='') $funktion->hauptberuf=' '; + if ($funktion->hauptberuflich='') $funktion->hauptberuflich=' '; + if ($funktion->entwicklungsteam='') $funktion->entwicklungsteam=' '; + if ($funktion->besonderequalifikation='') $funktion->besonderequalifikation=' '; + if ($funktion->ausmass='') $funktion->ausmass=' '; + + } +?> + + + funktion_id; ?> + mitarbeiter_id; ?> + studiensemester_id; ?> +load($funktionen->studiensemester_id)) + echo $stsem_obj->errormsg; + $bezeichnung = ($stsem_obj->art=='1'?'WS':'SS').$stsem_obj->jahr; + if($leerzeichencodierung && $bezeichnung =='') + $bezeichnung = ' '; +?> + + erhalter_id=='1'?'Technikum Wien':'unbekannt'); ?> + studiengang_id; ?> +load($funktionen->studiengang_id); + $bezeichnung = $stg_obj->kuerzel; + if($stg_obj->studiengangsart==1) + $bezeichnung = '(B)'.$bezeichnung; + elseif($stg_obj->studiengangsart==2) + $bezeichnung = '(M)'.$bezeichnung; + elseif($stg_obj->studiengangsart==3) + $bezeichnung = '(D)'.$bezeichnung; + if($leerzeichencodierung && $bezeichnung =='') + $bezeichnung = ' '; +?> + + fachbereich_id; ?> +load($funktionen->fachbereich_id); + $bezeichnung = $fachb_obj->name; + if($leerzeichencodierung && $bezeichnung =='') + $bezeichnung = ' '; +?> + + name; ?> + funktion; ?> +getNameFunktion($funktionen->funktion); + if($leerzeichencodierung && $bezeichnung =='') + $bezeichnung = ' '; +?> + + beschart1; ?> +getNameBeschart1($funktionen->beschart1); + if($leerzeichencodierung && $bezeichnung =='') + $bezeichnung = ' '; +?> + + beschart2; ?> +getNameBeschart2($funktionen->beschart2); + if($leerzeichencodierung && $bezeichnung =='') + $bezeichnung = ' '; +?> + + verwendung; ?> +getNameVerwendung($funktionen->verwendung); + if($leerzeichencodierung && $bezeichnung =='') + $bezeichnung = ' '; +?> + + hauptberuf; ?> +getNameHauptberuf($funktionen->hauptberuf); + if($leerzeichencodierung && $bezeichnung =='') + $bezeichnung = ' '; +?> + + hauptberuflich?'Ja':'Nein'); ?> + entwicklungsteam?'Ja':'Nein'); ?> + besonderequalifikation; ?> +getNameBesonderequalifikation($funktionen->besonderequalifikation); + if($leerzeichencodierung && $bezeichnung =='') + $bezeichnung = ' '; +?> + + ausmass; ?> +getNameAusmass($funktionen->ausmass); + if($leerzeichencodierung && $bezeichnung =='') + $bezeichnung = ' '; +?> + + + +load($funktion_id); + ?> + + + funktion_id; ?> + mitarbeiter_id; ?> + studiensemester_id; ?> + erhalter_id; ?> + studiengang_id; ?> + fachbereich_id; ?> + name; ?> + funktion; ?> + beschart1; ?> + beschart2; ?> + verwendung; ?> + hauptberuf; ?> + hauptberuflich?'Ja':'Nein'); ?> + entwicklungsteam?'Ja':'Nein'); ?> + besonderequalifikation; ?> + ausmass; ?> + + + + + \ No newline at end of file diff --git a/rdf/fas/generate_kuerzel.rdf.php b/rdf/fas/generate_kuerzel.rdf.php new file mode 100644 index 000000000..dddcaf306 --- /dev/null +++ b/rdf/fas/generate_kuerzel.rdf.php @@ -0,0 +1,155 @@ +'; + + // Clean stuff from a string + function clean_string($string) + { + $trans = array("ä" => "ae", + "Ä" => "Ae", + "ö" => "oe", + "Ö" => "Oe", + "ü" => "ue", + "Ü" => "Ue", + "á" => "a", + "à" => "a", + "é" => "e", + "è" => "e", + "ó" => "o", + "ò" => "o", + "í" => "i", + "ì" => "i", + "ú" => "u", + "ù" => "u", + "ß" => "ss"); + $string = strtr($string, $trans); + return ereg_replace("[^a-zA-Z0-9]", "", $string); + //[:space:] + } + + $return=false; + $msg='unbekannter Fehler'; + + //Connection zu FAS DB herstellen + if(!$conn = pg_connect(CONN_STRING_FAS)) + { + $return = 'false'; + $msg = 'Datenbankverbindung konnte nicht hergestellt werden'; + } + + if(isset($_GET['type'])) + $type=$_GET['type']; + else + $type=null; + + if(isset($_GET['vorname'])) + $vorname = $_GET['vorname']; + else + $vorname = null; + + if(isset($_GET['nachname'])) + $nachname = $_GET['nachname']; + else + $nachname = null; + + if($type!=null && $vorname!=null && $nachname!=null) + { + if($type=='kurzbz') + { + $kurzbz=''; + $mitarbeiter = new mitarbeiter($conn); + $nachname = clean_string($nachname); + $vorname = clean_string($vorname); + for($nn=6,$vn=2;$nn!=0;$nn--,$vn++) + { + $kurzbz = substr($nachname,0,$nn); + $kurzbz .= substr($vorname,0,$vn); + + if(!$mitarbeiter->kurzbz_exists($kurzbz)) + if($mitarbeiter->errormsg=='') + break; + } + + if($mitarbeiter->kurzbz_exists($kurzbz)) + { + $return = 'false'; + $msg = 'Es konnte keine Kurzbezeichnung ermittelt werden'; + } + else + { + $return = 'true'; + $msg = $kurzbz; + } + } + if($type=='uid') + { + $return = 'true'; + $nachname = strtolower(clean_string($nachname)); + $vorname = strtolower(clean_string($vorname)); + $uid=''; + $mitarbeiter = new mitarbeiter($conn); + + for($nn=8,$vn=0;$nn!=0;$nn--,$vn++) + { + $uid = substr($nachname,0,$nn); + $uid .= substr($vorname,0,$vn); + + if(!$mitarbeiter->uid_exists($uid)) + if($mitarbeiter->errormsg=='') + break; + //echo "
    $uid"; + } + + if($mitarbeiter->uid_exists($uid)) + { + $return = 'false'; + $msg = 'Es konnte keine UID ermittelt werden'; + } + else + { + $return = 'true'; + $msg = $uid; + } + } + } + else + { + $return = false; + $msg = 'Fehler bei der Parameteruebergabe'; + } + + $rdf_url='http://www.technikum-wien.at/generate_kurzbz'; +?> + + + + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/gruppen.rdf.php b/rdf/fas/gruppen.rdf.php new file mode 100644 index 000000000..22781399a --- /dev/null +++ b/rdf/fas/gruppen.rdf.php @@ -0,0 +1,82 @@ +'; +// DAO +require('../../vilesci/config.inc.php'); +require('../../include/fas/gruppe.class.php'); +require('../../include/fas/benutzer.class.php'); +require('../../include/functions.inc.php'); +require('../../include/fas/functions.inc.php'); + +// Datenbank Verbindung +if (!$conn = pg_pconnect(CONN_STRING_FAS)) + die('Es konnte keine Verbindung zum Server aufgebaut werden!'); + +if(!$conn_vilesci = pg_pconnect(CONN_STRING)) + die('Es konnte keine Verbindung zur Datenbank hergestellt werden!'); + +$rdf_url='http://www.technikum-wien.at/gruppen'; + +$user = get_uid(); +$benutzer = new benutzer($conn_vilesci); +if(!$benutzer->loadVariables($user)) + die($benutzer->errormsg); + +?> + + + + + +load_gruppen($_GET['stg'], getStudiensemesterIdFromName($conn, $benutzer->variable->semester_aktuell), $_GET['ausbsem']); + $arr = array(); + foreach ($gruppen_obj->result as $grp) + { + $arr['id'][] = $grp->gruppe_id; + $arr['fullname'][] = $grp->fullname; + } + if(isset($arr['id'])) + { + array_multisort($arr['fullname'],$arr['id']); + for($i=0;$i + + + + + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/hauptberuf.rdf.php b/rdf/fas/hauptberuf.rdf.php new file mode 100644 index 000000000..f00a6dc07 --- /dev/null +++ b/rdf/fas/hauptberuf.rdf.php @@ -0,0 +1,114 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); + +$rdf_url='http://www.technikum-wien.at/hauptberuf'; + +?> + + + + + + + + + 0 + Universität + + + + + 1 + Fachhochschule + + + + + 2 + Andere postsekundäre Bildungseinrichtung + + + + + 3 + Allgemeinbildende höhere Schule + + + + + 4 + Berufsbildende höhere Schule + + + + + 5 + Andere Schule + + + + + 6 + Öffentlicher Sektor + + + + + 7 + Unternehmenssektor + + + + + 8 + Freiberuflich tätig + + + + + 9 + Privater gemeinnütziger Sektor + + + + + 10 + Ausserhochschulische Forschungseinrichtung + + + + + 11 + Internationale Organisation + + + + + 12 + Sonstiges + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/lehreinheiten.rdf.php b/rdf/fas/lehreinheiten.rdf.php new file mode 100644 index 000000000..3f3aa5d15 --- /dev/null +++ b/rdf/fas/lehreinheiten.rdf.php @@ -0,0 +1,177 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include('../../include/functions.inc.php'); +include('../../include/fas/functions.inc.php'); +include('../../include/fas/benutzer.class.php'); +include('../../include/fas/lehreinheit.class.php'); +include('../../include/fas/raumtyp.class.php'); + +error_reporting(E_ALL); +ini_set('display_errors','1'); +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +if (!$conn_fas = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$studiengang_id = isset($_GET['studiengang_id'])?$_GET['studiengang_id']:''; +$lehreinheit_id = isset($_GET['lehreinheit_id'])?$_GET['lehreinheit_id']:''; +$gruppe_id = isset($_GET['gruppe_id'])?$_GET['gruppe_id']:''; + +$user = get_uid(); +$benutzer = new benutzer($conn); +if(!$benutzer->loadVariables($user)) + die("error:".$benutzer->errormsg); + +// LVAs holen +$lvaDAO=new lehreinheit($conn_fas); +if($lehreinheit_id!='') +{ + if(!$lvaDAO->getLehreinheiten(null,null,null,$lehreinheit_id)) + die("error:".$lvaDAO->errormsg); +} +elseif($gruppe_id!='') +{ + if(!$lvaDAO->getLehreinheitenfromGruppe($gruppe_id, getStudiensemesterIdFromName($conn_fas, $benutzer->variable->semester_aktuell))) + die("error:".$lvaDAO->errormsg); +} +else +{ + if(!$lvaDAO->getLehreinheiten($studiengang_id, null, getStudiensemesterIdFromName($conn_fas, $benutzer->variable->semester_aktuell),null,true)) + die("error:".$lvaDAO->errormsg); +} + +$lehreinheiten = $lvaDAO->result; +$raumtyp_obj = new raumtyp($conn_fas); + +$rdf_url='http://www.technikum-wien.at/lehreinheiten'; + +?> + + + +lehreinheit_fk; + $currentLPK=$lva->lehreinheit_id; + $descr.=" + lehreinheit_id."\" about=\"".$rdf_url.'/'.$lva->lehreinheit_id."\" > + ".$lva->lehreinheit_id." + ".$lva->studiengang_id." + studiengang_kurzbz."]]> + ".$lva->studiensemester_id." + ".$lva->studiensemester_kurzbz." + ".$lva->lehrveranstaltung_id." + ".$lva->fachbereich_id." + fachbereich_bezeichnung."]]> + ".$lva->ausbildungssemester_id." + ".$lva->ausbildungssemester_semester." + ".$lva->ausbildungssemester_kurzbz." + ".$lva->lehreinheit_fk." + ".$lva->lehrform_id." + ".$lva->lehrform_kurzbz." + ".$lva->gruppe_id." + ".$lva->gruppe_kurzbz." + ".$lva->nummer." + bezeichnung."]]> + kurzbezeichnung."]]> + ".$lva->semesterwochenstunden." + ".$lva->gesamtstunden." + ".$lva->plankostenprolektor." + ".$lva->planfaktor." + ".$lva->planlektoren." + ".$lva->raumtyp_id.""; + if($raumtyp_obj->load($lva->raumtyp_id)) + $bezeichnung = $raumtyp_obj->bezeichnung; + else + $bezeichnung = ''; + $descr.=" + + ".$lva->raumtypalternativ_id.""; + if($raumtyp_obj->load($lva->raumtypalternativ_id)) + $bezeichnung = $raumtyp_obj->bezeichnung; + else + $bezeichnung = ''; + $descr.=" + + bemerkungen."]]> + ".$lva->wochenrythmus." + ".$lva->start_kw." + ".$lva->stundenblockung." + ".$lva->koordinator_id." + ".$lva->koordinator_nachname." + ".$lva->koordinator_vorname." + ".$lva->updateamum." + ".$lva->updatevon." + + "; + + if($currentLFK!=0 && $currentLFK!=-1) + { + $hier_arr[$currentLFK][] = $currentLPK; + } + else + { + if(!array_key_exists($currentLPK,$hier_arr)) + $hier_arr[$currentLPK]=''; + } + } + + foreach ($hier_arr as $hkey=>$hval) + { + if(is_array($hier_arr[$hkey])) + { + $hier.=" + + "; + foreach ($hier_arr[$hkey] as $elem) + $hier .= " + "; + $hier.= " + + "; + } + else + $hier.=" + "; + } + + $hier=" + ".$hier." + "; + echo $descr; + echo $hier; +} +?> + + + diff --git a/rdf/fas/lehrform.rdf.php b/rdf/fas/lehrform.rdf.php new file mode 100644 index 000000000..a9a64c3d7 --- /dev/null +++ b/rdf/fas/lehrform.rdf.php @@ -0,0 +1,53 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include('../../include/fas/lehrform.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$rdf_url='http://www.technikum-wien.at/lehrform'; + +?> + + + + + +getAll(); + + foreach ($lehrformDAO->result as $lehrform) + { + ?> + + + lehrform_id; ?> + bezeichnung; ?> + kurzbezeichnung; ?> + standardfaktor; ?> + + + + + \ No newline at end of file diff --git a/rdf/fas/lehrveranstaltungen.rdf.php b/rdf/fas/lehrveranstaltungen.rdf.php new file mode 100644 index 000000000..7c1ff14c4 --- /dev/null +++ b/rdf/fas/lehrveranstaltungen.rdf.php @@ -0,0 +1,95 @@ +'; +// DAO +error_reporting(E_ALL); +ini_set('display_errors','1'); + +require('../../vilesci/config.inc.php'); +require('../../include/fas/lehrveranstaltung.class.php'); +require('../../include/functions.inc.php'); +require('../../include/fas/benutzer.class.php'); +require('../../include/fas/functions.inc.php'); +require('../../include/fas/fachbereich.class.php'); +require('../../include/fas/ausbildungssemester.class.php'); + +// Datenbank Verbindung +if (!$conn_fas = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +if (!$conn = @pg_pconnect(CONN_STRING)) +$error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$studiengang_id = isset($_GET['studiengang_id'])?$_GET['studiengang_id']:''; +$ausbildungssemester_id = isset($_GET['ausbildungssemester_id'])?$_GET['ausbildungssemester_id']:null; + +$user = get_uid(); +$benutzer = new benutzer($conn); +$benutzer->loadVariables($user); +$studiensemester_id = getStudiensemesterIdFromName($conn_fas, $benutzer->variable->semester_aktuell); + +$rdf_url='http://www.technikum-wien.at/lehrveranstaltung'; +?> + + + + + +load_lva($studiengang_id, $studiensemester_id, $ausbildungssemester_id); + + foreach ($lehrveranstaltungDAO->result as $lehrveranstaltung) + { + ?> + + + lehrveranstaltung_id; ?> + art; ?> + ausbildungssemester_id; ?> +load($lehrveranstaltung->ausbildungssemester_id); +?> + name; ?> + beschreibung; ?> + ectspunkte; ?> + fachbereich_id; ?> +load($lehrveranstaltung->fachbereich_id); +?> + name; ?> + kategorie; ?> + kurzbezeichnung; ?> + name; ?> + notenlektor_id; ?> + nummer; ?> + nummerintern; ?> + sortierung; ?> + studentenwochenstunden; ?> + studiengang_id; ?> + studiensemester_id; ?> + updateamum; ?> + updatevon; ?> + + + + + \ No newline at end of file diff --git a/rdf/fas/mitarbeiter.rdf.php b/rdf/fas/mitarbeiter.rdf.php new file mode 100644 index 000000000..dc64b9646 --- /dev/null +++ b/rdf/fas/mitarbeiter.rdf.php @@ -0,0 +1,209 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include_once('../../include/fas/person.class.php'); +include_once('../../include/fas/mitarbeiter.class.php'); +require('../../include/fas/benutzer.class.php'); +require('../../include/fas/functions.inc.php'); +require('../../include/functions.inc.php'); +$error_msg=''; +// Datenbank Verbindung + if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + + if(!$conn_vilesci = @pg_pconnect(CONN_STRING)) + $error_msg.='Es konnte keine Verbindung zum Server aufgebaut werden!'; +/** + * Fuegt CDATA String hinzu falls String nicht leerzeichencodiert ist + */ +function addCDATA($str) +{ + return ($str==' '?' ':''); +} + +function convdate($date) +{ + list($y,$m,$d) = explode('-',$date); + return $d.'.'.$m.'.'.$y; +} + +//Parameter holen +if (isset($_GET['mitarbeiter_id'])) + $mitarbeiter_id = $_GET['mitarbeiter_id']; +else + $mitarbeiter_id=null; + +if (isset($_GET['fix'])) + $fix = $_GET['fix']; +else + $fix=null; + +if (isset($_GET['stgl'])) + $stgl = $_GET['stgl']; +else + $stgl=null; + +if (isset($_GET['fbl'])) + $fbl = $_GET['fbl']; +else + $fbl=null; + +if (isset($_GET['aktiv'])) + $aktiv = $_GET['aktiv']; +else + $aktiv=null; + +if (isset($_GET['karenziert'])) + $karenziert = $_GET['karenziert']; +else + $karenziert=null; + +if (isset($_GET['ausgeschieden'])) + $ausgeschieden = $_GET['ausgeschieden']; +else + $ausgeschieden=null; + +if (isset($_GET['leerzeichencodierung'])) + $leerzeichencodierung=true; +else + $leerzeichencodierung=false; + +$user = get_uid(); +$benutzer = new benutzer($conn_vilesci); +if(!$benutzer->loadVariables($user)) + die($benutzer->errormsg); + +// Mitarbeiter holen +$mitarbeiterDAO=new mitarbeiter($conn); +$mitarbeiterDAO->getMitarbeiter($mitarbeiter_id, $fix, $stgl, $fbl, $aktiv, $karenziert, $ausgeschieden,false,getStudiensemesterIdFromName($conn, $benutzer->variable->semester_aktuell)); + +$rdf_url='http://www.technikum-wien.at/mitarbeiter'; + +?> + + + + + +result as $mitarbeiter) +{ + //if ($mitarbeiter->titelpre=='') $mitarbeiter->titelpre='​'; + //Konvertierung der Leerzeichen damit die Sortierung funktioniert + //Wird nur konvertier wenn die Daten in den tree geladen werden + //Nicht wenn die Details fuer einen Mitarbeiter geladen werden + //Funktioniert NICHT zusammen mit CDATA -> addCDATA() verwenden + if($leerzeichencodierung) + { + if ($mitarbeiter->familienname=='') $mitarbeiter->familienname=' '; + if ($mitarbeiter->vorname=='') $mitarbeiter->vorname=' '; + if ($mitarbeiter->vornamen=='') $mitarbeiter->vornamen=' '; + if ($mitarbeiter->anrede=='') $mitarbeiter->anrede=' '; + if ($mitarbeiter->geschlecht=='') $mitarbeiter->geschlecht=' '; + if ($mitarbeiter->gebort=='') $mitarbeiter->gebort=' '; + if ($mitarbeiter->staatsbuergerschaft=='') $mitarbeiter->staatsbuergerschaft=' '; + if ($mitarbeiter->familienstand=='') $mitarbeiter->familienstand=' '; + if ($mitarbeiter->svnr=='') $mitarbeiter->svnr=' '; + if ($mitarbeiter->anzahlderkinder=='') $mitarbeiter->anzahlderkinder=' '; + if ($mitarbeiter->ersatzkennzeichen=='') $mitarbeiter->ersatzkennzeichen=' '; + if ($mitarbeiter->bemerkung=='') $mitarbeiter->bemerkung=' '; + if ($mitarbeiter->aktstatus=='') $mitarbeiter->aktstatus=' '; + if ($mitarbeiter->titelpost=='') $mitarbeiter->titelpost=' '; + if ($mitarbeiter->titelpre=='') $mitarbeiter->titelpre=' '; + if ($mitarbeiter->uid=='') $mitarbeiter->uid=' '; + if ($mitarbeiter->gebnation=='') $mitarbeiter->gebnation=' '; + if ($mitarbeiter->qualifikation=='') $mitarbeiter->qualifikation=' '; + if ($mitarbeiter->hauptberuf=='') $mitarbeiter->hauptberuf=' '; + if ($mitarbeiter->persnr=='') $mitarbeiter->persnr=' '; + if ($mitarbeiter->kurzbez=='') $mitarbeiter->kurzbez=' '; + if ($mitarbeiter->stundensatz=='') $mitarbeiter->stundensatz=' '; + if ($mitarbeiter->ausbildung=='') $mitarbeiter->ausbildung=' '; + } + + ?> + + + person_id; ?> + familienname); ?> + vorname; ?> + vornamen; ?> + anrede; ?> + geschlecht; ?> + gebdat!=''?convdate($mitarbeiter->gebdat):''); ?> + gebdat; ?> + gebort; ?> + staatsbuergerschaft; ?> + familienstand; ?> + familienstand_bezeichnung; ?> + svnr; ?> + anzahlderkinder; ?> + ersatzkennzeichen; ?> + bemerkung); ?> + aktstatus; ?> + aktstatus_bezeichnung; ?> + bismelden?'Ja':'Nein'); ?> + titelpre); ?> + titelpost); ?> + uid; ?> + gebnation; ?> + mitarbeiter_id; ?> + beginndatum!=''?date('d.m.Y',strtotime($mitarbeiter->beginndatum)):''); ?> + beginndatum; ?> + akadgrad_bezeichnung; ?> + habilitation_bezeichnung; ?> + mitgliedentwicklungsteam?'Ja':'Nein'); ?> + qualifikation; ?> + hauptberuflich?'Ja':'Nein'); ?> + hauptberuf; ?> + semesterwochenstunden; ?> + persnr; ?> + beendigungsdatum)>0?date('d.m.Y',strtotime($mitarbeiter->beendigungsdatum)):''); ?> + beendigungsdatum; ?> + ausgeschieden_bezeichnung; ?> + kurzbez); ?> + stundensatz ?> + ausbildung ?> + ausbildung_bezeichnung ?> + aktiv_bezeichnung; ?> + updateamum))<7*24*60*60) + { + $qry = "Select uid from tbl_variable where name='fas_id' AND wert='$mitarbeiter->updatevon'"; + if($result=pg_query($conn_vilesci,$qry)) + if($row=pg_fetch_object($result)) + echo $row->uid; + } + ?> + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/mitarbeiterlehreinheiten.rdf.php b/rdf/fas/mitarbeiterlehreinheiten.rdf.php new file mode 100644 index 000000000..cdc381366 --- /dev/null +++ b/rdf/fas/mitarbeiterlehreinheiten.rdf.php @@ -0,0 +1,103 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include('../../include/functions.inc.php'); +include('../../include/fas/benutzer.class.php'); +include('../../include/fas/lehreinheit.class.php'); +include('../../include/fas/person.class.php'); +include('../../include/fas/mitarbeiter.class.php'); + +error_reporting(E_ALL); +ini_set('display_errors','1'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +if (!$conn_fas = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$lehreinheit_id = isset($_GET['lehreinheit_id'])?$_GET['lehreinheit_id']:''; +$mitarbeiter_id = isset($_GET['mitarbeiter_id'])?$_GET['mitarbeiter_id']:''; +$mitarbeiter_lehreinheit_id = isset($_GET['mitarbeiter_lehreinheit_id'])?$_GET['mitarbeiter_lehreinheit_id']:''; + +$user = get_uid(); +$benutzer = new benutzer($conn); +if(!$benutzer->loadVariables($user)) + die("error:".$benutzer->errormsg); + +// LVAs holen +$lvaDAO=new lehreinheit($conn_fas); + +if($lehreinheit_id!='') +{ + if($mitarbeiter_id!='') + { + //Lade einen bestimmten zugeteilten Mitarbeiter + if(!$lvaDAO->load_zuteilung($lehreinheit_id,$mitarbeiter_id)) + die($lvaDAO->errormsg); + } + else + { + //Lade alle zugeteilten Mitarbeiter + if(!$lvaDAO->load_zuteilung($lehreinheit_id)) + die($lvaDAO->errormsg); + } +} +elseif($mitarbeiter_lehreinheit_id!='') +{ + if(!$lvaDAO->load_mitarbeiterzuteilung($mitarbeiter_lehreinheit_id)) + die($lvaDAO->errormsg); +} +$malehreinheiten = $lvaDAO->result; + + +$rdf_url='http://www.technikum-wien.at/mitarbeiterlehreinheiten'; + +?> + + + + +load_mitarbeiter($maleh->mitarbeiter_id); + + echo " + mitarbeiter_lehreinheit_id."\" about=\"".$rdf_url.'/'.$maleh->mitarbeiter_lehreinheit_id."\" > + ".$maleh->mitarbeiter_lehreinheit_id." + ".$maleh->mitarbeiter_id." + ".$maleh->lehreinheit_fk." + ".$maleh->lehrfunktion_id." + ".$maleh->kosten." + ".$maleh->faktor." + ".$maleh->gesamtstunden_mitarbeiter." + ".$mitarbeiter->familienname." + ".$mitarbeiter->vorname." + + "; +} +?> + + + + diff --git a/rdf/fas/mitarbeiterlehreinheitenauswahl.rdf.php b/rdf/fas/mitarbeiterlehreinheitenauswahl.rdf.php new file mode 100644 index 000000000..33a7f0d01 --- /dev/null +++ b/rdf/fas/mitarbeiterlehreinheitenauswahl.rdf.php @@ -0,0 +1,105 @@ +'; +// Klassen inkludieren +include('../../vilesci/config.inc.php'); +include('../../include/functions.inc.php'); +include('../../include/fas/benutzer.class.php'); +include('../../include/fas/person.class.php'); +include('../../include/fas/mitarbeiter.class.php'); +include('../../include/fas/funktion.class.php'); + +error_reporting(E_ALL); +ini_set('display_errors','1'); + +// Datenbank Verbindung herstellen +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +if (!$conn_fas = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$stg = isset($_GET['stg'])?$_GET['stg']:''; +$fb = isset($_GET['fb'])?$_GET['fb']:''; + +$user = get_uid(); + +//Aktuelles Studiensemester holen +$benutzer = new benutzer($conn); +if(!$benutzer->loadVariables($user)) + die("error:".$benutzer->errormsg); + +// Mitarbeiter holen +$fkt_obj = new funktion($conn_fas); +if($stg!='' && $fb !='') +{ + //Alle laden die eine Funktion in diesem Bereich haben + if(!$fkt_obj->getMitarbeiter($stg,$fb,$benutzer->variable->semester_aktuell)) + die("Error: $fkt_obj->errormsg"); + +} + +$rdf_url='http://www.technikum-wien.at/mitarbeiterlehreinheitenauswahl'; + +?> + + + + + + + 2701 + Dieter + Dummy + +result as $elem) + { + if($elem->mitarbeiter_id!=2701) //Dummy nicht nochmal in die Liste schreiben + { + //Namen der Lektoren holen + $mitarbeiter = new mitarbeiter($conn_fas); + $mitarbeiter->load_mitarbeiter($elem->mitarbeiter_id); + $arr['id'][]=$mitarbeiter->mitarbeiter_id; + $arr['vn'][]=$mitarbeiter->vorname; + $arr['nn'][]=$mitarbeiter->familienname; + } + } + //Nach Nachname sortieren + array_multisort($arr['nn'],$arr['vn'],$arr['id']); + for($i=0;$i + ".$arr['id'][$i]." + ".$arr['vn'][$i]." + ".$arr['nn'][$i]." + + "; + } +} +?> + + + diff --git a/rdf/fas/mitarbeiterlehreinheitenfunktionen.rdf.php b/rdf/fas/mitarbeiterlehreinheitenfunktionen.rdf.php new file mode 100644 index 000000000..d58614e13 --- /dev/null +++ b/rdf/fas/mitarbeiterlehreinheitenfunktionen.rdf.php @@ -0,0 +1,44 @@ +'; +// DAO + +$rdf_url='http://www.technikum-wien.at/mitarbeiterlehreinheitenfunktionen'; + +?> + + + + + + + 1 + Betreuer + + + 2 + Lehrveranstaltungsleiter + + + 3 + Zweitbetreuer + + + + \ No newline at end of file diff --git a/rdf/fas/nation.rdf.php b/rdf/fas/nation.rdf.php new file mode 100644 index 000000000..a8c1b8f94 --- /dev/null +++ b/rdf/fas/nation.rdf.php @@ -0,0 +1,56 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include_once('../../include/fas/nation.class.php'); + +// Datenbank Verbindung +if (!$conn = pg_pconnect(CONN_STRING_FAS)) + die('Es konnte keine Verbindung zum Server aufgebaut werden!'); + +if(isset($_GET['ohnesperre']) && $_GET['ohnesperre']=='true') + $ohnesperre=true; +else + $ohnesperre=false; + +$nationDAO=new nation($conn); +if(!$nationDAO->getAll($ohnesperre)) + die("$nationDAO->errormsg"); + +$rdf_url='http://www.technikum-wien.at/nation'; +?> + + + +result as $nation) +{ +?> + + + code; ?> + kurztext; ?> + + + + + \ No newline at end of file diff --git a/rdf/fas/qualifikation.rdf.php b/rdf/fas/qualifikation.rdf.php new file mode 100644 index 000000000..f97b3ea71 --- /dev/null +++ b/rdf/fas/qualifikation.rdf.php @@ -0,0 +1,58 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); + +$rdf_url='http://www.technikum-wien.at/qualifikation'; + +?> + + + + + + + + + 0 + keine + + + + + 1 + Habilitation + + + + + 2 + der Habilitation gleichwertige Qualifikation + + + + + 3 + berufliche Tätigkeit + + + + + + \ No newline at end of file diff --git a/rdf/fas/raumtyp.rdf.php b/rdf/fas/raumtyp.rdf.php new file mode 100644 index 000000000..a74c069d7 --- /dev/null +++ b/rdf/fas/raumtyp.rdf.php @@ -0,0 +1,51 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include('../../include/fas/raumtyp.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$rdf_url='http://www.technikum-wien.at/raumtyp'; + +?> + + + + + +getAll(); + + foreach ($raumtypDAO->result as $raumtyp) + { + ?> + + + raumtyp_id; ?> + bezeichnung; ?> + + + + + \ No newline at end of file diff --git a/rdf/fas/student-verbaende.rdf.php b/rdf/fas/student-verbaende.rdf.php new file mode 100644 index 000000000..84f1a5008 --- /dev/null +++ b/rdf/fas/student-verbaende.rdf.php @@ -0,0 +1,203 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include('../../include/functions.inc.php'); +include('../../include/fas/functions.inc.php'); +include('../../include/fas/benutzer.class.php'); +include('../../include/berechtigung.class.php'); + +error_reporting(E_ALL); +ini_set('display_errors','1'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +if (!$conn_fas = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$sem = isset($_GET['sem'])?$_GET['sem']:''; +$stg = isset($_GET['stg'])?$_GET['stg']:''; + +$user = get_uid(); + +$benutzer = new benutzer($conn); +if(!$benutzer->loadVariables($user)) + die("error:".$benutzer->errormsg); +$stsem = getStudiensemesterIdFromName($conn_fas, $benutzer->variable->semester_aktuell); + +$rechte = new berechtigung($conn); +$rechte->getBerechtigungen($user); +$rdf_url='http://www.technikum-wien.at/gruppen'; + +?> + + + +isBerechtigt('admin', $row->kennzahl) || $rechte->isBerechtigt('lva-verwaltung',$row->kennzahl)) + { + if($laststg!=$row->studiengang_fk) + { + $laststg=$row->studiengang_fk; + $descr.=" + studiengang_fk."\" > + $row->studiengang_fk + 0 + (".$row->art_bez.") ".$row->kuerzel." + ($row->art_bez) $row->kuerzel + 0 + "; + } + $descr.=" + studiengang_fk.'/'.$row->gruppe_id."\" > + $row->studiengang_fk + $row->gruppe_id + (".$row->art_bez.") ".$row->kuerzel." + (".$row->art_bez.") ".$row->kuerzel." - $row->grpname + $row->ausbildungssemester_fk + + "; + if($row->obergruppe_id==0) + { + array_push($grps,$row->gruppe_id); + array_push($stgs,$row->studiengang_fk); + } + $i++; + } + } + + function myfkt($gid,$conn_fas,$rdf_url,$einr,$stg) + { + $qry = "Select * from gruppe where obergruppe_fk=$gid"; + if($result=pg_query($conn_fas,$qry)) + { + if(pg_num_rows($result)>1) + { + $row=pg_fetch_object($result,0); + //echo "\n$einr
  • studiengang_fk.'/'.$gid."\" />"; + echo "\n$einr\n$einr studiengang_fk.'/'.$gid."\" >"; + while($row=pg_fetch_object($result)) + { + myfkt($row->gruppe_pk,$conn_fas,$rdf_url,$einr.' ',$row->studiengang_fk); + } + echo "\n$einr \n$einr"; + } + else + { + if(pg_num_rows($result)>0) + { + $row=pg_fetch_object($result); + $qry = "Select count(*) as anz from gruppe where obergruppe_fk=$row->gruppe_pk"; + + if($result1=pg_query($conn_fas,$qry)) + { + if($row1=pg_fetch_object($result1)) + { + if($row1->anz>0) + { + //echo "\n$einr
  • studiengang_fk.'/'.$gid."\" />"; + echo "\n$einr\n$einr studiengang_fk.'/'.$gid."\" >"; + myfkt($row->gruppe_pk, $conn_fas,$rdf_url,$einr.' ',$row->studiengang_fk); + echo "\n$einr \n$einr"; + } + else + echo "\n$einr studiengang_fk.'/'.$row->gruppe_pk."\" />"; + } + else + echo "\nFAIL2\n"; + } + else + echo "\nFAIL1\n"; + } + else + { + echo "\n$einr "; + } + } + } + } + + echo $descr; + echo "\n"; + $laststg=0; + for ($i=0;$i"; + echo "\n "; + } + $laststg=$stgs[$i]; + echo "\n \n "; + + } + myfkt($grp,$conn_fas,$rdf_url,' ',0); + } + echo "\n "; + echo "\n "; + echo "\n"; + +?> + + + diff --git a/rdf/fas/studiengang.rdf.php b/rdf/fas/studiengang.rdf.php new file mode 100644 index 000000000..d4f719caf --- /dev/null +++ b/rdf/fas/studiengang.rdf.php @@ -0,0 +1,62 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include('../../include/fas/studiengang.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$rdf_url='http://www.technikum-wien.at/studiengang'; + +?> + + + + + +getAll(); + + foreach ($studiengangDAO->result as $studiengang) + { + ?> + + + studiengang_id; ?> + studiengangsart==1) + $art='(B) '; + if($studiengang->studiengangsart==2) + $art='(M) '; + if($studiengang->studiengangsart==3) + $art='(D) '; + echo $art.$studiengang->name; ?> + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/studiensemester.rdf.php b/rdf/fas/studiensemester.rdf.php new file mode 100644 index 000000000..83cadd8de --- /dev/null +++ b/rdf/fas/studiensemester.rdf.php @@ -0,0 +1,57 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include('../../include/fas/studiensemester.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$rdf_url='http://www.technikum-wien.at/studiensemester'; + +?> + + + + + +getAll(); + + foreach ($studiensemesterDAO->result as $studiensemester) + { + ?> + + + studiensemester_id; ?> + aktuell?'Ja':'Nein'); ?> + art; ?> + jahr; ?> + art==1?'WS':'SS').$studiensemester->jahr; ?> + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/telefonnummern.rdf.php b/rdf/fas/telefonnummern.rdf.php new file mode 100644 index 000000000..fe1e69edb --- /dev/null +++ b/rdf/fas/telefonnummern.rdf.php @@ -0,0 +1,83 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); +include_once('../../include/fas/telefonnummer.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING_FAS)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +$rdf_url='http://www.technikum-wien.at/telefonnummern'; + +?> + + + + + +load_pers($pers_id); + + foreach ($telefonnummernDAO->result as $telefonnummern) + { + ?> + + + telefonnummer_id; ?> + name; ?> + nummer; ?> + person_id; ?> + typ; ?> + + + load($telefonnummer_id); + ?> + + + telefonnummer_id; ?> + name; ?> + nummer; ?> + person_id; ?> + typ; ?> + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/telefonnummerntyp.rdf.php b/rdf/fas/telefonnummerntyp.rdf.php new file mode 100644 index 000000000..ffa14c48a --- /dev/null +++ b/rdf/fas/telefonnummerntyp.rdf.php @@ -0,0 +1,51 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); + +// Datenbank Verbindung +if (!$conn = pg_pconnect(CONN_STRING_FAS)) + die('Es konnte keine Verbindung zum Server aufgebaut werden!'); + +$rdf_url='http://www.technikum-wien.at/telefonnummerntyp'; +?> + + + + + + + name; ?> + typ; ?> + + + + + \ No newline at end of file diff --git a/rdf/fas/verwendung.rdf.php b/rdf/fas/verwendung.rdf.php new file mode 100644 index 000000000..6118c49f3 --- /dev/null +++ b/rdf/fas/verwendung.rdf.php @@ -0,0 +1,90 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); + +$rdf_url='http://www.technikum-wien.at/verwendung'; + +?> + + + + + + + + + 1 + Lehr- und Forschungspersonal (Academic staff) + + + + + 2 + Lehr- und Forschungshilfspersonal (Teaching and Research assistants) + + + + + 3 + Akademische Dienste für Studierende (Academic Support) + + + + + 4 + Soziale Dienste und Gesundheitsdienste (Health and Social Support) + + + + + 5 + Studiengangsleiter/in + + + + + 6 + Leiter/in FH-Kollegium + + + + + 7 + Management (School Level Management) + + + + + 8 + Verwaltung (School Level Administrative Personnel) + + + + + 9 + Hauspersonal, Gebäude- / Haustechnik (Maintenance and Operations Personnel) + + + + + + + + \ No newline at end of file diff --git a/rdf/fas/wochenrythmus.rdf.php b/rdf/fas/wochenrythmus.rdf.php new file mode 100644 index 000000000..758a1fd29 --- /dev/null +++ b/rdf/fas/wochenrythmus.rdf.php @@ -0,0 +1,63 @@ +'; +// DAO +include('../../vilesci/config.inc.php'); + +$rdf_url='http://www.technikum-wien.at/wochenrythmus'; + +?> + + + + + + + + + 0 + Geblockt + + + + + 1 + 1 Wöchentlich + + + + + 2 + 2 Wöchentlich + + + + + 3 + 3 Wöchentlich + + + + + 4 + 4 Wöchentlich + + + + + \ No newline at end of file diff --git a/rdf/index.html b/rdf/index.html new file mode 100644 index 000000000..3c2db98fc --- /dev/null +++ b/rdf/index.html @@ -0,0 +1,100 @@ + + + + + +

    RDF-Spezifikationen am Technikum Wien

    +
    +Diese Seite beschreibt den Inhalt und die Verwendung aller vorhandenen +RDF-Files am Technikum Wien. Die gesamte RDF-Struktur ist gerade im +Aufbau und kann sich deshalb jederzeit ändern. Es sei darauf +hingewiesen, dass die RDF-Files von heute, morgen vielleicht gar nicht +mehr oder anders zu verwenden sind.
    +
    +

    Student

    +Aufruf: +student.rdf.php?stg_kz=...&sem=...&ver=...&grp=...&einheit=...&uid=...
    +Beispiel: student.rdf.php?stg_kz=227&sem=2
    +
    +Parameter
    :
    +
      +
    • stg_kz: Studiengangskennzahl
      +
    • +
    • sem: Semester (optional)
      +
    • +
    • ver: Verband (optional)
    • +
    • grp: Gruppe (optional)
    • +
    • einheit: Spezialgruppen, Module, ... (optional)
    • +
    • uid: UID eines bestimmten Studenten (Wenn gesetzt werden alle anderen Parameter nicht verwendet)
    • +
    +
    +Attribute:

    +
      +
    • uid
    • +
    • titel
    • +
    • vornamen
    • +
    • nachname
    • +
    • matrikelnummer
    • +
    • geburtsdatum
    • +
    • email
    • +
    • homepage
    • +
    • aktiv
    • +
    • gebort
    • +
    • gebzeit
    • +
    • foto
    • +
    • anmerkungen
    • +
    • updateamum
    • +
    • updatevon
    • +
    • gruppe
    • +
    • verband
    • +
    • semester
    • +
    • studiengang_kz
    • +
    • stg_bezeichnung
    • +
    +
    +

    Lehrstunde

    +Aufruf: +lehrstunde.rdf.php?datum=...&datum_bis=...stg_kz=...&sem=...&ver=...&grp=...&einheit=...
    +Beispiel: lehrstunde.rdf.php?datum=2006-03-20&stg_kz=258
    +
    +Parameter
    :
    +
      +
    • datum
    • +
    • datum_bis: Endedatum (optional)
      +
    • +
    • stunde
    • +
    • type
    • +
    • stg_kz
    • +
    • sem
    • +
    • ver
    • +
    • grp
    • +
    • einheit
    • +
    • pers_uid
    • +
    • ort_kurzbz
      +
    • +
    +
    +Attribute:

    +
      +
    • datum
    • +
    • stunde
    • +
    • unr
    • +
    • ort_kurzbz
    • +
    • lehrfach
    • +
    • lehrfach_bez
    • +
    • lehrform
    • +
    • lektor
    • +
    • semester
    • +
    • verband
    • +
    • gruppe
    • +
    • einheit
    • +
    • lehrform
    • +
    • studiengang
    • +
    • farbe
    • +
    • anmerkung
      +
    • +
    + + diff --git a/rdf/lehrfach.rdf.php b/rdf/lehrfach.rdf.php new file mode 100644 index 000000000..f2bb9dbe6 --- /dev/null +++ b/rdf/lehrfach.rdf.php @@ -0,0 +1,69 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/lehrfach.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +// Einheiten holen +$lehrfachDAO=new lehrfach($conn); +$lehrfaecher=$lehrfachDAO->getAll(); + + + +$rdf_url='http://www.technikum-wien.at/tempus/lehrfach'; + +?> + + + + + + + + + + + lehrfach_nr ?> + bezeichnung ?> ]]> + fachbereich_id ?> + kurzbz ?> + lehrelink ?> + farbe ?> + lehrform_kurzbz ?> + aktiv ?> + studiengang_kz ?> + ects ?> + + + + + + + + \ No newline at end of file diff --git a/rdf/lehrform.rdf.php b/rdf/lehrform.rdf.php new file mode 100644 index 000000000..f47806e3d --- /dev/null +++ b/rdf/lehrform.rdf.php @@ -0,0 +1,55 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/lehrform.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +// Lehrformen holen +$lehrformDAO=new lehrform($conn); +$lehrform=$lehrformDAO->getAll(); + +$rdf_url='http://www.technikum-wien.at/lehrform'; + +?> + + + + + + + + + kurzbz ?> + bezeichnung ?> + + + + + \ No newline at end of file diff --git a/rdf/lehrstunde.rdf.php b/rdf/lehrstunde.rdf.php new file mode 100644 index 000000000..e05c0a63b --- /dev/null +++ b/rdf/lehrstunde.rdf.php @@ -0,0 +1,130 @@ +'; + +include('../cis/config.inc.php'); +include('../include/functions.inc.php'); +include('../include/lehrstunde.class.php'); + +function checkID($needle) +{ + global $id_list; + //echo "checkID $needle \n"; + reset($id_list); + foreach($id_list as $v) + if ($v==$needle) + return true; + return false; +} + +$id_list=array(); +while(list($k,$v)=each($_GET)) + if (strpos($k,'stundenplan_id')!==false) + $id_list[]=$v; + +//print_r($id_list); + +if (!isset($REMOTE_USER)) + $REMOTE_USER='pam'; +$uid=$REMOTE_USER; + +if (isset($_GET[datum])) + $datum=$_GET[datum]; +if (isset($_GET[datum_bis])) + $datum_bis=$_GET[datum_bis]; +if (isset($_GET[stunde])) + $stunde=$_GET[stunde]; +if (isset($_GET[type])) + $type=$_GET[type]; +if (isset($_GET[stg_kz])) + $stg_kz=$_GET[stg_kz]; +if (isset($_GET[sem])) + $sem=$_GET[sem]; +if (isset($_GET[ver])) + $ver=$_GET[ver]; +if (isset($_GET[grp])) + $grp=$_GET[grp]; +if (isset($_GET[einheit])) + $einheit=$_GET[einheit]; +if (isset($_GET[pers_uid])) + $pers_uid=$_GET[pers_uid]; +if (isset($_GET[ort_kurzbz])) + $ort_kurzbz=$_GET[ort_kurzbz]; + + +$error_msg=''; +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg.='Es konnte keine Verbindung zum Server aufgebaut werden!'; +$error_msg.=loadVariables($conn,$REMOTE_USER); + +if (!isset($datum_bis)) + $datum_bis=date('Y-m-d',(mktime(0,0,1,substr($datum,5,2),substr($datum,8),substr($datum,0,4))+86400)); + +$lehrstunden=new lehrstunde($conn); +$anz=$lehrstunden->load_lehrstunden($type,$datum,$datum_bis,$pers_uid,$ort_kurzbz,$stg_kz,$sem,$ver,$grp,$einheit,$db_stpl_table); +if ($anz<0) +{ + $errormsg=$lehrstunden->errormsg; + echo "Fehler: ".$errormsg; + exit(); +} + +$rdf_url='http://www.technikum-wien.at/tempus/lehrstunde'; +?> + + + + +lehrstunden)) + foreach ($lehrstunden->lehrstunden as $ls) + { + //var_dump($ls); + //echo $ls->stunde.";"; + //if ($ls->stunde == $stunde && checkID($ls->stundenplan_id)) + //{ + ?> + + + stundenplan_id ?> + datum ?> + stunde ?> + unr ?> + ort_kurzbz ?> + lehrfach ?> + lehrfach_bez ?> + lehrform ?> + lektor_kurzbz ?> + sem ?> + ver ?> + grp ?> + einheit_kurzbz ?> + lehrform ?> + studiengang ?> + farbe ?> + anmerkung ?>]]> + + + + + + \ No newline at end of file diff --git a/rdf/lehrveranstaltung.rdf.php b/rdf/lehrveranstaltung.rdf.php new file mode 100644 index 000000000..274c5cb22 --- /dev/null +++ b/rdf/lehrveranstaltung.rdf.php @@ -0,0 +1,214 @@ +'; +// DAO +include_once('../vilesci/config.inc.php'); +include_once('../include/functions.inc.php'); +include_once('../include/lehrveranstaltung.class.php'); +include_once('../include/berechtigung.class.php'); + +// Testumgebung +if (!isset($REMOTE_USER)) + $REMOTE_USER='pam'; +$uid=$REMOTE_USER; +$error_msg=''; + +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; +$berechtigung=new berechtigung($conn); +$berechtigung->getBerechtigungen($uid); +$error_msg.=loadVariables($conn,$uid); + +if (isset($semester_aktuell)) + $studiensemester=$semester_aktuell; +else + echo $error_msg='studiensemester is not set!'; +if (isset($_GET['type'])) + $type=$_GET['type']; +else + $type='lektor'; +if (isset($_GET['stg_kz'])) + $stg_kz=$_GET['stg_kz']; +else + $stg_kz=0; +if (isset($_GET['sem'])) + $sem=$_GET['sem']; +else + $sem=0; +if (isset($_GET['lektor'])) + $lektor=$_GET['lektor']; +else + $lektor=$uid; +if (isset($_GET['ver'])) + $ver=$_GET['ver']; +else + $ver=null; +if (isset($_GET['grp'])) + $grp=$_GET['grp']; +else + $grp=null; +if (isset($_GET['einheit'])) + $einheit_kurzbz=$_GET['einheit']; +else + $einheit_kurzbz=null; + +// LVA holen +$lva=array(); +$lehrveranstaltung=new lehrveranstaltung($conn); +if (!$error_msg) + $lva=$lehrveranstaltung->getLehrveranstaltungSTPL($db_stpl_table,$studiensemester,$type,$stg_kz,$sem,$lektor,$ver,$grp,$einheit_kurzbz); +$rdf_url='http://www.technikum-wien.at/tempus/lehrveranstaltung/'; +?> + + + + + +errormsg; +$anz=count($lva); +if ($anz>0) +foreach ($lva as $l) +{ + $lva_ids=''; + $lehrverband=''; + $lvnr=''; + $lektor=''; + $einheit=''; + $i=0; + // IDs der Lehrveranstaltungen + foreach($l->lehrveranstaltung_id as $lva_id) + $lva_ids.='&lva_id'.$i++.'='.$lva_id; + // Lektoren + $lektor=''; + $l->lektor=array_unique($l->lektor); + sort($l->lektor); + foreach($l->lektor as $lv) + $lektor.=$lv.' '; + // Lehrverbaende + $l->lehrverband=array_unique($l->lehrverband); + sort($l->lehrverband); + foreach($l->lehrverband as $lv) + $lehrverband.=$lv.' '; + // LVNRs + foreach($l->lvnr as $lv) + $lvnr.=$lv.' '; + foreach($l->einheit as $lv) + $einheit.=$lv.' '; + // Stundenblockung + $stundenblockung=''; + $l->stundenblockung=array_unique($l->stundenblockung); + sort($l->stundenblockung); + foreach($l->stundenblockung as $sb) + $stundenblockung.=$sb.' '; + if (count($l->stundenblockung)>1) + $stundenblockung.=' ?'; + // Start KW + $start_kw=''; + $l->start_kw=array_unique($l->start_kw); + sort($l->start_kw); + foreach($l->start_kw as $kw) + $start_kw.=$kw.' '; + if (count($l->start_kw)>1) + $start_kw.=' ?'; + // Wochenrythmus + $wochenrythmus=''; + $l->wochenrythmus=array_unique($l->wochenrythmus); + sort($l->wochenrythmus); + foreach($l->wochenrythmus as $wr) + $wochenrythmus.=$wr.' '; + if (count($l->wochenrythmus)>1) + $wochenrythmus.=' ?'; + // Lehrfach + $lehrfach=''; + $l->lehrfach=array_unique($l->lehrfach); + sort($l->lehrfach); + foreach($l->lehrfach as $lf) + $lehrfach.=$lf.' '; + if (count($l->lehrfach)>1) + $lehrfach.=' ?'; + // Lehrform + $lehrform=''; + $l->lehrform=array_unique($l->lehrform); + sort($l->lehrform); + foreach($l->lehrform as $lf) + $lehrform.=$lf.' '; + if (count($l->lehrform)>1) + $lehrform.=' ?'; + // Semesterstunden + $semesterstunden=''; + $l->semesterstunden=array_unique($l->semesterstunden); + sort($l->semesterstunden); + foreach($l->semesterstunden as $lf) + $semesterstunden.=$lf.' '; + if (count($l->semesterstunden)>1) + $semesterstunden.=' ?'; + // Verplant + $verplant=''; + $l->verplant=array_unique($l->verplant); + sort($l->verplant); + foreach($l->verplant as $lf) + $verplant.=$lf.' '; + if (count($l->verplant)>1) + $verplant.=' ?'; + // Offene Stunden + $offenestunden=''; + $l->offenestunden=array_unique($l->offenestunden); + sort($l->offenestunden); + foreach($l->offenestunden as $os) + $offenestunden.=$os.' '; + if (count($l->offenestunden)>1) + $offenestunden.=' ?'; + + if ($berechtigung->isBerechtigt('lvaVerplanung',$l->stg_kz[0]) || $berechtigung->isBerechtigt('admin',0) || $berechtigung->isBerechtigt('admin',$l->stg_kz[0])) + echo' + + '.$lvnr.' + '.$l->unr.' + '.$einheit.' + '.$lektor.' + '.$l->lehrfach_nr.' + '.$l->studiengang_kz.' + '.$l->fachbereich_id.' + '.$l->semester[0].' + '.$l->verband[0].' + '.$l->gruppe[0].' + '.$l->einheit[0].' + '.$l->raumtyp.' + '.$l->raumtypalternativ.' + '.$semesterstunden.' + '.$stundenblockung.' + '.$wochenrythmus.' + '.$verplant.' + '.$offenestunden.' + '.$start_kw.' + '.$l->anmerkung[0].' + '.$l->studiensemester_kurzbz.' + '.$lehrfach.' + '.$lehrform.' + lehrfach_bez[0].']]> + #'.$l->lehrfach_farbe[0].' + '.$lva_ids.' + '.$lehrverband.' + + '; +} +?> + + \ No newline at end of file diff --git a/rdf/lfvt.rdf.php b/rdf/lfvt.rdf.php new file mode 100644 index 000000000..e70973e83 --- /dev/null +++ b/rdf/lfvt.rdf.php @@ -0,0 +1,135 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/lfvt.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + + +// test + +//$einheit_kurzbz=''; +//$grp='1'; +//$ver='A'; +//$sem=5; +//$stg_kz=145; + + + +$einheit_kurzbz=$_GET['einheit']; +$grp=$_GET['grp']; +$ver=$_GET['ver']; +$sem=$_GET['sem']; +$stg_kz=$_GET['stg_kz']; +$lektor=$_GET['lektor']; + +// LVAs holen +$lvaDAO=new lfvt($conn); +$lvas=$lvaDAO->getLVAs($einheit_kurzbz, $grp, $ver, $sem, + $stg_kz,$lektor); + + + +$rdf_url='http://www.technikum-wien.at/tempus/lva'; + +?> + + + +unr; + $lastUNR=($i>0?$lvas[$i-1]->unr:''); + $nextUNR=($i<(count($lvas)-1)?$lvas[$i+1]->unr:''); + $descr.=" + lehrveranstaltung_id."\" about=\"".$rdf_url.'/'.$lva->lehrveranstaltung_id."\" > + ".$lva->lvnr." + ".$lva->unr." + ".$lva->einheit_kurzbz." + ".$lva->lektor." + ".utf8_encode($lva->lektorPrettyPrint)." + ".$lva->lehrfach_nr." + ".$lva->studiengang_kz." + ".$lva->fachbereich_id." + ".$lva->semester."". + (strlen(trim($lva->verband))>0?" ".$lva->verband."":""). + ($lva->gruppe>0?" ".$lva->gruppe."":"")." + ".$lva->raumtyp." + ".$lva->raumtypalternativ." + ".$lva->semesterstunden." + ".$lva->stundenblockung." + ".$lva->wochenrythmus." + ".$lva->start_kw." + ".$lva->anmerkung." + ".$lva->studiensemester_kurzbz." + lehrfach)."]]> + ".$lva->lehrveranstaltung_id." + "; + + $subClose=false; + if (($lastUNR!=$currentUNR && $currentUNR==$nextUNR) || count($lvas)==$i) { + $inSub=true; + $hier.=" + + + lehrveranstaltung_id."\" >"; + } + + if ($nextUNR!=$currentUNR && $inSub) { + $inSub=false; + $subClose=true; + $hier.=" + lehrveranstaltung_id."\" /> + + + "; + } + + if (($inSub && $lastUNR==$currentUNR) || (count($lvas)==1) || (!$inSub && $currentUNR!=nextUNR && !$subClose)) { + $hier.=" + lehrveranstaltung_id."\" /> "; + + } + + + + } + + $hier=" + ".$hier." + "; + echo $descr; + echo $hier; + //print_r($lvas); +} +?> + + + diff --git a/rdf/mitarbeiter.rdf.php b/rdf/mitarbeiter.rdf.php new file mode 100644 index 000000000..4fa07ee58 --- /dev/null +++ b/rdf/mitarbeiter.rdf.php @@ -0,0 +1,75 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/person.class.php'); +include_once('../include/mitarbeiter.class.php'); + +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +// test +/* +$einheit_kurzbz=''; +$grp='1'; +$ver='A'; +$sem=3; +$stg_kz=145; +*/ + +$einheit_kurzbz=''; +if (isset($_GET['lektor'])) + $lektor=$_GET['lektor']; +else + $lektor=true; +$fixangestellt=$_GET['fixangestellt']; +$stg_kz=$_GET['stg_kz']; +$fachbereich_id=$_GET['fachbereich_id']; + +// Mitarbeiter holen +$mitarbeiter=new mitarbeiter($conn); +$ma=$mitarbeiter->getMitarbeiter($lektor,$fixangestellt,$stg_kz,$fachbereich_id); + +$rdf_url='http://www.technikum-wien.at/tempus/mitarbeiter/'; +?> + + + + + + + + + + uid; ?> + titel; ?> + vornamen; ?> + nachname; ?> + kurzbz; ?> + + + + + \ No newline at end of file diff --git a/rdf/ort.rdf.php b/rdf/ort.rdf.php new file mode 100644 index 000000000..af9840dfd --- /dev/null +++ b/rdf/ort.rdf.php @@ -0,0 +1,81 @@ +'; +// DAO +include('../vilesci/config.inc.php'); + +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; +// Orte holen +$sql_query="SELECT * FROM (tbl_ort NATURAL JOIN tbl_ortraumtyp) JOIN tbl_raumtyp USING (raumtyp_kurzbz) + WHERE aktiv AND raumtyp_kurzbz!='LM' ORDER BY raumtyp_kurzbz, hierarchie,ort_kurzbz"; +if(!$result=pg_query($conn, $sql_query)) + $error_msg.=pg_errormessage($conn); +else + $num_rows=@pg_numrows($result); + +$rdf_url='http://www.technikum-wien.at/tempus/ort'; +?> + + + +0?pg_fetch_object($result,$i-1):null); + $ort=pg_fetch_object($result,$i); + $ortNEXT=(($i<$num_rows-1)?pg_fetch_object($result,$i+1):null); + $currentTYP=$ort->raumtyp_kurzbz; + $lastTYP=$ortLAST->raumtyp_kurzbz; + $nextTYP=$ortNEXT->raumtyp_kurzbz; + //echo "current:$currentTYP last:$lastTYP next:$nextTYP"; + if ($lastTYP!=$currentTYP || $i==0) + $descr.=' + '.$ort->raumtyp_kurzbz.' + + + + + '; + $descr.=' + '.$ort->ort_kurzbz." + ".$ort->hierarchie." + ".$ort->ort_kurzbz." + ".$ort->bezeichnung." + ".$ort->max_person.' + '."\n"; + + if ($lastTYP!=$currentTYP) + $sequenz.=' + + '."\n"; + if ($nextTYP!=$currentTYP || $i==$num_rows-1) + $sequenz.=' + + '."\n"; + elseif ($lastTYP==$currentTYP || $nextTYP==$currentTYP || $num_rows==1) + $sequenz.=''."\n"; +} +$sequenz=''."\n".$sequenz.' + '; +echo $descr; +echo $sequenz; +?> + \ No newline at end of file diff --git a/rdf/orte.rdf.php b/rdf/orte.rdf.php new file mode 100644 index 000000000..b28584ee8 --- /dev/null +++ b/rdf/orte.rdf.php @@ -0,0 +1,80 @@ +'; +// DAO +include('../vilesci/config.inc.php'); + +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; +// Orte holen +$sql_query="SELECT * FROM (tbl_ort NATURAL JOIN tbl_ortraumtyp) JOIN tbl_raumtyp USING (raumtyp_kurzbz) + WHERE aktiv AND raumtyp_kurzbz!='LM' ORDER BY raumtyp_kurzbz, hierarchie,ort_kurzbz"; +if(!$result=pg_query($conn, $sql_query)) + $error_msg.=pg_errormessage($conn); +else + $num_rows=@pg_numrows($result); + +$rdf_url='http://www.technikum-wien.at/tempus/ort'; +?> + + + +0?pg_fetch_object($result,$i-1):null); + $ort=pg_fetch_object($result,$i); + $ortNEXT=(($i<$num_rows-1)?pg_fetch_object($result,$i+1):null); + $currentTYP=$ort->raumtyp_kurzbz; + $lastTYP=$ortLAST->raumtyp_kurzbz; + $nextTYP=$ortNEXT->raumtyp_kurzbz; + //echo "current:$currentTYP last:$lastTYP next:$nextTYP"; + if ($lastTYP!=$currentTYP || $i==0) + $descr.=' + '.$ort->raumtyp_kurzbz.' + + + + + '; + $descr.=' + '.$ort->ort_kurzbz." + ".$ort->hierarchie." + ".$ort->ort_kurzbz." + ".$ort->bezeichnung." + ".$ort->max_person.' + '."\n"; + + if ($lastTYP!=$currentTYP) + $sequenz.=' + + '."\n"; + if ($nextTYP!=$currentTYP || $i==$num_rows-1) + $sequenz.=' + + '."\n"; + elseif ($lastTYP==$currentTYP || $nextTYP==$currentTYP || $num_rows==1) + $sequenz.=''."\n"; +} +$sequenz=''."\n".$sequenz.' + '; +echo $descr; +echo $sequenz; +?> + \ No newline at end of file diff --git a/rdf/orte2.rdf.php b/rdf/orte2.rdf.php new file mode 100644 index 000000000..ca936fb11 --- /dev/null +++ b/rdf/orte2.rdf.php @@ -0,0 +1,75 @@ +'; +// DAO +include('../vilesci/config.inc.php'); + +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; +// ORT holen +if(!($result=pg_query($conn, 'SELECT * FROM (tbl_ort NATURAL JOIN tbl_ortraumtyp) + JOIN tbl_raumtyp USING (raumtyp_kurzbz) WHERE aktiv + ORDER BY raumtyp_kurzbz, hierarchie,ort_kurzbz'))) + $error_msg.=pg_errormessage($conn); +else + $num_rows=@pg_numrows($result); + +$rdf_url='http://www.technikum-wien.at/tempus/ort'; +?> + + + +0?pg_fetch_object($result,$i-1):null); + $ort=pg_fetch_object($result,$i); + $ortNEXT=(($i<$num_rows-1)?pg_fetch_object($result,$i+1):null); + $currentTYP=$ort->raumtyp_kurzbz; + $lastTYP=$ortLAST->raumtyp_kurzbz; + $nextTYP=$ortNEXT->raumtyp_kurzbz; + //echo "current:$currentTYP last:$lastTYP next:$nextTYP"; + $descr.=' + + '.$ort->raumtyp_kurzbz." + ".$ort->hierarchie." + ".$ort->ort_kurzbz." + ".$ort->bezeichnung." + ".$ort->max_person.' + '; + + if ($lastTYP!=$currentTYP) + $sequenz.=' + '; + if ($nextTYP!=$currentTYP || $i==$num_rows-1) + $sequenz.=' + + '; + if ($lastTYP==$currentTYP || $nextTYP==$currentTYP || $num_rows==1) + $sequenz.=''; +} +$sequenz=''.$sequenz.' + '; +echo $descr; +echo $sequenz; +?> + \ No newline at end of file diff --git a/rdf/orte_liste.rdf.php b/rdf/orte_liste.rdf.php new file mode 100644 index 000000000..ba1bd7f21 --- /dev/null +++ b/rdf/orte_liste.rdf.php @@ -0,0 +1,58 @@ +'; +// DAO +include('../vilesci/config.inc.php'); + +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; +// ORT holen +if(!($result=pg_query($conn, 'SELECT * FROM (tbl_ort NATURAL JOIN tbl_ortraumtyp) + JOIN tbl_raumtyp USING (raumtyp_kurzbz) WHERE aktiv + ORDER BY raumtyp_kurzbz, hierarchie,ort_kurzbz'))) + $error_msg.=pg_errormessage($conn); +else + $num_rows=@pg_numrows($result); + +$rdf_url='http://www.technikum-wien.at/tempus/ort/'; +?> + + + + + + + + + raumtyp_kurzbz; ?> + hierarchie; ?> + ort_kurzbz; ?> + bezeichnung; ?> + max_person; ?> + + + + + \ No newline at end of file diff --git a/rdf/raumtyp.rdf.php b/rdf/raumtyp.rdf.php new file mode 100644 index 000000000..23d735f41 --- /dev/null +++ b/rdf/raumtyp.rdf.php @@ -0,0 +1,61 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/raumtyp.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + + +// raumtypen holen +$raumtypDAO=new raumtyp($conn); +$raumtypen=$raumtypDAO->getAll(); + +$rdf_url='http://www.technikum-wien.at/tempus/raumtyp'; + +?> + + + + + + + + + kurzbz ?> + beschreibung ?> + + + + + + + \ No newline at end of file diff --git a/rdf/student-verbaende.rdf.php b/rdf/student-verbaende.rdf.php new file mode 100644 index 000000000..1cf93962f --- /dev/null +++ b/rdf/student-verbaende.rdf.php @@ -0,0 +1,200 @@ +'; +include('../vilesci/config.inc.php'); +include('../include/berechtigung.class.php'); + +$rdf_url='http://www.tempus-student-verbaende.at/'; + +if (!isset($REMOTE_USER)) + $REMOTE_USER='pam'; +$uid=$REMOTE_USER; + +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +// Berechtigungen ermitteln +$berechtigung=new berechtigung($conn); +$berechtigung->getBerechtigungen($uid); +$berechtigt_studiengang=$berechtigung->getStgKz(); +$stg_kz_query=''; +if ($berechtigt_studiengang[0]!=0 && count($berechtigt_studiengang)>0) +{ + foreach ($berechtigt_studiengang as $b_stg) + $stg_kz_query.=' OR studiengang_kz='.$b_stg; + $stg_kz_query='AND ('.substr($stg_kz_query,3).')'; +} + +$sql_query="SELECT studiengang_kz, bezeichnung, kurzbz FROM tbl_studiengang WHERE studiengang_kz>=0 $stg_kz_query ORDER BY bezeichnung"; +//echo $sql_query; +if(!$result_stg=pg_query($conn, $sql_query)) + $error_msg.=pg_errormessage($conn); +else + $num_rows_stg=@pg_numrows($result_stg); +?> + + + + + + kurzbz.' - '.$row_stg->bezeichnung; ?> + kurzbz; ?> + studiengang_kz; ?> + + studiengang_kz ORDER BY semester"; + if(!($result_sem=pg_query($conn, $sql_query))) + die(pg_errormessage($conn)); + $num_rows_sem=pg_numrows($result_sem); + for ($j=0; $j<$num_rows_sem; $j++) + { + $row_sem=pg_fetch_object($result_sem, $j); + ?> + + kurzbz.'-'.$row_sem->semester; ?> + kurzbz; ?> + studiengang_kz; ?> + semester; ?> + + studiengang_kz AND semester=$row_sem->semester ORDER BY verband"; + if(!($result_ver=pg_exec($conn, $sql_query))) + die(pg_errormessage($conn)); + $num_rows_ver=pg_numrows($result_ver); + for ($k=0; $k<$num_rows_ver; $k++) + { + $row_ver=pg_fetch_object($result_ver, $k); + ?> + + kurzbz.'-'.$row_sem->semester.$row_ver->verband; ?> + kurzbz; ?> + studiengang_kz; ?> + semester; ?> + verband; ?> + + studiengang_kz AND semester=$row_sem->semester AND verband='$row_ver->verband' ORDER BY gruppe"; + if(!($result_grp=pg_exec($conn, $sql_query))) die(pg_errormessage($conn)); + $num_rows_grp=pg_numrows($result_grp); + for ($l=0; $l<$num_rows_grp; $l++) + { + $row_grp=pg_fetch_object($result_grp, $l); + ?> + + kurzbz.'-'.$row_sem->semester.$row_ver->verband.$row_grp->gruppe; ?> + kurzbz; ?> + studiengang_kz; ?> + semester; ?> + verband; ?> + gruppe; ?> + + studiengang_kz AND semester=$row_sem->semester ORDER BY bezeichnung"; + //echo $sql_query; + if(!($result_einh=pg_exec($conn, $sql_query))) + die(pg_errormessage($conn)); + $num_rows_einh=pg_numrows($result_einh); + for ($m=0; $m<$num_rows_einh; $m++) + { + $row_einh=pg_fetch_object($result_einh, $m); + ?> + + einheit_kurzbz.'-'.$row_einh->bezeichnung; ?> + kurzbz; ?> + studiengang_kz; ?> + semester; ?> + einheit_kurzbz; ?> + + + + + + + + + studiengang_kz ORDER BY semester"; + if(!($result_sem=pg_query($conn, $sql_query))) + die(pg_errormessage($conn)); + $num_rows_sem=pg_numrows($result_sem); + for ($j=0; $j<$num_rows_sem; $j++) + { + $row_sem=pg_fetch_object($result_sem, $j); + ?> + + + + studiengang_kz AND semester=$row_sem->semester ORDER BY verband"; + if(!($result_ver=pg_exec($conn, $sql_query))) + die(pg_errormessage($conn)); + $num_rows_ver=pg_numrows($result_ver); + for ($k=0; $k<$num_rows_ver; $k++) + { + $row_ver=pg_fetch_object($result_ver, $k); + ?> + + + + studiengang_kz AND semester=$row_sem->semester AND verband='$row_ver->verband' ORDER BY gruppe"; + if(!($result_grp=pg_exec($conn, $sql_query))) + die(pg_errormessage($conn)); + $num_rows_grp=pg_numrows($result_grp); + for ($l=0; $l<$num_rows_grp; $l++) + { + $row_grp=pg_fetch_object($result_grp, $l); + ?> + + + + + studiengang_kz AND semester=$row_sem->semester ORDER BY bezeichnung"; + //echo $sql_query; + if(!($result_einh=pg_exec($conn, $sql_query))) + die(pg_errormessage($conn)); + $num_rows_einh=pg_numrows($result_einh); + for ($m=0; $m<$num_rows_einh; $m++) + { + $row_einh=pg_fetch_object($result_einh, $m); + ?> + + + + + + + + + + + + diff --git a/rdf/student.rdf.php b/rdf/student.rdf.php new file mode 100644 index 000000000..1a772e764 --- /dev/null +++ b/rdf/student.rdf.php @@ -0,0 +1,102 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/person.class.php'); +include_once('../include/student.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +// test +/* +$einheit_kurzbz=''; +$grp='1'; +$ver='A'; +$sem=3; +$stg_kz=145; +*/ +function convdate($date) +{ + list($d,$m,$y) = explode('.',$date); + return $y.'-'.$m.'-'.$d; +} +$einheit_kurzbz=(isset($_GET['einheit'])?$_GET['einheit']:''); +$grp=(isset($_GET['grp'])?$_GET['grp']:''); +$ver=(isset($_GET['ver'])?$_GET['ver']:''); +$sem=(isset($_GET['sem'])?$_GET['sem']:''); +$stg_kz=(isset($_GET['stg_kz'])?$_GET['stg_kz']:''); +if(isset($_GET['uid'])) + $uid=$_GET['uid']; + +// Studenten holen +$studentenDAO=new student($conn); +if (isset($uid)) + $studenten=$studentenDAO->load($uid); +else + $studenten=$studentenDAO->getStudents($einheit_kurzbz, $grp, $ver, $sem,$stg_kz); + +$rdf_url='http://www.technikum-wien.at/tempus/studenten'; + +?> + + + + + + + + + + uid ?> + titel ?> + vornamen ?> + nachname ?> + matrikelnr ?> + gebdatum ?> + gebdatum); ?> + email ?> + homepage ?> + aktiv?'True':'False') ?> + gebort ?> + gebzeit ?> + foto ?> + anmerkungen ?> + updateamum ?> + updatevon ?> + semester ?> + verband ?> + gruppe ?> + studiengang_kz ?> + stg_bezeichnung ?> + + + + + + + + \ No newline at end of file diff --git a/rdf/studenten.rdf.php b/rdf/studenten.rdf.php new file mode 100644 index 000000000..d467843bd --- /dev/null +++ b/rdf/studenten.rdf.php @@ -0,0 +1,97 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/person.class.php'); +include_once('../include/student.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +// test +/* +$einheit_kurzbz=''; +$grp='1'; +$ver='A'; +$sem=3; +$stg_kz=145; +*/ +function convdate($date) +{ + list($d,$m,$y) = explode('.',$date); + return $y.'-'.$m.'-'.$d; +} +$einheit_kurzbz=$_GET['einheit']; +$grp=$_GET['grp']; +$ver=$_GET['ver']; +$sem=$_GET['sem']; +$stg_kz=$_GET['stg_kz']; + +// Studenten holen +$studentenDAO=new student($conn); +$studenten=$studentenDAO->getStudents($einheit_kurzbz, $grp, $ver, $sem,$stg_kz); + +$rdf_url='http://www.technikum-wien.at/tempus/studenten'; + +?> + + + + + + + + + + uid ?> + titel ?> + vornamen ?> + nachname ?> + matrikelnr ?> + gebdatum ?> + gebdatum); ?> + email ?> + homepage ?> + aktiv?'True':'False') ?> + gebort ?> + gebzeit ?> + foto ?> + anmerkungen ?> + updateamum ?> + updatevon ?> + gruppe ?> + verband ?> + semester ?> + studiengang_kz ?> + stg_bezeichnung ?> + + + + + + + + \ No newline at end of file diff --git a/rdf/studiengang.rdf.php b/rdf/studiengang.rdf.php new file mode 100644 index 000000000..d498ab26f --- /dev/null +++ b/rdf/studiengang.rdf.php @@ -0,0 +1,66 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/studiengang.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +// raumtypen holen +$studiengangDAO=new studiengang($conn); +$studiengaenge=$studiengangDAO->getAll(); + +$rdf_url='http://www.technikum-wien.at/tempus/studiengang'; + +?> + + + + + + + + + studiengang_kz ?> + kurzbz ?> + kurzbzlang ?> + bezeichnung ?> + max_semester ?> + typ ?> + farbe ?> + email ?> + + + + + + + \ No newline at end of file diff --git a/rdf/studiensemester.rdf.php b/rdf/studiensemester.rdf.php new file mode 100644 index 000000000..a29eaf0c0 --- /dev/null +++ b/rdf/studiensemester.rdf.php @@ -0,0 +1,60 @@ +'; +// DAO +include('../vilesci/config.inc.php'); +include_once('../include/studiensemester.class.php'); + +// Datenbank Verbindung +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; + +// studiensemester holen +$studiensemesterDAO=new studiensemester($conn); +$studiensemesterAll=$studiensemesterDAO->getAll(); + +$rdf_url='http://www.technikum-wien.at/tempus/studiensemester'; + +?> + + + + + + + + + + + kurzbz ?> + start ?> ]]> + ende ?> + + + + + + + + diff --git a/rdf/xxxstpl-lehrstunde.rdf.php b/rdf/xxxstpl-lehrstunde.rdf.php new file mode 100644 index 000000000..e6cbee098 --- /dev/null +++ b/rdf/xxxstpl-lehrstunde.rdf.php @@ -0,0 +1,101 @@ +'; +echo ''; +include('../vilesci/config.inc.php'); +include('../include/functions.inc.php'); +include('../include/lehrstunde.class.php'); +include('../include/stundenplan.class.php'); + +// Testumgebung +if (!isset($REMOTE_USER)) + $REMOTE_USER='pam'; + +$uid=$REMOTE_USER; + +// Variablen uebernehmen +if (isset($_GET[aktion])) + $aktion=$_GET[aktion]; +if (isset($_GET[new_stunde])) + $new_stunde=$_GET[new_stunde]; +if (isset($_GET[new_datum])) + $new_datum=$_GET[new_datum]; +if (isset($_GET[type])) + $type=$_GET[type]; +if (isset($_GET[ort_kurzbz])) + $ort_kurzbz=$_GET[ort_kurzbz]; +else + $ort_kurzbz='EDV6.08'; +$i=0; +$name_stpl_id='stundenplan_id'.$i; +while ($i<100 && isset($_GET[$name_stpl_id])) +{ + $stpl_id[]=$_GET[$name_stpl_id]; + //echo $stpl_id[$i]; + $name_stpl_id='stundenplan_id'.++$i; + +} + + +if (!$conn = @pg_pconnect(CONN_STRING)) + $error_msg='Es konnte keine Verbindung zum Server aufgebaut werden!'; +$error_msg.=loadVariables($conn,$REMOTE_USER); + +// Authentifizierung +if ($uid=check_student($REMOTE_USER, $conn)) + $user='student'; +elseif ($uid=check_lektor($REMOTE_USER, $conn)) + $user='lektor'; +else + die("Cannot set usertype!"); + + // User bestimmen +if (!isset($type)) + $type=$user; +if (!isset($pers_uid)) + $pers_uid=$uid; + + // Datums Format +$erg_std=pg_query($conn, "SET datestyle TO ISO;") + or die(pg_last_error($conn)); + + +// Aktionen durchfuehren +if ($aktion=='stplverschieben') +{ + foreach ($stpl_id as $stundenplan_id) + { + $lehrstunde=new lehrstunde($conn); + $lehrstunde->load($stundenplan_id,$db_stpl_table); + $lehrstunde->datum=$new_datum; + $lehrstunde->stunde=$new_stunde; + $lehrstunde->save($db_stpl_table); + } +} +// Stundenplan abfragen +$stdplan=new stundenplan($type,$conn); +if (!isset($datum)) + $datum=mktime(); + +// Benutzergruppe +$stdplan->user=$user; +// aktueller Benutzer +$stdplan->user_uid=$uid; + +// Zusaetzliche Daten laden +if (! $stdplan->load_data($type,$pers_uid,$ort_kurzbz,$stg_kz,$sem,$ver,$grp,$einheit_kurzbz,$db_table) ) + die($stdplan->errormsg); +// Stundenplan einer Woche laden +if (! $stdplan->load_week($datum,$db_stpl_table)) + die($stdplan->errormsg); +// Kopfbereich drucken + +// Stundenplan der Woche in RDF drucken +$stdplan->draw_week_rdf(); +?> \ No newline at end of file diff --git a/skin/cis.css b/skin/cis.css new file mode 100644 index 000000000..82ba86ae8 --- /dev/null +++ b/skin/cis.css @@ -0,0 +1,273 @@ +body +{ + background-color: White; + font-family: Arial, Helvetica, sans-serif; + font-size: x-small; + /*IE hack*/ + voice-family: "\"}\""; + voice-family: inherit; + font-size: small; + /*IE hack end*/ +} + +a +{ + color: #008381; text-decoration: none; + cursor: pointer; +} + +a.HyperItem +{ + color: Black; text-decoration: none; + font-weight: bold; +} + +a.Item2 +{ + color: Black; text-decoration: none; +} + +a[onClick]:hover.Item +{ + color: Black; text-decoration: none; +} + +a:hover.Item +{ + color: Black; text-decoration: none; +} + +a:hover.Item +{ + color: Black; text-decoration: none; +} + +a:hover.Item2 +{ + color: #008381; text-decoration: none; +} + +a.MenuItem +{ + color: #008381; text-decoration: none; + font-weight: bold; +} + +a:hover.MenuItem +{ + color: Black; text-decoration: none; + font-weight: bold; +} + +img +{ + border: 0; +} + +td.ContentHeader +{ + background-color: #008381; + font-weight: bold; + height: 19px; +} + +td.ContentHeader2 +{ + background-color: #CCCCCC; + font-weight: normal; + height: 19px +} + +td.ContentHeader3 +{ + background-color: #CCCCCC; + font-weight: bold; + height: 19px +} + +td.MarkLine +{ + background-color: #F2F2F2; +} + +TR.liste +{ + background-color: #D3DCE3; +} +TR.liste0 +{ + background-color: #FFFFFF; +} +TR.liste1 +{ + background-color: #EEEEEE; +} +TABLE.stdplan +{ + border: 1; + cellspacing: 0; + cellpadding: 0; + font-size: small; +} + +TABLE.stdplan TH +{ + background-color: #DDDDDD; +} + +TABLE.stdplan TD +{ + background-color: #EEEEEE +} + + +input.TextBox +{ + background-color: White; +} + +font.headline +{ + font-size: 20px; + line-height: 24px; + color: #003399; + font-family: Verdana, Arial, Helvetica, sans-serif; + margin-bottom: 0px; + margin-top: 0px; +} + +font.subline +{ + font-size: 17px; + line-height: 20px; + color: #003399; + font-family: Verdana, Arial, Helvetica, sans-serif; + margin-bottom: 0px; + margin-top: 0px; +} + +font.ContentHeader +{ + color: #FFFFFF; +} + +.row-even { + background-color:#f2f2f2; +} + +.row-odd { + background-color:#ffffff; +} +A.stpl_detail +{ + font-size:x-small; + color:#000000; + text-decoration:none; +} +A.stpl_detail:hover +{ + font-size:x-small; + color:#000000; + text-decoration:underline; + cursor:hand; +} +A.hilfe +{ + text-decoration:none; +} +A.hilfe:hover +{ + text-decoration:none; + cursor:help; +} +#bgcolor0 +{ + background-color: #FF0000; +} +#bgcolor1 +{ + background-color: #FF4444; +} +#bgcolor2 +{ + background-color: #FF7777; +} +#bgcolor3 +{ + background-color: #C0EEC0; +} +#bgcolor4 +{ + background-color: #77FF77; +} +#bgcolor5 +{ + background-color: #44FF44; +} +#bgcolor6 +{ + background-color: #00FF00; +} + +h1 +{ + font-size: medium; + color: #ffffff; + background-color: #009e84; +} +h1 td +{ + font-size: medium; + color: #ffffff; + background-color: #009e84; +} +h1 a +{ + color: #dddddd; +} +h1 a:hover +{ + color: #ffffff; + text-decoration:none; +} + +h2 +{ + font-size: small; + color: #ffffff; + background-color: #00a4d2; +} +h2 td +{ + font-size: small; + color: #ffffff; + background-color: #00a4d2; +} +h2 a +{ + color: #dddddd; +} +h2 a:hover +{ + color: #ffffff; + text-decoration:none; +} + +h3 +{ + font-size: small; + font-weight: bold; + color: #008E74; +} +h4 +{ + font-size: x-small; + font-style: normal; + line-height: normal; + font-weight: bold; + font-variant: normal; + text-transform: none; + color: #008E74; + cursor: hand; + text-decoration: none; +} \ No newline at end of file diff --git a/skin/fas.css b/skin/fas.css new file mode 100644 index 000000000..783689abf --- /dev/null +++ b/skin/fas.css @@ -0,0 +1,43 @@ +@import url("chrome://navigator/skin/"); +tree treecol +{ + background-color: #82DCFF; /*F2F2FC*/ +} + +treechildren::-moz-tree-row(selected) { background-color: #50D1E1; } +treechildren::-moz-tree-row(odd) { background-color: #EEEEEE; } +treechildren::-moz-tree-row(odd, selected) { background-color: #50D1E1; } +treechildren::-moz-tree-row(even, selected) { background-color: #50D1E1; } +treechildren::-moz-tree-cell-text(selected) { color: #000000; } +treechildren::-moz-tree-cell-text(odd, selected) { color: #000000; } + +menubar,menulist,toolbar,tabpanels,tabbox,iframe,box,hbox,vbox,tree,description +{ + border-width: 0px; + border-color: #AAAAAA; + padding: 0px; +} + + +button.change +{ + border-style:solid; + padding:0px; + margin: 0px; +} + +.hbox-tree +{ + padding: 5px; +} + +.style-groupbox +{ + padding-bottom: 5px; +} + +.pflichtfeld +{ + /*Formatierungen fuer die Pflichtfelder*/ +} + diff --git a/skin/images/1st_floor.gif b/skin/images/1st_floor.gif new file mode 100644 index 0000000000000000000000000000000000000000..e297e19345b448493fe8d2faa2d9dac7c877496b GIT binary patch literal 27113 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 KoE_Ey0RTIWWeoxV literal 0 HcmV?d00001 diff --git a/skin/images/2nd_floor.gif b/skin/images/2nd_floor.gif new file mode 100644 index 0000000000000000000000000000000000000000..957f94a45aa8cc780eabf014445e4f14f015c2cb GIT binary patch literal 29158 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 Yqi9ljH{Ua4XEv<-9PN~VK!DEw05Cpj3;+NC literal 0 HcmV?d00001 diff --git a/skin/images/3rd_floor.gif b/skin/images/3rd_floor.gif new file mode 100644 index 0000000000000000000000000000000000000000..9306507c30e7202b59683386c165e178074bdd60 GIT binary patch literal 30010 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 SU}2?JpW>6nO)&@)K=pq;OY(65 literal 0 HcmV?d00001 diff --git a/skin/images/4th_floor.gif b/skin/images/4th_floor.gif new file mode 100644 index 0000000000000000000000000000000000000000..8d3202939b3b79624500771de9c82ca323b5cf72 GIT binary patch literal 37994 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 QcmF~LxNH16L_h!lJI$m`v;Y7A literal 0 HcmV?d00001 diff --git a/skin/images/5th_floor.gif b/skin/images/5th_floor.gif new file mode 100644 index 0000000000000000000000000000000000000000..ba2480ee7359ba25ef42174ceb40cd3ca8fbfdff GIT binary patch literal 43880 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 Dq~*4} literal 0 HcmV?d00001 diff --git a/skin/images/6th_floor.gif b/skin/images/6th_floor.gif new file mode 100644 index 0000000000000000000000000000000000000000..9b7c2c823b7dca4557c795aeaf2bd6c1d095f7a7 GIT binary patch literal 38990 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 literal 0 HcmV?d00001 diff --git a/skin/images/DeleteIcon.png b/skin/images/DeleteIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..9db040b43a37bdcbecc427eb38b3828cd033a4e6 GIT binary patch literal 1278 zcmd^<>raz+6vrRNW`sy^dqHGmSui76++4_bu}csH$^bzET4LlPpwQH@*$EZPWgt*N zE|YAav{R`Fj?GX(E-gan1uWR6E#;w?r==Gv?enzQ8`|=~xct^-f5uL7&UyF!e)3Ju zY0b(^2?_o%7=oaXv{b?w{|^1P4+i?@p@XF~2nvL2QSR~AO_mn z1vW1*x`52O@B15Ybo(X~rnK$f88>Wh;c-q*5TZfQtIjr)pq24soYl zMxznKoFo!yQSWZ*=GV1z^YYuR8~ca@R5h?GYX+4@w-rSn!(g0aZ@IVN_V~EkU0*D; zb28vJwz^|Lj=6ApuN=>bUU;e1W4_iuRCGGMgw#DSFyNvUBcDPX4wublQz#S}Y}|`K zT-!XV(qVs2D@96dYnWA4RV9=GytWY4np{s=x9hM7#})+bDr;ssFR+{A;=Gp+sZx3{EQ_Pr~=O247OpZg!a2vDq_N)35a3yWd%ym&=ZQ|4$c+Ys}`Iy+uN z8lXbGP@6C!&Vq3*kNZ!;qlOol&OG(A$R_p0iynj6Yq!5W;FX^Rh?;7F~o zQmk|73KB-1iI2WWuZN%jhvbgt}cmUiLSj_55Z8<8ikv4$y@Nnq9GFGb>#DKR|hu#d}~r9 z*O;7LJy(Lo4fVvH!^5H@E3*&uO2&rbp`y=EVJ#Osa-6l{%{|GgvFQ89-v27c8Zpz5|pkb;1d;~j$AWyuNOPD?VdJp9u&)vIL{Z6|3 V{VHBpT!-w+BW7 z$x_mUzj**?kU+9zJH#Kw`RtQpf6{7qX7`) zPQ9RLfDH>yt*6iEjW5f$UX#pTDTz z2V80kOdts}BUQh2R-4_fHV*d1%8IB~wb||J`KOPfRMITcFuC>mLq}Ar+Bn!(^V?T( z^@;gZ9v&U3@#DLw*TuQAC>Dit+Vim_X(Ua~ zSpau`ZH-&aCf6Q4;MMAFF7yX9I`5%Y=lc3O6bhV}!+URu_hw=;f$&fAvSY8&zqS{F^>A`FX!CrfpLEtzs!+Xz*tu0>OxS957Fr>Y+LqQ|F_a;eZ zsQ@z*K;SfD>EFlz%E!l2zmNCc!Z4Kg-on*YWj2#xPT^$Jn$jtyztVee05fDVza(S& zL&#)h`-GJ38F3bFo-izMbWA33m}01E0`?x TRd{lG00000NkvXXu0mjf6Y%z{ literal 0 HcmV?d00001 diff --git a/skin/images/FAS.ico b/skin/images/FAS.ico new file mode 100644 index 0000000000000000000000000000000000000000..7ab8e913c379ce0ab8caf3b0e2e11d478cf8d408 GIT binary patch literal 15086 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 XLcS6H>h@|2IBEg$uBcAGp#}a2WDTuD literal 0 HcmV?d00001 diff --git a/skin/images/Hauptmenue.png b/skin/images/Hauptmenue.png new file mode 100644 index 0000000000000000000000000000000000000000..2d2258177335a4170497f8197a04ac1db1aaefc8 GIT binary patch literal 91688 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

    QSg`!4 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 #Wj2&(u)Gsp| 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 bLFd9Xj8o_w){5%)fG-(I1&LBIL;wE+7>0T2 literal 0 HcmV?d00001 diff --git a/skin/images/NeuDokument.png b/skin/images/NeuDokument.png new file mode 100644 index 0000000000000000000000000000000000000000..3e3a02ecce115c234f7aec256cf9f5fdf65e48bb GIT binary patch literal 175 zcmeAS@N?(olHy`uVBq!ia0vp@K+MO%1|+}KPrC%9$~;{hLn`LHowSjw!GOm_|I+@z z3m5;-w+dTv|FcZa8n4pAuM1jQ_MH~ZQn;oXWq)q^D)C6az`qv7JaX%vhxGDF(?rkYH&AMLqZFk)ZZjp1nwzYd^ Zn^oTPm(F&(sS9)ggQu&X%Q~loCIF0MMN9wy literal 0 HcmV?d00001 diff --git a/skin/images/OutlookImpDuplikate.png b/skin/images/OutlookImpDuplikate.png new file mode 100644 index 0000000000000000000000000000000000000000..41bc65f24bf20155014412bdf3a461006da38961 GIT binary patch literal 17193 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 C7%4XZ literal 0 HcmV?d00001 diff --git a/skin/images/OutlookImpImport.png b/skin/images/OutlookImpImport.png new file mode 100644 index 0000000000000000000000000000000000000000..bb917e624b5cfc376f7c6f20236b1079b15887c6 GIT binary patch literal 20333 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 literal 0 HcmV?d00001 diff --git a/skin/images/OutlookImpKomma.png b/skin/images/OutlookImpKomma.png new file mode 100644 index 0000000000000000000000000000000000000000..fbb24c4d4c2b0610b34d0d66f9bd63b1602a7f02 GIT binary patch literal 19416 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 )T5X(chG7PefXc6H|sB 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 literal 0 HcmV?d00001 diff --git a/skin/images/OutlookImpSmbol.gif b/skin/images/OutlookImpSmbol.gif new file mode 100644 index 0000000000000000000000000000000000000000..b9ebbe08024bccc0193c2f44e992bf9a2f1ec177 GIT binary patch literal 137867 zcmX6@WmHt%*B`o(E&+)FY3T-OX6Trq2k9Q9Q1{fm9ix#ws@wPfY&qwv^q|A78~z(F812n2w@AP^W10;54-00aer zpl}cr4T1t7BnX6rgOF$t5&)q&|nY%27|z0I2eoug8?uU1ct)FP&60{fRP|D5)MY9!AJm%0)bI* zFbWMu0bmRWjDdqOXfOr?!BnCiYK}akdiA5u^z&{j`02~RRkpS>NI6-g}2#o>( zC@=^GhNHk}6c|83K`1C31x2Hv01630A>k+_8ifQ3Jd&W1_i)T02&1V|Dy;5$AHin5P$)LFkm1Wc!ZA=Z1`1%1 zAPf?YL83880D}TyP;d+ijX?nz3`G!_8>YtbZFdP7*|0&=f@cm06_nn z3H{Fj|MLQf_}^O+R!DRCU<@&>fX!HQ#m59HZk=LCOXWxklZ40SSj(GFuQ}9{S)r{} z<5_&B>Diahi!h!W4ahda#X?Mx?DL+@`o$ILQjuWy#X#CasRAuWfsS#yTHR`$cPA+M zOMWASM1_0@?^3SxJMj*sM(EO8;ieUDAcj>g`FqejNDM59`yE)_H?_E84c`%&iC{{wS;U#{9 zPiwe>>0ngy`J<<)uKaCy_8MD(~+E=_~rYK6{ADpt{n%SpYd6S7UN(x zxY4@ClCLKsm=z|%NxT#267iVLQKB?t>sj}gDn?^9944}_Dp0dwX=-%8@safVJ}w-ymARFKW7>Uj~9Cz$zy0EUADEd5lEg; zQ*MAsCSN}qx@w!$)^AaSYNQ}^c6MP7!rGw>Dn6CXWMSAOEbB( zZvpWzkJjz3J>#w|jaB#65m)mU11>q7wP;@#bGIb9&|R13^2BTL&y)zP+SF;_%tp8j z5BVE1Z7rFRjl9d~BrBepEX1p*xcx*0lDAp)=&PK|p;-;oD_GRdrX%4;gVK1|Gu}Dzx0sTp?IhPkQ`*(y8 z;{>DCk)xv$8RWotO{~Y>wG2ThglgEua5PI6=?a>qq^ z16{a;*_1t}`L%Xxxap4Gy|}#jM$se!`5fV-JfL@KBp<&U$Y1b-48tx6!0$jmy0t&_ zk}lo;r|^CJEr-JIP5(07KYiw(`~Q6OeE#3{{wpBjYI{@-IkoTs;2lTUy<0ogCn z|LJt8^wZv$M%`!IJq6)jyu{Tj$H5Cx!IiIgr4zz|Q&f&iDm_R7HBzIMtouM2tVxhq7SK?f&ZhOXk_<_^Bxu3l*d;U3lKc&AH)K@Y&zI6!gPY}` zSxXo*pX%eZ_i(*SQ)%#?9|5CMRLj9yIVOIXg<$+k{xSor*1MM`JS28e^%u3C_aHVfVM5JZf z+k2Pc^RSE5C#arZxA0>k9%NP9BwmNOA%BY3xu+v{#*I}fvzdYaTj#3`|+3!^T zRX_VuAmo{0MVNA(juiSZ{4+e|^aG)Q=&O5w9GqJsGf)o)fyfvK&WOAjj{HR=f2tkm z_DGf5?;<)R@C&KuwHjUJMeGZT20O%>s)c=_ zx;7hw`R`d>f){lsoy8^cziGaE@do6XmX^U$jx_`*bK|pAviWC2*uS)G*&DTA|MY_(x zzJ7O@YCr$an!Dayvw~X1K=f61Ml?8^x&Cw8Gt#jJI8Lq{@Yd0`t+-mpMO=ZCAlOWe z47L_ajv1KJfv6G6)D7J(%aJfmN!TLhaH+*bqxs40NoY&(871vs3E)>C&IL~NpNGYj zvsYB9E3KKdQMJ^Sa-w5GK5|L_NYGm1qJoBx@aTM5c{l1nC)caFAa0zbvoF+as6aI7 za2nSVcOO3z_|uWdk^D~g%G!n(U?KBho1Pc};c?MZSud(wu{~ZYe^*eE2=j1PQTR6(E9J9}rQklY zXV){Uu#0=8sWAnCyv&3TLyYvVGG4vdKQh0TdQ26SZjQbmE*$69u4)A`Oug3eBJ!B3J+^PArv z@Ab?ck9oEE?wo%3!2Q78=JM8eCwLg@?*mDpgYK+oAH-Y71rRL{-1T;SYINW%Q@OAi%1PC2)#f%Ch zjI?rbX?PslO^pau6eJI2>8cfUa^nfgK_nR<(hOOii+F)@BYz7JZl5M zYVB$3vR)sK2+O3rPP;TJ;xwkTwSFdQRY)OweiQDjdM+J$4ij3xSbAxFX?fxL3Uvu3 zmecOa(Jl*s+?hWwiPiS1(uvrIpkdypt2Xhmk#Vt+c&j$UQjvdTB3}OTkbmm<>VcO|2{(ieBND{LkcgRn#VXfrbcWN<(} z%z3_{v5*}D_X0`Tc|zqbk|#KUiEXmDJ0Qx7f6s#_98?<|Bw+=z!PkLl^|G(!j8K+w z0yXjkoQZ%@K{km(F^Pg@zT=30$Z%F%!k+|OU!~9LrnQ#J=Zng3>y=xs3msMp+boOP znN#>9i!?QDEf=x0})n=CYqRR+u>Nt0XPrBpYIP zR1M6h=(6m;deqMEvZ)S)prtNRVL3}z`J+$e%n&~fl8Q69-(!mkhOml{F#YeB21e`p z8h=?b@q0){)2ah2`ZJf~%F@`#U2>9n&GsYB@#Lr?rMTN>flJD<0R{ zP?wM6uEqyXJ%C(AXnFF3>;OO|#e#<_TH4G>Q|V!>Ya+&_Wi9#Pl1i<%SxbWIf9k4t z{$cFxY87E>HAkV8bRMtbQs*HhBA4dXn6#zil4Yj!jbn@Vf7Ba;G_rFv&4xARSJek< z8afHRyaF^w7#gQX8x&z)h}Z~dyQKqIPu1!K>9f^+`h=2f{gjXVZk%&^=KQ|F{QJSV5(?4SSbvLx_NQMfxQPv&Lj$J8SU(SPt<1&n z7K(v(Xrx2PdNTNCd?|eD8SDiatcw^kL9uu|pv;{IaW@ZmeQ+pMz#Be+CRXw)0#tN4 zafBRH;R=boDpcJuo!%*qgE5`%+Efvq1>V+FW}{uN9@geF*S-w<=S@YFE|qS4jc=Wj zc1;LAb$3B%U0-OSHM;u4O;?v?ca}moP_F#BtuWQI$9SygyJJ1jT#TQoikc|ynk;_q zQtvoYj5@_9@Kv3H_Tj0jPKEZ0s8BrwQw@8*Ei*H3`;;o2{j^HEB$v>AbzE(RFAWQX zdTjB(k3D$1a@<&z6QL4NYSXT<#^5y(=Cv+kbr9-#PNtFP+|cKu^$n{zR@-ECX?YO( zdNfx%JX`B`SJU>WRo{s9xfODV;9WpftfQsFLliq)q7^+Ptyum6vU%67A zw?h~Bk~2@{3%&HUz64I-Q)8p_@&`{u^JCXz{fhAOf90#7yJDs~RjiCGiK`+2!Ld|R zs&v|vDAuZo@G+IYUE)Cr!Nk?IH(gderjgn`jkjHKw+~{bjK!9f490q_{&q#OD7L<> ze%D*wQ(yg)n@Wo+1ts8G!q-#%u&A1BvfHM+b{%)ly7;{fEZB@{c(bQVchYL3uT!C} zT!>2Fu6}N+XDP`o5fkPKcdtu!7jtr7`5K00EfJ1QZAYuJE)l9+ny*0K_x>%Z<4r%R zQ#T)e`tLTtp?hQ_WuGN@f+R$$=Pvk^&$ z9MpPEb=R=G^78rc0H_{$(F0jLuy&Pv6;h>hoC|5x&|X}A2WA`kkL39)0PO9x55aSd zL`yCbLn6sTpx`^3i}+W|Jc~5u-kAZqOmz?qxn~3I2zsUp_FAag<`UIu>z@w)A87sw10}`ZCfWWH0jpxY4us;wfYUIlh@r4j_@j!XL zQXZEUWJeq3o;Mp!?_(*0jKrS<(On<9^>6L-pp(MX;cvI2K<}r9Lf>SidWzl( z!O2EX<(~1$)~^b+Nd=Lllg7VYURq7QBAsZqr0Nz@8NGWjS=^foSed>2t9+$SMUCIz zmD1N`?LP9N7vx0MHJO?*>K3`|o-VESZcX*`ZE>Q@%$y~9K_RV6;QcDGdQX_eVZMdV z<&1gNhl$e{XGKkCNyyu;o z&_p2jO60w_ILSLaZEq2hCH`9*0&U-<_Px$n9qCXaFc!*ht(z=aJ~bS9aJ6_YRnG9x zRz2+_+p!Ph)bqS-9dLs#gXbPoupb4>uuyNgW>PfeX^!ONaBex7^pOF7URz$|p}t@) z$R)rgbwuB5#A@^K=jE_+r@jiGwD~Tb?@sPU`6$MBG>SbS7#Od7!or`HfiKQTYoz^# zFoQ7D4)o*#A7e+xYqSpRJP`TuChXz3&-GZ01*lUg=!IZ)L27)eg+s*G+9bTm{O+3O z)Xt>d!r;6(1IUCMX_akZ9PSUr!EaUV=}NIFiry)O<$7N?Vv35-YL_H>8p-N1?uz_e zx~-FYOFcH3@y}y*zIN%Vd@5F2W{so4PXTtG79aI>^}1pvx0V{J$KEC%vAG@eR|n^Q zCy#Z#^;a!lsRwDKoNl5Y!~U7Y{OGJ-3O}4+I~@Pp+s}OI)DM2_ba|n2cJgyPbE_N3 zg`3iT<6kKt@y{DgMH{cbHhwz%;Ai(jZ#d$^s`{=+<2m5@^6q+`m15vb=QV4@OJ+sy zKZV{0SI~<;O(&x|3c{!aN!0P-JJPNUe&H;Ib13+$F1O9|g&Zj73qNkJX0SVvN-5%& z0YSN{Q;h!r~h*IDD$W`~z1es&i=+{$4=4p`afYdu5HjsAB zl`8UEt@`7e>U4+%z`U$kaoqW@_8uxGA<~fB2PDuE=lRQ z9H4a$r$zeQq<$pUYF2pCjQgbd)92;~+jBJj*s&_|g!-A=zS4pOz0;bQ@!of`4R2&^ zA$L#WYX(XSUj9AJ551)yKRPNW%J)Fwg&v5xAGnI-%JaA|8kG} z7g(W%a+56*k1u(k!Qgcqim>$R+05^Htudj$fU4CR<2UaekJ8=ba;1Yy+Y~N+*0O#U zYRy=Noa$2%jFGyZmB}hgnnL*s5Jx-|5acA zI{#Sq`h#-B-&{#VE6;n-^Ok)E&=WDEynlaYFBq)J`<%0M!No>uWSqmZz4{!A%>%$C z7Oaf-}V zX+ldCR~M@_Jq24x)YBg%Hf5HoTU3?ep@nH=Wxxp124eXL^sM8?%)}YtuvIY2y(?!d z``=~mnCz|`PR88oV@q*P58Rsg>^f;)9+Z(9Gp^%Mww*!F8dD*+-H38 z=kg7F(MJ&7`mS7bs`vn(`g-dMZ_HHd2lQKmwhuv`H&3AQy`ddY1BGeXDZ93+&b9c_ z)Q%aqNivCvprVgQt7vs^2{|ALo2K;j1-3v^cS!J^B36j`-PZ+hRQmhFiI30wuV3uF zR=j#2{!QWf>X*TX|AfYyzfqpNnd=4mBz*F8>Fz|;$eH!NtKySsTznc~)9|4kiDy&w9(4*+}prh?Yil z5G2s4-4;Q=l<dN2P5#5BTl?^eKxgMsjt&PJcmEwIR!0@5BQM%eDkG}W ziUYs5wqHlph=A-ayGf)=6(CDaj>^Ziuh(Ewqwy9n;SjU0jqgyiF3A9I>ZsB<$*Qv~ zOvH<&+LO5v&}2w*5-8I_$#UkRIi+#9g?+}JqT_}cLQ)b9H*;0+E2DYMj0yD1cd0sv zHMwYpxiuuA+D#)u;wWF9GZV(%kOdKG%=}|Wl;hxO^plttXMRe@WaCSSn9@&80e2km zGko{FG^8GXZ2KfT9z%|1Y20hNtiAV=(oi`eEfJlT{V@jGyzD?4@lyP1dyRD_55fYvJ6b3jT{ZAre52(g=jr@qM`Ncwa@+LY zXg20niKT^2)yVv}222+&_wjDGck6oxEf#I`J&aOwC9(F}_3NC|kXv>)n6va|?D2W5 zcyKd=aH}lY>wA1m_~*^sd0R<3-a?YMZyJ)ky&NA=@-XA#!Iso`h5iQOHQn$WviMkI z)dHbTFVICRJj?QltSpbUB~8eE@6qQuBAt}%Soy|rgP_*Z?9+XoLarw`PpWANh%D+2 znK`0zTVXhZe?9;a-=mkgVI*^Tk)(gyqa945Na!+PxK^jplGCNtgdu}K#6)yHZaGY> z4o+*6Q(ubfQ6o@S|KR0>sWF>21=;Adi#GPBO0V;4lmh(MVkX$zULzLLJn2 zh479w_u6xQQaoqIXV9|xVgKNrhH{*PZWPn_S~T4o@`cwp-0NdiTnzPR)tz>k(L>3C zkQP18jF+5FW}>+aS;EewQq~i8UANu9}>rNZOdf!`!KQO62_c=S61XMu2-^HzCN!-Ohz zaR~#6FVp5 zWKJlDTdxekoLlm#pT{|2*BpeqgBGZA5_7qkI1`yZtkHON3~zsZIqveY8YPvhoAwoV zf)yB##zx^a@GH$TS~vW(ZUyDpc|O@rkuLl zZ7bXIQW`ASSb5=Ca%7~9oNK3ykbkkW)lBHMTj3lwhgWv7X>v;EQncX`s((|geZB_s zOhXr@ z>i@WYrPJ%UB}wcs>@WPF8%1^hJ@2cn)WM3u$wW*+mcC(XVotp8%pNi~;HFBsJ!OF@mQEZ*42pVS%q+tyyRGg$`o1ZTpm?s!t zCm0Xy^VrlJd0YIbrO&}B;}Mp6LxQ@XHS40gf7kPo##{cY`ud$Let*{Xj17Jndx6tm zs7iS$kd<=9DZAFK^0#?q861HJ9&e2V-?seCKDjLiy3scz6*^zae`iVk-75$FresHJ z2qyJG?(wAi3*R~}W;^0xya(Unk*jFQsbsj}==n->I?&Bk(p$?3E&L>oJto%YIqE*#k_%-!C& zkqmyx+@$D18g;{1#|I8$maWTYR31udv;aqRCwFY-cjS{5D!fbb&2IoPpC+e1F3&$* zP#dNqzh;@5kbR^ZI~7akde8CP>$i?#9y%jHkGdvIuf;4? z6W6^Mx1yNQbY_1^6IYCids1v*ooZBUrnjy4*=7byR^KD{*3oXNftC@LNrR8$tVdqO z-z~HvPg(KSspa_C_o57y!s`;`GmqD)IqUg^=Vyh#7z)=@GpVus#Yi#7Vp$@LG-gekBkCYzfExp!soD9r+Hj`l+2D)P zQVYD*i}J_?+=E%rvf&pwqg%zflm*kLnnw5(OLs!3t)y9oOeOBj1(i6Ogr0bk2sV%~ z%DT>oFADVl0b8y&`eL7{f+!(@v(eVq#f!sfBTTPZ7mmjlxd}`Z?~PeG7nHYX7za)D zkeN3xjChdnzjOioVN)y8nJiOA=cWG!}ufv`P`k2wa(illolbv z^LL6SJa8j$hpA78sY1>?e$Jvpnvo?EB~Y@+EoDOQY%Wl}D1$Vm$T8*=TXbq%RI)CW z^N)r2;6oE*`HRHApzyVQ@U%JFVvw<~0@oxJEX29n0Lhp&t&AART&hU#TG}~z>U8S| zI|=DuWN`!%kpvd}y%w<}YmhGH0a?q}{cB<=;<-pX(U`WBoLCW0JXz1SjOsP5u~s2L zOF5r5fs|H$g=A@2t85+%ndVjjGD}haSm^=roIt!M57*+CTVn(9wcXa<{oc@`!p2u` zlr(NgN?1yJ#zGQfwWusQ8!e?BEpyLXWfSpx`wP0AC4_pddpoRC8nNk(;^iaar36+O zdW%Y_4G~9cF+t1j{tZ5|jm9)Q!Emc;VJlhB*ufmUl;0LZ`fYCz64g9g{FANI^lh~{ z;*-K#3v6qvX)zr+h!$i_3mX=bBQ6`$h9_(2j_~vhw$OMvizbT!OF2>PO>x7eU)}T-!W_{SsSS{qj~x;6_bHE2X#9BHU{F ze6u?LOO@sqG5<}ewzac+1crW>LwOS;wTsC?a5Gp8>+imb!xkYdDJZSB+3e$lu?>w| zYsjq$sf~rLO*DLC+SzL1-XR)k1>8?N2)#uJ@9i=XS}h@CHr^;bP1$?avZpY*r?|4G zbhxK{wfFRJ?+|BSm3LoFdS6{@U&Cx)(`8>PXkREon`gdiTe_b~rSlH!`K43)^Dj)^~P@sMDT?Gt3_{FfV!6EPLM{ayYvL zQkW6L&EfG&pvHM8jEmjyt+3j+$A! z-}5vCFgFpD6JjZqhP{ju#y`zhvu(tubR51+0{Wb+1@iR5o=1GG<&BF!52OC!6n=LRZe+4wpeCUeWK*+RR+drQp}#x?_<#<1}|r z$zpi_fw1#=WQ|$pw%0fBdGZl&r8g!_Y;aHnA79{CKZZHKZHXs=i-8eGXCfXv&Sn&i znFdNrEMJU=YK-@ikepCcam{(>Z^qk6-$2guMo7+73AFW2d z!SvF2lyNr0Vk$%FCO@*~a8?=#AKf;QtvGhu|%6xVH@5G`J zd4QSkOE0A@m;>I=J`6>QJvRbNEvY)2ByJl+0OL2(Mz-k}|FzE^@%nlz8zmopwK(|B z9k=RF`7O|Pk!saLuHP@9|1gvnZt?sp;fMp=I53?HTD99gzN%T2Ju;QiKC(Ukt!;ivXXxzF zbmhTdZe?J$F!L)|hMi#$9`?>i5{?X?eNGUuvcqc>B;)a%mrn*TL%RJ`#w3I#CWP1} zxHJ<2YC*Hfr>oY9jzody*)QiA8NG~V4@m>5qyNs;@glvq59>$ab_VW@#`D7U^AQi` zRtx4f>sPXxjC4nq7y-i)-o=|Gn6PEZ=zljcr){g8e_w|gm*?Kl#d*fqE(t{ZczzYi ziA4681!a|8Xl|Vm-W#Q|zy&@mY4*F_Um2%S-d2|eD%2iIOv5dmGs`|NWWR)6Vlo*5 zGetWVAX{t^1ir2v&Q7!bWmgxF&XpIB`O4xw>j}egUb$wu!d5Vcf=XB1^uJec>husU z*7rAzkNA|d=its>nj_12Y}c#XVfY_@Z`m8W{W%YL!spF?v+$m}xa`jfW*M(zslL<* zpuYFr8^4cXSr$Y@SjW+Heu$r$S-Bg%xx&nOcKYg41g@?gkn)_bzQ0uy=36)Y!N3;c zw}Qm|WO%(v%~0X|HGY1#iEr!^wboOYz0i_he}YKp50^tr48NE3e>cu}d{YCshW{y% zj9A*lNwi)KuxxYIFYiEZw68Boi$vU7fu8mfuQ>YrxTV3?A(g-RxwJC@RcsPn% zwUrJky5A8^ws-f|{nz1ii2PoQZi3#1bg`Q60zUuA=O(20f5Ls3^EZn~(pm!;vB~LB zy-BBEQM46#QCDa5>XjRk__tYFFLb@R1)YKTQqB+FVfN?%JrRBN1N=knYpX zthDW?z|qDhhc|tBZTH~Q3jyEVPg9X>;i)I{dxz77vj&%^n9H@rI^C4>uYppYsZ6(( zk_yy3hYM}?-(754e>lfK)RvywY`)$Zh?3!bJl5KNG*?-xyGnlBp_Y> zWV4*@*Rl#;ga)v{UqSN=gGmv5W2Z1>3`N)-Fx7 zPtL=kFe1&|A*ta0h~C|};;P29!Z&tV{jXe4VRZz0jV;)`L_oN7BwE8>k9ytVt>d%kYGtFySculKO>9dV-)X>Prnv+?&H5-kOga9aP>ow!JL*3Ei-T zu6!j;3)K;;Agh9|N)iio_k!N%g(Uni3!UcwFe`4Z)Il6tj7sLUz+gK;!b3~0FU;sJ zT5m#EwYDV5mMYXKsfD#k6vL*KhJz*tBy4MnxhsL-bS+Xdx@fN4Xde0_5>Myomx2(0sWxnx?yqlJvzD-y_CM=hqS4=@W9_dB=evPx4I^q(X}|7iTW&AIzFkt2GmMiq$!MZH&2)Alh_D7-hX`rdr`xE zlno7gSOlAr=c}r9`{q3<4!@b<>e_*xGEDGiH|D$5Y`&m+s@<-&(th>2YO4 z0y4VD=Jmz3go<_5Brj#M&tBVNsrCt_YRc+mi9peS!VFlKLH^+PGlEz(EejBBCbpz z#GxUU##ozpA)`vg1wJ?U0NFJ5*rLQhEqZ+hBkM=;BnS+{hIZbZM3X~EFVaOXmVjRe)+dx6MMR19=a7eDNTy4ckU8u ze6`b27SmV>svKv8z|W$Iil(1w?H8fqT68_`J}K|wJQ%+MGp{t`v+k%6={e!j2F`6{ z(hW&hixO0}e04g`l@nB}k%+dwL^zg&P26{h7hZj(pyXE@<7#pfuk<8qagqJFaM$e1 zKT*z6F*?2OQK7BpAIN14m(TUL`z?&WX#aY9bCT|T# zbgA!%PZg&W3`^@wR6RE)dVmF^6mLMPbG?t!V39ekP$Uq(#CrDOq-Vu#CA6pcEFo@) zf4kD}BeNouR29z68t9`rf#wymO;Y=!Y;L*NkcclXn)>L+``rrs(RL5!+y{0#&biMj zI`yX3A;a>&cs*va6j&AV=XHJ-&{cFzk6KY#{#2g;DQI$Bx7cTFn&khslo85hrD~X2 zN3SG<)690QB&(>?Tx8uJ`9==0{>VsBbW-!Q7B6PcYt6CZ`W8Awj_^}W+fpT5lsd*8 zf7%wkWzXW2(FG1XmKTN&4HRa?yqMrn;u;qU&opEuZ_x1K>@i3QTl+}2&;QiV6Dsg9 zN3b%*daNhI@VQe~bT(OluJ9=US2fQs);MU=3dV`L*5F`qLzGo&P1>OIBuWjrQd(&AQjcr~aojGF;U7Psce? z3zXo>P4Q#t;qi*05J4kSYki*|=+e5EUCg=0BcduPI!SS3HSdVqA%Yb;h`&}Ev*i3v z>kV7adR)!-y?h$;NZ{l*lYHKU7XICw!B@Q14pNLZD#5;GULuP{>IHh%X3z>x$drU< z>qR*V%ao>ELq)-y`PqJS=LG~Mw0K7J#lfT1E%A!xU}HS~`SK&ZAX9<%@*gen*byF) z`Aio#M=zJR8ti-((qMXEgu(iB@9Fzn))xts%T!MsK!R5*e@a6)khUS} zjN9XcNk6{mzX;NPt1Nl%D}&&t-+#WK9({*Zi&gsD-B>H$(PN`+0M(?6c?{E}kpBbu zITSNbi;n!6`({%!%1686F4J&+#DzGPG4R=6W5ml;O}%omS0oz*KT1yc=QZ8ehU*vc z_$kiTbY=Su{M;bz_(cg_i-Q4MVH!CuYvT>z@-jNITk=%BeXQW}Q8&WcY(r zIVO9nLvPtLO*6FtDDm^vbgW_fer&6eX&q~Z_KPGTI z!pQ*}m%%ImQnQ@m6q^z7GzHqn-kZ)s**)3Tm{6i*(YZavc`QHOUT3ckf185Y61hAV zl`vyrinxC8<(RlHgA;K_+AWm2wU);-Z!(=fo8P>dRty=boBIz;6)v}yRJA_c73*@A zoi41eqc>f>#zDgWIfNojXx`9Q$N=x>>{lm(XLZb@RKujp`KjyK^P=g|RkT`Zmb}%b zGxSM>?j@ze&kikSElNl@TozT4d9`#&JNcjPA_&WDMk}g52~_VpfEekkhqo<0;d--9 zH;xQ?F?D6@*>Q3r$ZZWWKanDnR?eciZE?Z!QM97QY}IMfb(vVNkH#-FxSiNDM+#%s zt(?~Y7T6hsL}h+$-)QYtbYt3=-xQ1dIHa5h4o8RwkJo3t>kC7>8N17iM7C^2BOITg zKYKYmyU|?!>71fMoqR>TS!-F=koHIy@=OL(bB8Q-rb4;$84&h698sr9v5)p-a$k)T za-M7iAhH7W(o3AI6|LgC?>?y-O{BULk*4WZbPXriQCW*Jg$$I$z*xJ-H>2yRWPex3 z7(1zrmTBf_nljN*oR=Dg;+q^+|2CRH2D~nsCT2OL3}xUd9iWY?+njepjEzAPdU1yZ0fbTe<4rH(L5=Xc0_S4mQ9a{y)At6k6$$>a6HCP-DR%2I1v7X}_9Jj$ zdN~c9j!K=#>TS454&V3In$oW z3~h^+jCgQSKHsf_lIN=s>T%`@-fkD zcys5wz+$k#rFts3%O`|l5?Pq=wtRHuo?6r7pw@iK72)Wisj=%dqtBMD=(iWdLAjf# z@tgWt^XarNI`0ou@26Y*q|+9YI76geVo!!fQaNK%+7!#~=bAfLB{m&Hu|?npD3{-w z%frceM?nsZ!*e^5PO3@9zM$wlViE2dcNHWN8-nJU6DfR|I{(p3mn7yD5~aN)h?+ut z=Rnx*yctDmMqQ9PJ1s#LblmDT;pLC;*69l?Ig=yvmkD%qUC{B*7*1^l9=b<5`mYq$ z**<(9!P0fGBsITSl=?=3%e#R;{%s)pl|I%xb3;JwYt-qgpHX7R0ZWjaU|q+d>RI7g zx<*uds>J97217at`-F#UTX8Y#BgWA=G`4g~S^}!HX-R5sjxXEM7K0+(hzZ9qg!oOY z1I^>90ojhk>61n$KdNHyNuKxH(9w59;EQj|_<-4RuK|6HZ1zj59L%=;R^P<2o24m)m`^I>%7l>1;ep0>;wwy|H{I*B zvs6mCxzt!#0q+x)!(4)UUGjLaYOKko@$A4_S)&jizo$rJ8Xi=RTJ0sw*kxva>qAqkymFLq(2E>CXm*Hlm6)NA!jTlcH7j|*@|1v zCW$j4e)@M*O_Jvo4ePb70o~Ay*BU9k)LVNmE$ib47uSW9H-Pwze5Sh4^BYpVXABhb zS)=s^Otx-Wee96D^wEbV^~D7Sf464m*FH1bzc!&~(l9H@ugSqZu~-xpvdUhz)u8oG zeVc|u6-CKqEMOt~D$!-&ljev~G6(oI;bh3zi4oHwo7WJJ23P4QF2iaJ!=Add;!5?& zkZ~fuzSjdVJ%8f*n&rKrE} zDnG`zs|oB1GMjy1<(HohSd-5wwRBrLnk_UwGVAEvryexHOh=rQ;(iCJu!WH4BM0YH z@5dH-^djC9QNmN?=-2Q8gSPzG4|@2PJWQ(EIoq-G>J?*2m%8u!)7wjYqcxV}uCuu^ zPpF2{_50VDDZ#IiM9AQ;nF~LE$*z@Ml3rKpj7u?ixZzt)vmv4`;6^h^?*3N8Tv2vO zIUL)CD|Q2zYRkB_8llr&S-Egx8eE!|xF zq0~FGfgnyOg2{y*9hx=6pRc&bh8*ramO7C6%yg)1*bE;jVB-|AoCd0hq-Zz0zsRaG zWNp7NNh&=Z`9A zoG(+i=(Pk&oJ2*{ZuASw^))6l4afmxT!;p{&gk7t98{X-gN^gO7*d&-@cB;4ZCTla zVNQBySt|MX8q#CnJO`j?hK!YWzr06@M)70WL`Pt8HN^jI-0s7LXP!13NkqU61z~ap zg#{8lkCj8u29Ydecj#UCtd?b640Ee?9}kF3Dh`6s28#uSDsxa#!UbR2Y`1T+e;*87RSUt>aX>tWQU@um}x`eEHgp-G_cpq|o1rr+CiEJ|gek*o^b%xCe#iCkDEno|pNQdd;ZX63$M$dlwMeUM>3H1*FQ7L&i zhYM3_W7KMO`MxM*6UP~5&z`|k;AQ`1arahLG!nl1414zqgO(ZU{9CXX z@qJ%y)JZfVb0o&u6->HDO5chVqW6;y`%DQLbI_lDxmTQ?yHHp|EYySCQbRSI`zKNwkQiSO6A;OIgwe2D}(j-KM54T-YI8z%&j0SB{v_?=M z&5Z>Ia@VNQu3by{?}@uV)M5EJrrs_p+;LxVwAI<;!8rNmt%p}q{7^VU$N4LgS1 zsBx%Nfi*cA%t$pX&71{YQnWf$Zc&9u4Px9C_wF{MS7!!oC{X5LxCtFgjA^mzN3DQ2&kTh+snK5Qi}g6vFHrD3dMt-(~c?@p~B52o?3foqn41OX(o+; zf(a_PIzno#An8hM$qylNY^JlIYzQy;YJ?~>!KgDx#e?8tDkp20a!)R>U}~-`@8){w z%!$sUGboB=suC)MCi2M3z<{)+x6*9FX{Q=9%;?a!Y^toGueQ>OyS{7!Z?3p9V{)hM zq$9I6*%-30AtkRF($gfjDT}|6AbK*h!T3b!E39(bs5OO5l$9>~C{u2m=J*0ms2hy} z??6^h78!<5K-KTj`ty*QU8H3rfjE z1=Utd)2!N3NUj1y4z(KWC4YVDS-q{ za#Dv*D%Mk9w+fgkT}@K*T_07lki3Y_%nCi^GD{Qam>Nc{H@-l6cS#DVqK&67J;QU< zhSR+&O7QGMGp>Qcb?!XP@`6t()V#A5ugz=}65y!}16fs-b;C~ZrySCjCc?_i^ID&xcUK6OSS?5y8w6hX#lc%mHvRZ7uI_hZgH9=OLuBSg;S0|~&b{!aC>(FWb~U$$M<+x6mAD+>jPW_gBe<4IZ?|szr{% zn|6$9uD^g~vEYdX-F!zGopzf`;*iTwD86kK9`Q9zQ@Nw;W+jg!8$rkxB>D*?JYQjv z!2S}X(pac8YEzl1B!iLUrLJ)3+YhoVvJ-Wsg+#fln`^Y?k$d6mgRjFB%U%{k8U7;< z53+?MBos3@w80H=*r6LF(S{(pp%IN}LnGYK!yU?@4NP=I9GEDFB)UP0Zg`>*k@&h5o%ndAWwNz zKf-aFy_6yvl~_tG@-dl-6e&}Y*~dMCQw~rxqBAaTNr6>53+j(+U zx%L0J#YYrLOWsITDz>nSZjhl$2#rOqJ}JpUw^CPK9K4f4A&+C0(u{0+QZKrA=_3@3 zkwa8R5?wiEU7oX6&g`_GsDW-vjKYsl_H;K2^5`e#5n;3pbrXwShQwwe8rO)HnA_bg zGqRZuS>Q&rpUFrh4K~-iBGNSUnWso1vDWK&6dv^K2PO=T){(cx829v!B+YS*t>W9e z=2(agifrt+8^QEWYWHJZly?+7^z@|Aq}j|` zN(U$of{Aa7vEO+_XcVbkSuO>cUi#=mo7im_F%j@JvYC~-Vp6EE@dp2b zF7&jgA{gmg2`pX2QAkoBWXbY>oBFNj3q9~*H{LSkkvBj0HuOd3wLH*_78 z?O821c}ljt)3{F=i8E))53+q`>8+7UQdhdnup=C#T+=0WWJ+6|mZZIKMT$R-0@{oF zjIW1y&A)UBj<2;+nlk|mG4yM*QG7DpLTY zwnWHtzF9k%%TM881f!L4A_K`M>D!4)T=Z%A^e@@)(NY4Zv%715TU=1O6QI?CW&iDN za{XJ=m&iu17XzB;WE$SgM{{Xz8=PFLN!!R0Y@VP$xPF)zP%mhrA-Y#utLO=|yv_w2>yd*!pLbat@jwGa8Ag#NA%_x3Mz z7$|3iZTIeMN>D7{4v+y?WAS*;U5M`j&+pRQFZ{&f|LD&=Xb(?d&-?#ekN3V$0(%by zRj~FlumDXk{Q9r^mIU$8t2J!K8oo;#{zFkHgEG9NVLU=S>Lb-E$0;C%?RJDvMj}*3 zg>S-Tyqe-yzK1fvLMuwFfWX5lzy;@|u*~ueI>2zeLW6jg#cZg94B3s(I%2#O1x~=v z8WO=38c$!UB_S?h67cX6=0HvKCpvB}CAy1B_6{X(K@uck4kTgKfD9qVL<@66BZ?<} zVnoF%BYEJjJ4mBcPC_Q2LCCTtH0C0NwoN5!MS&WE%*bqfY6CooCsn%RJ?@MV$%Ien z%tI!ESD>&|Ji@$kq|BsnW7NbsDrGk2LPZ*;BWfdJ_JeTtwKAb@GCZG zQ$*+^qT?MmQ4^^nV&rUVPO%5M<~KORHHbz~MkZT&5n&W(cmCuQqe3Q}#aZ}*(+UF= zGsZa>L&PpJd!TS#2q)Zh3~%)9U|a}Nw1+C(u@d)97cKHHCZ`c2hhm84=THtIsW2u$ zQNps&S>&t>$qXN%<1}=UCGK%4flM1BBqhRY8*1n^me3Arpa!a-3M@gvd`G`9uz_r03jKuV<%)WJBDHs24oUu2O-(R+5X}1 zx~ybw=n{5eHFx0>BtdNCrtr3nz*;O-s#R^xIQh=4*v;;1iY z7OpQm=e{U{Z%k(KBIoDkgiT`PM~IU#gc37&F5t3;T;%I*Fz^HOjWfP)8*GO3WClv7 zL>H<63p61UGNBIWfCivoE3IWe;?nQTjz58dJogbL?1I$Fq|XAQE#0&&CE+a-11mZ# z{t{y0E@42t;UBy~2e&fL9E>mpHVHVnb?>hvU$#^KeCl$Svj=gVFzl<;IxwJgg)$7A}R1q()xi*TMoVV-+Qs zv?QNI0U=B#V)OO771Mw;TTD<+4s1#!?07m)3-9J8_EExarPy}UR$vatLX|#g(ndID z<)qDe@+HtJPhTS}^v2^YG>kK(gKp3S*vd}66IFFO@u;a8=MaZC1fgf zq6ReKO7ox&w3H6000s_qKs`@+Si~smEqkg001%DK4uw414BeiiEjhwX-%=JNVOpiE zD^ZT?1a&}?YZu&L3SKkveDE49AwmDP;cX`&ED;PmWMWbMwjSak8pQF()vW6gI0$YUq|0i4ouLZbhegg>}Ep| zj7QD{HG(gMW>gAk6iH~}L)r01JWSvewo0BuYA-@4Tovy23pcFxb0aT#8OY=c4NvZa z#b6VDwG4Z#BZAoR+DKz6LL$SS#4wzsZ?I)v4&oqv^C%3B3?pOS==9Oz5rRsR{XnLF zo&qwNw}RiMMKM@lTC@}^LvH`lrZUL&dr+=6HY_o)hAvEEK*@wCfUFG<)Ej}sg^z?M zz)n;^j5H16KNzS7i|AfLp_%HX;uOw>&6>bZ6Od0U#DYokZdJba$}~0gYB<M)!*W4oumvlD-$6@MYS;M1IeB&T8*D@pz zIe<-9J1sK@?k~8kPb8AkdhUNP?8&-AH7JZd?CgNXHz%;7B;o=!EFyWaLvIA8U_NwP z1g7fh&D;vs9I3KKNTt6vmug62RFao3IKxF$WZodJjO7AfpVaxZp@tMi7pNc;@*oc~ z0YG%24wAMGpdb!1b5s

  • Nr.
    Fachbereich
    Name
    Kurzbezeichnung'; + echo '
    Lehre Vz'; + echo '
    Farbe'; + echo '
    Lehrelehre=='t'?'checked':'').'>
    Sprache
    '; + echo ''; + echo ''; + +?> + + + + + +

    + +
    + +

    Übersicht

    + + +id\n"; + + for($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object($result_lehrfach); + echo ""; + echo ""; + echo ""; + echo ""; + echo "\n"; + } + + /* + $num_fields=pg_numfields($result_lehrfach); + $foo = 0; + for ($i=0;$i<$num_fields; $i++) + echo ""; + for ($j=0; $j<$num_rows;$j++) + { + $row=pg_fetch_row($result_lehrfach,$j); + $bgcolor = $cfgBgcolorOne; + $foo % 2 ? 0: $bgcolor = $cfgBgcolorTwo; + echo ""; + for ($i=0; $i<$num_fields; $i++) + echo ""; + //echo ""; + echo ""; + //echo "\n"; + $foo++; + } + */ +} +else + echo "Kein Eintrag gefunden!"; +?> +
    kurzbzbezeichnunglehrevzfarbeaktivectsfachbereichsprachelehre
    $row->nummer$row->fach$row->bezeichnung$row->lehrevz$row->farbe$row->aktiv$row->ects$row->fachbereich$row->sprachelehre=='t'?'checked':'').">nummer&type=edit&stg_kz=$stg_kz&semester=$semester\">Edit
    ".pg_fieldname($result_lehrfach,$i)."
    $row[$i]Details"; + //echo "EditEditDelete"; + echo "
    + + +
    + + \ No newline at end of file diff --git a/vilesci/stundenplan/lehrfach/wartung.php b/vilesci/stundenplan/lehrfach/wartung.php new file mode 100644 index 000000000..ecf4efd0e --- /dev/null +++ b/vilesci/stundenplan/lehrfach/wartung.php @@ -0,0 +1,232 @@ +18) + return substr($string,0,15)."..."; + else + return $string; + } + + if(isset($radio_1) && isset($radio_2)) + { + if($radio_1==$radio_2) + $msg="Die Datensätze dürfen nicht die gleiche id haben"; + else + { + $sql_query_upd1="UPDATE tbl_stundenplan Set lehrfach_nr='$radio_2' WHERE lehrfach_nr='$radio_1';"; + $sql_query_upd1.=" UPDATE tbl_stundenplandev Set lehrfach_nr='$radio_2' WHERE lehrfach_nr='$radio_1';"; + $sql_query_upd1.=" UPDATE tbl_lehrveranstaltung Set lehrfach_nr='$radio_2' WHERE lehrfach_nr='$radio_1';"; + $sql_query_upd1.=" UPDATE tbl_lvinfo Set lehrfach_nr='$radio_2' WHERE lehrfach_nr='$radio_1';"; + $sql_query_upd1.=" DELETE FROM tbl_lehrfach WHERE lehrfach_nr='$radio_1';"; + + if(pg_exec($conn,$sql_query_upd1)) + { + $msg = "Daten Erfolgreich gespeichert
    "; + } + $msg .= $sql_query_upd1 ."
    "; + + } + } + + if((isset($radio_1) && !isset($radio_2))||(!isset($radio_1) && isset($radio_2))) + { + $msg="Es müssen beide Radio Buttons angeklickt werden"; + } +?> + + + + + + +LV-Verteilung + + + +

    Lehrfach - Wartung

    + + + +"; + echo ""; + + //Drop Down Menü für Stg Tab1 + echo "  "; + + //Drop Down Menü für Sem Tab1 + echo "  "; + + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; +?> + +
     "; + echo "
    "; + + //Drop Down Menü für Stg Tab2 + echo "  "; + + //Drop Down Menü für Sem Tab2 + echo "  "; + + echo ""; + echo "
    "; + echo "
    +
    +

    +
    + +"; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo "
    Das wird geloescht:"; + + //Tabelle 1 + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + + $lf = new lehrfach($conn); + $lf->getTab($stg_1,$sem_1, $order_1); + $i=0; + foreach($lf->fkterg as $l) + { + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + $i++; + } + echo "
     LFNrKurzbzFormBezeichnungLVZECTS
    lehrfach_nr)?'checked':'').">$l->lehrfach_nr$l->kurzbz$l->lehrform_kurzbz".kuerze($l->bezeichnung)."$l->lehrevz$l->ects
    "; + echo "
    Das bleibt"; + + //Tabelle 2 + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + + $lf = new lehrfach($conn); + $lf->getTab($stg_2,$sem_2, $order_2); + $i=0; + foreach($lf->fkterg as $l) + { + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + $i++; + } + echo "
     LFNrKurzbzFormBezeichnungLVZECTS
    lehrfach_nr)?'checked':'').">$l->lehrfach_nr$l->kurzbz$l->lehrform_kurzbz".kuerze($l->bezeichnung)."$l->lehrevz$l->ects
    "; + echo "
    "; + echo ""; + +?> + + + + + + + + diff --git a/vilesci/stundenplan/lehrfach_verteilung.php b/vilesci/stundenplan/lehrfach_verteilung.php new file mode 100644 index 000000000..9a45dee68 --- /dev/null +++ b/vilesci/stundenplan/lehrfach_verteilung.php @@ -0,0 +1,214 @@ +0 ORDER BY kurzbz"; + //echo $sql_query."
    "; + $result_stg=pg_exec($conn, $sql_query); + if(!$result_stg) error ("studiengang not found!"); + $sql_query="SELECT id, kurzbz FROM lehrfach ORDER BY kurzbz"; + $result_lehrf=pg_exec($conn, $sql_query); + if(!$result_lehrf) echo "lehrfach not found!"; + $sql_query="SELECT id, kurzbz FROM ort ORDER BY kurzbz"; + $result_ort=pg_exec($conn, $sql_query); + if(!$result_ort) echo "ort not found!"; + if (!isset($stgid)) + $stgid=1; + $sql_query="SELECT kurzbz FROM studiengang WHERE id=$stgid"; + $result_stgbz=pg_exec($conn, $sql_query); + if(!$result_stgbz) + echo "lehrfach not found!"; + else + $stgbz=pg_result($result_stgbz,0,'kurzbz'); + if (!isset($semester)) + $semester=0; + if (!isset($verband)) + $verband='0'; + if (!isset($gruppe)) + $gruppe=0; + if (!isset($tag)) + $tag=1; + if (!isset($monat)) + $monat=1; + if (!isset($jahr)) + $jahr=2002; + $datum=" AND datum<='2002-07-01' AND datum>='2002-02-05'"; +?> + + + +Lehrfachverteilung + + + + +

    Lehrfachverteilung

    +
    +
    +

    Studiengang + + Semester + +

    +

    + + +

    +
    +
    + + + + + + + + + + + + + + + + + lehrfach_id; + $bgcolor = $cfgBgcolorOne; + $foo % 2 ? 0: $bgcolor = $cfgBgcolorTwo; + echo ""; + + $sql_query="SELECT kurzbz FROM lehrfach WHERE id='$lehrfachid'"; + $result=pg_exec($conn, $sql_query); + $row_lfbz=pg_fetch_object ($result, 0); + echo ""; + + $sql_query="SELECT count(*) AS stunden FROM stundenplan WHERE studiengang_id='$stgid' AND semester='$semester' AND lehrfach_id='$lehrfachid'".$datum." GROUP BY lehrfach_id"; + $result=pg_exec($conn, $sql_query); + if (pg_numrows($result)>0) + $row=pg_fetch_object ($result, 0); + else + $row->stunden=0; + echo ""; + + $sql_query="SELECT count(*) AS stunden FROM stundenplan WHERE studiengang_id='$stgid' AND semester='$semester' AND verband='0' AND gruppe='0' AND lehrfach_id='$lehrfachid'".$datum." GROUP BY lehrfach_id"; + $result=pg_exec($conn, $sql_query); + if (pg_numrows($result)>0) + $row=pg_fetch_object ($result, 0); + else + $row->stunden=0; + echo ""; + + $sql_query="SELECT count(*) AS stunden FROM stundenplan WHERE studiengang_id='$stgid' AND semester='$semester' AND verband='A' AND gruppe='0' AND lehrfach_id='$lehrfachid'".$datum." GROUP BY lehrfach_id"; + $result=pg_exec($conn, $sql_query); + if (pg_numrows($result)>0) + $row=pg_fetch_object ($result, 0); + else + $row->stunden=0; + echo ""; + + $sql_query="SELECT count(*) AS stunden FROM stundenplan WHERE studiengang_id='$stgid' AND semester='$semester' AND verband='A' AND gruppe='1' AND lehrfach_id='$lehrfachid'".$datum." GROUP BY lehrfach_id"; + $result=pg_exec($conn, $sql_query); + if (pg_numrows($result)>0) + $row=pg_fetch_object ($result, 0); + else + $row->stunden=0; + echo ""; + + $sql_query="SELECT count(*) AS stunden FROM stundenplan WHERE studiengang_id='$stgid' AND semester='$semester' AND verband='A' AND gruppe='2' AND lehrfach_id='$lehrfachid'".$datum." GROUP BY lehrfach_id"; + $result=pg_exec($conn, $sql_query); + if (pg_numrows($result)>0) + $row=pg_fetch_object ($result, 0); + else + $row->stunden=0; + echo ""; + + $sql_query="SELECT count(*) AS stunden FROM stundenplan WHERE studiengang_id='$stgid' AND semester='$semester' AND verband='B' AND gruppe='0' AND lehrfach_id='$lehrfachid'".$datum." GROUP BY lehrfach_id"; + $result=pg_exec($conn, $sql_query); + if (pg_numrows($result)>0) + $row=pg_fetch_object ($result, 0); + else + $row->stunden=0; + echo ""; + + $sql_query="SELECT count(*) AS stunden FROM stundenplan WHERE studiengang_id='$stgid' AND semester='$semester' AND verband='B' AND gruppe='1' AND lehrfach_id='$lehrfachid'".$datum." GROUP BY lehrfach_id"; + $result=pg_exec($conn, $sql_query); + if (pg_numrows($result)>0) + $row=pg_fetch_object ($result, 0); + else + $row->stunden=0; + echo ""; + + $sql_query="SELECT count(*) AS stunden FROM stundenplan WHERE studiengang_id='$stgid' AND semester='$semester' AND verband='B' AND gruppe='2' AND lehrfach_id='$lehrfachid'".$datum." GROUP BY lehrfach_id"; + $result=pg_exec($conn, $sql_query); + if (pg_numrows($result)>0) + $row=pg_fetch_object ($result, 0); + else + $row->stunden=0; + echo ""; + + $sql_query="SELECT count(*) AS stunden FROM stundenplan WHERE studiengang_id='$stgid' AND semester='$semester' AND verband='C' AND gruppe='0' AND lehrfach_id='$lehrfachid'".$datum." GROUP BY lehrfach_id"; + $result=pg_exec($conn, $sql_query); + if (pg_numrows($result)>0) + $row=pg_fetch_object ($result, 0); + else + $row->stunden=0; + echo ""; + + $sql_query="SELECT count(*) AS stunden FROM stundenplan WHERE studiengang_id='$stgid' AND semester='$semester' AND verband='C' AND gruppe='1' AND lehrfach_id='$lehrfachid'".$datum." GROUP BY lehrfach_id"; + $result=pg_exec($conn, $sql_query); + if (pg_numrows($result)>0) + $row=pg_fetch_object ($result, 0); + else + $row->stunden=0; + echo ""; + + $sql_query="SELECT count(*) AS stunden FROM stundenplan WHERE studiengang_id='$stgid' AND semester='$semester' AND verband='C' AND gruppe='2' AND lehrfach_id='$lehrfachid'".$datum." GROUP BY lehrfach_id"; + $result=pg_exec($conn, $sql_query); + if (pg_numrows($result)>0) + $row=pg_fetch_object ($result, 0); + else + $row->stunden=0; + echo ""; + + echo "\n"; + $foo++; + } + +} +?> +
    LehrfachGesamt
    $row_lfbz->kurzbz$row->stunden$row->stunden$row->stunden$row->stunden$row->stunden$row->stunden$row->stunden$row->stunden$row->stunden$row->stunden$row->stunden
    + + \ No newline at end of file diff --git a/vilesci/stundenplan/lv_verteilung.php b/vilesci/stundenplan/lv_verteilung.php new file mode 100644 index 000000000..ecf95f5c9 --- /dev/null +++ b/vilesci/stundenplan/lv_verteilung.php @@ -0,0 +1,61 @@ +='$datum_beginn' AND datum<='$datum_ende'"; + $sql_query.=" GROUP BY unr, semester, lehrfach_id, lehrfachkurzbz, lektor_id, lektorkurzbz"; + $sql_query.=" ORDER BY semester,unr,lektor_id"; + //echo $sql_query."
    "; + $result=pg_exec($conn, $sql_query); + $num_rows=pg_numrows($result); + // Daten in Array übernehmen + for ($i=0;$i<$num_rows;$i++) + { + $row=pg_fetch_object ($result, $i); + $unterricht[$i]->lektor_kbz=$row->lektorkurzbz; + $unterricht[$i]->lektor_id=$row->lektor_id; + $unterricht[$i]->lehrfach_kbz=$row->lehrfachkurzbz; + $unterricht[$i]->lehrfach_id=$row->lehrfach_id; + $unterricht[$i]->unr=$row->unr; + $unterricht[$i]->sem=$row->semester; + $unterricht[$i]->stunden=$row->stunden; + } +?> + + +<?PHP echo $stg_bez; ?> - Lehrfachverteilung + + + +

    - Überblick des Stundenplans

    +

    Von bis

    +
    + + +"; + echo ''; + echo ''; + echo ''; + } +?> +
    SemesterUNrLehrfachLektor(en) [Stunden]
    '.$unterricht[$i]->sem.''.$unterricht[$i]->unr.''.$unterricht[$i]->lehrfach_kbz.''.$unterricht[$i]->lektor_kbz.' ['.$unterricht[$i]->stunden.']'; + while ($unterricht[$i]->unr==$unterricht[$i+1]->unr) + echo ', '.$unterricht[++$i]->lektor_kbz.' ['.$unterricht[$i]->stunden.']'; + echo '
    + + \ No newline at end of file diff --git a/vilesci/stundenplan/lv_verteilung/lv_edit.php b/vilesci/stundenplan/lv_verteilung/lv_edit.php new file mode 100644 index 000000000..6cbce1896 --- /dev/null +++ b/vilesci/stundenplan/lv_verteilung/lv_edit.php @@ -0,0 +1,340 @@ + + + + + + + +LV-Verteilung + +lehrveranstaltung_id = $lv_id; + $lv->lvnr = $lvnr; + $lv->lehrform = $lehrform; + $lv->einheit_kurzbz = $einheit_kurzbz; + $lv->lektor = $lektor1; + $lv->lehrfach_nr = $lehrfach; + $lv->studiengang_kz=$studiengang; + $lv->fachbereich_id = $fachbereich; + $lv->semester = $semester; + $lv->verband= $verband; + $lv->gruppe = $gruppe; + $lv->raumtyp = $raumtyp; + $lv->raumtypalternativ = $raumtypalternativ; + $lv->semesterstunden = $semesterstunden; + $lv->stundenblockung = $stundenblockung; + $lv->wochenrythmus = $wochenrythmus; + $lv->start_kw = $startkw; + $lv->anmerkung = $anmerkung; + $lv->studiensemester_kurzbz = $studiensemester; + $lv->unr = $unr; + $lv->fas_id = $fasid; + $lv->lehre= $lehre; + $lv->new = $new; + if($status==1) + { + + if($lv->save()) + echo ""; + else + { + echo ""; + echo ""; + if(isset($new) && $new) + echo "

    LV Verteilung - NEW


    "; + else + echo "

    LV Verteilung - EDIT


    "; + echo "\n"; + echo "

    $lv->errormsg


    "; + } + + } + else if($status==3) + { + echo ""; + echo ""; + if(isset($new) && $new) + echo "

    LV Verteilung - NEW


    "; + else + echo "

    LV Verteilung - EDIT


    "; + echo "\n"; + if($lv->save()) + echo "

    Daten wurden gespeichert

    "; + else + echo "

    $lv->errormsg


    "; + } + else + { + echo ""; + echo ""; + if(isset($new) && $new) + echo "

    LV Verteilung - NEW


    "; + else + echo "

    LV Verteilung - EDIT


    "; + echo "\n"; + + } + } + else + { + echo ""; + echo ""; + if(isset($new) && $new) + echo "

    LV Verteilung - NEW


    "; + else + echo "

    LV Verteilung - EDIT


    "; + echo "\n"; + + if(!isset($new)) + { + if(isset($lvid)) + $lv->load($lvid); + else + die("Fehler bei der Parameterübergabe"); + } + else + { + if($new) + { + $lv->new=true; + + $lv->studiengang_kz = ($stg!=-1?$stg:'227'); + $lv->semester=$sem; + $lv->lvnr=0; + $lv->semesterstunden = 0; + $lv->stundenblockung = 0; + $lv->wochenrythmus = 1; + $lv->start_kw = 1; + $lv->unr = 0; + $lv->lehre = "on"; + + $sql_query="select studiensemester_kurzbz from tbl_studiensemester where startstudiensemester_kurzbz=$row->studiensemester_kurzbz; + else + $lv->studiensemester_kurzbz=-1; + + } + } + } + //Formular anzeigen + echo "<- Zurück zur Übersicht
    "; + echo ''; + echo "\n"; + echo ""; + echo "\n"; + //echo ""; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + echo ""; + + echo "\n"; + echo ""; + + // echo ""; + echo "\n"; + echo ""; + + echo "\n"; + echo ""; + + echo "\n"; + echo ""; + + + echo "\n"; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + echo ""; + echo "\n"; + //echo ""; + echo "\n"; + echo ""; + echo "\n"; + if($lv->lehre=='t') + $lv->lehre='on'; + echo ""; + echo ""; + echo "\n"; + echo ""; + echo "
    Lehrveranstaltungs ID
    Lvnr
    Lektor
    Studiengang
    Semester
    Verband
    Gruppe
    Einheit kurzbz
    einheit_kurzbz
    Lehrfach
    Lehrform
    Fachbereich
    Raumtyp
    Raumtyp Alternativ
    Semesterstunden
    Stundenblockung
    Wochenrythmus
    StartKW
    Anmerkung
    Studiensemester
    FasId
    UNr
    Lehrelehre=='on'?'checked':'').">
     
     "; + if(isset($new) && $new) + echo "
    "; + echo ""; +?> + \ No newline at end of file diff --git a/vilesci/stundenplan/lv_verteilung/lv_verteilung.php b/vilesci/stundenplan/lv_verteilung/lv_verteilung.php new file mode 100644 index 000000000..95ceb0773 --- /dev/null +++ b/vilesci/stundenplan/lv_verteilung/lv_verteilung.php @@ -0,0 +1,249 @@ + + + + + + + +LV-Verteilung + + + +

    LV Verteilung

    +studiensemester_kurzbz; + else + $stsem=-1; + } + if(!isset($stg)) + { + $stg=227; + } + if(!isset($lektor)) + { + $lektor=-1; + } + if(!isset($sem)) + { + $sem=-1; + } + + if(isset($saved)) + { + echo "

    Daten wurden gespeichert


    "; + } + + if(isset($lfnr) && isset($lvz)) //ändern des LVZ + { + $sql_query = "Update tbl_lehrfach SET lehrevz='$lvz' WHERE lehrfach_nr='$lfnr' "; + pg_exec($conn,$sql_query); + echo "

    Update durchgeführt


    "; + } + + if(isset($lfnr) && isset($_POST['stb']) && isset($_GET['lvnr'])) //ändern der Stundenblockung + { + $sql_query = "Update tbl_lehrveranstaltung SET stundenblockung='". $_POST['stb']."' WHERE lvnr='". $_GET['lvnr']."'"; + if(pg_exec($conn,$sql_query)) + echo "

    Update durchgeführt


    "; + else + echo "

    Update Fehlgeschlagen, Bitte erneut versuchen


    "; + } + + if(isset($lvid) && isset($lehre)) //ändern von Lehre + { + $sql_query = "Update tbl_lehrveranstaltung SET lehre=not lehre WHERE lehrveranstaltung_id ='$lvid'"; + if(pg_exec($conn,$sql_query)) + echo "

    Update durchgeführt


    "; + else + echo "

    Fehler beim Update


    "; + } + + if(isset($del) && isset($lvid)) + { + + $sql_query = "DELETE FROM tbl_lehrveranstaltung WHERE lehrveranstaltung_id='$lvid'"; + pg_exec($conn,$sql_query); + echo "

    DELETE durchgeführt


    "; + + } + $sql_query = "SELECT studiensemester_kurzbz FROM public.tbl_studiensemester order by start DESC"; + $result = pg_exec($conn, $sql_query); + $numrows = pg_num_rows($result); + $aktrows=0; + echo '
    '; + //Ausgeben der Studiensemester zb WS2005, SS2006 etc + echo "Alle -"; + while($row=pg_fetch_object($result)) + { + $aktrows++; + if($aktrows==$numrows) + echo " $row->studiensemester_kurzbz "; + else + echo " $row->studiensemester_kurzbz -"; + } + echo ""; + echo "
    "; + echo "
    "; + $sql_query = "SELECT studiengang_kz, kurzbz FROM public.tbl_studiengang ORDER BY kurzbz"; + $result = pg_exec($conn,$sql_query); + echo "\n"; + echo ''; + echo ""; + echo ""; + echo "\n"; + + $sql_query = "SELECT a.uid, nachname, vornamen FROM public.tbl_mitarbeiter a, public.tbl_person b where a.uid=b.uid AND a.lektor='true' ORDER BY b.nachname"; + $result = pg_exec($conn,$sql_query); + echo "\n"; + echo ""; + echo "
    Studiengang:Lektor:
    "; + echo "
    "; + echo "
    "; + echo "\n"; + + if($stg!=-1) //Wenn ein Studiengang ausgewählt wurde + { + //Anzeigen der Semester + echo "Semester:Alle "; + + $sql_query = "SELECT max_semester FROM public.tbl_studiengang WHERE studiengang_kz='$stg' LIMIT 1"; + //echo $sql_query; + $result = pg_exec($conn,$sql_query); + if($row=pg_fetch_object($result)) + { + for($i=1;$i<($row->max_semester+1);$i++) + { + echo "- $i "; + } + } + + } + echo " 

    "; + + echo "Aktuelle Auswahl:"; + if($stsem!=-1) + echo " Studiensemester: $stsem"; + if($stg!=-1) + { + $sql_query = "SELECT kurzbz FROM tbl_studiengang where studiengang_kz='$stg'"; + $result=pg_exec($conn,$sql_query); + $row = pg_fetch_object($result); + echo " Studiengang: $row->kurzbz"; + } + if($sem!=-1) + echo " Semester: $sem"; + if($lektor!=-1) + echo " Lektor: $lektor"; + + echo "
    "; + //Tabelle aufbauen + + //Daten holen + $lvobj = new lv_verteilung($conn); + + + if($lvobj->getTab($stsem,$sem,$stg,$lektor,$order)) + { + echo "\n"; + echo ''; + echo "\n"; + echo ' '; + //Kopfzeile der Tabelle + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo "\n"; + + + //Tabellenelemente rausschreiben + for($i=0;$i<$lvobj->anz;$i++) + { + $fe = $lvobj->retwert[$i]; + echo "\n"; + echo ' '; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + //echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + } + } + else + { + echo "
    Keine Daten mit diesen Kriterien Vorhanden"; + } + +?> + + \ No newline at end of file diff --git a/vilesci/stundenplan/modulplan_insert.php b/vilesci/stundenplan/modulplan_insert.php new file mode 100644 index 000000000..e49729cca --- /dev/null +++ b/vilesci/stundenplan/modulplan_insert.php @@ -0,0 +1,234 @@ + + + + +Modulplan Eingabe + + + +

    Eingabe in Modulplan

    +
    + +

    Einheit + + Lehrfach + + Ort + +

    + Tag + + Monat + + Jahr + + 1. Stunde + +

    +

    Stunden/Block + + Stunden/Semester + + Rythmus + + wöchig +

    +

    + + +

    +
    + +"; + echo "Kontrolle auf Doppelbelegungen! ... "; + + // checken auf Ort + $date[mday]=$tag; $date[mon]=$monat; $date[year]=$jahr; + $datum=$jahr."-".$monat."-".$tag; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$rythmus)); + $datum=$date[year]."-".$date[mon]."-".$date[mday]; + } + $sql_query="SELECT id FROM stundenplan WHERE datum='$datum' AND stunde_id='$std' AND ort_id='$ortid'"; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + echo "error!
    Doppelbelegung gefunden auf Ort=$ortid Datum=$datum Stunde=$stunde!
    "; + $error=true; + } + } + // checken auf Lehrfach + $date[mday]=$tag; $date[mon]=$monat; $date[year]=$jahr; + $datum=$jahr."-".$monat."-".$tag; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$rythmus)); + $datum=$date[year]."-".$date[mon]."-".$date[mday]; + } + $sql_query="SELECT id FROM stundenplan WHERE datum='$datum' AND stunde_id='$std' AND lehrfach_id='$lehrfachid'"; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + echo "error!
    Doppelbelegung gefunden auf Lehrfach=$lehrfachid Datum=$datum Stunde=$stunde!
    "; + $error=true; + } + } + + // checken auf Ort im Einheitenplan + $date[mday]=$tag; $date[mon]=$monat; $date[year]=$jahr; + $datum=$jahr."-".$monat."-".$tag; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$rythmus)); + $datum=$date[year]."-".$date[mon]."-".$date[mday]; + } + $sql_query="SELECT id FROM einheiten WHERE datum='$datum' AND stunde_id='$std' AND ort_id='$ortid'"; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + echo "error!
    Doppelbelegung gefunden im Einheitenplan auf Ort=$ortid Datum=$datum Stunde=$stunde!
    "; + $error=true; + } + } + // checken auf Lehrfach im Einheitenplan + $date[mday]=$tag; $date[mon]=$monat; $date[year]=$jahr; + $datum=$jahr."-".$monat."-".$tag; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$rythmus)); + $datum=$date[year]."-".$date[mon]."-".$date[mday]; + } + $sql_query="SELECT id FROM einheitenplan WHERE datum='$datum' AND stunde_id='$std' AND lehrfach_id='$lehrfachid'"; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + echo "error!
    Doppelbelegung gefunden im Einheitenplan auf Lehrfach=$lehrfachid Datum=$datum Stunde=$stunde!
    "; + $error=true; + } + } + + //Einfügen in die Datenbank + if (!$error) + { + echo "OK!
    "; + $date[mday]=$tag; $date[mon]=$monat; $date[year]=$jahr; + $datum=$jahr."-".$monat."-".$tag; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$rythmus)); + $datum=$date[year]."-".$date[mon]."-".$date[mday]; + } + $sql_query="INSERT INTO einheitenplan (einheit_id, lehrfach_id, ort_id, datum, stunde_id) VALUES ('$einheitid', '$lehrfachid', '$ortid', '$datum', '$std')"; + //echo $sql_query; + $result=pg_exec($conn, $sql_query); + if(!$result) + { + echo pg_errormessage()."
    "; + $error=true; + } + else + echo "Einheit_ID: $stgid - Lehrfach_ID: $lehrfachid - Ort_ID: $ortid - Datum: $datum - Stunde: $std -- Eingefuegt!
    "; + + } + if (!$error) + echo "Einfügen erfolgreich abgeschlossen!
    "; + else + echo "Es ist ein Fehler aufgetreten!
    "; + } +} +?> + + \ No newline at end of file diff --git a/vilesci/stundenplan/ort.php b/vilesci/stundenplan/ort.php new file mode 100644 index 000000000..7dc3290d1 --- /dev/null +++ b/vilesci/stundenplan/ort.php @@ -0,0 +1,10 @@ + + +Untitled Document + + + + + + + diff --git a/vilesci/stundenplan/ort_edit_save.php b/vilesci/stundenplan/ort_edit_save.php new file mode 100644 index 000000000..c73a635b7 --- /dev/null +++ b/vilesci/stundenplan/ort_edit_save.php @@ -0,0 +1,39 @@ +; + //echo $sql_query; + } + +?> + + + +Ort ändern + + + + + +

    Ort ändern

    + + + ID: + + + + + + + diff --git a/vilesci/stundenplan/stdplan_clean_check.php b/vilesci/stundenplan/stdplan_clean_check.php new file mode 100644 index 000000000..28522345a --- /dev/null +++ b/vilesci/stundenplan/stdplan_clean_check.php @@ -0,0 +1,74 @@ + + + Stundenplan säubern + + +

    Stundenplan säubern

    +

    Folgende Einträge kommen doppelt vor:

    +

    +"; + if (!$equl) + { + $equl=true; + echo $stdplan_table[$i][1],"
    "; + $anz++; + } + } + else + $equl=false; +} +echo "$anz doppelte Einträge wurden gefunden und gelöscht.
    $num_rows Einträge gesamt."; +/*$foo = 0; +for ($j=0; $j<$num_rows; $j++) +{ + $bestell_id=mysql_result($result, $j, "ID"); + $bestell_nr=mysql_result($result, $j, "BestellNr"); + $bgcolor = $cfgBgcolorOne; + $foo % 2 ? 0: $bgcolor = $cfgBgcolorTwo; + echo "

    "; + echo ""; + echo ""; + echo ""; + $body.="$bestell_nr: \t http://data.technikum-wien.at/bestellungen/bestell_det_ueb.php3?bestellid=$bestell_id\n"; + echo "\n"; + $foo++; +} */ +?> +

    +
    +Erstellt am 28. Mai 2001 von Christian Humer
    +Letzte Änderung: 28. Mai 2001 von Christian Humer + + diff --git a/vilesci/stundenplan/stdplan_clean_go.php b/vilesci/stundenplan/stdplan_clean_go.php new file mode 100644 index 000000000..a0293ee90 --- /dev/null +++ b/vilesci/stundenplan/stdplan_clean_go.php @@ -0,0 +1,54 @@ + + + + Stundenplan säubern + + +

    Stundenplan säubern

    +

    Folgende Einträge kommen doppelt vor:

    +

    +helpstr=".$help_str." - table0=".$stdplan_table[$i][0]." - table1=".$stdplan_table[$i][1]; +} + +//Sortieren +for ($i=1; $i<$num_rows; $i++) + { + $erg=strcmp($stdplan_table[$i-1][1],$stdplan_table[$i][1]); + if ($erg==0) + { + echo $stdplan_table[$i][1]."
    "; + $mysql_query="DELETE FROM stundenplan WHERE id=".$stdplan_table[$i][0]; + $result=mysql_query($mysql_query); + $anz++; + } + } + +echo "$anz doppelte Einträge wurden gefunden und gelöscht.
    $num_rows Einträge gesamt."; + +?> +

    +
    +Erstellt am 28. Mai 2001 von Christian Humer
    +Letzte Änderung: 18. Juni 2001 von Christian Humer + + diff --git a/vilesci/stundenplan/stdplan_delete.php b/vilesci/stundenplan/stdplan_delete.php new file mode 100644 index 000000000..9b62b385f --- /dev/null +++ b/vilesci/stundenplan/stdplan_delete.php @@ -0,0 +1,231 @@ +0 ORDER BY kurzbz"; + $result_stg=pg_exec($conn, $sql_query); + if(!$result_stg) + error ("studiengang not found!"); + if ($mode=='del') + { + $sql_query="DELETE FROM tbl_stundenplan WHERE studiengang_kz=$stg_kz AND datum>='$jahrv-$monatv-$tagv' AND datum<='$jahrb-$monatb-$tagb'"; + //echo $sql_query.'
    '; + $result=pg_query($conn, $sql_query); + $anz=pg_numrows($result); + echo $anz.' Records deleted!
    '; + } + if (!isset($stg_kz)) + $stg_kz=0; + if (!isset($tagv)) + $tag=1; + if (!isset($monatv)) + $monat=1; + if (!isset($jahrv)) + $jahr=2002; + if (!isset($tagb)) + $tag=1; + if (!isset($monatb)) + $monat=1; + if (!isset($jahrb)) + $jahr=2002; + + //echo '
    Beginn:'.mktime(0,0,0,2,23,2004).'
    '; + //echo '
    Ende:'.mktime(0,0,0,6,17,2004).'
    '; +?> + + + +Delete Stundenplan + + + +

    Delete from Stundenplan

    +
    + +

    Studiengang + +

    +

    Von (inkl): Tag + + Monat + + Jahr + +

    +

    Bis (inkl): Tag + + Monat + + Jahr + +

    +

    + + +

    +
    + +"; + echo "Kontrolle auf Doppelbelegungen! ... "; + + // checken auf Ort + $date[mday]=$tag; $date[mon]=$monat; $date[year]=$jahr; + $datum=$jahr."-".$monat."-".$tag; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$rythmus)); + $datum=$date[year]."-".$date[mon]."-".$date[mday]; + } + $sql_query="SELECT id FROM stundenplan WHERE datum='$datum' AND stunde_id='$std' AND ort_id='$ortid'"; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + echo "error!
    Doppelbelegung gefunden auf Ort=$ortid Datum=$datum Stunde=$stunde!
    "; + $error=true; + } + } + // checken auf Lehrfach + $date[mday]=$tag; $date[mon]=$monat; $date[year]=$jahr; + $datum=$jahr."-".$monat."-".$tag; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$rythmus)); + $datum=$date[year]."-".$date[mon]."-".$date[mday]; + } + $sql_query="SELECT id FROM stundenplan WHERE datum='$datum' AND stunde_id='$std' AND lehrfach_id='$lehrfachid'"; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + echo "error!
    Doppelbelegung gefunden auf Lehrfach=$lehrfachid Datum=$datum Stunde=$stunde!
    "; + $error=true; + } + } + // checken auf Verband + $date[mday]=$tag; $date[mon]=$monat; $date[year]=$jahr; + $datum=$jahr."-".$monat."-".$tag; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$rythmus)); + $datum=$date[year]."-".$date[mon]."-".$date[mday]; + } + $sql_query="SELECT semester, verband, gruppe, studiengang_kz FROM tbl_stundenplan WHERE datum='$datum' AND stunde_id='$std' AND studiengang_kz='$stg_kz' AND semester='$semester' AND (verband='$verband' OR verband=NULL) AND (gruppe='$gruppe' OR gruppe=NULL)"; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + $row=pg_fetch_object($result,0); + echo "error!
    Doppelbelegung gefunden auf Datum=$datum - Stunde=$stunde - StudiengangID=$row->studiengang_id - Semester=$row->semester Verband=$row->verband Gruppe=$row->gruppe!
    "; + $error=true; + } + } + + // checken auf Ort im Einheitenplan + $date[mday]=$tag; $date[mon]=$monat; $date[year]=$jahr; + $datum=$jahr."-".$monat."-".$tag; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$rythmus)); + $datum=$date[year]."-".$date[mon]."-".$date[mday]; + } + $sql_query="SELECT id FROM einheitenplan WHERE datum='$datum' AND stunde_id='$std' AND ort_id='$ortid'"; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + echo "error!
    Doppelbelegung gefunden im Einheitenplan auf Ort=$ortid Datum=$datum Stunde=$stunde!
    "; + $error=true; + } + } + // checken auf Lehrfach im Einheitenplan + $date[mday]=$tag; $date[mon]=$monat; $date[year]=$jahr; + $datum=$jahr."-".$monat."-".$tag; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$rythmus)); + $datum=$date[year]."-".$date[mon]."-".$date[mday]; + } + $sql_query="SELECT id FROM einheitenplan WHERE datum='$datum' AND stunde_id='$std' AND lehrfach_id='$lehrfachid'"; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + echo "error!
    Doppelbelegung gefunden im Einheitenplan auf Lehrfach=$lehrfachid Datum=$datum Stunde=$stunde!
    "; + $error=true; + } + } + + //Einfügen in die Datenbank + if (!$error) + { + echo "OK!
    "; + $date[mday]=$tag; $date[mon]=$monat; $date[year]=$jahr; + $datum=$jahr."-".$monat."-".$tag; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$rythmus)); + $datum=$date[year]."-".$date[mon]."-".$date[mday]; + } + if (($verband=='0') && ($gruppe==0)) + $sql_query="INSERT INTO stundenplan (studiengang_id, semester, verband, gruppe, lehrfach_id, ort_id, datum, stunde_id) VALUES ('$stgid', '$semester', NULL, NULL, '$lehrfachid', '$ortid', '$datum', '$std')"; + elseif ($gruppe=0) + $sql_query="INSERT INTO stundenplan (studiengang_id, semester, verband, gruppe, lehrfach_id, ort_id, datum, stunde_id) VALUES ('$stgid', '$semester', '$verband', NULL, '$lehrfachid', '$ortid', '$datum', '$std')"; + else + $sql_query="INSERT INTO stundenplan (studiengang_id, semester, verband, gruppe, lehrfach_id, ort_id, datum, stunde_id) VALUES ('$stgid', '$semester', '$verband', '$gruppe', '$lehrfachid', '$ortid', '$datum', '$std')"; + //echo $sql_query; + $result=pg_exec($conn, $sql_query); + if(!$result) + { + echo pg_errormessage()."
    "; + $error=true; + } + else + echo "Studiengang_ID: $stgid - Semester: $semester - Verband: $verband - Gruppe: $gruppe - Lehrfach_ID: $lehrfachid - Ort_ID: $ortid - Datum: $datum - Stunde: $std -- Eingefuegt!
    "; + + } + if (!$error) + echo "Einfügen erfolgreich abgeschlossen!
    "; + else + echo "Es ist ein Fehler aufgetreten!
    "; + } +} +?> + + diff --git a/vilesci/stundenplan/stdplan_insert.php b/vilesci/stundenplan/stdplan_insert.php new file mode 100644 index 000000000..55e3a6f3c --- /dev/null +++ b/vilesci/stundenplan/stdplan_insert.php @@ -0,0 +1,347 @@ +0 ORDER BY kurzbz"; + //echo $sql_query."
    "; + $result_stg=pg_exec($conn, $sql_query); + if(!$result_stg) + error ("studiengang not found!"); + $sql_query="SELECT lehrfach_nr, kurzbz,bezeichnung FROM tbl_lehrfach where aktiv=true or aktiv is null ORDER BY kurzbz"; + $result_lehrf=pg_exec($conn, $sql_query); + if(!$result_lehrf) + error ("lehrfach not found!"); + $sql_query="SELECT tbl_person.uid, kurzbz FROM tbl_person join tbl_mitarbeiter using(uid) where lektor=true ORDER BY kurzbz"; + $result_lektor=pg_exec($conn, $sql_query); + if(!$result_lektor) + error ("lektor not found!"); + $sql_query="SELECT ort_kurzbz FROM tbl_ort ORDER BY ort_kurzbz"; + $result_ort=pg_exec($conn, $sql_query); + $sql_query="SELECT einheit_kurzbz,bezeichnung FROM tbl_einheit ORDER BY einheit_kurzbz"; + $result_einheit=pg_exec($conn, $sql_query); + if(!$result_einheit) error("Einheit not found!"); + if(!$result_ort) + error ("ort not found!"); + + $sql_query="SELECT lehrform_kurzbz,bezeichnung FROM tbl_lehrform where verplanen=true ORDER BY lehrform_kurzbz"; + $result_lehrform=pg_exec($conn, $sql_query); + if(!$result_lehrform) error("Lehrform not found!"); + + if (!isset($stgid)) + $stgid=1; + if (!isset($lektorid)) + $lektorid=1; + if (!isset($semester)) + $semester=0; + if (!isset($verband)) + $verband='0'; + if (!isset($gruppe)) + $gruppe=0; + if (!isset($tag)) + $tag=1; + if (!isset($monat)) + $monat=1; + if (!isset($jahr)) + $jahr=2002; + if (!isset($stdbegin)) + $stdbegin=1; + if (!isset($stdblock)) + $stdblock=1; + if (!isset($stdsemester)) + $stdsemester=1; + if (!isset($lehrformid)) + $lehrformid=''; +?> + + + +Stundenplan Check + + + + +

    Eingabe in Stundenplan

    +
    + +

    Studiengang +

    +

    Semester + + Verband + + Gruppe + +

    +

    + [ Einheit + ] + + + Lehrfach + + +

    + Unterrichtsnummer + +

    + + + Lektor + + + + Lehrform + + +

    +

    + Ort + + + + Tag + + Monat + + Jahr + + 1. Stunde + +

    +

    Stunden/Block + + Stunden/Semester + + Rythmus + + wöchig +

    +

    + + +

    +
    + +"; + echo "Kontrolle auf Doppelbelegungen! ... "; + + // checken auf Ort + $date[mday]=$_POST['tag']; $date[mon]=$_POST['monat']; $date[year]=$_POST['jahr']; + $datum=$tag.".".$monat.".".$jahr; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$_POST['rythmus'])); + $datum=$date[mday].".".$date[mon].".".$date[year]; + } + $sql_query="set datestyle to german;SELECT stundenplandev_id FROM tbl_stundenplandev WHERE datum='$datum' AND stunde='$std' AND ort_kurzbz='".$_POST['ortid']."'"; + if ($_POST['unr']=='') + $sql_query.=" AND unr IS NOT NULL"; + else + $sql_query.=" AND unr!=".$_POST['unr']; + echo $sql_query; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + echo "error!
    Doppelbelegung gefunden auf Ort=".$_POST['ortid']." Datum=$datum Stunde=$stunde!
    "; + $error=true; + } + } + + // checken auf Lektor im Stundenplan + $date[mday]=$_POST['tag']; $date[mon]=$_POST['monat']; $date[year]=$_POST['jahr']; + $datum=$tag.".".$monat.".".$jahr; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$_POST['rythmus'])); + $datum=$date[mday].".".$date[mon].".".$date[year]; + } + $sql_query="SELECT stundenplandev_id FROM tbl_stundenplandev WHERE datum='$datum' AND stunde='$std' AND uid='".$_POST['$lektorid']."'"; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + echo "error!
    Doppelbelegung gefunden auf Lektor=".$_POST['$lektorid']." Datum=$datum Stunde=$stunde!
    "; + $error=true; + } + } + + // checken auf Verband + $date[mday]=$_POST['tag']; $date[mon]=$_POST['monat']; $date[year]=$_POST['jahr']; + $datum=$tag.".".$monat.".".$jahr; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$_POST['rythmus'])); + $datum=$date[mday].".".$date[mon].".".$date[year]; + } + $sql_query="SELECT semester, verband, gruppe, tbl_stundenplandev.studiengang_kz,tbl_studiengang.kurzbz FROM tbl_stundenplandev JOIN tbl_studiengang using(studiengang_kz) WHERE datum='$datum' AND stunde='$std' AND studiengang_kz='".$_POST['stgid']."' AND semester='$semester' AND (verband='".$_POST['verband']."' OR verband=NULL) AND (gruppe='".$_POST['gruppe']."' OR gruppe=NULL)"; + $result=pg_exec($conn, $sql_query); + if($result && (pg_numrows($result)>0)) + { + $row=pg_fetch_object($result,0); + echo "error!
    Doppelbelegung gefunden auf Datum=$datum - Stunde=$stunde - Studiengang=$row->kurzbz - Semester=$row->semester Verband=$row->verband Gruppe=$row->gruppe!
    "; + $error=true; + } + } + + //Einfuegen in die Datenbank + if (!$error) + { + echo "OK!
    "; + $date[mday]=$_POST['tag']; $date[mon]=$_POST['monat']; $date[year]=$_POST['jahr']; + $datum=$tag.".".$monat.".".$jahr; + for ($i=0; ($i<$stdsemester)&&!$error; $i++) + { + $std=$stunde+($i % $stdblock); + if ( ($std==$stunde) && (($i>0)||($stdblock==1)) ) + { + $time=mktime(0, 0, 0, $date[mon], $date[mday], $date[year]); + $date=getdate($time+(604800*$_POST['rythmus'])); + $datum=$date[mday].".".$date[mon].".".$date[year]; + } + // todo: unr als string? + $sql_query="INSERT INTO tbl_stundenplandev (studiengang_kz, semester, verband, gruppe, lehrfach_nr, uid, ort_kurzbz, datum, stunde,einheit_kurzbz,unr,updateamum,updatevon, lehrform_kurzbz) ". + "VALUES ('".$_POST['stgid']."', '".$_POST['semester']."', '".$_POST['verband']."', '".$_POST['gruppe']."', '".$_POST['lehrfachid']."', '".$_POST['lektorid']."', '".$_POST['ortid']."', '$datum', $std,".($_POST['einheit_kurzbz']==-1?'NULL':"'".$_POST['einheit_kurzbz']."'").",".($_POST['unr']==-1?'NULL':$_POST['unr']).",now(),'".$_SERVER['PHP_AUTH_USER']."','".$_POST['lehrformid']."')"; + echo $sql_query; + $result=pg_exec($conn, $sql_query); + if(!$result) + { + echo pg_errormessage()."
    "; + $error=true; + } + else + echo "Studiengang_ID: ".$_POST['stgid']." - Semester: ".$_POST['semester']." - Verband: ".$_POST['verband']." - Gruppe: ".$_POST['gruppe']." - Lehrfach_Nr: ".$_POST['lehrfachid']." - Lektor_ID: ".$_POST['lektorid']." - Lehrform: ".$_POST['lehrformid']." - Ort_ID: ".$_POST['ortid']." - Datum: $datum - Stunde: $std -- Eingefuegt!
    "; + + } + if (!$error) + echo "Einfuegen erfolgreich abgeschlossen!
    "; + else + echo "Es ist ein Fehler aufgetreten!
    "; + } +} +?> + + diff --git a/vilesci/stundenplan/stundenplan_info.html b/vilesci/stundenplan/stundenplan_info.html new file mode 100644 index 000000000..b1e132d3e --- /dev/null +++ b/vilesci/stundenplan/stundenplan_info.html @@ -0,0 +1,10 @@ + + +Untitled Document + + + + + + + diff --git a/vilesci/stundenplan/zeitwuensche.php b/vilesci/stundenplan/zeitwuensche.php new file mode 100644 index 000000000..730dcfca3 --- /dev/null +++ b/vilesci/stundenplan/zeitwuensche.php @@ -0,0 +1,108 @@ +tag][$row->stunde][$row->gewicht]=$row->anz; + } + +?> + + + +Profil + + + + + +

    Statistik der Zeitwünsche

    +Anzahl der Lektoren: +
      SVGEinheitLektorRaumtypSSBlockungWRLFKZLehreLVZLehrfachbezeichnung
    editdelete$fe->semester$fe->verband$fe->gruppe$fe->einheit_kurzbz$fe->lektor$fe->raumtyp / $fe->raumtypalternativ$fe->semesterstunden$fe->stundenblockung
    $fe->wochenrythmus$fe->lehrfach_kurzbz
    $fe->lehrfach_bz
    $bestell_id
    $bestell_nr
    Details
    + + Stunde
    Beginn
    Ende'; + for ($i=0;$i<$num_rows_stunde; $i++) + { + $beginn=pg_result($result_stunde,$i,'"beginn"'); + $beginn=substr($beginn,0,5); + $ende=pg_result($result_stunde,$i,'"ende"'); + $ende=substr($ende,0,5); + $stunde=pg_result($result_stunde,$i,'"stunde"'); + echo ""; + } + ?> + + '; + for ($i=0;$i<$num_rows_stunde;$i++) + { + $pos=$wunsch[$j][$i+1][4]+$wunsch[$j][$i+1][5]; + $neg=$wunsch[$j][$i+1][3]+$wunsch[$j][$i+1][2]+$wunsch[$j][$i+1][1]+$wunsch[$j][$i+1][0]; + $bgcolor=$cfgStdBgcolor[round(14/$anz_lektoren*$pos)-4]; + echo ''; + } + echo ''; + } + ?> +
    $stunde
    $beginn
    $ende
    '.$tagbez[$j].''; + echo '+:'.round(100/$anz_lektoren*$pos).'%
    '; + echo '-:'.round(100/$anz_lektoren*$neg).'%'; + echo '
    +Details + + + Stunde
    Beginn
    Ende'; + for ($i=0;$i<$num_rows_stunde; $i++) + { + $beginn=pg_result($result_stunde,$i,'"beginn"'); + $beginn=substr($beginn,0,5); + $ende=pg_result($result_stunde,$i,'"ende"'); + $ende=substr($ende,0,5); + $stunde=pg_result($result_stunde,$i,'"stunde"'); + echo ""; + } + ?> + + '; + for ($i=0;$i<$num_rows_stunde;$i++) + { + echo ''; + } + echo ''; + } + ?> +
    $stunde
    $beginn
    $ende
    '.$tagbez[$j].''; + for ($g=5;$g>=0;$g--) + if (isset($wunsch[$j][$i+1][$g])) + echo ($g-3).':'.round(100/$anz_lektoren*$wunsch[$j][$i+1][$g]).'%
    '; + echo '
    + + diff --git a/wap/index.php b/wap/index.php new file mode 100644 index 000000000..82629ca43 --- /dev/null +++ b/wap/index.php @@ -0,0 +1,10 @@ + \ No newline at end of file