dadabik

Check-in [ea538d2a63]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:import
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | descendants | trunk
Files: files | file ages | folders
SHA3-256:ea538d2a63895af354df9a6dcb917a9d32ce56667148591418d8ba00570ab272
User & Date: feld@feld.me 2012-04-27 21:52:06
Context
2012-04-30
17:15
Cleanup horrible DOS carriage returns Fix some english translation stuff check-in: d38db9a4b3 user: feld@nas.feld.me tags: master, trunk
2012-04-27
21:52
import Leaf check-in: ea538d2a63 user: feld@feld.me tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace

Added buttons/Thumbs.db.

cannot compute difference between binary files

Added buttons/dadabik_button.gif.

cannot compute difference between binary files

Added buttons/dadabik_button_small.gif.

cannot compute difference between binary files

Added changelog.htm.







































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
Please note that in the "Fixed bugs" sections, the bugs are not just related to the previous version, most of the time they also affect other old releases.


<h1>April 3, 2012<br>
v. 4.4<br></h1><hr size="1">

<b>New features and feature changes</b><br/><br/>

DaDaBIK can now officially handle and create front-end for views, in addition to front-end for normal tables. This can help in creating more flexible database applications.<br><br>

It is now possible to avoid the display of the NULL column in the insert/edit form. A parameter $null_checkbox is now available in config.php. Note that, if the record you are editing contains a NULL value for one or more fields, the NULL checkboxes are displayed anyway, even if $null_checkbox is set to 0.<br><br>

The DaDaBIK end-user interface is now available in Russian.<br><br>

Oracle and MS SQL Server are not officially supported anymore.<br><br>

German, Dutch and French translations are now complete.<br><br>



<b>Fixed bugs</b><br><br>

Some special characters were not correctly escaped in some situations, this chould lead to errors and/or insert/update of wrong data in the database.<br><br>

DaDaBIK, with SQLite, didn't produce error messages if an SQL query failed. For example, an insert query which violated a constrain, was reported as "Record correctly inserted." even if the record was not inserted. Fixed.<br/><br/>

DaDaBIK produced a "Fatal error: Cannot re-assign auto-global variable _POST" if used together with PHP 4.4. Fixed.<br/><br/>

DaDaBIK produced an error during installation with PostgreSQL >= 9.1. Fixed. <br/><br/>

If all the fields of an edit form were required but one or more fields were NULL in the database, the corresponding NULL checkbox were displayed but the column label "NULL" were not. Fixed, the column label is now displayed.<br><br>

A bug prevented to work correctly with date type field and SQLite. Fixed. Thanks to Triton for having reported it (<a href="http://www.dadabik.org/forum/read.php?1,14771">http://www.dadabik.org/forum/read.php?1,14771</a>).<br/><br/>

If, for a date field, the value of the month was set to other than [1-12] OR the value of the day was set to other than [1-31] OR the value of the year was set to other than [$start_year-$end_year] DaDaBIK will displayed in the edit view, for the relative field, the first default value available in the listbox. For example if a date field was set 1940-00-00 in the database, DaDaBIK will display, in its default configuration, 1968-01-01 and updated the date to 1968-01-01 if the record is saved. Fixed. Now DaDaBIK produce an error message if a date value is not representable with the day-month-year listboxes.<br><br>

If, for a select_single field, the user selected "other" and didn't specify a custom value during insert/update, the value "......" was inserted. Fixed, now a "required field" error message is displayed. <br><br>

If, after a insert/update operation, the form was displayed again to the user because of an error (e.g. a required field was not filled) and the value of a date field was set to NULL, some undefined variable messages were displayed. Fixed.<br><br>

If, for a select_single field, the user selected "other" and specify a custom value during insert, that new value was not included as additional option. Fixed.<br><br>

<b>Other changes</b><br/><br/>

A new section, "Unexpected behaviors" has been added to the documentation. It's a list of behaviors which the average user doesn't expect from DaDaBIK but that probably can't be considered real bugs. An important point discussed here is about the value actually inserted in the database during an insert/update, if the value typed in the form is not part of the domain specified during table creation.<br><br>

The "Known bugs and limitations" section of the documentation has been updated, highlighting two bugs, one related to search operations and the other related to some characters which, for some languages, are incorrectly displayed.


<br/>

<h1>February 14, 2012<br>
v. 4.4 beta<br></h1><hr size="1">

<b>Fixed bugs</b><br><br>

The authentication didn't work correctly and prevent users to log-in if the DBMS chosen was SQLite. FIXED.<br/><br/>

The date field type didn't work properly during insert/update/search and produced a "Notice: Undefined property" message. FIXED.<br/><br/>

Master/details view didn't work correctly with SQLite and produced a "Call to undefined method PDOStatement::MoveFirst()" message. FIXED.<br/><br/>

When a new item was inserted in a master-details view, the default "parent" item wasn't selected if the field name of the parent table and the (fk) field name of the items table were different. FIXED.<br/><br/>

<b>Other changes</b><br/><br/>
The "Known bugs and limitations" section of the documentation has been updated, highlighting a new date-field related bug; the lack of a locking mechanism during records editing has also been highlighted in the documentation, since the current behaviour could lead to unexpected results and data loss.

<br/>

<h1>February 2, 2011<br>
v. 4.4 alpha<br></h1><hr size="1">

<b>New features and feature changes</b><br/><br/>
DaDaBIK now supports <a href="http://www.sqlite.org/">SQLite</a><br/><br/>

A new content type "timestamp" is available. The corresponding field must contain an integer, which is displayed as a date and time according to the format chosen with the paramenter $date_format.<br/><br/>

magic_quotes_sybase = on in php.ini is no longer required for Oracle and MS SQL Server<br/><br/>

The documentation is now more clear about the master/details view.<br/><br/>

A new parameter, $timezone, allows to set the timezone.<br/><br/>

The sql logging feature is not available anymore.<br/><br/>

<b>Fixed bugs</b><br><br>

The authentication didn't work if DaDaBIK was installed in the root of a Website (e.g. www.mysite.com and not www.mysite.com/dadabik).<br/><br/>

DaDaBIK produced an error about date_default_timezone_set if the PHP version was < 5.1.<br/>


<h1>December 8, 2010<br>
v. 4.3 final<br></h1><hr size="1">

<b>Fixed bugs and feature changes<br><br></b>
The TinyMCE version used to implement the rich_editor is now the 3.3.9.2 . This can fix security problems and other issues that the old TinyMCE version used could cause.
<br><br>

Some MAC OS not needed files were included in the DaDaBIK release. Fixed (thanks Tobias S. for pointing out).<br><br>

On Windows Vista (and maybe on other Operating Systems), some warnings about encoding were displayed by the system during the extraction of the zip release file. Fixed (thanks Tobias S. for pointing out).<br><br>

DaDaBIK showed a "delete all" link for an items table even if the delete operation was disabled for that table. The "delete all" operation, however, wasn't executed. Fixed.<br><br>

After a "delete all" operation performed on a master/details view, DaDaBIK showed the results view of the details table instead of coming back to the master/details view. Fixed.<br><br>

DaDaBIK now shows a table alias near to the "insert item" link.<br><br>

Minor change to the English interface<br><br>

A small banner is now showed in the homepage of the admin interface.<br><br>

The changelog didn't contain the changes for DaDaBIK 4.3 beta. Fixed.

<br>


<h1>November 28, 2010<br>
v. 4.3 beta RC2 (release candidate 2)<br></h1><hr size="1">

<b>New features, fixed bugs and feature changes<br><br></b>
DaDaBIK, with some PHP versions and error reporting settings, produced some "Deprecated" and "Strict Standard" warnings. This was due to the ADOdb version used, which was too old. DaDaBIK now uses the last ADOdb version for PHP5 and automatically load the last PHP4 compatible ADOdb library if you are still using PHP4. This can also fix security problems and other issues that the old ADOdb version used could cause.
<br><br>

The single-donation button of the admin section didn't work.<br><br>

A lot of not strictly-needed files has been removed from the official release, which is now lighter.<br><br>

It is now possible to to send feedback on DaDaBIK to hotscripts.com directly from the admin section.<br><br>

The documentation didn't explain how to upgrade to 4.3 rc1. Fixed.
<br>

<h1>November 23, 2010<br>
v. 4.3 beta RC1 (release candidate 1)<br></h1><hr size="1">

<b>New features and feature changes<br><br></b>DaDaBIK has a new administration section: new look, some improvements in the interface, in-line help for the interface configurator, possibility to send feedback, to donate and to buy email/phone commercial support. The configuration file has been improved in clarity too.<br><br>It is now possible to choose if a table can appear in the table list menu.<br><br>The "home" button, which had been deleted, is now available again.<br><br>If a table is an "items table" in a master-details view, the insert/search/show all/last search results top buttons are not anymore displayed,<br><br>The documentation has been completely revised, clarifying some aspects when needed and highlighting some new known bugs/limitations.<br><br>Minor GUI enanchements.<br><br><b><br>Fixed bugs</b><br><br>DaDaBIK 4.3 beta3 in a case-sensitive environment didn't include the htmLawed library because of a mistake in the case of a letter. This leave DaDaBIK exposed to the security risk that version 4.3 beta3 was supposed to fix (see 4.3 beta 3 changelog's entry for details). A "Warning: include(./include/htmlawed/htmlawed.php) : failed to open stream" warning messase could also be produced. Thanks to <a href="http://www.dadabik.org/forum/profile.php?1,65597">Kaiya</a> for pointing this out.<br><br>
With PHP &lt; 4.1.0 and DaDaBIK 4.3 beta, beta2 or beta3 there could be
problems with the escaping procedure, this could lead to various
problems (even security problems).<br><br>The URL validation didn't work as expected.<br><br>The enable/disable features control didn't work as expected.<br><br>If the first table present in the table list menu was empty (no records), DaDaBIK didn't show the table list menu.<br><br>When $enable_browse_authorization was enabled, using the previous-next links DaDaBIK tried to show also non-authorized records; the records details weren't showed but a message "You don't have the authorization to view this record." was displayed.<br><br>DaDaBIK, if a table was used as "items" table, didn't correctly take into consideration the permissions (insert, edit, details, delete) set in order to display the corresponding controls.<br><br>When a record is deleted, now also the files linked to the record are deleted. Is it possible to control this behaviour changing the new config parameters delete_files_when_delete_record.<br>

<h1>November 15, 2010<br>
v. 4.3 beta3</h1><hr size="1">

<b>Fixed bugs and changes</b><br><br>

If a DaDaBIK application was configured to use at least one html content type field or one rich_editor field type field, a malicious user who had access to the application could insert in the field some arbitrary javascript code, which was then executed by other users just by using the application.
Among other problems, this could lead to XSS attack (<a href="http://en.wikipedia.org/wiki/Cross-site_scripting">http://en.wikipedia.org/wiki/Cross-site_scripting</a>), which in turn could allow an unauthorized access to the application (<a href="http://en.wikipedia.org/wiki/Session_hijacking">http://en.wikipedia.org/wiki/Session_hijacking</a>) and, if the Internet browser of the user contained security holes, even the execution of arbitrary code in the client machine. The problem is now fixed applying a filter provided by the htmLawed library (<a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed</a>) when the output is displayed. You must however keep in mind that, as the documentation states (<a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/htmLawed_README.htm#s2.8">http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/htmLawed_README.htm#s2.8</a>), there are some minor cases in which htmLawed can fail.<br><br>

Since htmLawed requires at least PHP version 4.3, even the PHP minimum version requirements of DaDaBIK have changed from 4.05 to 4.3.

<h1>November 11, 2010<br>
v. 4.3 beta2</h1><hr size="1">

<b>Fixed bugs</b><br><br>

If in a DaDaBIK application the insert or edit feature was enabled (at least for one table) and a select_single field type was used (at least once, even in another table), a malicious user who had access to the application could in many cases insert in a listbox some arbitrary javascript code, which was then executed by other users just by using the application.
Among other problems, this could lead to XSS attack (<a href="http://en.wikipedia.org/wiki/Cross-site_scripting">http://en.wikipedia.org/wiki/Cross-site_scripting</a>), which in turn could allow an unauthorized access to the application (<a href="http://en.wikipedia.org/wiki/Session_hijacking">http://en.wikipedia.org/wiki/Session_hijacking</a>) and, if the Internet browser of the user contained security holes, even the execution of arbitrary code in the client machine. This problem have been fixed in version 4.3 beta2.<br>The problems described above can occur even when the insert or edit feature was enabled (at least for one table) and the HTML content type is used; at the moment there isn't a patch for this second scenario, the HTML content type should be used carefully, as highlighted in the upgraded documentation.<br><br>


DaDaBIK didn't show the default edit, delete and delete icons.

<h1>October 21, 2010<br>
v. 4.3 beta</h1><hr size="1">
<b>New features and feature changes</b><br><br>

DaDaBIK has now a new and better Graphic User Interface.<br><br>

Having magic_quotes_gpc set to On is not anymore needed.<br><br>

The documentation, in particular the "Known bugs and limitations" sections, has been updated.<br><br>

<b>Fixed bugs</b><br><br>

DaDaBIK showed a notice error message when the previous/next button was used after an error on update (e.g. a missing field); now the buttons are not anymore displayed.<br><br>

DaDaBIK produced a "Undefined variable" notice when showing results and nor records were found.<br><br>

DaDaBIK could display a deprecated warning related to eregi if used together with PHP &gt;= 5.3<br><br>

The upgrade file upgrade_4.3.php was not adodb-compatible and therefore probably didn't work with all the DBMS supported.

<h1>September 14, 2010<br>
v. 4.3 alpha</h1><hr size="1">
<b>New features and feature changes</b><br><br>

DaDaBIK now supports a master/details view: for example if you have an <i>albums</i> table and a <i>songs</i> table you can set DaDaBIK to display in the same page the details of an album and the result list of the songs linked to.<br><br>

The documentation, in particular the "Security" and "Multiple function views" sections, have been updated.<br><br>

<b>Fixed bugs</b><br><br>

DaDaBIK didn't correctly execute a search based on a field if, for that field, you choosed from the interface configurator just one search operator.<br><br>

DaDaBIK showed a javascript error message when a results view was displayed.

<h1>February 18, 2007<br>
v. 4.2</h1><hr size="1">
<b>Fixed bugs</b><br><br>

The Rumanian language is now complete.

<h1>February 8, 2007<br>
v. 4.2 beta</h1><hr size="1">
<b>Fixed bugs</b><br><br>

Previous and next buttons didn't work correctly after an update operation which caused an error (for example for a missed required field value) and now are not displayed any more in the above case.<br><br>

<b>New features and feature changes</b><br><br>

DaDaBIK now handles the NULL values, it is now possible to insert a NULL value in a field and to search for NULL values.<br><br>

New search operator available: is empty.<br><br>

The required fields are now displayed using a * sign, instead of using a different color.<br><br>

The documentation, in particular the "Known bugs and limitations" section, has been updated.

<h1>January 18, 2007<br>
v. 4.1 final release</h1><hr size="1">
<b>Fixed bugs</b><br><br>

After a login or a "Show all" operation the order type stored for the current table was not cleaned, as expected.<br><br>

In some particular cases, the previous and next record links didn't work and DaDaBIK produced a "Notice: Undefined index:..." message.<br><br>

For a linked field, DaDaBIK didn't use its own type and content in order to correctly display it in the results and details view.

<h1>January 14, 2007<br>
v. 4.1 release candidate 3</h1><hr size="1">
<b>Fixed bugs</b><br><br>

DaDaBIK version 4.1 rc2 produced a "[08] Error: during query execution." error message during the installation.

<h1>January 14, 2007<br>
v. 4.1 release candidate 2</h1><hr size="1">
<b>Fixed bugs</b><br><br>

The "refresh installation" admin operation didn't work correctly and could lead to an interface configurator settings loss. Please note that this bug can appear even on a DaDaBIK version &gt;= 4.1 rc2 if the installation is the result of an upgrade from a version &lt; 4.1 rc2; the bug is considered fixed only for tables installed (DaDaBIK installation from scratch or single table installation from the admin interface) using a DaDaBIK version &gt;= 4.1 rc2.<br><br>

DaDaBIK in some cases produced an "[08] Error: during query execution." error message if the user clicked on the previous or next record links.<br><br>

DaDaBIK lost the "Field present in the details page?" option setting after a "Refresh installation" procedure.<br><br>

Rumanian language is now complete.<br><br>

Some CSS style settings were repeated twice in css/styles_screen.css, in some cases using different values.<br><br>

The documentation has been revisited, in particular the upgrade process is now clearer and a new known bug has been added to the documentation.<br><br>

If one or more tables name were particularly long DaDaBIK could produce a "[08] Error: during query execution." error message on Oracle during the DaDaBIK installation or during a single table installation.<br><br>

The default upper limit for the year part of a date is now 2010.<br><br>

styles_print.css code clean-up.
<br><br>

<b>New features and feature changes</b><br><br>

The pdf file extension is now allowed by default for file upload.

<h1>November 13, 2006<br>
v. 4.1 release candidate 1</h1><hr size="1">
<b>Fixed bugs</b><br><br>

If a table was empty and the user selected it, the tables listbox disappeared so it was impossible to choose another table.<br><br>

The upgrade script upgrade_4.1.php had the name of one of the DaDaBIK tables hard-coded; this could lead to problems during the upgrade process if the $table_list_name (confgi.php) variable value was not "dadabik_table_list".<br><br>

The upgrade script upgrade_4.1.php didn't work correctly on Oracle.<br><br>

Portuguese language  is now complete.<br><br>

Croatian language is now complete.<br><br>

Swedish language was not present in the documentation languages list.

<h1>October 24, 2006<br>
v. 4.1 beta</h1><hr size="1">
<b>New features and feature changes</b><br><br>

Better form errors handling: if an error occurs when the user fills a form (e.g. an URL format is not correct), DaDaBIK will display again the form and point out the type of error.<br><br>

E-mail notices: DaDaBIK sends an e-mail message to some specified people when a new record is inserted or an existent record modified.<br><br>

Previous and next buttons are now available in edit and details views.<br><br>

Also the administration pages are now protected by authentication (if enabled); only administrator users can enter the administration pages. Note that the installation file (install.php) is not protected, should be used only for the first installation and then removed.<br><br>

DaDaBIK now remembers the last search executed on a table, even if you change table.<br><br>

It is now possible to choose the number of result records displayed per page on the fly. DaDaBIK also saves the number choosed on a per-table base.<br><br>

It is now possible to set an alias for each table, the alias is used in the table listbox instead of the table name.<br><br>

DaDaBIK now uses tinymce 2.0.7 (<a href="http://tinymce.moxiecode.com">http://tinymce.moxiecode.com</a>) to implement the rich_editor field type instead of htmlarea. This leads to FireFox compatibily.<br><br>

DaDaBIK now highlights a results table row when the mouse pointer is over it. It also highlights a results table row when the user click on it, until the user click it again. You can disable this feature by using the new config.php parameter $enable_row_highlighting.<br><br>

Some changes in the layout element positions to increase usability.<br><br>

Finnish language is now available.<br><br>

A link to the administration page is now available and is displayed only if the user is an administrator.<br><br>

DaDaBIK now display using a small arrow the current type of order (ASC or DESC).<br><br>

By default, after an insert is now displayed the results view.<br><br>

<b>Fixed bugs</b><br><br>

During an insert, even if authentication and browse authorization were enabled, the similarity check procedure checked not only the records that the curent user owned, but all the records and showed the possible duplicates even if the current user didn't own them.<br><br>

The documentation has been revisited, in particular it has been highlighted that Oracle needs magic_quotes_sybase = on set in php.ini.

<h1>October 04, 2006<br>
v. 4.0</h1><hr size="1">
<b>New features</b><br><br>

DaDaBIK now uses ADOdb version 4.92. This change fixes the "Notice: Only variable references should be returned by reference in..." messages.<br><br>

Swedish language is now available<br><br>

DaDaBIK installation process on Oracle is now clearer.<br><br>

<b>Fixed bugs</b><br><br>

On Oracle, from the record results view, several "Undefined index" notices were displayed, it was not possible to correctly enter the detail and the edit form of the records and the delete record function didn't work.<br><br>

On Oracle 10, DaDaBIK tried to use the recycle bin tables too.<br><br>

The documentation has been revisited.<br><br>

In the install.php and header_admin.php scripts the name of the file index.php was hard-coded, instead of varying according to the $dadabik_main_file config variable.<br><br>

The configuration file is now clearer about the $host parameter and specify the possible need of the instance name for MS SQL server

<h1>January 24, 2006<br>
v. 4.0 beta 2</h1><hr size="1">

<b>Fixed bugs</b><br><br>

There was some missing information in the documentation.

<h1>January 24, 2006<br>
v. 4.0 beta</h1><hr size="1">
<b>New features</b><br><br>

DaDaBIK officially supports Oracle and MS SQL Server DBMS. A special thanks to Claude Moreau (claude dot moreau dot olom at gmail dot com) for the great work he did on the Oracle porting.<br><br>

The Hungarian and Slovak languages are now available.<br><br>

The documentation has been improved and a new section "Coding guidelines" has been added.<br><br>

DaDaBIK now checks for duplications by default for the username field of the users table.<br><br>

It is now possible to set the CSV creation time limit; this can fix the problems related to the CSV creation time limit errors.<br><br>

Two DaDaBIK buttons are now available ("buttons" folder).<br><br>

<b>Fixed bugs</b><br><br>

DaDaBIK didn't display correct search result values when the same field name appears in two linked tables as linked field. This bug, supposed to be fixed in the 3.1 beta release, is now really fixed.<br><br>

DaDaBIK showed a wrong list of result records for a search if $enable_authentication and $enable_browse_authorization were enabled and the user specified more than one search criteria, setting also "Any of the conditions required".<br><br>

The required property didn't work properly with file types, now the setting of a file-type field as "not required" is not needed any more. Thanks to alpha2zee (drpatnaik at yahoo dot com) who proposed the first version of the patch.<br><br>

DaDaBIK produced a "Fatal error: Call to undefined function: newadoconnection()" message if upgrade.php or upgrade_3.2.php were executed.<br><br>

DaDaBIK produced a "Notice: Undefined variable: upgrade...." message when upgrade.php was executed.<br><br>

In the login.php script the name of the file index.php was hard-coded, instead of varying according to the $dadabik_main_file config variable.<br><br>

DaDaBIK didn't display the "create password" after a user adding if $insert_again_after_insert was set to 1.<br><br>

DaDaBIK displayed some messages in English even if the language set was "Italian".

<h1>June 20, 2005<br>
v. 4.0 alpha</h1><hr size="1">
<b>Fixed bugs</b><br><br>

DaDaBIK produced some "Notice: Undefined variable....." messages and a "[08] Error: during query execution" error message in the details or edit view (if $enable_browse_authorization was enabled) or after a delete (if $enable_delete_authorization was enabled) or update (if $enable_update_authorization was enabled); only if $enable_authentication was enabled and the current table or the ID_user field name needed to be quoted.<br><br>

If the $autosumbit_change_table_control parameter was set to 1 the tables listbox form in the administration section was not auto-submitted "on change" and a javascript error was produced when the current table was changed.<br><br>

<b>New features</b><br><br>
DaDaBIK uses now the <a href="http://adodb.sourceforge.net/">ADOdb</a> Database Abstraction Library in order to support as many DBMS as possible, at the moment it has been tested just with MySQL 4.0.x and PostgreSQL 8.x.<br><br>

SQL logging: it is now possible to configure DaDaBIK for logging all SQL queries in the adodb_logsql table ($enable_sql_logging parameter in config.php)<br><br>

The documentation has been revised.<br><br>

<h1>June 4, 2005<br>
v. 3.2</h1><hr size="1">
<b>Fixed bugs</b><br><br>

If two or more DaDaBIK installations were hosted under the same domain, if a user logged into one of them it was possible to access all the others bypassing the login procedure. DaDaBIK session cookies are now valid only for the directory where DaDaBIK is installed (set through the new configuration variable $site_path).<br><br>

DaDaBIK produced a parse error if the Portuguese language was used.<br><br>

Croatian translation is now complete.<br><br>

DaDaBIK produced a "[08] Error: during query execution" error message in the results view if the table in use or the current "order by" field name needed to be quoted and the current "order by" field hadn't any linked fields.<br><br>

The possible duplications results view didn't show linked field values and produced a "Notice: Undefined index....." error message if one ore more fields had linked fields (<a href="http://www.dadabik.org/forum/read.php?f=1&amp;i=4302&amp;t=4154">http://www.dadabik.org/forum/read.php?f=1&amp;i=4302&amp;t=4154</a>).<br><br>

<b>New features</b><br><br>
Added two known bugs to the documentation, in particular it has been highlighted a possible security problem of the DaDaBIK authentication model.<br><br>


<h1>March 31, 2005<br>
v. 3.2 beta</h1><hr size="1">
<b>Fixed bugs</b><br><br>

DaDaBIK produced a "[08] Error: during query execution" error message in the details view if, for a field, the primary key field name of the main table was the same of the primary key field name of the linked table.<br><br>

All the "Undefined variable" error messages have been fixed, DaDaBIK can now works correctly with error_reporting = E_ALL.<br><br>

DaDaBIK lost the "Other choices allowed?" option information after a "Refresh installation" procedure (administration interface).<br><br>

DaDaBIK produced a "[08] Error: during query execution" error message if, during an insert or update, a new option was added to a select_single field with no linked fields and at least one of the preexisting options contained a character to be escaped (e.g. ').<br><br>

DaDaBIK produced a "[08] Error: during query execution" error message if, during an insert or update, there was at least one select_single field with linked fields, $enable_authentication and $enable_browse_authorization were enabled, the table contains an ID_user field and the linked table doesn't contain any ID_user fields with the same field name.<br><br>

An Italian sentence was not correct.<br><br>

DaDaBIK produced a parse error message if the German language was used<br>(<a href="http://www.dadabik.org/forum/read.php?f=1&amp;i=3432&amp;t=3432">http://www.dadabik.org/forum/read.php?f=1&amp;i=3432&amp;t=3432</a>).<br><br>

In the footer page the name of the file index.php was hard-coded, instead of varying according to the $dadabik_main_file config variable.<br>
(<a href="http://www.dadabik.org/forum/read.php?f=2&amp;i=371&amp;t=371">http://www.dadabik.org/forum/read.php?f=2&amp;i=371&amp;t=371</a>).<br><br>

Config variable $always_add_blank_option_search didn't work correctly, the variable is not used any more and now DaDaBIK always add a blank option to the select_single fields.<br><br>

<b>New features and feature changes</b><br><br>

The authentication code has been in part rewritten:
<ul>
	<li>The class simpleLogin (<a href="http://www.phpclasses.org/browse/package/1492.html">http://www.phpclasses.org/browse/package/1492.html</a>) is not used any more
	</li><li>DaDaBIK stores now user information in the database and passwords are now md5 encrypted
	</li><li>It is also possible to use a pre-existent users table
	</li><li>You can use DaDaBIK itself in order to add and delete users, show and modify users information
	</li><li>The admin pages (admin.php, install.php) are not login-protected any more, you have to provide your own protection
	</li><li>A select_single field with linked fields now shows a listbox with all the corresponding linked table records, regardless of the ownership.
</li></ul>

Six new languages are available: Croatian, Polish, Catalan, Estonian, Rumanian, Portuguese.<br><br>

A "top" link has been added to the HTML footer.<br><br>

The documentation has been updated and improved, in particular a FAQ section is now available.<br><br>

The installation procedure has now more explicative messages.<br><br>


<h1>July 19, 2004<br>
v. 3.1 beta</h1><hr size="1">
<b>Fixed bugs</b><br><br>

DaDaBIK produced a "[08] Error: during query execution" when a linked table was referenced more than once in the same table.<br><br>

DaDaBIK didn't display correct result values when the same field name appears both in a table and in a linked table as linked field or in two linked tables as linked field.<br><br>


<b>New features</b><br><br>
DaDaBIK has now a rewritten engine that perform the select query using joins and aliases (this fixes the bug above)<br><br>

A basic authorization model is available, it is now possible to allow a user to delete only his own records, modify only his own records, view only his own records. For the authentication the class simpleLogin (<a href="http://www.phpclasses.org/browse/package/1492.html">http://www.phpclasses.org/browse/package/1492.html</a>) has been (probably temporary) used, but it is possible to easily customize the authentication.<br><br>

A new field type is available: <i>rich_editor</i>; it is a rich text editor (htmlArea 2.03 by interactivetools.com <a href="http://www.interactivetools.com/products/htmlarea/">http://www.interactivetools.com/products/htmlarea/</a>) that allows to easily insert/modify HTML content<br><br>

A new content type is available: <i>html</i>, DaDaBIK doesn't perform a conversion from special characters to HTML entities with <i>htmlspecialchars</i> for the fields having this content type<br><br>

DaDaBIK starts now displaying the records of the first table available, without showing the home page menu. All the application (except from the administration area) uses now just one file index.php, easily renameable to embed it in a pre-existent Web site.<br><br>

An upgrade script is now available, it is possible to upgrade from 3.0 beta or 3.0 to 3.1 beta without loosing the interface configurator settings.<br><br>

A new parameter $enable_delete_all_feature allows to enable/disable the <i>delete all</i> feature<br><br>


<h1>May 25, 2004<br>
v. 3.0</h1><hr size="1">
<b>Fixed bugs</b><br><br>

DaDaBIK produced a "[08] Error: during query execution" error when a table name contained blank spaces
(<a href="http://www.dadabik.org/forum/read.php?f=1&amp;i=2136&amp;t=2136">http://www.dadabik.org/forum/read.php?f=1&amp;i=2136&amp;t=2136</a>).<br><br>

DaDaBIK produced a "[08] Error: during query execution" error when the MySQL version was prior to 3.23.06.<br><br>

DaDaBIK produced a "[08] Error: during query execution" error when a field has some linked fields associated and the primary key field is not numeric
(<a href="http://www.dadabik.org/forum/read.php?f=1&amp;i=2365&amp;t=2365">http://www.dadabik.org/forum/read.php?f=1&amp;i=2365&amp;t=2365</a>).<br><br>

DaDaBIK produced a "Call to undefined function: ob_clean()...." fatal error if the export to CSV feature was enabled and the PHP version was &lt; 4.2.0 (<a href="http://www.dadabik.org/forum/read.php?f=1&amp;i=2329&amp;t=2209">http://www.dadabik.org/forum/read.php?f=1&amp;i=2329&amp;t=2209</a>); the export to CSV now works also with PHP version prior to 4.2.0.<br><br>

DaDaBIK produced a parse error when the Italian language was used.<br><br>

Fixed some translations and added a missing sentence in the Italian language file.<br><br>

The word "home" in the bottom links menu is now available in each language file and no more hard-coded.<br><br>

DaDaBIK produced a "Undefined variable: mail_feature....." notice.<br><br>
<b>New features</b><br><br>
A new parameter $word_wrap_fix_width allows to choose if $word_wrap_col determines also the width of the column in the results table or not.<br><br>
<b>Notes</b><br><br>
The following two bugs have been discovered during the beta testing:<br><br>

DaDaBIK produces a "[08] Error: during query execution" when a linked table is referenced more than once in the same table (<a href="http://www.dadabik.org/forum/read.php?f=1&amp;i=2374&amp;t=2374">http://www.dadabik.org/forum/read.php?f=1&amp;i=2374&amp;t=2374</a>).<br><br>

DaDaBIK doesn't display correct result values when the same field name appears both in a table and in a linked table as linked field or in two linked tables as linked field.<br><br>

These bugs will be fixed in the version 3.1 because they require to partially rewrite the engine that produce the SELECT statement.

<br>


<h1>March 10, 2004<br>
v. 3.0 Beta</h1><hr size="1">
All the code has been revisited and in some case rewritten in order to increase efficiency and clarity.<br>
<br>
<b>New features and feature changes</b><br>
<br>
The primary-foreign key feature is now complete: it is possible to link a field of a table (foreign key) to a number of fields of another table (containing the primary key). The produced HTML select menu will have the linked field values as "options" and the primary key values as "values". This allow to use a normalized db design.<br>
<br>
The "export to CSV" feature has been added: it is now possible to export the current result records to a CSV file.<br>
<br>
The speed of DaDaBIK when the database managed contains a lot of tables is now dramatically increased.<br>
<br>
"Delete all" feature is now available: it is possible to delete all the current result records.<br>
<br>
It is now possible to handle all the HTML produced by DaDaBIK by the CSS file, which is now very clear and complete, a new CSS file specific for printing has been also added.<br>
<br>
It is now possible to order result records both in ASC and DESC.<br>
<br>
The HTML produced by DaDaBIK is now more clean and complete than before.<br>
<br>
If no order field is specified, the result records are displayed ordered by the first field present in the results table.<br>
<br>
Two new select operators have been added: "starts with" and "ends with"<br>
<br>
The confirmation message of a delete operation is now a javascript prompt confirmation message (it is possible to disable it through config.php, however).<br>
<br>
After a delete operation DaDaBIK now display again the results page.<br>
<br>
The alternate row colors feature is now available. The record results table is now displayed using alternate row colors.<br>
<br>
When you save a record, now the edit form is displayed again on the screen.<br>
<br>
When you insert a new record, you can now choose (through config.php) if you want to see again the insert form, otherwise the results table is again displayed.<br>
<br>
Edit, delete and details buttons are now normal links (not HTML forms as before) and pass all the necessary values via GET, so it is now possible to call the detail page of a record from its own unique URL.<br>
<br>
Documentation, administration interface and config.php file are now more clear and complete than before.<br>
<br>
Each DaDaBIK error message has now a code, in order to identify it better, especially during bug reports.<br>
<br>
DaDaBIK messages are now displayed everywhere needed and are more clean than before.<br>
<br>
It is now possible to disable the displaying of the search/insert/update buttons at the top of the form through config.php.<br>
<br>
It is now possible to change the select operator names (is equal/contains/greater than/less than/starts with/ends with) according to the language<br>
<br>
The function that validate URLs now support port numbers, https protocol and four letters primary domain name (e.g. .info).<br>
<br>
The validity of a date field is now checked during insert/update.<br>
<br>
The word wrap column choosen in config.php now determines also width of the columns in the results table; the width is now fixed and equal for all column.<br>
<br>
It is now possible to choose (through config.php) if always wrap words at the $word_wrap_col column, even if it is necessary to cut them.<br>
<br>
DaDaBIK now use the $_GET $_POST $_FILES....variables introduced in PHP 4.1.0<br>
<br>
The change table select menu is now an auto-submit one (it is possible to disable this feature through config.php, however).<br>
<br>
The update statements now use "LIMIT 1" to ensure that only one record is updated, but only if the MySQL version is &gt;= 3.23.<br>
<br>
A blank first option is always added to select_single fields when a search form is produced (it is possible to disable this feature through config.php, however).<br>
<br>
The select_multiple field types are not handled any more, at least for the moment.<br>
<br>
Linking tables contained in different databases isn't handled any more.<br>
<br>
DaDaBIK no more display automatically a column sign (":") after each label.<br>
<br>
<b>Fixed bugs:</b><br>
DaDaBIK didn't update correctly a record when the "Other...." option of a select_single field was used.<br>
<br>
DaDaBIK produced an error when tried to display the possible duplicates during an insert operation if some field names need back quotes.<br>
<br>
DaDaBIK produced an error when the user clicked on a result page link and the current "order by" field needed to be url encoded.<br>
<br>
DaDaBIK produced an error when tried to retrieve values of a select_single from another table if some field or table names need back quotes.<br>
<br>
Field order changer didn't work properly: field positions weren't shifted correctly.<br>
<br>
DaDaBIK check the similarity of records during and insert operation by using a case sensitive function, this was not correct.<br>
<br>
DaDaBIK failed to handle properly the upload when the uploaded file name contained a single quote.<br>
<br>
DaDaBIK displayed a broken image link if a record containing an image_file field had no images associated. This happened only with MS IE as a browser.<br>
<br>
Fixed the bug that produced a "Warning:  stat failed...." message sometimes during an upload.<br>
<br>
DaDaBIK lost the value associated with the "Other choices allowed" parameter when, from the administration interface, you clicked on "Refresh internal table".<br>
<br>
Upload failed when two files with the same name were uploaded in the same time.<br>
<br>
Word wrap feature now works also with email and url fields.<br>
<br>
Back quotes were used only if the MySQL version was &gt; 3.23.6, even if also MySQL 3.23.6 supports them, now are used if the MySQL version is &gt;= 3.23.6 <br>
<br>
It was possible, by maliciously changing the HTML of a form produced by DaDaBIK when possible duplicated were found and post it, to bypass fields check.<br>
<br>
DaDaBIK didn't show the SQL statement ($display_sql set to 1) related to a search if no records were found.<br>
<br>
<h1>March 11, 2003<br>
v. 2.2.1</h1><hr size="1">

<b>Fixed bugs</b><br>
<br>
When a record containing an image_file or generic_file field was updated without uploading a new file, the record loosed the link with the old file; this bug has been fixed.<br>
<br>
When a user perform a search in a table containing an image_file or generic_file field the "browse" button was displayed by the browser for those fields, this behavior makes no sense; this bug has been fixed.<br>
<br>
The field names of the where clause in the update statements were not back quoted, consequently the update failed if the name of the primary key field needed to be escaped (e.g. a reserved word), this bug has been fixed.<br>
<br>
The dutch version of DaDaBIK produced a parse error, this bug has been fixed.<br>
<br>
<br>
<b>New features</b><br>
It is now possible to choose if you want to delete (both in the database and phisically) a previously uploaded file.<br>
<br>
When two or more files with the same name are uploaded, a new name is assigned automatically (e.g. my_file.txt become my_file_2.txt if my_file.txt already exists, my_file_3 if also my_file_2 already exists and so on).<br>
<br>
It is now possible to configure DaDaBIK to accept all files (regardless to the extensions) coming from upload.<br>
<br>
Since DaDaBIK requires to set magic_quotes_gpc = on in php.ini (which is the default setting), now if magic_quotes_gpc is off DaDaBIK will stop and display an error message.<br>

<h1>Novermber 9, 2002<br>
v. 2.2.1 beta</h1><hr size="1">
The bug that caused the lost of the correct search results when the user click on a page number, supposed to be fixed in the previous release, is now completely fixed.<br>
<br>
The version of the MySQL server is now correctly checked, in this way the "Your database is empty" bug, supposed to be fixed in the previous release, is now completely fixed.<br>
<br>
A known bugs document is now available.<br>
<h1>October 22, 2002<br>
v. 2.2 beta</h1>
Support for file uploading (images and other) is now available.<br>
The bug that caused the lost of the results order when the user click on &gt; has been fixed.<br>
The bug that caused the lost of the correct search results when the user click on a page number has been fiexed.<br>
Fixed the bug that prevented the internal table manager to work correctly when the result order is changed.<br>
The version of the MySQL server is now checked, in this way the "Your database is empty" bug has been fixed.<br>
The numeric type now accepts also float and other numeric fields.<br>
<h1>July 31, 2002<br>
v. 2.1b beta</h1><hr size="1">
<br>
Web and e-mail fields weren't display correctly in the version 2.1 beta. The bug is fixed with tihs version.<br>
<h1>July 30, 2002<br>
v. 2.1 beta</h1><hr size="1">
A new, lighter and easier to use administration interface (related to the internal table manager) is available.<br>
<br>
The form has now a better layout, all the fields are correctly aligned, including dates.<br>
<br>
All the translations are now up-to-date.<br>
<br>
It is now possible, for select_single fields, to choice "other" during an insert and fill a textbox by hand with an alternative value. That value also update the select options, unless option had driven with a custom query ("SQL:......").<br>
<br>
It is now possible to choice if a field has to be displayed in the details page or not.<br>
<br>
Completely fixed the bug the caused the warning message: "Warning: Call-time pass-by-reference has been deprecated......" with particular php.ini settings<br>
<br>
It is now possible to use the "-" sign and other allowed signs in MySQL table and field names.<br>
<br>
Fixed a bug that prevent some text to be displayed if written after a special html char (e.g. &lt;).<br>
<br>
Fixed a bug that prevent to choose more than 999 characters as maxlength of a field.<br>
<br>
Fixed a bug related to the use of the double quote in the include statements, that can cause error messages.<br>
<br>
Textbox and password fields are now checked for max lenght also server side.<br>
<br>
Select_single fields are now checked for length and type, this improve security because a malicious user could change the html of the form and then post it.<br>
<h1>Jun 28, 2002<br>
v. 2.0.1 beta</h1><hr size="1">
DaDaBIK is now compatible with PHP 4.2, and works also with register_global directive set to off.<br>
Added two new date display formats, which fix the problem of displaying dates before 1970<br>
Fixed a bug that caused the insert of a separator if a select_multiple_menu or a select_multiple_checkbox were empty<br>
The "Any/all" conditions menu now appers also in Netscape and other browsers.<br>
Fixed some minor bugs that caused warnings and notices.<br>
<h1>Jun 1, 2002<br>
v. 2.0 beta</h1><hr size="1">
Support for multiple tables available.<br>
"View all records" feature.<br>
It is now possible to order a group of record by a field clicking on the corrisponding coloumn.<br>
The pages navigation tool has been improved.<br>
Fixed a bug about size of input field in Netscape.<br>
Fixed a bug that about the color of the required fields in the search form.<br>
<h1>Apr 21, 2002<br>
v. 1.9.1</h1><hr size="1">
Fixed a bug that allowed an attacker to execute arbitrary sql query on the database (e.g. insert or delete records even if insert and delete feature were disabled).<br>
<br>
Fixed a bug about double quotes handling in the search function.<br>
<br>
All DaDaBIK users are encouraged to update to the latest version.<br>

<h1>Apr 15, 2002<br>
v. 1.9</h1><hr size="1">
Fixed the bug that caused an error during the insert if you didn't enable the check similiarity for any fields.<br>
<br>
Fixed the bug that caused a "Required field" message even if a date field was filled by the user.<br>
<br>
Fixed the bug the caused a warning message if allow_call_time_pass_reference is set to false in php.ini.<br>
<br>
Added Spanish and French versions.<br>
<h1>Mar 18, 2002<br>
v. 1.8</h1><hr size="1">
The algorithm that scans existing records during an insert in order to find similar records is now more efficient (e.g. for a table with &gt;8000 records, 2 fields to check, it is now 5 times faster than before).<br>
<br>
Update now works also with a MySQL version &lt; 3.23.x<br>
<br>
Fixed the bug that caused an error if a date field was initally null.<br>
<h1>Feb 28, 2002<br>
v. 1.7</h1><hr size="1">
<b>New features:</b><br>
A new administration interface is now available and allows you to manage the internal table without any other software!! So you don't need PHPMyAdmin any more in order to customize DaDaBIK.<br>
<br>
Configuration is now easier.<br>
<br>
Debug mode added.<br>
<h1>Feb 11, 2002<br>
v. 1.6</h1><hr size="1">
<b>New features:</b><br>
It is now possible to disable the functions: insert, update, delete and details; in this way you can safety use DaDaBIK in a public site.<br>
<br>
New administration interface for the internal table.<br>
<br>
The installation procedure is now more explicative.<br>
<br>
New customizable graphic icons for edit/delete/details buttons.<br>
<br>
You can now choice the coloumn at which a text, textarea, password or select sinlge field will be wrapped in the results.<br>
<br>
It is now possible to choice the target window for edit/details (self or new).<br>
<br>
The graphic layout of the form looks now better with Netscape.<br>
<br>
German translation added.<br>
<h1>Jan 27, 2002<br>
v. 1.5b</h1><hr size="1">
<br>
In the version 1.5 I missed the code line that allow to use the dutch version, the version 1.5b include a fix to that bug together with a config.php file more precise.<br>
<h1>Jan 26, 2002<br>
v. 1.5</h1><hr size="1">
<br>
DaDaBIK is now considered out of beta and has some important new features, for this reason I decided to call this release 1.5 (the last was 1.1 beta)<br>
<br>
<b>New features</b><br>
Partial foreign key support: it is now possibile to drive the possible options of a "select_multiple" or "select_single" field from another table, even with a customized SQL query!!<br>
<br>
It is now possible to select between any/all the conditions during a search<br>
<br>
It in now possible to display a select_multiple field also with a menu (HTML select multiple tag)<br>
<br>
For each field you can now specify a prefix value (e.g. http://) and a default value<br>
<br>
For each field you can now specify which operator the user can use, including exactly, like, &gt;, &lt;<br>
<br>
A Dutch version of DaDaBIK is now available<br>
<br>
An on-line demo is now available<br>
<br>
<b>Minor bug fixed</b><br>
The results of a search are now displayed taking the carriage return (\n) into account.<br>
<h1>Jan 14, 2002<br>
v. 1.1 beta</h1><hr size="1">
<br>
<b>New features:</b><br>
According to user's needs, now the internal table and the main table are in the same database, so you don't need two databases in order to run DaDaBIK.<br>
It is now possible to specify the order of a field in the form.<br>
<br>
<b>Fixed bugs:</b><br>
Required fields message now apper only if there are at least one required field.<br>
Search of a "select single" field with exact/like feature enabled now works.<br>
Some updates didn't work, now the bug has been fixed.<br>
Bug about searching by date fixed, now you can search properly a record by date using &lt; or &gt;.<br>
Time generated by insert_date and update_date are now in 0-24 format.<br>
<h1>Dec 9, 2001<br>
v. 1.0.5 beta</h1><hr size="1">
Documentation:<br>
The configuration file is now more explicative.<br>
The readme file is now more explicative.<br>
A new document about the internal database is now available.<br>
New features:<br>
Now you can select between an "exact match" or a "like" search also in the form, on the fly. (You can also disable this feature)<br>
Hints are now visible even during the update procedure<br>
Bugs fixed:<br>
The maxlength property in the internal database now works<br>
<br>
A very small part of the function build_form() rewritten in order to make DaDaBIK more flexible.<br>
<h1>Dec 5, 2001<br>
v. 1.0.4 beta</h1><hr size="1">
The readme file is now more explicative.<br>
Two HTML-related bugs fixed: <br>
the background of an empty cell now appears even with Netscape<br>
the select input field now appear correctly even with Netscape<br>
<h1>Dec 1, 2001<br>
v. 1.0.3 beta</h1><hr size="1">
Italian version added<br>
Some english mistakes fixed<br>
Configuration option (display the "I think that x is similar to y......" statement during duplication check) added<br>
<h1>Nov 24, 2001<br>
v. 1.0.2 beta</h1>
One bug fixed (creation of the internal database didn't work due to bug in db_functions.php)<br>
<h1>Nov 24, 2001<br>
v. 1.0.1 beta</h1><hr size="1">
Several bugs fixed (creation of the internal database didn't work, navigation buttons didn't work)<br>
<h1>Nov 21, 2001<br>
V. 1.0 beta</h1><hr size="1">
The first release of DaDaBIK.

Added credits.txt.







>
>
>
1
2
3
The edit, delete and details icons are a derivate work of three icons by Onur Oztaskiran (http://www.monofactor.com/free-vector-icon-set-1-25-icons/)

The layout is in part inspired by a work by Erik Pšhler http://contactsheet.de/dadabik-revised.xhtml

Added documentation.htm.



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
  <title>DaDaBIK (DaDaBIK is a DataBase Interfaces Kreator)
http://www.dadabik.org/ - Documentation</title>

  
  
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

</head><body>
<h1>DaDaBIK Documentation</h1>

<a name="general_information"></a>
<h1>General information</h1>

<p><b>Project name:</b> DaDaBIK (DaDaBIK is a DataBase Interfaces
Kreator)<br>
<b>Author:</b> Eugenio Tacchini <span style="text-decoration: underline;"></span>(eugenio at favoriti dot it)<br>
<b>Web site:</b> <a href="http://www.dadabik.org/">http://www.dadabik.org/</a><br>
<b>Last release:</b> 4.4 (released April 3, 2012). This
documentation is about the 4.4 release, if you need the
documentation for a previous release please read the documentation file
included in each downloaded package.<br>
<b>License:</b> DaDaBIK is released under the GPL license.</p>

<h1><a name="table_of_contents"></a>Table of contents<br>
</h1>

<p><a href="#what_is_dadabik">What is DaDaBIK?</a><br>
<a href="#requirements">Requirements</a><br>
<a href="#installation">Installation</a><br>
<a href="#upgrade">Upgrade from previous versions</a><br>
<a href="#configuration">Configuration</a><br>
<a href="#authentication">Authentication</a><br>
<a href="#instances">Multiple function views: creating two instances of
DaDaBIK</a><br>
<a href="#security">Security</a><br>
<a href="#coding_guidelines">Coding guidelines</a><br>
<a href="#faqs">FAQs</a><br>
<a href="#bugs">Known bugs and limitations</a><br>
</p>

<h1><a name="what_is_dadabik">What is DaDaBIK?</a>
</h1>


<hr size="1">DaDaBIK is a very popular and mature Open Source PHP
application which allows you to easily create a
highly customizable database front-end/application without coding. You
can use it to create in a few minutes a very basic CRUD (create, read,
update, delete) database front-end or to develop a more sophisticated
database application.
<p>No programming skills are needed to use it; if however you are a PHP
programmer with DaDaBIK you can save tens of hours of work.</p>

<p>With DaDaBIK (differently from many competitors) you don't produce a
PHP script, which would become outdated when you modify the schema of
your database, but instead you directly use its abstraction layer that
can be easily updated every time you modify your database's schema.</p>

<p>DaDaBIK uses the <a href="http://adodb.sourceforge.net/">ADOdb</a> and the <a href="http://php.net/manual/en/book.pdo.php">PDO</a> database abstraction libraries in order to support as many DBMSs as
possible, at the moment it officially suport MySQL, PostgreSQL and SQLite.</p>

<p> The strength of DaDaBIK lies in its ability to be customized. For
example for each table field you can choose: </p>

<ul>

  <li>if the field must be included or not in a search/insert/update
form and results table</li>
  <li>its label</li>
  <li>its content format (e.g. numeric, alphabetic, e-mail,
url...) </li>
  <li>the HTML input type (e.g. textbox, menu, date, rich text editor,
password box...) </li>
  <li>the possible values, also driven from another table (foreign key
support)</li>
  <li>and more... </li>
</ul>

<p>Other features include file uploading, master/details view, export
to CSV, checking
for possible duplication during an insert, authentication and
authorization restrictions on view/update/delete, e-mail notices.</p>

<p>The graphic layout of DaDaBIK is customizable to help you to embed
it in your own site.</p>

<p>DaDaBIK differs from PHPMyAdmin: it has not been created to offer
the complete administration of a database, but rather to allow the
creation of a customizable and user friendly database application. The
target of a DaDaBIK application can be the final user instead of a DB
administrator.<br>
<br>
DaDaBIK is available in Italian, English, Dutch, German, Spanish,
French, Portuguese, Croatian, Polish, Catalan, Estonian, Rumanian,
Hungarian, Swedish, Slovak, Russian and Finnish.<br>
<br>
Since its first release in 2001 it has been downloaded more than
150.000 times and its users community has produced about 10.000 posts
in the forums.
<table>
  <tbody>
    <tr>
      <td> <iframe src="http://www.facebook.com/plugins/likebox.php?href=http%3A%2F%2Fwww.facebook.com%2Fpages%2FDaDaBIK%2F154757317877584&amp;width=292&amp;connections=0&amp;stream=false&amp;header=false&amp;height=62" style="border: medium none ; overflow: hidden; width: 292px; height: 62px;" allowtransparency="true" frameborder="0" scrolling="no"></iframe><br>
      </td>
      <td>Follow DaDaBIK on <a href="http://twitter.com/DaDaBIK">Twitter</a>!
      </td>
    </tr>
  </tbody>
</table>
<a href="#general_information">[back to top]</a></p>

<h1><a name="requirements"></a>Requirements</h1>

<hr size="1">
<ul>

  <li> PHP</li>
  <ul>
    <li>version &gt;= 4.3 ( &gt;= 5.1 if you want to use it with SQLite)</li>
    <li>PHP upload enabled if &nbsp;you want to use the upload feature
(see PHP manual for php.ini and file permissions settings)<br>
    </li>
  </ul>
  <li>MySQL</li>
  <ul>
    <li>version &gt;= 3.23.x (probably also works with previous
releases)<br>
    </li>
  </ul>
  <li>PostgreSQL</li>
  <ul>
    <li>Tested with 8.x and 9.x versions, probably works with 7.x version too.<br>
    </li>
  </ul>
  <li>SQLite</li>
  <ul>
    <li>version  &gt;= 3 (it could work with version 2 too, not tested)
    </li>
  </ul>
  <li>A pre-existent database with AT LEAST ONE table to manage,
with DaDaBIK you can't create databases and tables,</li>
</ul>
<a href="#general_information">[back to top]</a>
<h1><a name="installation"></a>Installation</h1>

<hr size="1">
<ol>

  <li>Copy everything which is contained in the directory <i>program_files</i>
in a directory under your Web server </li>
  <li>Open the file <b>/include/config.php</b> with a text editor and
edit it (specify at least $dbms_type, $host, $db_name, $user, $pass,
$site_url, $site_path, $timezone)</li>
  <li>Run the file<b> http://your_host/your_dir/install.php</b> to
install DaDaBIK</li>
  <li> Open the file <b>http://your_host/your_dir/index.php</b> in
your
browser and have fun!! You can now start using DaDaBIK.<br>
    <br>
You can now insert, search, update, delete the records of the tables
contained in the database $db_name. You can also manage the views contained in the database. <b><font color="#ff0000">You
should have set a primary key for each table managed with DaDaBIK if
you want to delete and update records, otherwise
DaDaBIK won't show you the corresponding buttons.</font></b><br>
Also the "search similar record" feature during the insert needs a
primary key.<br>
The "insert e-mail notice" feature needs a primary key auto increment
field to work.</li>
</ol>

<p> Please leave the link<br>
Powered by: <a href="http://www.dadabik.org/">DaDaBIK</a> database
front-end<br>
somewhere if you use DaDaBIK; it isn't compulsory but I would really
appreciate it.</p>
<p><a href="#general_information">[back to top]</a> </p>

<h1><a name="upgrade"></a>Upgrade from previous versions</h1>

<hr size="1">

<p>If you want to upgrade from <i>4.4 beta</i> to <i>4.4</i>
without loosing your configuration you don't need to re-install
DaDaBIK:
</p>

<ul>

  <li>Replace all the old files with the new ones (keep your upload
folder if you want to save the uploaded files )</li>
  <li>Update your <b>/include/config.php</b> file using your old
configuration settings</li>
  <li>Run the file<b> http://your_host/your_dir/upgrade_4.4.php</b> included in the 4.4 release to upgrade DaDaBIK from 4.4 beta to 4.4</li>
</ul>

If you want to upgrade to 4.4 from a release older than 4.4 beta you should first upgrade to 4.4 beta, read the related documentation to know how to do it.<br>
<br>
<a href="#general_information">[back to top]</a><br>

<h1><a name="configuration"></a>Configuration</h1>

<hr size="1"><b>Introduction</b>
<br>

The configuration of DaDaBIK can be managed at two different levels:
<ol>

  <li>Some general configuration parameters can be set from the file <b>/include/config.php</b>,
just by opening it with a plain text editor and editing it. The file is
self-explanatory. At this level you can, for example, set the database
you want to manage with DaDaBIK, or enable/disable some DaDaBIK features<br>
  </li>
  <li>For a more analytic tuning you are supposed to use the
administration section <b>http://your_host/your_dir/admin.php</b>. At
this level you can choose the table you want to include/exclude and,
for each table, create your own DaDaBIK interface, choosing for example
the field you want to include/exclude from the forms, the content of
each field, the labels....<br>
Also the administration section is self-explanatory, so in the
following paragraph we will explain in detail only the <i>interface
configurator</i>, which is the core of the DaDaBIK configuration; you
can reach it from the home page of the administration section. </li>
</ol>

<p>The graphic customization can be done by changing the files <b>/include/header.php</b>
and <b>/include/footer.php</b> and by using the CSS files <b>/css/styles_screen.css</b>
and <b>/css/styles_print.css</b>, the former is the main one, the
latter is used only when you print a page produced by DaDaBIK.<br>
From the files under <b>/include/languages</b> you can customize all
the sentences DaDaBIK uses.
</p>

<p><b>Interface configurator</b>
<br>
Here is the meaning of all the parameters you can set for each table
field:
</p>

<ul>

  <li><b>Label:</b> the text that DaDaBIK will display in the interface
as label of the field</li>
  <li><b>Field type</b>, select among:
    <ul>
      <li><b>text:</b> a text box</li>
      <li><b>textarea:</b> a textarea box</li>
      <li><b>rich_editor:</b> a rich text editor that allows to easily
insert/modify HTML content. <font color="#ff0000"><b>This could lead
to the same security problems that can affect the html content type</b></font>,
see later for details.</li>
      <li><b>password:</b> a password text box</li>
      <li><b>insert_date:</b> the current date will be automatically
inserted into this field when you insert a new record in your table;
an insert_date field must be excluded from the insert/update form,
see below (Field present in the insert/update form?). Note that the
corresponding database field type must be date</li>
      <li><b>update_date:</b>
the current date will be automatically
inserted into this field when you update a record in your table; an
update_date field must be excluded from the insert/update form, see
below (Field present in the insert/update form?). Note that the
corresponding database field type must be date</li>
      <li><b>date:</b> three menu: day, month, year. Note that the
corresponding database field type must be date</li>
      <li><b>select_single:</b> a customizable menu, see below the
parameters Option to include, Primary key field, Primary key table,
Linked fields to specify the menu items</li>
      <li><b>generic_file:</b> an input field which allows the user to
browse in his file system and upload a file. You need to specify the
allowed file extensions in config.php. Note that the corresponding
database field type must be varchar.</li>
      <li><b>image_file:</b> the same as the above, but in this case
DaDaBIK supposes that the file is an image and shows it when the record
is displayed. You need to specify the allowed file extensions in
config.php. Note that the corresponding database field type must be
varchar</li>
      <li><b>ID_user:</b> the username of the current user will be
automatically inserted into this field when you insert a new record;
an ID_user field must be excluded from the insert/update form, see
below (Field present in the insert/update form?). Note that the
corresponding database field type must be varchar.</li>
      <li><b>unique_ID:</b>
a unique ID generated by using the PHP
function unique_ID() in conjunction with microtime(), getmypid() and
md5() will be automatically inserted in this field when you insert a
new record into your table; a unique_ID field must be excluded from the
insert/update form, see below (Field present in the insert/update
form?). Problably you will never use this field type, it can be useful
just in very special cases.</li>
    </ul>
  </li>
  <li><b>Content type:</b> the content typep determines the check
procedure DaDaBIK will use during an insert/update and how a field
value is displayed; select among:
    <ul>
      <li><b>alphabetic:</b> only alphabetic characters allowed</li>
      <li><b>alphanumeric:</b> all characters allowed</li>
      <li><b>numeric:</b> only numeric characters allowed</li>
      <li><b>url:</b> only URL with a correct syntax allowed, support
from http/https/ftp protocols and port numbers; field displayed as a
URL link</li>
    <li><b>timestamp:</b> only integers allowed; field displayed as date and time according to the <i>date_format</i> parameter in config.php
      <li><b>email:</b> only e-mail</li>
      <li><b>html:</b> all characters allowed; DaDaBIK doesn't perform
a conversion from special characters to HTML entities with
htmlspecialchars for the fields having this content type. For example,
this content type can be used to enter a full custom URL in the
standard HTML format or an HTML formatted text. <font color="#ff0000"><b>WARNING:
This can lead to
security risks</b></font>; DaDaBIK uses the popular <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">htmLawed</a>
library to prevent displaying of dangerous HTML/Javascript code but, as
the authors state, (<a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/htmLawed_README.htm#s2.8">http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/htmLawed_README.htm#s2.8</a>),
there are some minor cases in which htmLawed can fail. If a malicious
user insert some arbitrary javascript code and the library fails in
recognizing it, the code can be then executed by other users just by
using the application. Among other problems, this can lead to XSS
attack (<a href="http://en.wikipedia.org/wiki/Cross-site_scripting">http://en.wikipedia.org/wiki/Cross-site_scripting</a>),
which in turn can allow an unauthorized access to the application (<a href="http://en.wikipedia.org/wiki/Session_hijacking">http://en.wikipedia.org/wiki/Session_hijacking</a>)
and, if the Internet browser of the user contains security holes, even
the execution of arbitrary code in the client machine. Use at your own
risk.</li>
      <li><b>phone:</b> only phone numbers with a correct syntax (a +
sign followed by numbers e.g. +39025689781) allowed</li>
    </ul>
  </li>
  <li>The following parameters are used to <b>choose if a field must
be displayed</b> and used in the various sections of DaDaBIK: Field
present in the search form?/Field present in the results page?/Field
present in the details page?/Field present in the insert/update form?
For the last one (insert/update form), if the field is auto-increment
you should choose N.<br>
  </li>
  <li> <b>Is the field a required one?</b> Choose if the field should
be required during insert and update procedures</li>
  <li> <b>Check for duplicated entries during insert?</b> Choose if
the field value should be checked for possible duplication during the
insert procedure</li>
  <li><b>Other choices allowed?</b> Choose if the field, a
select_single one, can accept also values other than the pre-set
options during an insert/update.<br>
If the user add a different value, it will be included in the list of
pre-set options. Note that, if the field is a foreign key (see Primary
key field for a definition), the <i>other</i> value is used to insert
a new record in the primary key table.<br>
The use of this option together with a foreign key field makes sense
only if there is just one linked field and requires that <i>Primary
key table</i> has a primary key <b>auto-increment</b> field.</li>
  <li><b>Option to include:</b> specify the possible options of a
select_single field e.g. ~~teacher~manager~student~, in this example
the first option is blank.</li>
  <li><b>Primary key field:</b> if a field is a select_single and the
options must be driven from another table (so the field can be
considered foreign key for DaDaBIK, regardless of a real dbms foreign
key declaration), specify here the primary key of that table.</li>
  <li><b>Primary key table:</b> if a field is a select_single and the
options must be driven from another table, specify here the name of
that table.</li>
  <li><b>Linked fields: </b>the fields in the primary key table you
want to display. Imagine you have a table <i>albums_tab</i> that
contains information about CDs. In this table you have a field <i>ID_author</i>
that "links" the table <i>authors_tab</i>. If you want to display, for
each record, <i>first_name_author</i> and <i>last_name_author</i> of <i>authors_tab</i>,
you have to use <i>ID_author</i> as primary key field, <i>authors_tab</i>
as primary key table,<span style="font-style: italic;"> </span><i>first_name_author</i>~<i>last_name_author</i>
as linked fields</li>
  <li><b>Order by:</b> the linked field by which you want to order the
items in the menu created by a select_single field</li>
  <li><b>Order type:</b> the order type (ASC or DESC, if you leave
blank ASC is the default) to be used on the "Order by" field</li>
  <li><b>Search operator: </b>specify is_equal, contains, starts_with,
ends_with, greater_than, less_than or a group of this operator
separated by "/". E.g. if you specify just "contains" DaDaBIK will use
always the contains operator for this field during the search; if you
use "exactly/contains" DaDaBIK will create for this field a listbox
with the operators exactly/like, the user can then choose the preferred
one during each search operation</li>
  <li><b>Prefix: </b>for text, textarea and rich_editor fields you can
choose a prefix default value for your field, e.g. "http://" if your
field need to be filled with a Web url; the prefix will be displayed
directly in the insert form, but if the user doesn't fill-in the field
it will be considered as blank</li>
  <li><b>Default value:</b> for text, textarea and rich_editor fields
you can choose a default value for your field, the value will be
displayed directly in the insert form</li>
  <li><b>Width:</b> the width of an input box, used with text,
password, textarea and rich_editor boxes</li>
  <li><b>Height:</b> the height of an input box, used with textarea and
rich_editor boxes</li>
  <li><b>Maxlength:</b> the maximum number of characters allowed in the
input box, used with text, password, textarea, rich_editor boxes and
select_single (just for the "other" option)</li>
  <li><b>Hint:</b> the text of a hint for the user that will appear
during the insert/update procedure near the input field</li>
  <li><b>Linked items table names:</b> you should fill this property
only for the primary key of a table, when you want to enable a
master/details view.<br>
For example imagine you have an albums (id_album, title_album) table
and a songs (id_song, id_album, title_song) table; if you want to
display, in the album detail view, also the list of the linked songs,
you have to put <i>songs</i> in <i>Linked items table names</i> and <i>id_album</i>
in <i>Items table foreign key field names</i> (see below). Each table
can have more than one linked table; in this case you can add
additional table and foreign key field names using the separator</li>
  <li><b>Items table foreign key
field names:</b> you should fill this property only for the primary key
of a table, when you want to enable a master/details view.<br>
For example imagine you have an albums (id_album, title_album) table
and a songs (id_song, id_album, title_song) table; if you want to
display, in the album detail view, also the list of the linked songs,
you have to put <i>songs</i> in <i>Linked items table names</i> (see
above) and <i>id_album </i>in <i>Items table foreign key field names</i>. It is also important to highlight that, in this example, <i>id_album</i> in <i>songs</i> should be a select_single field with values driven from albums (see field type for information about select_single fields)
Each table can have more than one linked table; in this case you can
add additional table and foreign key field names using the separator</li>
  <li><b>Separator:</b> This is the separator characther used here to
separate values in the <i>Option to include</i>, <i>Linked fields</i>,
    <i>Linked items table names</i> and <i>Items table foreign key
field names</i> parameters. In most of the case you can safely leave
(and use) the default one, ~</li>
</ul>
<a href="#general_information">[back to top]</a>
<h1><a name="authentication"></a>Authentication</h1>

<hr size="1">
<p>An authorization model is available to prevent unauthorized accesses
and to allow users to:
</p>

<ul>

  <li>Delete only their own records </li>
  <li>Modify only their own records </li>
  <li>View only their own records </li>
</ul>

The owner of a record is the user who entered it.<br>

<br>

To enable authentication, each table you want to protect must have a
field whose field type is set to <i>ID_user</i>; you also have to set
$enable_authentication = 1 in <b>/include/config.php</b>. By setting
the parameters $enable_delete_authorization, $enable update
authorization and $enable_browse_authorization you can then customize
your authorization model.<br>

<br>

There are two types of users: normal users and administrator users.
Administrator users can view and manage users list by using DaDaBIK
itself.<br>

<br>

DaDaBIK is released with the following default administrator user:
<ul>

  <li>username: <i>root</i> </li>
  <li>password: <i>letizia</i> </li>
</ul>

It is strongly recommended to change the default root password for
security reasons.<br>

DaDaBIK uses by default the table users_tab to store user information,
but you can also use your own users table, changing the $users_table_*
parameters in <b>/include/config.php</b>.
User passwords need to be md5 encrypted before being
registered/updated, so before inserting a new user or changing the
password for an existing one it is necessary to create the encrypted
password by following the "md5 crypter" link in the users form. <br>
<br>
<a href="#general_information">[back to top]</a><br>

<br>

<h1><a name="instances"></a>Multiple function views: creating two
instances of DaDaBIK</h1>

<hr size="1">
<p>Sometimes it is necessary to have one view for users where they can
only
view the data and a second view for the database administrators to
manage
the data being displayed. This will help you set up two instances of
DaDaBIK to look at the same database.
</p>

<ol type="1">

  <li>Install your first instance of DaDaBIK using the default DaDaBIK
table
prefixes contained in the <b>/include/config.php</b> file (last two
variables in the
file).<br>
    <b>http://your_host/your_dir/install.php</b>
    <p>If you want things to look the same in both installations like
headers,
footers, logos, etc., you can make those changes now so that you only
have
to make them once; otherwise you can worry about prettying it up later.
    </p>
  </li>
  <li>Copy your entire DaDaBIK folder into a new folder you wish to use
for
the second instance: <b>http://your_host/your_dir/</b> &lt;-- all
contents copied to: <b>http://your_host/your_dir/admin-dir-name/</b> </li>
  <li>Open <b>/include/config.php</b> from the <b>/your_dir/admin-dir-name/include/</b>
folder and
change the table prefix and table list name in this file to something
like:<br>
dadabik<b>_admin</b>_<br>
and<br>
dadabik<b>_admin</b>_table_list
    <p>It does not matter what your prefixes are -- just so long as
they are
different from the first install prefixes. </p>
    <p>Also in <b>/include/config.php</b>, change the $site_url to the
correct URL for the admin area so the correct installation is used. </p>
  </li>
  <li>Now, install your second instance of DaDaBIK:<br>
http://your_host/your_dir/admin-dir-name/install.php </li>
  <li>This will create additional tables with your admin prefix for all
your
original DaDaBIK tables also. You should remove them by going to the
admin
interface for the second instance you just installed and uninstall
those
tables.
    <p>For this example, we'll assume you used the following:<br>
1st install: "dadabik_" table prefix with
"dadabik_table_list" table list name<br>
2nd install: "dadabik_admin_" table prefix with
"dadabik_admin_table_list" table list name </p>
    <p>In the admin for the 2nd install (<b>http://your_host/your_dir/admin-dir-name/admin.php</b>),
"uninstall" each table you see beginning with
"dadabik_". </p>
  </li>
  <li>Now you can manage both instances independent from each other
through:<br>
    <b>http://your_host/your_dir/admin.php</b><br>
and<br>
    <b>http://your_host/your_dir/admin-dir-name/admin.php</b>
    <p>Once you have two (or more) instances created, you can apply
security to
each one separately. Refer to the Authentication and Security sections
for more information.</p></li>
</ol>
<a href="#general_information">[back to top]</a>
<h1><a name="security"></a>Security</h1>

<hr size="1">
<p>After the program is installed it is a good practice to remove the
file
install.php and all the upgrade*.php files since they could be used by
malicious users in order to change or even re-install your DaDaBIK
installation.<br>
<br>
The files admin.php and internal_table_manager.php could also be used
to modify your installation. If you enable the
authentication within DaDaBIK, access to the files will be protected,
otherwise other methods of protecting these files may be required.</p>

<p>Read carefully this documentation file (see above, configuration
section) before using the HTML content type and the rich_editor field
type, which can lead to high
secrutity risks</p>
<p><a href="#general_information">[back to top]</a></p>

<h1><a name="coding_guidelines"></a>Coding guidelines</h1>

<hr size="1">
<p>If you want to contribute to the DaDaBIK code you have to follow
some
coding guidelines; this document: <a href="http://www.evolt.org/article/PHP_coding_guidelines/18/60247/">http://www.evolt.org/article/PHP_coding_guidelines/18/60247/</a>
fits most of DaDaBIK coding style rules, in particular follow the
sections:<br>
</p>

<ul>

  <li>Tabs v. spaces</li>
  <li>Variable names</li>
  <li>Loop indices</li>
  <li>Function names</li>
  <li>Function arguments</li>
  <li>Including braces</li>
  <li>SQL code layout</li>
  <li>Quoting strings</li>
  <li>Shortcut operators</li>
  <li>Turn on all error reporting</li>
</ul>

In addition and/or modification to the above document sections, here
are other rules: <br>

<ul>

  <li>The first&nbsp; brace must be put on the&nbsp;first
line of the block.<br>
Examples:<br>
if (isset($username_user)){ is ok<br>
if (isset($username_user))<br>
{ is wrong</li>
  <li>if, else, while , for....closing brace must be followed by
a // end if, // end else, // end while, // end for.....comment.<br>
Examples:<br>
if (isset($username_user)){<br>
&nbsp; &nbsp; echo 'Username set';<br>
} // end if<br>
else {<br>
&nbsp; &nbsp; echo 'Username not set';<br>
} // end else</li>
  <li>Array name must be plural and terminate with the _ar suffix.<br>
Examples:<br>
$users_ar is ok<br>
$user, $users, $user_ar are wrong</li>
  <li>Global variables must not be used, functions must receive
as parameters all the variables they need. Exceptions are made for:
$conn, $quote, $current_user, $current_user_is_administrator,
$submit_buttons_ar, $normal_messages_ar and all configuration variables
(the ones set in /include/config.php)</li>
  <li>$_GET variables are not used directly; corresponding
variables are set in index.php.<br>
Examples:<br>
if (isset($_GET["page"])){<br>
&nbsp; &nbsp; $page = $_GET["page"];<br>
} // end if<br>
After the above setting, the $page variable is used in the code.</li>
</ul>

Other coding rules should be learned looking for the DaDaBIK code.
Please contact me if you have any doubts.<br>
<br>
<a href="#general_information">[back to top]</a><br>

<br>

<h1><a name="faqs"></a>FAQs</h1>

<hr size="1">
<p><b>I am looking for an old version of DaDaBIK, can anybody help me
with a link to DaDaBIK x.x ??</b><br>
<br>
Old releases of DaDaBik can be found at&nbsp;<a href="http://sourceforge.net/project/showfiles.php?group_id=39649">sourceforge</a>.</p>

<p>but you are strongly encouraged not to use old releases, which can
have security problems<b><br>
</b></p>

<p><b>I get:<br>
"[06] Error: during database connection.<br>
MySQL server said: Client does not support authentication protocol
requested by server; consider upgrading MySQL client".<br>
Why?</b><br>
<br>
It is due to the authentication protocol introduced with MySQL
4.1.x; here:<br>
<a href="http://dev.mysql.com/doc/mysql/en/old-client.html">http://dev.mysql.com/doc/mysql/en/old-client.html</a>
you can find several solutions.</p>

<p><b>I get [08] Error Message<br>
I get "Error during query execution" </b><br>
<br>
Please open the file <b>include/config.php, </b>look for the variable
named <b>$debug_mode. </b>Set it to 1, so that you'll be able to see
what the error is. If you still cannot figure it out&nbsp;post the
error message in the support forum.</p>

<p><b>I can't see the edit/delete record icons in the results view </b><br>
<br>
You did not set a primary key in the table, so you are able to see the
records but DaDaBIK cannot edit/delete them.</p>

<p><b>I get "your database is empty" error, why? </b><br>
<br>
You first have to set up a database and then you can install DaDaBIK.</p>

<p><b>Are multiple primary keys supported? </b><br>
<br>
Not yet. Not planned. If you're interested in developing it please
contact me (eugenio at favoriti dot it).</p>

<p><b>Page not showing after Insert/Update.</b><br>
<br>
Open <b>include/config.php </b>and make sure&nbsp;the variable
$site_url is set to the the complete path to your DaDaBIK installation.<br>
(E.g <a href="http://www.yoursite.com/dadabik_folder/">http://www.yoursite.com/dadabik_folder/</a>)</p>

<p><b>How to change graphic layout etc? </b><br>
<br>
The role of the files is self-explicatory<br>
include/header.php<br>
include/footer.php<br>
<br>
This takes care of the general styles<br>
css/style.css<br>
<br>
These two functions take care of forms and results table styles<br>
change build_form() and build_results_table()</p>

<a href="#general_information">[back to top]</a>
<h1><a name="bugs"></a>Known bugs, limitations and unexpected behaviors</h1>

<hr size="1">
<ul>

  <li>Security/data-integrity related:</li>
  <ul>
    <li>Malicious users could use PHP scripts for setting session
variables to particular values in order to bypass the login procedure
and get unauthorized access to DaDaBIK. These scripts must be hosted on
the same domain where the DaDaBIK target installation is hosted. </li>
  </ul>
  <ul>
    <li>Malicious users can exploit a field with content type set to
HTML
or field type set to rich_edit to insert arbitrary javascript code,
this can lead to security risks if the htmLawed library doesn't filter
this content properly (see above, configuration section, for all the
details).</li>
  </ul>
  <ul>
    <li>DaDaBIK doesn't provide a locking mechanism during records editing. This could lead to unexpected results in some situations: for example imagine user A and user B opening in edit mode the same record about a product. Both the users modify the price, user A from 50 euros to 60 euros, user B from 50 euros to 70 euros. Imagine that user B clicks on the save button a few seconds after user A. Both the users would think to have correctly modify the price, but user A is wrong, the current price is now 70 euros. Another example: user A modify the price, user B the description; in this case user B overrides the price modifications made by user A, the price is therefore restored to its initial value.</li>
  </ul>
  <ul>
    <li>Searching values containing % or _ using the "contains", "starts with" or "ends with" conditions could lead to wrong search results.</li>
  </ul>
  
  
  
  <li>Table and field names related:<br>
  </li>
  <ul>
    <li>Insert/search/update fail if one or more field names contain
blank spaces or dots (e.g. "my field" or "my.field" are not allowed,
use "my_field" instead). </li>
  </ul>
  <ul>
    <li>Quote characters, such as ' ` ", could lead to problems if used
in table and field names.</li>
    <li>Using field names containing the value set for $alias_prefix,
$null_checkbox_prefix, $select_type_select_suffix, $year_field_suffix,
$month_field_suffix, $day_field_suffix could lead to unexpected
results; you can change the value of the above variables editing
/include/config.php</li>
  </ul>
  <li>User interface related:<br>
  </li>
  <ul>
    <li>Some language translations are not completed.</li>
    <li>A few sentences are not translated in all the languages available.</li>
    <li>A few sentences are not translated in all the languages available.</li>
    <li>For some languages, some characters could be incorrectly displayed.</li>
    <li>The rich editor interface (TinyMCE) is displayed in english
only. </li>
  </ul>
  <li>PosgreSQL and Oracle related:<br>
  </li>
  <ul>
    <li>DaDaBIK needs table names in lower case to work on PostgreSQL. </li>
  </ul>
  <ul>
    <li>DaDaBIK doesn't work correctly on Oracle if table and/or field
names are in mixed case. </li>
  </ul>
  <ul>
    <li>The insert e-mail notice doesn't work on PostgreSQL and Oracle.</li>
    <li>Insert/update don't work correctly on PostgreSQL and Oracle if
the user choose "Other...." from a select_single field menu and the
field has some linked fields.</li>
  </ul>
  <li>Admin section related:<br>
  </li>
  <ul>
    <li>The field renaming feature of the administration page doesn't
work as expected if the renamed field is used in one of the following
properties: "Primary key field", "Linked fields", "Order by" in the
interface configurator related to any of the tables. In particular,
after the renaming, you will get "[08] Error: during query execution"
messages from the DaDaBIK front end; you should edit the above
properties by hand, renaming the field in the interface configurator. </li>
  </ul>
  <ul>
    <li>The "refresh installation" admin operation doesn't work
correctly
and could lead to an interface configurator settings loss if the
installation is the result of an upgrade from a DaDaBIK version &lt;
4.1 rc2; the "refresh installation" bug is considered fixed only for
tables installed (DaDaBIK installation from scratch or single table
installation from the admin interface) using a DaDaBIK version &gt;=
4.1 rc2.</li>
  </ul>
  <li>Master/details related:<br>
  </li>
  <ul>
    <li>In a master/details view, the details table is correctly showed
below the corresponding master table record when the edit function is
used, but it is not showed when the details function is used</li>
    <li>After having accessed (in edit mode) a record with
master/details view, DaDaBIK will show only the records related to that
master record if the details table is accessed in "last search results"
mode. A "show all" is needed to remove the incorrect filter.<br>
    </li>
  </ul>

  <li>Others:</li><ul>
    <li>The "previous" and "next" buttons don't work correctly after
this
sequence of operations:
- perform a search based on a field A
- change the value the field A for a record of the resultset </li>
  </ul>
  <ul>
    <li>If, for a date field, the value of the month is set to other than [1-12] OR the value of the day is set to other than [1-31] OR the value of the year is set to other than [$start_year-$end_year] (see config.php) DaDaBIK will display in the edit view, for the relative field, the first default value available in the listbox. For example if a date field is 1940-00-00 DaDaBIK will display, in its default configuration, 1968-01-01 and will update the date to 1968-01-01 if the record is saved.</li>
  </ul>
  <ul>
    
    <li>Primary keys composed by multiple columns are not handled. </li>
    <li>The "check for duplicated" doesn't work with file types:
DaDaBIK
doesn't warn about similarity when two files have a similar name;
furthermore, the "check for duplicated" feature causes uploads to fail
during insert, in particular the files are not uploaded if some
possible duplicated records are found and the user decides to insert it
anyway. </li>
    <li>HTML content is not set correctly as "Default value" (interface
configurator). </li>
    <li>When
a new option of a select_single field with linked fields
is
inserted through the "other..." option, the current user is not
inserted in the ID_user field of the
linked table. This means that the new record in the linked table won't
get an owner and the&nbsp; $enable_delete_authorization,
$enable_update_authorization and $enable_browse_authorization options
won't work as expected.<br>
</li>
  </ul>
  <li>Unexpected behaviors (not really DaDaBIK bugs but behaviors which the average user doesn't expect)</li><ul>
  	<li>DaDaBIK relies on the system's (server) timezone settings (or on the $timezone parameter with PHP version >= 5.1) for
date functions (e.g. to produce the current date), which can be different
from the client's one.</li>
    <li>The value actually inserted in the database during an insert/update, if the value typed in the form is not part of the domain specified during table creation (e.g. integer, varchar,...), depends on the DBMS settings and on the domain itself. For example if an integer field is left blank during insert/update (not NULL, blank), MySQL could insert 0 as value, because an empty string is not part of the integer domain and very often the default value for integers is set to 0.</li>
  </ul>
</ul>
<a href="#general_information">[back to top]</a>
</body></html>

Added gpl.txt.













































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
		    GNU GENERAL PUBLIC LICENSE
		       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

			    Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.
 
		    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)
 
These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
 
  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
 
  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

			    NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

		     END OF TERMS AND CONDITIONS
 
	    How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Library General
Public License instead of this License.


Added program_files/admin.php.



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
<?php
/*
***********************************************************************************
DaDaBIK (DaDaBIK is a DataBase Interfaces Kreator) http://www.dadabik.org/
Copyright (C) 2001-2012  Eugenio Tacchini

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

If you want to contact me by e-mail, this is my address: eugenio.tacchini@unicatt.it
***********************************************************************************
*/
?>
<?php
include ("./include/config.php");

if ($db_library === 'adodb'){
	include('./include/adodb'.DADABIK_ADODB_VERSION.'/adodb.inc.php');
	
	// hack for oracle, all field names fetched in lower case
	if ($dbms_type === 'oci8po') {
		define('ADODB_ASSOC_CASE', 0); 
	} // end if
}
include ("./include/functions.php");
include ("./include/common_start.php");
include ("./include/check_installation.php");
include ("./include/check_admin_login.php");

$page_name = 'admin';


// variables:
// GET
// $table_name
// POST
// 
// $function from this page ("delete_records", "refresh_table",......)

// get the array containing the names of the tables installed
$installed_tables_ar = build_tables_names_array(0, 1, 1);

// get the table name to use in the second part of the administration
if (isset($_GET["table_name"])){
	$table_name = $_GET["table_name"];
} // end if
else{
	if (count($installed_tables_ar)>0){
		// get the first table
		$table_name = $installed_tables_ar[0];
	} // end if
} // end else

if (isset($_POST["function"])){
	$function = $_POST["function"];
} // end if
elseif (isset($_GET["function"])){
	$function = $_GET["function"];
} // end if
else{
	$function = "";
} // end else

include ("./include/header.php");
?>

<?php
// POST
// $allow_table_ar from this page
// $deleted_fields from this page
// field_to_change_name from this page
// field_to_change_new_position from this page
// old_field_name
// new_field_name
// $table_name from this page
// $enable_insert from this file
// $enable_edit from this file
// $enable_delete from this file
// $enable_details from this file
// $enable_list from this file
// $donation_answer from this file
// $dan from this file
// $dfe from this file

if (isset($_POST["allow_table_ar"])){
	$allow_table_ar = $_POST["allow_table_ar"];
} // end if
if (isset($_POST["deleted_fields_ar"])){
	$deleted_fields_ar = $_POST["deleted_fields_ar"];
} // end if
if (isset($_POST["field_to_change_name"])){
	$field_to_change_name = $_POST["field_to_change_name"];
} // end if
if (isset($_POST["field_to_change_name"])){
	$field_to_change_name = $_POST["field_to_change_name"];
} // end if
if (isset($_POST["field_to_change_new_position"])){
$field_to_change_new_position = $_POST["field_to_change_new_position"];
} // end if
if (isset($_POST["old_field_name"])){
	$old_field_name = $_POST["old_field_name"];
} // end if
if (isset($_POST["new_field_name"])){
	$new_field_name = $_POST["new_field_name"];
} // end if
if (isset($_POST["new_field_name"])){
	$new_field_name = $_POST["new_field_name"];
} // end if
if (isset($_POST["enable_insert"])){
	$enable_insert = $_POST["enable_insert"];
} // end if
if (isset($_POST["enable_edit"])){
	$enable_edit = $_POST["enable_edit"];
} // end if
if (isset($_POST["enable_delete"])){
	$enable_delete = $_POST["enable_delete"];
} // end if
if (isset($_POST["enable_details"])){
	$enable_details = $_POST["enable_details"];
} // end if
if (isset($_POST["enable_list"])){
	$enable_list = $_POST["enable_list"];
} // end if
if (isset($_POST["alias_table"])){
	$alias_table = $_POST["alias_table"];
} // end if
if (isset($_POST["dan"])){
	$dan = $_POST["dan"];
} // end if
if (isset($_POST["dfe"])){
	$dfe = $_POST["dfe"];
} // end if

$confirmation_message = "";

if (isset($table_name)){
	// build the select with all installed table
	$change_table_select = build_change_table_select(0, 1);
	$table_internal_name = $prefix_internal_table.$table_name;
} // end if

// this is useful to display the tables that could be installed
$complete_tables_names_ar = build_tables_names_array(0, 0, 1);

switch($function){
	case "show_help":
		
		require './include/forms/help.php';
		exit;
		break;
	case "show_hotscripts_feedback":
		
		require './include/forms/hotscripts_feedback.php';
		exit;
		break;
	case "show_donation_form":
		$sql = "SELECT date_time_installation FROM ".$prefix_internal_table."installation_tab";
		
		$res = execute_db($sql, $conn);
	
		$num_rows= get_num_rows_db($res);

		if ($num_rows === 1){ // just one record should be available
			$row = fetch_row_db($res);
			$date_time_installation = $row['date_time_installation'];
		} // end if
		else{
			echo "<p>An error occured";
		} // end else
		
		require './include/forms/donation.php';
		manage_other_infos_installation('update', 'das',time());		
		exit;
		break;
	case "process_donation":
		if ($dan === '1'){
			require './include/forms/paypal.php';
		} // end if
		
		manage_other_infos_installation('update', 'dan',$dan);
		
		$date_time = date("Y-m-d H:i:s");
		
		$sql = "SELECT id_installation, code_installation FROM ".$prefix_internal_table."installation_tab";
		
		$res = execute_db($sql, $conn);
		
		$num_rows= get_num_rows_db($res);
		
		if ($num_rows === 1){ // just one record should be available
			$row = fetch_row_db($res);
			$id_installation = $row['id_installation'];
			$code_installation = $row['code_installation'];
		}
		else{
			echo "<p>An error occured";
		} // end else
		
		$process_donation_answer = @file_get_contents('http://www.dadabik.org/process_donation.php?dan='.$dan.'&id_installation='.$id_installation.'&code_installation='.$code_installation.'&dfe='.urlencode($dfe).'&date_time='.urlencode($date_time));
		
		if ($dan === '1'){
			exit;
		} // end if
		
		$confirmation_message = "<p>Infomation registered, thanks.";
		
		break;
	case "install_table":
		$table_internal_name_temp = $prefix_internal_table.$table_name;

		$unique_field_name = get_unique_field_db($table_name);
	
		// get the array containing the names of the fields
		$fields_names_ar = build_fields_names_array($table_name);

		// drop (if present) the old internal table and create the new one.
		create_internal_table ($table_internal_name_temp);

		// delete the previous record about the table
		$sql = "delete from ".$quote.$table_list_name.$quote." where ".$quote."name_table".$quote." = '".$table_name."'";			
		$res_delete = execute_db($sql, $conn);
		
		$sql = "insert into ".$quote.$table_list_name.$quote." (".$quote."name_table".$quote.", ".$quote."allowed_table".$quote.", ".$quote."enable_insert_table".$quote.", ".$quote."enable_edit_table".$quote.", ".$quote."enable_delete_table".$quote.", ".$quote."enable_details_table".$quote.", ".$quote."enable_list_table".$quote.", ".$quote."alias_table".$quote.") values ('".$table_name."', '1', '1', '1', '1', '1', '1', '".$table_name."')";
		$res_insert = execute_db($sql, $conn);

		if ($table_name === $users_table_name) {
			$sql = "INSERT INTO ".$quote.$table_internal_name_temp.$quote." VALUES (1, 'id_user', 'id_user', 'text', 'alphanumeric', '0', '0', '0', '0', '1', '0', '0', '0', '', '', '', '', '', '', '', 'is_equal/contains/starts_with/ends_with/greater_than/less_then', '', '', '', '', '100', '', 1, '~')";
			$res_insert = execute_db($sql, $conn);
			
			$sql = "INSERT INTO ".$quote.$table_internal_name_temp.$quote." VALUES (2, 'user_type_user', 'User type', 'select_single', 'alphanumeric', '1', '1', '1', '1', '1', '1', '0', '0', '~admin~normal~', '', '', '', '', '', '', 'is_equal/contains/starts_with/ends_with/greater_than/less_then', '', '', '', '', '100', '', 2, '~')";
			$res_insert = execute_db($sql, $conn);
			
			$sql = "INSERT INTO ".$quote.$table_internal_name_temp.$quote." VALUES (3, 'username_user', 'Username', 'text', 'alphanumeric', '1', '1', '1', '1', '1', '1', '1', '0', '', '', '', '', '', '', '', 'is_equal/contains/starts_with/ends_with/greater_than/less_then', '', '', '', '', '100', '', 3, '~')";
			$res_insert = execute_db($sql, $conn);

			$sql = "INSERT INTO ".$quote.$table_internal_name_temp.$quote." VALUES (4, 'password_user', 'Password (md5 hash)', 'text', 'alphanumeric', '0', '0', '1', '1', '1', '1', '0', '0', '', '', '', '', '', '', '', 'is_equal/contains/starts_with/ends_with/greater_than/less_then', '', '', '', '', '100', '', 4, '~')";
			$res_insert = execute_db($sql, $conn);
		} // end if
		else {
			for ($j=0; $j<count($fields_names_ar); $j++){
				// insert a new record in the internal table with the name of the field as name and label
				$sql = "insert into ".$quote.$table_internal_name_temp.$quote." (".$quote."name_field".$quote.", ".$quote."label_field".$quote.", ".$quote."order_form_field".$quote.") values ('".$fields_names_ar[$j]."', '".$fields_names_ar[$j]."', '".($j+1)."')";
				
				$res_insert = execute_db($sql, $conn);
			} // end for
		} // end else
		
		if (table_exists($table_internal_name_temp)){ // just a check if always is fine
			$confirmation_message = "<p>Internal table <b>".$table_internal_name_temp."</b> correctly created......";
		} // end if
		else{
			$confirmation_message = "<p>An error during installation occured";
			exit;
		} // end else

		if ($unique_field_name == ""){
			$confirmation_message .= "<p><b>Warning:</b> your table <b>".$table_name."</b> hasn't any primary keys set, if you don't set a primary key DaDaBIK won't show the edit/delete/details buttons.";
		} // end if
		
		// re-get the array containing the names of the tables installed
		$installed_tables_ar = build_tables_names_array(0, 1, 1);
		
		// re-build the select with all installed table
		$change_table_select = build_change_table_select(0, 1);

		break;
	case "uninstall_table":
		// delete the table from table_list_name
		$sql = "DELETE FROM ".$quote.$table_list_name.$quote." WHERE name_table = '".$table_name."'";
		execute_db($sql, $conn);

		// drop the internal table
		$sql = "DROP TABLE ".$quote.$table_internal_name.$quote;
		execute_db($sql, $conn);

		$confirmation_message .= "Table ".$table_name." uninstalled.";

		// re-get the array containing the names of the tables installed
		$installed_tables_ar = build_tables_names_array(0, 1, 1);

		if (count($installed_tables_ar)>0){
			// get the first table
			$table_name = $installed_tables_ar[0];
		} // end if

		if (isset($table_name)){
			// build the select with all installed table
			$change_table_select = build_change_table_select(0, 1);
			$table_internal_name = $prefix_internal_table.$table_name;
		} // end if

		break;
	case "include_tables":
		for ($i=0; $i<count($complete_tables_names_ar); $i++){
			if (in_array($complete_tables_names_ar[$i], $installed_tables_ar)){
				if (isset($allow_table_ar[$i])){
					if ($allow_table_ar[$i] == "1"){
						$sql = "update ".$quote."$table_list_name".$quote." set ".$quote."allowed_table".$quote." = '1' where ".$quote."name_table".$quote." = '".$complete_tables_names_ar[$i]."'";
					} // end if
				} // en if
				else{
					$sql = "update ".$quote."$table_list_name".$quote." set ".$quote."allowed_table".$quote." = '0' where ".$quote."name_table".$quote." = '".$complete_tables_names_ar[$i]."'";
				} // end else
			execute_db($sql, $conn);
			}
		} // end for

		//$installed_tables_ar = build_tables_names_array(0, 1); // reload to show the correct values

		$confirmation_message .= "Changes correctly saved.";

		break; // break case "include tables"
	case "change_field_name":
		// change the name of the field
		$sql = "update ".$quote.$table_internal_name.$quote." set ".$quote."name_field".$quote." = '$new_field_name' where ".$quote."name_field".$quote." = '$old_field_name'";

		execute_db($sql, $conn);

		$confirmation_message .= "$old_field_name correctly changed to $new_field_name.";
		
		break;
	case "enable_features":
		if (!isset($enable_insert)){
			$enable_insert = "0";
		} // end if

		if (!isset($enable_edit)){
			$enable_edit = "0";
		} // end if

		if (!isset($enable_delete)){
			$enable_delete = "0";
		} // end if

		if (!isset($enable_details)){
			$enable_details = "0";
		} // end if

		if (!isset($enable_list)){
			$enable_list = "0";
		} // end if

		// save the configuration about features enabled
		$sql = "update ".$quote."$table_list_name".$quote." set ".$quote."enable_insert_table".$quote." = '".$enable_insert."', ".$quote."enable_edit_table".$quote." = '".$enable_edit."', ".$quote."enable_delete_table".$quote." = '".$enable_delete."', ".$quote."enable_details_table".$quote." = '".$enable_details."', ".$quote."enable_list_table".$quote." = '".$enable_list."' where ".$quote."name_table".$quote." = '$table_name'";

		// execute the update
		$res_update = execute_db($sql, $conn);

		$confirmation_message .= "Changes correctly saved.";
		break;
	case "save_table_alias":

		// save the configuration about table alias
		$sql = "UPDATE ".$quote.$table_list_name.$quote." SET ".$quote."alias_table".$quote." = '".$alias_table."' where ".$quote."name_table".$quote." = '".$table_name."'";

		// execute the update
		$res_update = execute_db($sql, $conn);

		$confirmation_message .= "Changes correctly saved.";
		break;
	case "delete_records":
		// get the array containg label and other information about the fields
		$fields_labels_ar = build_fields_labels_array($table_internal_name, "1");
		
		if (isset($deleted_fields_ar)){
			for ($i=0; $i<count($deleted_fields_ar); $i++){
				// delete the record of the internal table
				$sql = "delete from ".$quote."$table_internal_name".$quote." where ".$quote."name_field".$quote." = '".$deleted_fields_ar[$i]."'";
				$res_delete = execute_db("$sql", $conn);

				// get the order_form_field of the field
				for ($j=0; $j<count($fields_labels_ar); $j++){
					if ($deleted_fields_ar[$i] == $fields_labels_ar[$j]["name_field"]){
						$order_form_field_temp = $fields_labels_ar[$j]["order_form_field"];
					} // end if
				} // end for

				// re-get the array containg label and other information about the fields
				$fields_labels_ar = build_fields_labels_array($table_internal_name, "1");

				if (isset($order_form_field_temp)){ // otherwise I could have done a reload of a delete page
					// decrease the order_form_field of all the following record by one
					for ($j=($order_form_field_temp+1); $j<=(count($fields_labels_ar)+1); $j++){
						$sql ="update ".$quote."$table_internal_name".$quote." set ".$quote."order_form_field".$quote." = order_form_field-1 where ".$quote."order_form_field".$quote." = $j";
						$res_update = execute_db("$sql", $conn);
					} // end for
				} // end if

				// re-get the array containg label and other information about the fields
				$fields_labels_ar = build_fields_labels_array($table_internal_name, "1");
			} // end for

			$confirmation_message .= "$i fields correctly deleted from the internal table $table_internal_name.";
		} // end if
		else{
			$confirmation_message .= "Please select one or more fields to delete.";
		} // end else
		break;
	case "refresh_table":
		// get the array containing the names of the fields
		$fields_names_ar = build_fields_names_array($table_name);

		// get the array containg label ant other information about the fields
		$fields_labels_ar = build_fields_labels_array($table_internal_name, "2");

		// get the max order from the table
		$sql_max = "select max(order_form_field) from ".$quote."$table_internal_name".$quote."";
		$res_max = execute_db("$sql_max", $conn);
		while ($max_row = fetch_row_db($res_max)){
			$max_order_form = $max_row[0];
		} // end while

		// drop (if present) the old internal table and create the new one.
		create_internal_table($table_internal_name);

		$j = 0;  // set to 0 the counter for the $fields_labels_ar
		$new_fields_nr = 0; // set to 0 the counter for the number of new fields inserted

		for ($i=0; $i<count($fields_names_ar); $i++){
			if (isset($fields_labels_ar[$j]["name_field"]) and $fields_names_ar[$i] == $fields_labels_ar[$j]["name_field"]){



				// insert a previous present record in the internal table
				$name_field_temp = addslashes($fields_labels_ar[$j]["name_field"]);
				$present_insert_form_field_temp = addslashes($fields_labels_ar[$j]["present_insert_form_field"]);
				$present_search_form_field_temp = addslashes($fields_labels_ar[$j]["present_search_form_field"]);
				$present_ext_update_form_field_temp = addslashes($fields_labels_ar[$j]["present_ext_update_form_field"]);
				$required_field_temp = addslashes($fields_labels_ar[$j]["required_field"]);
				$present_results_search_field_temp = addslashes($fields_labels_ar[$j]["present_results_search_field"]);
				$present_details_form_field_temp = addslashes($fields_labels_ar[$j]["present_details_form_field"]);
				$check_duplicated_insert_field_temp = addslashes($fields_labels_ar[$j]["check_duplicated_insert_field"]);
				$type_field_temp = addslashes($fields_labels_ar[$j]["type_field"]);
				$content_field_temp = addslashes($fields_labels_ar[$j]["content_field"]);
				$separator_field_temp = addslashes($fields_labels_ar[$j]["separator_field"]);
				$items_table_names_field_temp = addslashes($fields_labels_ar[$j]["items_table_names_field"]);
				$items_table_fk_field_names_field_temp = addslashes($fields_labels_ar[$j]["items_table_fk_field_names_field"]);
				$select_options_field_temp = addslashes($fields_labels_ar[$j]["select_options_field"]);
				$select_type_field_temp = addslashes($fields_labels_ar[$j]["select_type_field"]);
				$prefix_field = addslashes($fields_labels_ar[$j]["prefix_field"]);
				$default_value_field = addslashes($fields_labels_ar[$j]["default_value_field"]);
				$label_field_temp = addslashes($fields_labels_ar[$j]["label_field"]);
				$width_field_temp = addslashes($fields_labels_ar[$j]["width_field"]);
				$height_field_temp = addslashes($fields_labels_ar[$j]["height_field"]);
				$maxlength_field_temp = addslashes($fields_labels_ar[$j]["maxlength_field"]);
				$hint_insert_field_temp = addslashes($fields_labels_ar[$j]["hint_insert_field"]);
				$order_form_field_temp = addslashes($fields_labels_ar[$j]["order_form_field"]);
				
				$other_choices_field_temp = addslashes($fields_labels_ar[$j]["other_choices_field"]);

				$primary_key_field_field_temp = addslashes($fields_labels_ar[$j]["primary_key_field_field"]);
				$primary_key_table_field_temp  = addslashes($fields_labels_ar[$j]["primary_key_table_field"]);
				$primary_key_db_field_temp = addslashes($fields_labels_ar[$j]["primary_key_db_field"]);

				$linked_fields_field_temp = addslashes($fields_labels_ar[$j]["linked_fields_field"]);
				$linked_fields_order_by_field_temp = addslashes($fields_labels_ar[$j]["linked_fields_order_by_field"]);
				$linked_fields_order_type_field_temp = addslashes($fields_labels_ar[$j]["linked_fields_order_type_field"]);
			

				$sql = "insert into ".$quote."$table_internal_name".$quote." (".$quote."name_field".$quote.", ".$quote."present_insert_form_field".$quote.", ".$quote."present_search_form_field".$quote.", ".$quote."required_field".$quote.", ".$quote."present_results_search_field".$quote.", ".$quote."present_details_form_field".$quote.", ".$quote."present_ext_update_form_field".$quote.", ".$quote."check_duplicated_insert_field".$quote.", ".$quote."type_field".$quote.", ".$quote."content_field".$quote.", ".$quote."separator_field".$quote.", ".$quote."select_options_field".$quote.", ".$quote."select_type_field".$quote.", ".$quote."prefix_field".$quote.", ".$quote."default_value_field".$quote.", ".$quote."label_field".$quote.", ".$quote."width_field".$quote.", ".$quote."height_field".$quote.", ".$quote."maxlength_field".$quote.", ".$quote."hint_insert_field".$quote.", ".$quote."order_form_field".$quote.", ".$quote."other_choices_field".$quote.", ".$quote."primary_key_field_field".$quote.", ".$quote."primary_key_table_field".$quote.", ".$quote."primary_key_db_field".$quote.", ".$quote."linked_fields_field".$quote.", ".$quote."linked_fields_order_by_field".$quote.", ".$quote."linked_fields_order_type_field".$quote.") values ('$name_field_temp', '$present_insert_form_field_temp', '$present_search_form_field_temp', '$required_field_temp', '$present_results_search_field_temp', '$present_details_form_field_temp', '$present_ext_update_form_field_temp', '$check_duplicated_insert_field_temp', '$type_field_temp', '$content_field_temp', '$separator_field_temp', '$select_options_field_temp', '$select_type_field_temp', '$prefix_field', '$default_value_field', '$label_field_temp', '$width_field_temp', '$height_field_temp', '$maxlength_field_temp', '$hint_insert_field_temp', '$order_form_field_temp', '$other_choices_field_temp', '$primary_key_field_field_temp', '$primary_key_table_field_temp', '$primary_key_db_field_temp', '$linked_fields_field_temp', '$linked_fields_order_by_field_temp', '$linked_fields_order_type_field_temp')";

				$j++; // go to the next record in the internal table
			} // end if
			else{
				$max_order_form++;
				// insert a new record in the internal table with the name of the field
				$sql = "insert into ".$quote."$table_internal_name".$quote." (".$quote."name_field".$quote.", ".$quote."label_field".$quote.", ".$quote."order_form_field".$quote.") values ('$fields_names_ar[$i]', '$fields_names_ar[$i]', '$max_order_form')";
				
				$new_fields_ar[$new_fields_nr] = $fields_names_ar[$i]; // insert the name of the new field in the array to display it in the confirmation message
				$new_fields_nr++; // increment the counter of the $new_fields_ar array
			} // end else	
			$res_insert = execute_db($sql, $conn);
		} // end for
		$confirmation_message .= "Internal table correctly refreshed.<br>$new_fields_nr field/s added";
		if ($new_fields_nr > 0){
			$confirmation_message .= " (";
			for ($i=0; $i<count($new_fields_ar); $i++){
				$confirmation_message .= $new_fields_ar[$i].", ";
			} // end for
			$confirmation_message = substr($confirmation_message, 0, -2); // delete the last ", "
			$confirmation_message .= ")";
		} // end if
		$confirmation_message .= ".";
		break;
	case "change_position":
		// get the array containg label and other information about the fields
		$fields_labels_ar = build_fields_labels_array($table_internal_name, "1");

		// get the order_form_field of the field
		for ($i=0; $i<count($fields_labels_ar); $i++){
			if ($field_to_change_name == $fields_labels_ar[$i]["name_field"]){
				$field_to_change_old_position = $fields_labels_ar[$i]["order_form_field"];
			} // end if
		} // end for

		if ($field_to_change_new_position < $field_to_change_old_position){
			// increase the order_form_field of all the following record by one
			for ($i=$field_to_change_old_position-1; $i>=$field_to_change_new_position; $i--){
				$sql ="update ".$quote.$table_internal_name.$quote." set ".$quote."order_form_field".$quote." = ".$quote."order_form_field".$quote."+1 where ".$quote."order_form_field".$quote." = '".$i."'";
				$res_update = execute_db($sql, $conn);
			} // end for
		} // end if
		else{
			// decrease the order_form_field of all the previous record by one
			for ($i=$field_to_change_old_position+1; $i<=$field_to_change_new_position; $i++){
				$sql ="update ".$quote.$table_internal_name.$quote." set ".$quote."order_form_field".$quote." = ".$quote."order_form_field".$quote."-1 where ".$quote."order_form_field".$quote." = '".$i."'";
				$res_update = execute_db($sql, $conn);
			} // end for
		} // end if

		// change the order_form_field of the field selected
		$sql ="update ".$quote.$table_internal_name.$quote." set ".$quote."order_form_field".$quote." = '".$field_to_change_new_position."' where ".$quote."name_field".$quote." = '".$field_to_change_name."'";
		$res_update = execute_db($sql, $conn);
		$confirmation_message .= "Field $field_to_change_name position correctly changed from $field_to_change_old_position to $field_to_change_new_position.";		
		break;
	default:
		break;
} // end switch
?>

<?php
if ($confirmation_message != ""){
	echo "<p><b><font color=\"#ff0000\">$confirmation_message</font></b>";
} // end if
?>

<table>
<tr><td valign="top">
<p>Some general configuration parameters can be directly set from the file <b>/include/config.php</b>, just by opening it with a plain text editor and editing it. The file is self-explanatory. At that level you can, for example, set the database you want to manage with DaDaBIK or enable/disable/configure some DaDaBIK features (e.g. authentication, authorization, upload, email notices, duplication check, language,...).</p>
<p>For a more analytic tuning you are supposed to use this admin area. At this level you can choose the database tables you want to put in your DaDaBIK application and, for each table, through the Interface configurator, create your own DaDaBIK interface, choosing for example the fields you want to include/exclude from the forms, the content of each field, the labels....
</p>
<p><font size="+1">Which tables of the <font color="#FF0000"><?php echo $db_name; ?></font> database you want to use in DaDaBIK?</font></p>


<p>In order to use a table in a DaDaBIK application, the table must be <i>installed</i> and <i>enabled</i> in DaDaBIK. When you install DaDaBIK the first time, by default all the tables are installed and enabled.</p><p><font color="#ff0000"><b>Here is the list of the available tables:</b></font>
<form name="include_tables_form" method="post" action="admin.php">
<input type="hidden" name="function" value="include_tables">
<?php //if (count($installed_tables_ar) != 0){ ?>

<table cellpadding="5">
<tr>
<th>Table name</th>
<th>Installed</th>
<th>Enabled</th>
</tr>
<?php
/*
for ($i=0; $i<count($installed_tables_ar); $i++){
	echo "<tr><td><input type=\"checkbox\" onclick=\"javascript:document.include_tables_form.submit()\" name=\"allow_table_ar[$i]\" value=\"1\"";
	if (table_allowed($installed_tables_ar[$i])){
		echo " checked";
	} // end if
	echo "</td><td><input type=\"checkbox\" onclick=\"javascript:document.include_tables_form.submit()\" name=\"allow_table_ar[$i]\" value=\"1\"";
	if (table_allowed($installed_tables_ar[$i])){
		echo " checked";
	} // end if
	echo "></td><td>".$installed_tables_ar[$i]." <a href=\"admin.php?function=uninstall_table&table_name=".urlencode($installed_tables_ar[$i])."\">Uninstall</a></td></tr>";
} // end for
*/
for ($i=0; $i<count($complete_tables_names_ar); $i++){
	echo "<tr><td>".$complete_tables_names_ar[$i]."</td>";
	
	echo "<td>";
	//echo "<td><input type=\"checkbox\" onclick=\"javascript:document.include_tables_form.submit()\" name=\"install_table_ar[$i]\" value=\"1\"";
	if (in_array($complete_tables_names_ar[$i], $installed_tables_ar)){
		echo "Yes (<a href=\"admin.php?function=uninstall_table&table_name=".urlencode($complete_tables_names_ar[$i])."\">Uninstall</a>)</td>";
	} // end if
	else{
		echo "No (<a href=\"admin.php?function=install_table&table_name=".urlencode($complete_tables_names_ar[$i])."\">Install</a>)</td>";
	}
	
	if (in_array($complete_tables_names_ar[$i], $installed_tables_ar)){
	
		echo "<td><input type=\"checkbox\" onclick=\"javascript:document.include_tables_form.submit()\" name=\"allow_table_ar[$i]\" value=\"1\"";
		if (table_allowed($complete_tables_names_ar[$i])){
			echo " checked";
		} // end if	
		echo ">";
	}
	echo "</td></tr>";
} // end for
?>
</table>
Uncheck enable to temporarily exclude the table from DaDaBIK.<br>Click Uninstall to permanently remove the table from DaDaBKIK (for example if the table doesn't anymore exist in the database).<br>
<br><!--<input type="submit" value="Save changes">-->

<?php
/* } // end if
else{	
	echo "No tables installed.";
} // end else
*/
?>

</form>

<?php if (count($installed_tables_ar)>0){ // otherwise it means that no internal tables are installed

// get the array containg label and other information about the fields
$fields_labels_ar = build_fields_labels_array($table_internal_name, "1"); // because I need it for the display of the select in the form

?>

<p><font size="+1">Configure the DaDaBIK interface of the table <b><?php echo $table_name; ?></b></font></p>

<?php
if ($change_table_select != ""){
?>
<form method="get" action="admin.php" name="change_table_form"><input type="hidden" name="function" value="change_table">
<?php echo $change_table_select; ?>
<?php
if ( $autosumbit_change_table_control == 0) {
?>
<input type="submit" value="Change table">
<?php
}
else{
?>
 Change table
<?php
}
?>

</form>
<?php
}
$enable_features_checkboxes = build_enable_features_checkboxes($table_name);

$only_include_allowed = 0;
$installed_table_infos_ar = build_installed_table_infos_ar($only_include_allowed, 1);

foreach ($installed_table_infos_ar as $installed_table_infos) {
	if ($installed_table_infos['name_table'] === $table_name) {
		$table_alias = $installed_table_infos['alias_table'];
	} // end if
} // end while
?>

<p><form method="post" action="admin.php?table_name=<?php echo urlencode($table_name); ?>"><input type="hidden" name="function" value="enable_features">For this table enable: <?php echo $enable_features_checkboxes ?><input type="submit" value="Enable/disable"></form>

<p><form method="post" action="admin.php?table_name=<?php echo urlencode($table_name); ?>"><input type="hidden" name="function" value="save_table_alias">Table alias (this is what DaDaBIK will displays in the interface) <input type="text" name="alias_table" value="<?php echo $table_alias; ?>"> <input type="submit" value="Save alias"></form>

<p>If you want to configure the interface of the table in detail (e.g. want to specify if a field should be included or not in the search/insert/update form, the content of the field,...) you have to use the <a href="internal_table_manager.php?table_name=<?php echo urlencode($table_name); ?>">Interface configurator</a>.
<p>Directly from here you can, instead, update DaDaBIK when you have modified some fields of your table (e.g. when you have added one or more fields, deleted one or more fields, renamed one or more fields from <b><?php echo $table_name; ?></b>) or you want to modify the displaying order of the fields in the DaDaBIK interface.</p>

<p>Please follow these steps in the correct order:
<p>&nbsp;
<table border="0" cellpadding="6" width="100%">
  <tr bgcolor="#F0F0F0"> 
    <td><b><font color="#ff0000">Step 1:</font></b><br>
      If you have renamed some fields of <b><?php echo $table_name; ?></b> you 
      have to specify here the new names.</b>

	   <p>Select the field name you want to change and specify the new name:<br>
      <form name="change_field_name_form" method="post" action="admin.php?table_name=<?php echo $table_name; ?>">
	  <input type="hidden" name="function" value="change_field_name">
        Old field name: <select name="old_field_name">
          <?php
for ($i=0; $i<count($fields_labels_ar); $i++){
	echo "<option value=\"".$fields_labels_ar[$i]["name_field"]."\">".$fields_labels_ar[$i]["name_field"]."</option>";	
} // end for
?> 
        </select>
		new field name: <input type="text" name="new_field_name">
		<input type="submit" value="Change">
		</form>
    </td>
  </tr>
</table>
<br>
<table border="0" cellpadding="6" width="100%">
  <tr bgcolor="#F0F0F0"> 
    <td>
      <p><b><font color="#ff0000">Step 2:</font></b><br>
        If you have deleted some fields of <b><?php echo $table_name; ?></b> you 
        have to specify here which fields you have deleted
        by selecting it/them and clicking the delete button. 
      <p>Select the field/s you want to delete:<br>
        (multiple selection available) 
      <form name="deleted_fields_form" method="post" action="admin.php?table_name=<?php echo $table_name; ?>">
	  <input type="hidden" name="function" value="delete_records">
        <select multiple name="deleted_fields_ar[]" size="10">
          <?php
for ($i=0; $i<count($fields_labels_ar); $i++){
	echo "<option value=\"".$fields_labels_ar[$i]["name_field"]."\">".$fields_labels_ar[$i]["name_field"]."</option>";	
} // end for
?> 
        </select>
        <input type="submit" value="Delete this/these field/fields" name="submit">
      </form>
    </td>
  </tr>
</table>
<br>
<table border="0" cellpadding="6" width="100%">
  <tr bgcolor="#F0F0F0"> 
    <td>
      <p><b><font color="#ff0000">Step 3:</font></b><br>
        If you have added some fields to <b><?php echo $table_name; ?></b> you 
        have to update DaDaBIK by pressing the refresh installation button: 
      <form name="refresh_form" method="post" action="admin.php?table_name=<?php echo $table_name; ?>">
		<input type="hidden" name="function" value="refresh_table">
        <input type="submit" value="Refresh installation" name="submit">
      </form>
      <br>
      <br>
    </td>
  </tr>
</table>
<br>
<table border="0" cellpadding="6" width="100%">
  <tr bgcolor="#F0F0F0"> 
    <td>
      <p><b><font color="#ff0000">Step 4:</font></b><br>
        If you want to change the displaying order of a field in the DaDaBIK interfaces, you can do it by selecting the field from the following menu and specifying the new position. All the other field positions will be shifted correctly.
		<form name="change_position_form" method="post" action="admin.php?table_name=<?php echo $table_name; ?>">
		<input type="hidden" name="function" value="change_position">
		Field name (position): 
        <select  name="field_to_change_name">
         <?php
		for ($i=0; $i<count($fields_labels_ar); $i++){
			echo "<option value=\"".$fields_labels_ar[$i]["name_field"]."\">".$fields_labels_ar[$i]["name_field"]." (".$fields_labels_ar[$i]["order_form_field"].")</option>";	
		} // end for
		?> 
        </select>
		 New position: 
		<select  name="field_to_change_new_position">
         <?php
		for ($i=0; $i<count($fields_labels_ar); $i++){
			echo "<option value=\"".$fields_labels_ar[$i]["order_form_field"]."\">".$fields_labels_ar[$i]["order_form_field"]."</option>";	
		} // end for
		?> 
        </select>
        <input type="submit" value="Change position" name="submit">
      </form>
	</td>
  </tr>
</table></td><!--<td valign="top"><b>Buying mp3s</b> from Amazon you can support the DaDaBIK project</br></br>-->

<?php
if (date("Ymd") < '2011-01-30'){

?>

<iframe src="http://rcm.amazon.com/e/cm?t=dadabik-20&o=1&p=21&l=ur1&category=50mp3albums5each&banner=19QT8FZHDHFZDN87C482&f=ifr" width="125" height="125" scrolling="no" border="0" marginwidth="0" style="border:none;" frameborder="0"></iframe>

<?php
}
?>

</td></tr></table>


<?php } // end if?>
<?php
// include footer
include ("./include/footer.php");
?>

Added program_files/css/styles_print.css.





























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
body {  font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt ; background-color: #ffffff}
p {  font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt}
a {  font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt}
a.navig {  color:blue}
a.order {  color:blue}
td {  font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt}
th.results {  font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 8pt; background-color: #EFEFEF}
td.results {  font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 8pt; background-color: #ffffff}
table.results { background-color: #D0DCE0}
div.break {page-break-before:always}
table.labels {  width: 21cm}
td.address {  height: 3.4cm; width: 10cm; text-align: left; vertical-align: top; margin-top: 10px; margin-left: 10px; font-size: 14px}
td.marginvert {  width: 0.5cm}
td.marginorizz {  height: 1.2cm}
.onlyscreen {display: none;}
.export_to_csv{
	display: none;
}
/* previous next links */
a.previous_next {
	color:blue;
	text-decoration: none;
}
/* change records per page combo box*/
.select_records_per_page{
}
/* the small arrow near the column head which represents currently the order by field */
.arrow {
	font-size: 8pt;
}

Added program_files/css/styles_screen.css.



























































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
body {
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-size: 14px ;
	background-color: #d6d6d6;
	margin-left: 10px;
	margin-top: 10px;
}
p {
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-size: 14px;
}
a {
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-size: 14px;
	color: blue;
}
th {
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-size: 14px;
}
td {
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-size: 14px;
}
input{
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-size: 14px;
}
select{
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-size: 14px;
}
option{
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-size: 14px;
}
textarea{
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-size: 14px;
	border-style: outset;
}
hr{
	height: 1px;
	border-style: none;
	color: black; /* need this for IE */
	background-color: black;  /* need this for Mozilla */
}

/* used with subtitles ("Search for records", "Edit the record", etc.) */
h3{
}

.button_form{
border: 1px solid;
background-color:#a9b299;
}

/* the main big table that contain all the page */
.main_table{
	width:100%;
	height: 100%;
	background-color: #d6d6d6;
	padding: 10px; /* doesn't work with IE, cellpadding in header */
	border-style: solid;
	border-width: 0px;
	border-color: black;
	vertical-align: bottom;
}


/*******************************************************/
/************************************************ RESULTS PAGE */

/* "n records found" message */
.n_results_found {
	color:black;
	font-weight: bold;
}

/* "page n of m" sentence */
.page_n_of_m {
	color:black;
}

/* links of the navigation bar ( << < 1 2 3......) */
a.navig {
	color:blue;
}

/* previous next links */
a.previous_next {
	color:blue;
	text-decoration: none;
}

/* current page in the navigation bar ( << < 1 2 3......) */
.navig {
	color:black;
}

/* order by links */
/* normal */
a.order_link {
	color:blue;
	font-size: 14px;
	font-weight:normal;
	text-decoration: none;
}
/* currently selected */
a.order_link_selected {
	color:blue;
	font-size: 14px;
	font-weight:normal;
	text-decoration: none;
}

/* the small arrow near the column head which represents currently the order by field */
.arrow {
	font-size: 14px;
}


/* results table */

table.results {
	background-color: #d6d6d6; /* used to make the table bordered */
}

/* result rows */
/* results_1 and results_2 differ only for the background-color, this create the alternate row colors effect */
.tr_results_1 {
	font-size: 8pt;
	vertical-align: top;
	white-space: nowrap;
	background-color: #EFEFEF;
}
.tr_results_2 {
	font-size: 8pt;
	vertical-align: top;
	white-space: nowrap;
	background-color: #ffffff;
}

.tr_highlighted_onmouseover{ /* a results table row when the mouse pointer is over it */
	font-size: 8pt;
	color: #ffffff;
	vertical-align: top;
	white-space: nowrap;
	background-color: #a8b19b;
}
.tr_highlighted_onclick{ /* a results table row when the click on it */
	font-size: 8pt;
	color: #ffffff;
	vertical-align: top;
	white-space: nowrap;
	background-color: #a8b19b;
}

/* coloumn headings */
th.results {
	background-color: #EFEFEF;
	white-space: nowrap;
}
/* result cells */
/* results_1 and results_2 differ only for the background-color, this create the alternate row colors effect */
/*
td.results_1 {
	font-size: 8pt;
	vertical-align: top;
	white-space: nowrap;
	background-color: #EFEFEF;
}
td.results_2 {
	font-size: 8pt;
	vertical-align: top;
	white-space: nowrap;
	background-color: #ffffff;
}
*/
/* control (edit, delete, details) cells */
/* results_1 and results_2 differ only for the background-color, this create the alternate row colors effect */
td.controls_1 {
	font-size: 8pt;
	background-color: #EFEFEF;
}
td.controls_2 {
	font-size: 8pt;
	background-color: #ffffff;
}

.export_to_csv{
}

/* "Total records: n" sentence */
.total_records {
}

/* links of the bottom menu (insert, search, show all) */
/* now this links are on the TOP but keep the old name */
a.bottom_menu{
	color: black;
	font-size: 18px;
	text-decoration: none;
}
a.bottom_menu_active{
	color: black;
	font-size: 18px;
	text-decoration: none;
	background-color:#ffffff;
	-webkit-border-radius:6px;
	-moz-border-radius:9px;
}
a.bottom_menu:hover{
background-color:#ffffff;
-webkit-border-radius:6px;
-moz-border-radius:9px;
}

/* home link */
a.home{
	color: black;
	font-size: 18px;
	text-decoration: none;
}
a.home:hover{
background-color:#ffffff;
-webkit-border-radius:6px;
-moz-border-radius:9px;
}

/* change table combo box  */
.select_change_table{
}

/* change table button */
.button_change_table{
}

/* change records per page combo box*/
.select_records_per_page{
}
/*******************************************************/

/*******************************************************/
/************************************************ FORM (insert, search and update form) */

/* insert, save and search buttons */
.button_form{
}

/* rows containing insert, save and search buttons */
.tr_button_form {
	text-align: center;
}

/* rows containing the all/any in the search form */
.tr_operator_form{
	text-align: center;
}

/* the cell that contains the label in the form */
.td_label_form{
	text-align: right;
	vertical-align: top;
}

/* the cell that contains the input (textbox, textarea, etc) in the form */
.td_input_form{
	vertical-align: top;
}

/* the cell that contains the hint in the form */
.td_hint_form{
	vertical-align: top;
}

/* NULL word */
.null_word{
	font-style: italic;
}

/* error messages (e.g. "You haven't filled out some required fields...." */
.error_messages_form{
	color: red;
}

.change_table{
	margin-top: 0px;
	margin-left: 0px;
	}


/*******************************************************/
/************************************************ DETAIL PAGE */
/* the cell that contains the label */
.td_label_details{
	text-align: right;
	vertical-align: top;
}

/* the cell that contains the value */
.td_value_details{
	vertical-align: top;
}
/*******************************************************/

/*******************************************************/
/************************************************ LOGIN FORM */
.table_login_form{
text-align: center;
border-width:1px;
border-color: #000000;
border-style: solid;
text-align:"center";
background-color:#eeeeee;
font-size:20pt;
padding: 5px;
}

.tr_header_login_form{
background-color:#a9b299;
font-weight:bold;
color:#ffffff;
}

.td_label_login_form{
font-size:15pt;
}

.input_login_form{
border-width:1px;
border-color: #cccccc;
border-style: solid;
padding: 5px;
font-size:20pt;
}

.login_button{
border: 1px solid;
background-color:#a9b299;

}
/*******************************************************/


div.break {
	page-break-before:always
}
table.labels {
	width: 21cm
}
td.address {
	height: 3.4cm;
	width: 10cm;
	text-align: left;
	vertical-align: top;
	margin-top: 10px;
	margin-left: 10px;
	font-size: 14px
}
td.marginvert {
	width: 0.5cm
}
td.marginorizz {
	height: 1.2cm
}

/* bottom right credits */
.powered_by_dadabik{
	font-size: 12px
}

/* the table containing all the interface */
.table_interface_container{
	background-color:#eeeeee;
	width:100%;
	border:0px;
	padding:0px;
	
}
/* the table containing all the interface, login page */
.table_interface_container_login{
	background-color:#eeeeee;
	border:0px;
	padding:0px;
	
}
/* the logo row of the container table */
.table_interface_container_tr_logo{
	background-color: #a9b299;
	width:100%;
	padding:0px;
	
}
/* the menu (home, insert, search,...) row of the container table, see table_interface_container_table_menu for additional settings */
.table_interface_container_tr_menu{
	background-color: #d5c287;	
}
/* the menu (home, insert, search,...) subtable of the container table */
.table_interface_container_table_menu{
	background-color: #d5c287;
	width:100%;
	padding:4;
	
}
/* the menu (home, insert, search,...) row of the container table, see table_interface_container_table_menu_admin for additional settings */
.table_interface_container_tr_menu_admin_area{
	background-color: #ff7700;	
}
/* the menu (home, insert, search,...) subtable of the container table */
.table_interface_container_table_menu_admin_area{
	background-color: #ff7700;
	width:100%;
	padding:4;
	
}

/* the popup div that shows the help in the interface configurator */
#div_help
{
    position: absolute;
    display: none;
    width: 400px;
    border: 2px solid #ff7700;
}

#div_help_content
{
    background-color: White;
    height: 200px;
    padding: 8px;
    overflow: scroll;
}

#div_help_content_title
{
    font-weight: bold;
    margin-bottom: 3px;
}






Added program_files/images/delete.png.

cannot compute difference between binary files

Added program_files/images/details.png.

cannot compute difference between binary files

Added program_files/images/donate.png.

cannot compute difference between binary files

Added program_files/images/download.png.

cannot compute difference between binary files

Added program_files/images/edit.png.

cannot compute difference between binary files

Added program_files/images/help.png.

cannot compute difference between binary files

Added program_files/images/logo.gif.

cannot compute difference between binary files

Added program_files/include/adodb4/adodb-active-record.inc.php.











































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
<?php
/*

@version v4.992 10 Nov 2009  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  Latest version is available at http://adodb.sourceforge.net
 
  Released under both BSD license and Lesser GPL library license. 
  Whenever there is any discrepancy between the two licenses, 
  the BSD license will take precedence.
  
  Active Record implementation. Superset of Zend Framework's.
  
  Version 0.09
  
  See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 
  	for info on Ruby on Rails Active Record implementation
*/

global $_ADODB_ACTIVE_DBS;
global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks
global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record.

// array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
$_ADODB_ACTIVE_DBS = array();
$ACTIVE_RECORD_SAFETY = true;
$ADODB_ACTIVE_DEFVALS = false;

class ADODB_Active_DB {
	var $db; // ADOConnection
	var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
}

class ADODB_Active_Table {
	var $name; // table name
	var $flds; // assoc array of adofieldobjs, indexed by fieldname
	var $keys; // assoc array of primary keys, indexed by fieldname
	var $_created; // only used when stored as a cached file
}

// returns index into $_ADODB_ACTIVE_DBS
function ADODB_SetDatabaseAdapter(&$db)
{
	global $_ADODB_ACTIVE_DBS;
	
		foreach($_ADODB_ACTIVE_DBS as $k => $d) {
			if (PHP_VERSION >= 5) {
				if ($d->db === $db) return $k;
			} else {
				if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) 
					return $k;
			}
		}
		
		$obj = new ADODB_Active_DB();
		$obj->db =& $db;
		$obj->tables = array();
		
		$_ADODB_ACTIVE_DBS[] = $obj;
		
		return sizeof($_ADODB_ACTIVE_DBS)-1;
}


class ADODB_Active_Record {
	var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
	var $_table; // tablename, if set in class definition then use it as table name
	var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
	var $_where; // where clause set in Load()
	var $_saved = false; // indicates whether data is already inserted.
	var $_lasterr = false; // last error message
	var $_original = false; // the original values loaded or inserted, refreshed on update
	
	// should be static
	function UseDefaultValues($bool=null)
	{
	global $ADODB_ACTIVE_DEFVALS;
		if (isset($bool)) $ADODB_ACTIVE_DEFVALS = $bool;
		return $ADODB_ACTIVE_DEFVALS;
	}

	// should be static
	function SetDatabaseAdapter(&$db) 
	{
		return ADODB_SetDatabaseAdapter($db);
	}
	
	// php4 constructor
	function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false)
	{
		ADODB_Active_Record::__construct($table,$pkeyarr,$db);
	}
	
	// php5 constructor
	function __construct($table = false, $pkeyarr=false, $db=false)
	{
	global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
	
		if ($db == false && is_object($pkeyarr)) {
			$db = $pkeyarr;
			$pkeyarr = false;
		}
		
		if (!$table) { 
			if (!empty($this->_table)) $table = $this->_table;
			else $table = $this->_pluralize(get_class($this));
		}
		if ($db) {
			$this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
		} else
			$this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
		
		
		if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
		
		$this->_table = $table;
		$this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
		$this->UpdateActiveTable($pkeyarr);
	}
	
	function __wakeup()
	{
  		$class = get_class($this);
  		new $class;
	}
	
	function _pluralize($table)
	{
		$ut = strtoupper($table);
		$len = strlen($table);
		$lastc = $ut[$len-1];
		$lastc2 = substr($ut,$len-2);
		switch ($lastc) {
		case 'S':
			return $table.'es';	
		case 'Y':
			return substr($table,0,$len-1).'ies';
		case 'X':	
			return $table.'es';
		case 'H': 
			if ($lastc2 == 'CH' || $lastc2 == 'SH')
				return $table.'es';
		default:
			return $table.'s';
		}
	}
	
	//////////////////////////////////
	
	// update metadata
	function UpdateActiveTable($pkeys=false,$forceUpdate=false)
	{
	global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
	global $ADODB_ACTIVE_DEFVALS;

		$activedb =& $_ADODB_ACTIVE_DBS[$this->_dbat];

		$table = $this->_table;
		$tables = $activedb->tables;
		$tableat = $this->_tableat;
		if (!$forceUpdate && !empty($tables[$tableat])) {
			$tobj =& $tables[$tableat];
			foreach($tobj->flds as $name => $fld) {
				if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 
					$this->$name = $fld->default_value;
				else
					$this->$name = null;
			}
			return;
		}
		
		$db =& $activedb->db;
		$fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
		if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
			$fp = fopen($fname,'r');
			@flock($fp, LOCK_SH);
			$acttab = unserialize(fread($fp,100000));
			fclose($fp);
			if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { 
				// abs(rand()) randomizes deletion, reducing contention to delete/refresh file
				// ideally, you should cache at least 32 secs
				$activedb->tables[$table] = $acttab;
				
				//if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
			  	return;
			} else if ($db->debug) {
				ADOConnection::outp("Refreshing cached active record file: $fname");
			}
		}
		$activetab = new ADODB_Active_Table();
		$activetab->name = $table;
		
		
		$cols = $db->MetaColumns($table);
		if (!$cols) {
			$this->Error("Invalid table name: $table",'UpdateActiveTable'); 
			return false;
		}
		$fld = reset($cols);
		if (!$pkeys) {
			if (isset($fld->primary_key)) {
				$pkeys = array();
				foreach($cols as $name => $fld) {
					if (!empty($fld->primary_key)) $pkeys[] = $name;
				}
			} else	
				$pkeys = $this->GetPrimaryKeys($db, $table);
		}
		if (empty($pkeys)) {
			$this->Error("No primary key found for table $table",'UpdateActiveTable');
			return false;
		}
		
		$attr = array();
		$keys = array();
		
		switch($ADODB_ASSOC_CASE) {
		case 0:
			foreach($cols as $name => $fldobj) {
				$name = strtolower($name);
                if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
                    $this->$name = $fldobj->default_value;
                else
					$this->$name = null;
				$attr[$name] = $fldobj;
			}
			foreach($pkeys as $k => $name) {
				$keys[strtolower($name)] = strtolower($name);
			}
			break;
			
		case 1: 
			foreach($cols as $name => $fldobj) {
				$name = strtoupper($name);
               
                if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
                    $this->$name = $fldobj->default_value;
                else
					$this->$name = null;
				$attr[$name] = $fldobj;
			}
			
			foreach($pkeys as $k => $name) {
				$keys[strtoupper($name)] = strtoupper($name);
			}
			break;
		default:
			foreach($cols as $name => $fldobj) {
				$name = ($fldobj->name);
                
                if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
                    $this->$name = $fldobj->default_value;
                else
					$this->$name = null;
				$attr[$name] = $fldobj;
			}
			foreach($pkeys as $k => $name) {
				$keys[$name] = $cols[$name]->name;
			}
			break;
		}
		
		$activetab->keys = $keys;
		$activetab->flds = $attr;

		if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
			$activetab->_created = time();
			$s = serialize($activetab);
			if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
			adodb_write_file($fname,$s);
		}
		$activedb->tables[$table] = $activetab;
	}
	
	function GetPrimaryKeys(&$db, $table)
	{
		return $db->MetaPrimaryKeys($table);
	}
	
	// error handler for both PHP4+5. 
	function Error($err,$fn)
	{
	global $_ADODB_ACTIVE_DBS;
	
		$fn = get_class($this).'::'.$fn;
		$this->_lasterr = $fn.': '.$err;
		
		if ($this->_dbat < 0) $db = false;
		else {
			$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
			$db =& $activedb->db;
		}
		
		if (function_exists('adodb_throw')) {	
			if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
			else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
		} else
			if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
		
	}
	
	// return last error message
	function ErrorMsg()
	{
		if (!function_exists('adodb_throw')) {
			if ($this->_dbat < 0) $db = false;
			else $db = $this->DB();
		
			// last error could be database error too
			if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
		}
		return $this->_lasterr;
	}
	
	function ErrorNo() 
	{
		if ($this->_dbat < 0) return -9999; // no database connection...
		$db = $this->DB();
		
		return (int) $db->ErrorNo();
	}


	// retrieve ADOConnection from _ADODB_Active_DBs
	function &DB()
	{
	global $_ADODB_ACTIVE_DBS;
	
		if ($this->_dbat < 0) {
			$false = false;
			$this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
			return $false;
		}
		$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
		$db =& $activedb->db;
		return $db;
	}
	
	// retrieve ADODB_Active_Table
	function &TableInfo()
	{
	global $_ADODB_ACTIVE_DBS;
	
		$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
		$table =& $activedb->tables[$this->_tableat];
		return $table;
	}
	
	// I have an ON INSERT trigger on a table that sets other columns in the table.
	// So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
	function Reload()
	{
		$db =& $this->DB(); if (!$db) return false;
		$table =& $this->TableInfo();
		$where = $this->GenWhere($db, $table);
		return($this->Load($where));
	}
	
	// set a numeric array (using natural table field ordering) as object properties
	function Set(&$row)
	{
	global $ACTIVE_RECORD_SAFETY;
	
		$db =& $this->DB();
		
		if (!$row) {
			$this->_saved = false;		
			return false;
		}
		
		$this->_saved = true;
		
		$table =& $this->TableInfo();
		if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) {
            $bad_size = TRUE;
            if (sizeof($row) == 2 * sizeof($table->flds)) {
                // Only keep string keys
                $keys = array_filter(array_keys($row), 'is_string');
                if (sizeof($keys) == sizeof($table->flds))
                    $bad_size = FALSE;
            }
            if ($bad_size) {
				$this->Error("Table structure of $this->_table has changed","Load");
				return false;
			}
		}
        else
			$keys = array_keys($row);
      
        reset($keys);
        $this->_original = array();
		foreach($table->flds as $name=>$fld) {
            $value = $row[current($keys)];
			$this->$name = $value;
            $this->_original[] = $value;
            next($keys);
		}
        # </AP>
		return true;
	}
	
	// get last inserted id for INSERT
	function LastInsertID(&$db,$fieldname)
	{
		if ($db->hasInsertID)
			$val = $db->Insert_ID($this->_table,$fieldname);
		else
			$val = false;
			
		if (is_null($val) || $val === false) {
			// this might not work reliably in multi-user environment
			return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
		}
		return $val;
	}
	
	// quote data in where clause
	function doquote(&$db, $val,$t)
	{
		switch($t) {
		case 'D':
		case 'T':
			if (empty($val)) return 'null';
			
		case 'B':
		case 'N':
		case 'C':
		case 'X':
			if (is_null($val)) return 'null';
			
			if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") { 
				return $db->qstr($val);
				break;
			}
		default:
			return $val;
			break;
		}
	}
	
	// generate where clause for an UPDATE/SELECT
	function GenWhere(&$db, &$table)
	{
		$keys = $table->keys;
		$parr = array();
		
		foreach($keys as $k) {
			$f = $table->flds[$k];
			if ($f) {
				$parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
			}
		}
		return implode(' and ', $parr);
	}
	
	
	//------------------------------------------------------------ Public functions below
	
	function Load($where,$bindarr=false)
	{
		$db =& $this->DB(); if (!$db) return false;
		$this->_where = $where;
		
		$save = $db->SetFetchMode(ADODB_FETCH_NUM);
		$row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
		$db->SetFetchMode($save);
		
		return $this->Set($row);
	}
	
	// false on error
	function Save()
	{
		if ($this->_saved) $ok = $this->Update();
		else $ok = $this->Insert();
		
		return $ok;
	}
	
	// false on error
	function Insert()
	{
		$db =& $this->DB(); if (!$db) return false;
		$cnt = 0;
		$table =& $this->TableInfo();
		
		$valarr = array();
		$names = array();
		$valstr = array();

		foreach($table->flds as $name=>$fld) {
			$val = $this->$name;
			if(!is_null($val) || !array_key_exists($name, $table->keys)) {
				$valarr[] = $val;
				$names[] = $name;
				$valstr[] = $db->Param($cnt);
				$cnt += 1;
			}
		}
		
		if (empty($names)){
			foreach($table->flds as $name=>$fld) {
				$valarr[] = null;
				$names[] = $name;
				$valstr[] = $db->Param($cnt);
				$cnt += 1;
			}
		}
		$sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
		$ok = $db->Execute($sql,$valarr);
		
		if ($ok) {
			$this->_saved = true;
			$autoinc = false;
			foreach($table->keys as $k) {
				if (is_null($this->$k)) {
					$autoinc = true;
					break;
				}
			}
			if ($autoinc && sizeof($table->keys) == 1) {
				$k = reset($table->keys);
				$this->$k = $this->LastInsertID($db,$k);
			}
		}
		
		$this->_original = $valarr;
		return !empty($ok);
	}
	
	function Delete()
	{
		$db =& $this->DB(); if (!$db) return false;
		$table =& $this->TableInfo();
		
		$where = $this->GenWhere($db,$table);
		$sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
		$ok = $db->Execute($sql);
		
		return $ok ? true : false;
	}
	
	// returns an array of active record objects
	function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false)
	{
		$db =& $this->DB(); if (!$db || empty($this->_table)) return false;
		$arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr);
		return $arr;
	}
	
	// returns 0 on error, 1 on update, 2 on insert
	function Replace()
	{
	global $ADODB_ASSOC_CASE;
		
		$db =& $this->DB(); if (!$db) return false;
		$table =& $this->TableInfo();
		
		$pkey = $table->keys;
		
		foreach($table->flds as $name=>$fld) {
			$val = $this->$name;
			/*
			if (is_null($val)) {
				if (isset($fld->not_null) && $fld->not_null) {
					if (isset($fld->default_value) && strlen($fld->default_value)) continue;
					else {
						$this->Error("Cannot update null into $name","Replace");
						return false;
					}
				}
			}*/
			if (is_null($val) && !empty($fld->auto_increment)) {
            	continue;
            }
			$t = $db->MetaType($fld->type);
			$arr[$name] = $this->doquote($db,$val,$t);
			$valarr[] = $val;
		}
		
		if (!is_array($pkey)) $pkey = array($pkey);
		
		
		if ($ADODB_ASSOC_CASE == 0) 
			foreach($pkey as $k => $v)
				$pkey[$k] = strtolower($v);
		elseif ($ADODB_ASSOC_CASE == 1) 
			foreach($pkey as $k => $v)
				$pkey[$k] = strtoupper($v);
				
		$ok = $db->Replace($this->_table,$arr,$pkey);
		if ($ok) {
			$this->_saved = true; // 1= update 2=insert
			if ($ok == 2) {
				$autoinc = false;
				foreach($table->keys as $k) {
					if (is_null($this->$k)) {
						$autoinc = true;
						break;
					}
				}
				if ($autoinc && sizeof($table->keys) == 1) {
					$k = reset($table->keys);
					$this->$k = $this->LastInsertID($db,$k);
				}
			}
			
			$this->_original =& $valarr;
		} 
		return $ok;
	}

	// returns 0 on error, 1 on update, -1 if no change in data (no update)
	function Update()
	{
		$db =& $this->DB(); if (!$db) return false;
		$table =& $this->TableInfo();
		
		$where = $this->GenWhere($db, $table);
		
		if (!$where) {
			$this->error("Where missing for table $table", "Update");
			return false;
		}
		$valarr = array(); 
		$neworig = array();
		$pairs = array();
		$i = -1;
		$cnt = 0;
		foreach($table->flds as $name=>$fld) {
			$i += 1;
			$val = $this->$name;
			$neworig[] = $val;
			
			if (isset($table->keys[$name])) {
				continue;
			}
			
			if (is_null($val)) {
				if (isset($fld->not_null) && $fld->not_null) {
					if (isset($fld->default_value) && strlen($fld->default_value)) continue;
					else {
						$this->Error("Cannot set field $name to NULL","Update");
						return false;
					}
				}
			}
			
			if (isset($this->_original[$i]) && $val == $this->_original[$i]) {
				continue;
			}			
			$valarr[] = $val;
			$pairs[] = $name.'='.$db->Param($cnt);
			$cnt += 1;
		}
		
		
		if (!$cnt) return -1;
		$sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
		$ok = $db->Execute($sql,$valarr);
		if ($ok) {
			$this->_original =& $neworig;
			return 1;
		}
		return 0;
	}
	
	function GetAttributeNames()
	{
		$table =& $this->TableInfo();
		if (!$table) return false;
		return array_keys($table->flds);
	}
	
};

?>

Added program_files/include/adodb4/adodb-csvlib.inc.php.





























































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
<?php

// security - hide paths
if (!defined('ADODB_DIR')) die();

global $ADODB_INCLUDED_CSV;
$ADODB_INCLUDED_CSV = 1;

/* 

  v4.992 10 Nov 2009  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  Released under both BSD license and Lesser GPL library license. 
  Whenever there is any discrepancy between the two licenses, 
  the BSD license will take precedence. See License.txt. 
  Set tabs to 4 for best viewing.
  
  Latest version is available at http://adodb.sourceforge.net
  
  Library for CSV serialization. This is used by the csv/proxy driver and is the 
  CacheExecute() serialization format. 
  
  ==== NOTE ====
  Format documented at http://php.weblogs.com/ADODB_CSV
  ==============
*/

	/**
 	 * convert a recordset into special format
	 *
	 * @param rs	the recordset
	 *
	 * @return	the CSV formated data
	 */
	function _rs2serialize(&$rs,$conn=false,$sql='')
	{
		$max = ($rs) ? $rs->FieldCount() : 0;
		
		if ($sql) $sql = urlencode($sql);
		// metadata setup
		
		if ($max <= 0 || $rs->dataProvider == 'empty') { // is insert/update/delete
			if (is_object($conn)) {
				$sql .= ','.$conn->Affected_Rows();
				$sql .= ','.$conn->Insert_ID();
			} else
				$sql .= ',,';
			
			$text = "====-1,0,$sql\n";
			return $text;
		}
		$tt = ($rs->timeCreated) ? $rs->timeCreated : time();
		
		## changed format from ====0 to ====1
		$line = "====1,$tt,$sql\n";
		
		if ($rs->databaseType == 'array') {
			$rows =& $rs->_array;
		} else {
			$rows = array();
			while (!$rs->EOF) {	
				$rows[] = $rs->fields;
				$rs->MoveNext();
			} 
		}
		
		for($i=0; $i < $max; $i++) {
			$o =& $rs->FetchField($i);
			$flds[] = $o;
		}
	
		$savefetch = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
		$class = $rs->connection->arrayClass;
		$rs2 = new $class();
		$rs2->timeCreated = $rs->timeCreated; # memcache fix
		$rs2->sql = $rs->sql;
		$rs2->oldProvider = $rs->dataProvider; 
		$rs2->InitArrayFields($rows,$flds);
		$rs2->fetchMode = $savefetch;
		return $line.serialize($rs2);
	}

	
/**
* Open CSV file and convert it into Data. 
*
* @param url  		file/ftp/http url
* @param err		returns the error message
* @param timeout	dispose if recordset has been alive for $timeout secs
*
* @return		recordset, or false if error occured. If no
*			error occurred in sql INSERT/UPDATE/DELETE, 
*			empty recordset is returned
*/
	function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
	{
		$false = false;
		$err = false;
		$fp = @fopen($url,'rb');
		if (!$fp) {
			$err = $url.' file/URL not found';
			return $false;
		}
		@flock($fp, LOCK_SH);
		$arr = array();
		$ttl = 0;
		
		if ($meta = fgetcsv($fp, 32000, ",")) {
			// check if error message
			if (strncmp($meta[0],'****',4) === 0) {
				$err = trim(substr($meta[0],4,1024));
				fclose($fp);
				return $false;
			}
			// check for meta data
			// $meta[0] is -1 means return an empty recordset
			// $meta[1] contains a time 
	
			if (strncmp($meta[0], '====',4) === 0) {
			
				if ($meta[0] == "====-1") {
					if (sizeof($meta) < 5) {
						$err = "Corrupt first line for format -1";
						fclose($fp);
						return $false;
					}
					fclose($fp);
					
					if ($timeout > 0) {
						$err = " Illegal Timeout $timeout ";
						return $false;
					}
					
					$rs = new $rsclass($val=true);
					$rs->fields = array();
					$rs->timeCreated = $meta[1];
					$rs->EOF = true;
					$rs->_numOfFields = 0;
					$rs->sql = urldecode($meta[2]);
					$rs->affectedrows = (integer)$meta[3];
					$rs->insertid = $meta[4];	
					return $rs;
				} 
			# Under high volume loads, we want only 1 thread/process to _write_file
			# so that we don't have 50 processes queueing to write the same data.
			# We use probabilistic timeout, ahead of time.
			#
			# -4 sec before timeout, give processes 1/32 chance of timing out
			# -2 sec before timeout, give processes 1/16 chance of timing out
			# -1 sec after timeout give processes 1/4 chance of timing out
			# +0 sec after timeout, give processes 100% chance of timing out
				if (sizeof($meta) > 1) {
					if($timeout >0){ 
						$tdiff = (integer)( $meta[1]+$timeout - time());
						if ($tdiff <= 2) {
							switch($tdiff) {
							case 4:
							case 3:
								if ((rand() & 31) == 0) {
									fclose($fp);
									$err = "Timeout 3";
									return $false;
								}
								break;
							case 2: 
								if ((rand() & 15) == 0) {
									fclose($fp);
									$err = "Timeout 2";
									return $false;
								}
								break;
							case 1:
								if ((rand() & 3) == 0) {
									fclose($fp);
									$err = "Timeout 1";
									return $false;
								}
								break;
							default: 
								fclose($fp);
								$err = "Timeout 0";
								return $false;
							} // switch
							
						} // if check flush cache
					}// (timeout>0)
					$ttl = $meta[1];
				}
				//================================================
				// new cache format - use serialize extensively...
				if ($meta[0] === '====1') {
					// slurp in the data
					$MAXSIZE = 128000;
					
					$text = fread($fp,$MAXSIZE);
					if (strlen($text)) {
						while ($txt = fread($fp,$MAXSIZE)) {
							$text .= $txt;
						}
					}
					fclose($fp);
					$rs = unserialize($text);
					if (is_object($rs)) $rs->timeCreated = $ttl;
					else {
						$err = "Unable to unserialize recordset";
						//echo htmlspecialchars($text),' !--END--!<p>';
					}
					return $rs;
				}
				
				$meta = false;
				$meta = fgetcsv($fp, 32000, ",");
				if (!$meta) {
					fclose($fp);
					$err = "Unexpected EOF 1";
					return $false;
				}
			}

			// Get Column definitions
			$flds = array();
			foreach($meta as $o) {
				$o2 = explode(':',$o);
				if (sizeof($o2)!=3) {
					$arr[] = $meta;
					$flds = false;
					break;
				}
				$fld = new ADOFieldObject();
				$fld->name = urldecode($o2[0]);
				$fld->type = $o2[1];
				$fld->max_length = $o2[2];
				$flds[] = $fld;
			}
		} else {
			fclose($fp);
			$err = "Recordset had unexpected EOF 2";
			return $false;
		}
		
		// slurp in the data
		$MAXSIZE = 128000;
		
		$text = '';
		while ($txt = fread($fp,$MAXSIZE)) {
			$text .= $txt;
		}
			
		fclose($fp);
		@$arr = unserialize($text);
		//var_dump($arr);
		if (!is_array($arr)) {
			$err = "Recordset had unexpected EOF (in serialized recordset)";
			if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!";
			return $false;
		}
		$rs = new $rsclass();
		$rs->timeCreated = $ttl;
		$rs->InitArrayFields($arr,$flds);
		return $rs;
	}
	

	/**
	* Save a file $filename and its $contents (normally for caching) with file locking
	* Returns true if ok, false if fopen/fwrite error, 0 if rename error (eg. file is locked)
	*/
	function adodb_write_file($filename, $contents,$debug=false)
	{
	# http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
	# So to simulate locking, we assume that rename is an atomic operation.
	# First we delete $filename, then we create a $tempfile write to it and 
	# rename to the desired $filename. If the rename works, then we successfully 
	# modified the file exclusively.
	# What a stupid need - having to simulate locking.
	# Risks:
	# 1. $tempfile name is not unique -- very very low
	# 2. unlink($filename) fails -- ok, rename will fail
	# 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs
	# 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and  cache updated
		if (strncmp(PHP_OS,'WIN',3) === 0) {
			// skip the decimal place
			$mtime = substr(str_replace(' ','_',microtime()),2); 
			// getmypid() actually returns 0 on Win98 - never mind!
			$tmpname = $filename.uniqid($mtime).getmypid();
			if (!($fd = @fopen($tmpname,'w'))) return false;
			if (fwrite($fd,$contents)) $ok = true;
			else $ok = false;
			fclose($fd);

			if ($ok) {
				@chmod($tmpname,0644);
				// the tricky moment
				@unlink($filename);
				if (!@rename($tmpname,$filename)) {
					unlink($tmpname);
					$ok = 0;
				}
				if (!$ok) {
					if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
				}
			}
			return $ok;
		}
		if (!($fd = @fopen($filename, 'a'))) return false;
		if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
			if (fwrite( $fd, $contents )) $ok = true;
			else $ok = false;
			fclose($fd);
			@chmod($filename,0644);
		}else {
			fclose($fd);
			if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");
			$ok = false;
		}
	
		return $ok;
	}
?>

Added program_files/include/adodb4/adodb-datadict.inc.php.

















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?php

/**
  v4.992 10 Nov 2009  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  Released under both BSD license and Lesser GPL library license. 
  Whenever there is any discrepancy between the two licenses, 
  the BSD license will take precedence.
	
  Set tabs to 4 for best viewing.
 
 	DOCUMENTATION:
	
		See adodb/tests/test-datadict.php for docs and examples.
*/

/*
	Test script for parser
*/

// security - hide paths
if (!defined('ADODB_DIR')) die();

function Lens_ParseTest()
{
$str = "`zcol ACOL` NUMBER(32,2) DEFAULT 'The \"cow\" (and Jim''s dog) jumps over the moon' PRIMARY, INTI INT AUTO DEFAULT 0, zcol2\"afs ds";
print "<p>$str</p>";
$a= Lens_ParseArgs($str);
print "<pre>";
print_r($a);
print "</pre>";
}


if (!function_exists('ctype_alnum')) {
	function ctype_alnum($text) {
		return preg_match('/^[a-z0-9]*$/i', $text);
	}
}

//Lens_ParseTest();

/**
	Parse arguments, treat "text" (text) and 'text' as quotation marks.
	To escape, use "" or '' or ))
	
	Will read in "abc def" sans quotes, as: abc def
	Same with 'abc def'.
	However if `abc def`, then will read in as `abc def`
	
	@param endstmtchar    Character that indicates end of statement
	@param tokenchars     Include the following characters in tokens apart from A-Z and 0-9 
	@returns 2 dimensional array containing parsed tokens.
*/
function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
{
	$pos = 0;
	$intoken = false;
	$stmtno = 0;
	$endquote = false;
	$tokens = array();
	$tokens[$stmtno] = array();
	$max = strlen($args);
	$quoted = false;
	$tokarr = array();
	
	while ($pos < $max) {
		$ch = substr($args,$pos,1);
		switch($ch) {
		case ' ':
		case "\t":
		case "\n":
		case "\r":
			if (!$quoted) {
				if ($intoken) {
					$intoken = false;
					$tokens[$stmtno][] = implode('',$tokarr);
				}
				break;
			}
			
			$tokarr[] = $ch;
			break;
		
		case '`':
			if ($intoken) $tokarr[] = $ch;
		case '(':
		case ')':	
		case '"':
		case "'":
			
			if ($intoken) {
				if (empty($endquote)) {
					$tokens[$stmtno][] = implode('',$tokarr);
					if ($ch == '(') $endquote = ')';
					else $endquote = $ch;
					$quoted = true;
					$intoken = true;
					$tokarr = array();
				} else if ($endquote == $ch) {
					$ch2 = substr($args,$pos+1,1);
					if ($ch2 == $endquote) {
						$pos += 1;
						$tokarr[] = $ch2;
					} else {
						$quoted = false;
						$intoken = false;
						$tokens[$stmtno][] = implode('',$tokarr);
						$endquote = '';
					}
				} else
					$tokarr[] = $ch;
					
			}else {
			
				if ($ch == '(') $endquote = ')';
				else $endquote = $ch;
				$quoted = true;
				$intoken = true;
				$tokarr = array();
				if ($ch == '`') $tokarr[] = '`';
			}
			break;
			
		default:
			
			if (!$intoken) {
				if ($ch == $endstmtchar) {
					$stmtno += 1;
					$tokens[$stmtno] = array();
					break;
				}
			
				$intoken = true;
				$quoted = false;
				$endquote = false;
				$tokarr = array();
	
			}
			
			if ($quoted) $tokarr[] = $ch;
			else if (ctype_alnum($ch) || strpos($tokenchars,$ch) !== false) $tokarr[] = $ch;
			else {
				if ($ch == $endstmtchar) {			
					$tokens[$stmtno][] = implode('',$tokarr);
					$stmtno += 1;
					$tokens[$stmtno] = array();
					$intoken = false;
					$tokarr = array();
					break;
				}
				$tokens[$stmtno][] = implode('',$tokarr);
				$tokens[$stmtno][] = $ch;
				$intoken = false;
			}
		}
		$pos += 1;
	}
	if ($intoken) $tokens[$stmtno][] = implode('',$tokarr);
	
	return $tokens;
}


class ADODB_DataDict {
	var $connection;
	var $debug = false;
	var $dropTable = 'DROP TABLE %s';
	var $renameTable = 'RENAME TABLE %s TO %s'; 
	var $dropIndex = 'DROP INDEX %s';
	var $addCol = ' ADD';
	var $alterCol = ' ALTER COLUMN';
	var $dropCol = ' DROP COLUMN';
	var $renameColumn = 'ALTER TABLE %s RENAME COLUMN %s TO %s';	// table, old-column, new-column, column-definitions (not used by default)
	var $nameRegex = '\w';
	var $nameRegexBrackets = 'a-zA-Z0-9_\(\)';
	var $schema = false;
	var $serverInfo = array();
	var $autoIncrement = false;
	var $dataProvider;
	var $invalidResizeTypes4 = array('CLOB','BLOB','TEXT','DATE','TIME'); // for changetablesql
	var $blobSize = 100; 	/// any varchar/char field this size or greater is treated as a blob
							/// in other words, we use a text area for editting.
	
	function GetCommentSQL($table,$col)
	{
		return false;
	}
	
	function SetCommentSQL($table,$col,$cmt)
	{
		return false;
	}
	
	function MetaTables()
	{
		if (!$this->connection->IsConnected()) return array();
		return $this->connection->MetaTables();
	}
	
	function MetaColumns($tab, $upper=true, $schema=false)
	{
		if (!$this->connection->IsConnected()) return array();
		return $this->connection->MetaColumns($this->TableName($tab), $upper, $schema);
	}
	
	function MetaPrimaryKeys($tab,$owner=false,$intkey=false)
	{
		if (!$this->connection->IsConnected()) return array();
		return $this->connection->MetaPrimaryKeys($this->TableName($tab), $owner, $intkey);
	}
	
	function MetaIndexes($table, $primary = false, $owner = false)
	{
		if (!$this->connection->IsConnected()) return array();
		return $this->connection->MetaIndexes($this->TableName($table), $primary, $owner);
	}
	

	function MetaType($t,$len=-1,$fieldobj=false)
	{		
		static $typeMap = array(
		'VARCHAR' => 'C',
		'VARCHAR2' => 'C',
		'CHAR' => 'C',
		'C' => 'C',
		'STRING' => 'C',
		'NCHAR' => 'C',
		'NVARCHAR' => 'C',
		'VARYING' => 'C',
		'BPCHAR' => 'C',
		'CHARACTER' => 'C',
		'INTERVAL' => 'C',  # Postgres
		'MACADDR' => 'C', # postgres
		##
		'LONGCHAR' => 'X',
		'TEXT' => 'X',
		'NTEXT' => 'X',
		'M' => 'X',
		'X' => 'X',
		'CLOB' => 'X',
		'NCLOB' => 'X',
		'LVARCHAR' => 'X',
		##
		'BLOB' => 'B',
		'IMAGE' => 'B',
		'BINARY' => 'B',
		'VARBINARY' => 'B',
		'LONGBINARY' => 'B',
		'B' => 'B',
		##
		'YEAR' => 'D', // mysql
		'DATE' => 'D',
		'D' => 'D',
		##
		'UNIQUEIDENTIFIER' => 'C', # MS SQL Server
		##
		'TIME' => 'T',
		'TIMESTAMP' => 'T',
		'DATETIME' => 'T',
		'TIMESTAMPTZ' => 'T',
		'T' => 'T',
		'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
		##
		'BOOL' => 'L',
		'BOOLEAN' => 'L', 
		'BIT' => 'L',
		'L' => 'L',
		##
		'COUNTER' => 'R',
		'R' => 'R',
		'SERIAL' => 'R', // ifx
		'INT IDENTITY' => 'R',
		##
		'INT' => 'I',
		'INT2' => 'I',
		'INT4' => 'I',
		'INT8' => 'I',
		'INTEGER' => 'I',
		'INTEGER UNSIGNED' => 'I',
		'SHORT' => 'I',
		'TINYINT' => 'I',
		'SMALLINT' => 'I',
		'I' => 'I',
		##
		'LONG' => 'N', // interbase is numeric, oci8 is blob
		'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
		'DECIMAL' => 'N',
		'DEC' => 'N',
		'REAL' => 'N',
		'DOUBLE' => 'N',
		'DOUBLE PRECISION' => 'N',
		'SMALLFLOAT' => 'N',
		'FLOAT' => 'N',
		'NUMBER' => 'N',
		'NUM' => 'N',
		'NUMERIC' => 'N',
		'MONEY' => 'N',
		
		## informix 9.2
		'SQLINT' => 'I', 
		'SQLSERIAL' => 'I', 
		'SQLSMINT' => 'I', 
		'SQLSMFLOAT' => 'N', 
		'SQLFLOAT' => 'N', 
		'SQLMONEY' => 'N', 
		'SQLDECIMAL' => 'N', 
		'SQLDATE' => 'D', 
		'SQLVCHAR' => 'C', 
		'SQLCHAR' => 'C', 
		'SQLDTIME' => 'T', 
		'SQLINTERVAL' => 'N', 
		'SQLBYTES' => 'B', 
		'SQLTEXT' => 'X',
		 ## informix 10
		"SQLINT8" => 'I8',
		"SQLSERIAL8" => 'I8',
		"SQLNCHAR" => 'C',
		"SQLNVCHAR" => 'C',
		"SQLLVARCHAR" => 'X',
		"SQLBOOL" => 'L'
		);
		
		if (!$this->connection->IsConnected()) {
			$t = strtoupper($t);
			if (isset($typeMap[$t])) return $typeMap[$t];
			return 'N';
		}
		return $this->connection->MetaType($t,$len,$fieldobj);
	}
	
	function NameQuote($name = NULL,$allowBrackets=false)
	{
		if (!is_string($name)) {
			return FALSE;
		}
		
		$name = trim($name);
		
		if ( !is_object($this->connection) ) {
			return $name;
		}
		
		$quote = $this->connection->nameQuote;
		
		// if name is of the form `name`, quote it
		if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
			return $quote . $matches[1] . $quote;
		}
		
		// if name contains special characters, quote it
		$regex = ($allowBrackets) ? $this->nameRegexBrackets : $this->nameRegex;
		
		if ( !preg_match('/^[' . $regex . ']+$/', $name) ) {
			return $quote . $name . $quote;
		}
		
		return $name;
	}
	
	function TableName($name)
	{
		if ( $this->schema ) {
			return $this->NameQuote($this->schema) .'.'. $this->NameQuote($name);
		}
		return $this->NameQuote($name);
	}
	
	// Executes the sql array returned by GetTableSQL and GetIndexSQL
	function ExecuteSQLArray($sql, $continueOnError = true)
	{
		$rez = 2;
		$conn = &$this->connection;
		$saved = $conn->debug;
		foreach($sql as $line) {
			
			if ($this->debug) $conn->debug = true;
			$ok = $conn->Execute($line);
			$conn->debug = $saved;
			if (!$ok) {
				if ($this->debug) ADOConnection::outp($conn->ErrorMsg());
				if (!$continueOnError) return 0;
				$rez = 1;
			}
		}
		return $rez;
	}
	
	/**
	 	Returns the actual type given a character code.
		
		C:  varchar
		X:  CLOB (character large object) or largest varchar size if CLOB is not supported
		C2: Multibyte varchar
		X2: Multibyte CLOB
		
		B:  BLOB (binary large object)
		
		D:  Date
		T:  Date-time 
		L:  Integer field suitable for storing booleans (0 or 1)
		I:  Integer
		F:  Floating point number
		N:  Numeric or decimal number
	*/
	
	function ActualType($meta)
	{
		return $meta;
	}
	
	function CreateDatabase($dbname,$options=false)
	{
		$options = $this->_Options($options);
		$sql = array();
		
		$s = 'CREATE DATABASE ' . $this->NameQuote($dbname);
		if (isset($options[$this->upperName]))
			$s .= ' '.$options[$this->upperName];
		
		$sql[] = $s;
		return $sql;
	}
	
	/*
	 Generates the SQL to create index. Returns an array of sql strings.
	*/
	function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)
	{
		if (!is_array($flds)) {
			$flds = explode(',',$flds);
		}
		
		foreach($flds as $key => $fld) {
			# some indexes can use partial fields, eg. index first 32 chars of "name" with NAME(32)
			$flds[$key] = $this->NameQuote($fld,$allowBrackets=true);
		}
		
		return $this->_IndexSQL($this->NameQuote($idxname), $this->TableName($tabname), $flds, $this->_Options($idxoptions));
	}
	
	function DropIndexSQL ($idxname, $tabname = NULL)
	{
		return array(sprintf($this->dropIndex, $this->NameQuote($idxname), $this->TableName($tabname)));
	}
	
	function SetSchema($schema)
	{
		$this->schema = $schema;
	}
	
	function AddColumnSQL($tabname, $flds)
	{
		$tabname = $this->TableName ($tabname);
		$sql = array();
		list($lines,$pkey,$idxs) = $this->_GenFields($flds);
		// genfields can return FALSE at times
		if ($lines  == null) $lines = array();
		$alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
		foreach($lines as $v) {
			$sql[] = $alter . $v;
		}
		if (is_array($idxs)) {
			foreach($idxs as $idx => $idxdef) {
				$sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
				$sql = array_merge($sql, $sql_idxs);
			}
		}
		return $sql;
	}
	
	/**
	 * Change the definition of one column
	 *
	 * As some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
	 * to allow, recreating the table and copying the content over to the new table
	 * @param string $tabname table-name
	 * @param string $flds column-name and type for the changed column
	 * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
	 * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
	 * @return array with SQL strings
	 */
	function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
	{
		$tabname = $this->TableName ($tabname);
		$sql = array();
		list($lines,$pkey,$idxs) = $this->_GenFields($flds);
		// genfields can return FALSE at times
		if ($lines == null) $lines = array();
		$alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
		foreach($lines as $v) {
			$sql[] = $alter . $v;
		}
		if (is_array($idxs)) {
			foreach($idxs as $idx => $idxdef) {
				$sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
				$sql = array_merge($sql, $sql_idxs);
			}

		}
		return $sql;
	}
	
	/**
	 * Rename one column
	 *
	 * Some DBM's can only do this together with changeing the type of the column (even if that stays the same, eg. mysql)
	 * @param string $tabname table-name
	 * @param string $oldcolumn column-name to be renamed
	 * @param string $newcolumn new column-name
	 * @param string $flds='' complete column-defintion-string like for AddColumnSQL, only used by mysql atm., default=''
	 * @return array with SQL strings
	 */
	function RenameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='')
	{
		$tabname = $this->TableName ($tabname);
		if ($flds) {
			list($lines,$pkey,$idxs) = $this->_GenFields($flds);
			// genfields can return FALSE at times
			if ($lines == null) $lines = array();
			list(,$first) = each($lines);
			list(,$column_def) = split("[\t ]+",$first,2);
		}
		return array(sprintf($this->renameColumn,$tabname,$this->NameQuote($oldcolumn),$this->NameQuote($newcolumn),$column_def));
	}
		
	/**
	 * Drop one column
	 *
	 * Some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
	 * to allow, recreating the table and copying the content over to the new table
	 * @param string $tabname table-name
	 * @param string $flds column-name and type for the changed column
	 * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
	 * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
	 * @return array with SQL strings
	 */
	function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
	{
		$tabname = $this->TableName ($tabname);
		if (!is_array($flds)) $flds = explode(',',$flds);
		$sql = array();
		$alter = 'ALTER TABLE ' . $tabname . $this->dropCol . ' ';
		foreach($flds as $v) {
			$sql[] = $alter . $this->NameQuote($v);
		}
		return $sql;
	}
	
	function DropTableSQL($tabname)
	{
		return array (sprintf($this->dropTable, $this->TableName($tabname)));
	}
	
	function RenameTableSQL($tabname,$newname)
	{
		return array (sprintf($this->renameTable, $this->TableName($tabname),$this->TableName($newname)));
	}	
	
	/**
	 Generate the SQL to create table. Returns an array of sql strings.
	*/
	function CreateTableSQL($tabname, $flds, $tableoptions=array())
	{
		list($lines,$pkey,$idxs) = $this->_GenFields($flds, true);
		// genfields can return FALSE at times
		if ($lines == null) $lines = array();
		
		$taboptions = $this->_Options($tableoptions);
		$tabname = $this->TableName ($tabname);
		$sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
		
		// ggiunta - 2006/10/12 - KLUDGE:
        // if we are on autoincrement, and table options includes REPLACE, the
        // autoincrement sequence has already been dropped on table creation sql, so
        // we avoid passing REPLACE to trigger creation code. This prevents
        // creating sql that double-drops the sequence
        if ($this->autoIncrement && isset($taboptions['REPLACE']))
        	unset($taboptions['REPLACE']);
		$tsql = $this->_Triggers($tabname,$taboptions);
		foreach($tsql as $s) $sql[] = $s;
		
		if (is_array($idxs)) {
			foreach($idxs as $idx => $idxdef) {
				$sql_idxs = $this->CreateIndexSql($idx, $tabname,  $idxdef['cols'], $idxdef['opts']);
				$sql = array_merge($sql, $sql_idxs);
			}
		}

		return $sql;
	}
	
	function _GenFields($flds,$widespacing=false)
	{
		if (is_string($flds)) {
			$padding = '     ';
			$txt = $flds.$padding;
			$flds = array();
			$flds0 = Lens_ParseArgs($txt,',');
			$hasparam = false;
			foreach($flds0 as $f0) {
				$f1 = array();
				foreach($f0 as $token) {
					switch (strtoupper($token)) {
					case 'INDEX':
						$f1['INDEX'] = '';
						// fall through intentionally
					case 'CONSTRAINT':
					case 'DEFAULT': 
						$hasparam = $token;
						break;
					default:
						if ($hasparam) $f1[$hasparam] = $token;
						else $f1[] = $token;
						$hasparam = false;
						break;
					}
				}
				// 'index' token without a name means single column index: name it after column
				if (array_key_exists('INDEX', $f1) && $f1['INDEX'] == '') {
					$f1['INDEX'] = isset($f0['NAME']) ? $f0['NAME'] : $f0[0];
					// check if column name used to create an index name was quoted
					if (($f1['INDEX'][0] == '"' || $f1['INDEX'][0] == "'" || $f1['INDEX'][0] == "`") &&
						($f1['INDEX'][0] == substr($f1['INDEX'], -1))) {
						$f1['INDEX'] = $f1['INDEX'][0].'idx_'.substr($f1['INDEX'], 1, -1).$f1['INDEX'][0];
					}
					else
						$f1['INDEX'] = 'idx_'.$f1['INDEX'];
				}
				// reset it, so we don't get next field 1st token as INDEX...
				$hasparam = false;

				$flds[] = $f1;
				
			}
		}
		$this->autoIncrement = false;
		$lines = array();
		$pkey = array();
		$idxs = array();
		foreach($flds as $fld) {
			$fld = _array_change_key_case($fld);
			
			$fname = false;
			$fdefault = false;
			$fautoinc = false;
			$ftype = false;
			$fsize = false;
			$fprec = false;
			$fprimary = false;
			$fnoquote = false;
			$fdefts = false;
			$fdefdate = false;
			$fconstraint = false;
			$fnotnull = false;
			$funsigned = false;
			$findex = '';
			$funiqueindex = false;
			
			//-----------------
			// Parse attributes
			foreach($fld as $attr => $v) {
				if ($attr == 2 && is_numeric($v)) $attr = 'SIZE';
				else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v);
				
				switch($attr) {
				case '0':
				case 'NAME': 	$fname = $v; break;
				case '1':
				case 'TYPE': 	$ty = $v; $ftype = $this->ActualType(strtoupper($v)); break;
				
				case 'SIZE': 	
								$dotat = strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,',');
								if ($dotat === false) $fsize = $v;
								else {
									$fsize = substr($v,0,$dotat);
									$fprec = substr($v,$dotat+1);
								}
								break;
				case 'UNSIGNED': $funsigned = true; break;
				case 'AUTOINCREMENT':
				case 'AUTO':	$fautoinc = true; $fnotnull = true; break;
				case 'KEY':
                // a primary key col can be non unique in itself (if key spans many cols...)
				case 'PRIMARY':	$fprimary = $v; $fnotnull = true; /*$funiqueindex = true;*/ break;
				case 'DEF':
				case 'DEFAULT': $fdefault = $v; break;
				case 'NOTNULL': $fnotnull = $v; break;
				case 'NOQUOTE': $fnoquote = $v; break;
				case 'DEFDATE': $fdefdate = $v; break;
				case 'DEFTIMESTAMP': $fdefts = $v; break;
				case 'CONSTRAINT': $fconstraint = $v; break;
				// let INDEX keyword create a 'very standard' index on column
				case 'INDEX': $findex = $v; break;
				case 'UNIQUE': $funiqueindex = true; break;
				} //switch
			} // foreach $fld
			
			//--------------------
			// VALIDATE FIELD INFO
			if (!strlen($fname)) {
				if ($this->debug) ADOConnection::outp("Undefined NAME");
				return false;
			}
			
			$fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', $fname));
			$fname = $this->NameQuote($fname);
			
			if (!strlen($ftype)) {
				if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'");
				return false;
			} else {
				$ftype = strtoupper($ftype);
			}
			
			$ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
			
			if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull = false; // some blob types do not accept nulls
			
			if ($fprimary) $pkey[] = $fname;
			
			// some databases do not allow blobs to have defaults
			if ($ty == 'X') $fdefault = false;
			
			// build list of indexes
			if ($findex != '') {
				if (array_key_exists($findex, $idxs)) {
					$idxs[$findex]['cols'][] = ($fname);
					if (in_array('UNIQUE', $idxs[$findex]['opts']) != $funiqueindex) {
						if ($this->debug) ADOConnection::outp("Index $findex defined once UNIQUE and once not");
					}
					if ($funiqueindex && !in_array('UNIQUE', $idxs[$findex]['opts']))
						$idxs[$findex]['opts'][] = 'UNIQUE';
				}
				else
				{
					$idxs[$findex] = array();
					$idxs[$findex]['cols'] = array($fname);
					if ($funiqueindex)
						$idxs[$findex]['opts'] = array('UNIQUE');
					else
						$idxs[$findex]['opts'] = array();
				}
			}

			//--------------------
			// CONSTRUCT FIELD SQL
			if ($fdefts) {
				if (substr($this->connection->databaseType,0,5) == 'mysql') {
					$ftype = 'TIMESTAMP';
				} else {
					$fdefault = $this->connection->sysTimeStamp;
				}
			} else if ($fdefdate) {
				if (substr($this->connection->databaseType,0,5) == 'mysql') {
					$ftype = 'TIMESTAMP';
				} else {
					$fdefault = $this->connection->sysDate;
				}
			} else if ($fdefault !== false && !$fnoquote) {
				if ($ty == 'C' or $ty == 'X' or 
					( substr($fdefault,0,1) != "'" && !is_numeric($fdefault))) {

					if (($ty == 'D' || $ty == 'T') && strtolower($fdefault) != 'null') {
						// convert default date into database-aware code
						if ($ty == 'T')
						{
							$fdefault = $this->connection->DBTimeStamp($fdefault);
						}
						else
						{
							$fdefault = $this->connection->DBDate($fdefault);
						}
					}
					else
					if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ') 
						$fdefault = trim($fdefault);
					else if (strtolower($fdefault) != 'null')
						$fdefault = $this->connection->qstr($fdefault);
				}
			}
			$suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned);
			
			// add index creation
			if ($widespacing) $fname = str_pad($fname,24);
			
			 // check for field names appearing twice
            if (array_key_exists($fid, $lines)) {
            	 ADOConnection::outp("Field '$fname' defined twice");
            }
			
			$lines[$fid] = $fname.' '.$ftype.$suffix;
			
			if ($fautoinc) $this->autoIncrement = true;
		} // foreach $flds
		
		return array($lines,$pkey,$idxs);
	}

	/**
		 GENERATE THE SIZE PART OF THE DATATYPE
			$ftype is the actual type
			$ty is the type defined originally in the DDL
	*/
	function _GetSize($ftype, $ty, $fsize, $fprec)
	{
		if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) {
			$ftype .= "(".$fsize;
			if (strlen($fprec)) $ftype .= ",".$fprec;
			$ftype .= ')';
		}
		return $ftype;
	}
	
	
	// return string must begin with space
	function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
	{	
		$suffix = '';
		if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
		if ($fnotnull) $suffix .= ' NOT NULL';
		if ($fconstraint) $suffix .= ' '.$fconstraint;
		return $suffix;
	}
	
	function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
	{
		$sql = array();
		
		if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
			$sql[] = sprintf ($this->dropIndex, $idxname);
			if ( isset($idxoptions['DROP']) )
				return $sql;
		}
		
		if ( empty ($flds) ) {
			return $sql;
		}
		
		$unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
	
		$s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' ';
		
		if ( isset($idxoptions[$this->upperName]) )
			$s .= $idxoptions[$this->upperName];
		
		if ( is_array($flds) )
			$flds = implode(', ',$flds);
		$s .= '(' . $flds . ')';
		$sql[] = $s;
		
		return $sql;
	}
	
	function _DropAutoIncrement($tabname)
	{
		return false;
	}
	
	function _TableSQL($tabname,$lines,$pkey,$tableoptions)
	{
		$sql = array();
		
		if (isset($tableoptions['REPLACE']) || isset ($tableoptions['DROP'])) {
			$sql[] = sprintf($this->dropTable,$tabname);
			if ($this->autoIncrement) {
				$sInc = $this->_DropAutoIncrement($tabname);
				if ($sInc) $sql[] = $sInc;
			}
			if ( isset ($tableoptions['DROP']) ) {
				return $sql;
			}
		}
		$s = "CREATE TABLE $tabname (\n";
		$s .= implode(",\n", $lines);
		if (sizeof($pkey)>0) {
			$s .= ",\n                 PRIMARY KEY (";
			$s .= implode(", ",$pkey).")";
		}
		if (isset($tableoptions['CONSTRAINTS'])) 
			$s .= "\n".$tableoptions['CONSTRAINTS'];
		
		if (isset($tableoptions[$this->upperName.'_CONSTRAINTS'])) 
			$s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
		
		$s .= "\n)";
		if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName];
		$sql[] = $s;
		
		return $sql;
	}
	
	/**
		GENERATE TRIGGERS IF NEEDED
		used when table has auto-incrementing field that is emulated using triggers
	*/
	function _Triggers($tabname,$taboptions)
	{
		return array();
	}
	
	/**
		Sanitize options, so that array elements with no keys are promoted to keys
	*/
	function _Options($opts)
	{
		if (!is_array($opts)) return array();
		$newopts = array();
		foreach($opts as $k => $v) {
			if (is_numeric($k)) $newopts[strtoupper($v)] = $v;
			else $newopts[strtoupper($k)] = $v;
		}
		return $newopts;
	}
	
	/**
	"Florian Buzin [ easywe ]" <florian.buzin#easywe.de>
	
	This function changes/adds new fields to your table. You don't
	have to know if the col is new or not. It will check on its own.
	*/
	function ChangeTableSQL($tablename, $flds, $tableoptions = false)
	{
	global $ADODB_FETCH_MODE;
	
		$save = $ADODB_FETCH_MODE;
		$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
		if ($this->connection->fetchMode !== false) $savem = $this->connection->SetFetchMode(false);
		
		// check table exists
		$save_handler = $this->connection->raiseErrorFn;
		$this->connection->raiseErrorFn = '';
		$cols = $this->MetaColumns($tablename);
		$this->connection->raiseErrorFn = $save_handler;
		
		if (isset($savem)) $this->connection->SetFetchMode($savem);
		$ADODB_FETCH_MODE = $save;
		
		if ( empty($cols)) { 
			return $this->CreateTableSQL($tablename, $flds, $tableoptions);
		}
		
		if (is_array($flds)) {
		// Cycle through the update fields, comparing
		// existing fields to fields to update.
		// if the Metatype and size is exactly the
		// same, ignore - by Mark Newham
			$holdflds = array();
			foreach($flds as $k=>$v) {
				if ( isset($cols[$k]) && is_object($cols[$k]) ) {
					// If already not allowing nulls, then don't change
					$obj = $cols[$k];
					if (isset($obj->not_null) && $obj->not_null)
						$v = str_replace('NOT NULL','',$v);

					$c = $cols[$k];
					$ml = $c->max_length;
					$mt = $this->MetaType($c->type,$ml);
					if ($ml == -1) $ml = '';
					if ($mt == 'X') $ml = $v['SIZE'];
					if (($mt != $v['TYPE']) ||  $ml != $v['SIZE']) {
						$holdflds[$k] = $v;
					}
				} else {
					$holdflds[$k] = $v;
				}		
			}
			$flds = $holdflds;
		}
	

		// already exists, alter table instead
		list($lines,$pkey,$idxs) = $this->_GenFields($flds);
		// genfields can return FALSE at times
		if ($lines == null) $lines = array();
		$alter = 'ALTER TABLE ' . $this->TableName($tablename);
		$sql = array();

		foreach ( $lines as $id => $v ) {
			if ( isset($cols[$id]) && is_object($cols[$id]) ) {
			
				$flds = Lens_ParseArgs($v,',');
				
				//  We are trying to change the size of the field, if not allowed, simply ignore the request.
				// $flds[1] holds the type, $flds[2] holds the size -postnuke addition
				if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)
				 && (isset($flds[0][2]) && is_numeric($flds[0][2]))) {
					if ($this->debug) ADOConnection::outp(sprintf("<h3>%s cannot be changed to %s currently</h3>", $flds[0][0], $flds[0][1]));
					#echo "<h3>$this->alterCol cannot be changed to $flds currently</h3>";
					continue;	 
	 			}
				$sql[] = $alter . $this->alterCol . ' ' . $v;
			} else {
				$sql[] = $alter . $this->addCol . ' ' . $v;
			}
		}
		
		return $sql;
	}
} // class
?>

Added program_files/include/adodb4/adodb-error.inc.php.





































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
<?php
/** 
 * @version v4.992 10 Nov 2009 (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
 * Released under both BSD license and Lesser GPL library license. 
 * Whenever there is any discrepancy between the two licenses, 
 * the BSD license will take precedence. 
 *
 * Set tabs to 4 for best viewing.
 * 
 * The following code is adapted from the PEAR DB error handling code.
 * Portions (c)1997-2002 The PHP Group.
 */


if (!defined("DB_ERROR")) define("DB_ERROR",-1);

if (!defined("DB_ERROR_SYNTAX")) {
	define("DB_ERROR_SYNTAX",              -2);
	define("DB_ERROR_CONSTRAINT",          -3);
	define("DB_ERROR_NOT_FOUND",           -4);
	define("DB_ERROR_ALREADY_EXISTS",      -5);
	define("DB_ERROR_UNSUPPORTED",         -6);
	define("DB_ERROR_MISMATCH",            -7);
	define("DB_ERROR_INVALID",             -8);
	define("DB_ERROR_NOT_CAPABLE",         -9);
	define("DB_ERROR_TRUNCATED",          -10);
	define("DB_ERROR_INVALID_NUMBER",     -11);
	define("DB_ERROR_INVALID_DATE",       -12);
	define("DB_ERROR_DIVZERO",            -13);
	define("DB_ERROR_NODBSELECTED",       -14);
	define("DB_ERROR_CANNOT_CREATE",      -15);
	define("DB_ERROR_CANNOT_DELETE",      -16);
	define("DB_ERROR_CANNOT_DROP",        -17);
	define("DB_ERROR_NOSUCHTABLE",        -18);
	define("DB_ERROR_NOSUCHFIELD",        -19);
	define("DB_ERROR_NEED_MORE_DATA",     -20);
	define("DB_ERROR_NOT_LOCKED",         -21);
	define("DB_ERROR_VALUE_COUNT_ON_ROW", -22);
	define("DB_ERROR_INVALID_DSN",        -23);
	define("DB_ERROR_CONNECT_FAILED",     -24);
	define("DB_ERROR_EXTENSION_NOT_FOUND",-25);
	define("DB_ERROR_NOSUCHDB",           -25);
	define("DB_ERROR_ACCESS_VIOLATION",   -26);
}

function adodb_errormsg($value)
{
global $ADODB_LANG,$ADODB_LANG_ARRAY;

	if (empty($ADODB_LANG)) $ADODB_LANG = 'en';
	if (isset($ADODB_LANG_ARRAY['LANG']) && $ADODB_LANG_ARRAY['LANG'] == $ADODB_LANG) ;
	else {
		include_once(ADODB_DIR."/lang/adodb-$ADODB_LANG.inc.php");
    }
	return isset($ADODB_LANG_ARRAY[$value]) ? $ADODB_LANG_ARRAY[$value] : $ADODB_LANG_ARRAY[DB_ERROR];
}

function adodb_error($provider,$dbType,$errno)
{
	//var_dump($errno);
	if (is_numeric($errno) && $errno == 0) return 0;
	switch($provider) { 
	case 'mysql': $map = adodb_error_mysql(); break;
	
	case 'oracle':
	case 'oci8': $map = adodb_error_oci8(); break;
	
	case 'ibase': $map = adodb_error_ibase(); break;
	
	case 'odbc': $map = adodb_error_odbc(); break;
	
	case 'mssql':
	case 'sybase': $map = adodb_error_mssql(); break;
	
	case 'informix': $map = adodb_error_ifx(); break;
	
	case 'postgres': return adodb_error_pg($errno); break;
	
	case 'sqlite': return $map = adodb_error_sqlite(); break;
	default:
		return DB_ERROR;
	}	
	//print_r($map);
	//var_dump($errno);
	if (isset($map[$errno])) return $map[$errno];
	return DB_ERROR;
}

//**************************************************************************************

function adodb_error_pg($errormsg)
{
	if (is_numeric($errormsg)) return (integer) $errormsg;
    static $error_regexps = array(
            '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$/i' => DB_ERROR_NOSUCHTABLE,
            '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*/i'      => DB_ERROR_ALREADY_EXISTS,
            '/divide by zero$/i'                     => DB_ERROR_DIVZERO,
            '/pg_atoi: error in .*: can\'t parse /i' => DB_ERROR_INVALID_NUMBER,
            '/ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/i' => DB_ERROR_NOSUCHFIELD,
            '/parser: parse error at or near \"/i'   => DB_ERROR_SYNTAX,
            '/referential integrity violation/i'     => DB_ERROR_CONSTRAINT,
			'/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*|duplicate key violates unique constraint/i'     
			 	 => DB_ERROR_ALREADY_EXISTS
        );
	reset($error_regexps);
    while (list($regexp,$code) = each($error_regexps)) {
        if (preg_match($regexp, $errormsg)) {
            return $code;
        }
    }
    // Fall back to DB_ERROR if there was no mapping.
    return DB_ERROR;
}
	
function adodb_error_odbc()
{
static $MAP = array(
            '01004' => DB_ERROR_TRUNCATED,
            '07001' => DB_ERROR_MISMATCH,
            '21S01' => DB_ERROR_MISMATCH,
            '21S02' => DB_ERROR_MISMATCH,
            '22003' => DB_ERROR_INVALID_NUMBER,
            '22008' => DB_ERROR_INVALID_DATE,
            '22012' => DB_ERROR_DIVZERO,
            '23000' => DB_ERROR_CONSTRAINT,
            '24000' => DB_ERROR_INVALID,
            '34000' => DB_ERROR_INVALID,
            '37000' => DB_ERROR_SYNTAX,
            '42000' => DB_ERROR_SYNTAX,
            'IM001' => DB_ERROR_UNSUPPORTED,
            'S0000' => DB_ERROR_NOSUCHTABLE,
            'S0001' => DB_ERROR_NOT_FOUND,
            'S0002' => DB_ERROR_NOSUCHTABLE,
            'S0011' => DB_ERROR_ALREADY_EXISTS,
            'S0012' => DB_ERROR_NOT_FOUND,
            'S0021' => DB_ERROR_ALREADY_EXISTS,
            'S0022' => DB_ERROR_NOT_FOUND,
			'S1000' => DB_ERROR_NOSUCHTABLE,
            'S1009' => DB_ERROR_INVALID,
            'S1090' => DB_ERROR_INVALID,
            'S1C00' => DB_ERROR_NOT_CAPABLE
        );
		return $MAP;
}

function adodb_error_ibase()
{
static $MAP = array(
            -104 => DB_ERROR_SYNTAX,
            -150 => DB_ERROR_ACCESS_VIOLATION,
            -151 => DB_ERROR_ACCESS_VIOLATION,
            -155 => DB_ERROR_NOSUCHTABLE,
            -157 => DB_ERROR_NOSUCHFIELD,
            -158 => DB_ERROR_VALUE_COUNT_ON_ROW,
            -170 => DB_ERROR_MISMATCH,
            -171 => DB_ERROR_MISMATCH,
            -172 => DB_ERROR_INVALID,
            -204 => DB_ERROR_INVALID,
            -205 => DB_ERROR_NOSUCHFIELD,
            -206 => DB_ERROR_NOSUCHFIELD,
            -208 => DB_ERROR_INVALID,
            -219 => DB_ERROR_NOSUCHTABLE,
            -297 => DB_ERROR_CONSTRAINT,
            -530 => DB_ERROR_CONSTRAINT,
            -803 => DB_ERROR_CONSTRAINT,
            -551 => DB_ERROR_ACCESS_VIOLATION,
            -552 => DB_ERROR_ACCESS_VIOLATION,
            -922 => DB_ERROR_NOSUCHDB,
            -923 => DB_ERROR_CONNECT_FAILED,
            -924 => DB_ERROR_CONNECT_FAILED
        );
		
		return $MAP;
}

function adodb_error_ifx()
{
static $MAP = array(
            '-201'    => DB_ERROR_SYNTAX,
            '-206'    => DB_ERROR_NOSUCHTABLE,
            '-217'    => DB_ERROR_NOSUCHFIELD,
            '-329'    => DB_ERROR_NODBSELECTED,
            '-1204'   => DB_ERROR_INVALID_DATE,
            '-1205'   => DB_ERROR_INVALID_DATE,
            '-1206'   => DB_ERROR_INVALID_DATE,
            '-1209'   => DB_ERROR_INVALID_DATE,
            '-1210'   => DB_ERROR_INVALID_DATE,
            '-1212'   => DB_ERROR_INVALID_DATE
       );
	   
	   return $MAP;
}

function adodb_error_oci8()
{
static $MAP = array(
			 1 => DB_ERROR_ALREADY_EXISTS,
            900 => DB_ERROR_SYNTAX,
            904 => DB_ERROR_NOSUCHFIELD,
            923 => DB_ERROR_SYNTAX,
            942 => DB_ERROR_NOSUCHTABLE,
            955 => DB_ERROR_ALREADY_EXISTS,
            1476 => DB_ERROR_DIVZERO,
            1722 => DB_ERROR_INVALID_NUMBER,
            2289 => DB_ERROR_NOSUCHTABLE,
            2291 => DB_ERROR_CONSTRAINT,
            2449 => DB_ERROR_CONSTRAINT
        );
	   
	return $MAP;
}

function adodb_error_mssql()
{
static $MAP = array(
		  208 => DB_ERROR_NOSUCHTABLE,
          2601 => DB_ERROR_ALREADY_EXISTS
       );
	   
	return $MAP;
}

function adodb_error_sqlite()
{
static $MAP = array(
		  1 => DB_ERROR_SYNTAX
       );
	   
	return $MAP;
}

function adodb_error_mysql()
{
static $MAP = array(
           1004 => DB_ERROR_CANNOT_CREATE,
           1005 => DB_ERROR_CANNOT_CREATE,
           1006 => DB_ERROR_CANNOT_CREATE,
           1007 => DB_ERROR_ALREADY_EXISTS,
           1008 => DB_ERROR_CANNOT_DROP,
		   1045 => DB_ERROR_ACCESS_VIOLATION,
           1046 => DB_ERROR_NODBSELECTED,
		   1049 => DB_ERROR_NOSUCHDB,
           1050 => DB_ERROR_ALREADY_EXISTS,
           1051 => DB_ERROR_NOSUCHTABLE,
           1054 => DB_ERROR_NOSUCHFIELD,
           1062 => DB_ERROR_ALREADY_EXISTS,
           1064 => DB_ERROR_SYNTAX,
           1100 => DB_ERROR_NOT_LOCKED,
           1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
           1146 => DB_ERROR_NOSUCHTABLE,
           1048 => DB_ERROR_CONSTRAINT,
		    2002 => DB_ERROR_CONNECT_FAILED,
			2005 => DB_ERROR_CONNECT_FAILED
       );
	   
	return $MAP;
}
?>

Added program_files/include/adodb4/adodb-errorhandler.inc.php.































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?php
/**
 * @version v4.992 10 Nov 2009  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
 * Released under both BSD license and Lesser GPL library license.
 * Whenever there is any discrepancy between the two licenses,
 * the BSD license will take precedence.
 *
 * Set tabs to 4 for best viewing.
 *
 * Latest version is available at http://php.weblogs.com
 *
*/


// added Claudio Bustos  clbustos#entelchile.net
if (!defined('ADODB_ERROR_HANDLER_TYPE')) define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR); 

if (!defined('ADODB_ERROR_HANDLER')) define('ADODB_ERROR_HANDLER','ADODB_Error_Handler');

/**
* Default Error Handler. This will be called with the following params
*
* @param $dbms		the RDBMS you are connecting to
* @param $fn		the name of the calling function (in uppercase)
* @param $errno		the native error number from the database
* @param $errmsg	the native error msg from the database
* @param $p1		$fn specific parameter - see below
* @param $p2		$fn specific parameter - see below
* @param $thisConn	$current connection object - can be false if no connection object created
*/
function ADODB_Error_Handler($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)
{
	if (error_reporting() == 0) return; // obey @ protocol
	switch($fn) {
	case 'EXECUTE':
		$sql = $p1;
		$inputparams = $p2;

		$s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")\n";
		break;

	case 'PCONNECT':
	case 'CONNECT':
		$host = $p1;
		$database = $p2;

		$s = "$dbms error: [$errno: $errmsg] in $fn($host, '****', '****', $database)\n";
		break;
	default:
		$s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n";
		break;
	}
	/*
	* Log connection error somewhere
	*	0 message is sent to PHP's system logger, using the Operating System's system
	*		logging mechanism or a file, depending on what the error_log configuration
	*		directive is set to.
	*	1 message is sent by email to the address in the destination parameter.
	*		This is the only message type where the fourth parameter, extra_headers is used.
	*		This message type uses the same internal function as mail() does.
	*	2 message is sent through the PHP debugging connection.
	*		This option is only available if remote debugging has been enabled.
	*		In this case, the destination parameter specifies the host name or IP address
	*		and optionally, port number, of the socket receiving the debug information.
	*	3 message is appended to the file destination
	*/
	if (defined('ADODB_ERROR_LOG_TYPE')) {
		$t = date('Y-m-d H:i:s');
		if (defined('ADODB_ERROR_LOG_DEST'))
			error_log("($t) $s", ADODB_ERROR_LOG_TYPE, ADODB_ERROR_LOG_DEST);
		else
			error_log("($t) $s", ADODB_ERROR_LOG_TYPE);
	}


	//print "<p>$s</p>";
	trigger_error($s,ADODB_ERROR_HANDLER_TYPE); 
}
?>

Added program_files/include/adodb4/adodb-errorpear.inc.php.

















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<?php
/** 
 * @version v4.992 10 Nov 2009 (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
 * Released under both BSD license and Lesser GPL library license. 
  Whenever there is any discrepancy between the two licenses, 
  the BSD license will take precedence. 
 *
 * Set tabs to 4 for best viewing.
 * 
 * Latest version is available at http://php.weblogs.com
 * 
*/
include_once('PEAR.php');

if (!defined('ADODB_ERROR_HANDLER')) define('ADODB_ERROR_HANDLER','ADODB_Error_PEAR');

/*
* Enabled the following if you want to terminate scripts when an error occurs
*/
//PEAR::setErrorHandling (PEAR_ERROR_DIE);

/*
* Name of the PEAR_Error derived class to call.
*/
if (!defined('ADODB_PEAR_ERROR_CLASS')) define('ADODB_PEAR_ERROR_CLASS','PEAR_Error');

/*
* Store the last PEAR_Error object here
*/
global $ADODB_Last_PEAR_Error; $ADODB_Last_PEAR_Error = false;

  /**
* Error Handler with PEAR support. This will be called with the following params
*
* @param $dbms		the RDBMS you are connecting to
* @param $fn		the name of the calling function (in uppercase)
* @param $errno		the native error number from the database 
* @param $errmsg	the native error msg from the database
* @param $p1		$fn specific parameter - see below
* @param $P2		$fn specific parameter - see below
	*/
function ADODB_Error_PEAR($dbms, $fn, $errno, $errmsg, $p1=false, $p2=false)
{
global $ADODB_Last_PEAR_Error;
	
	if (error_reporting() == 0) return; // obey @ protocol
	switch($fn) {
	case 'EXECUTE':
		$sql = $p1;
		$inputparams = $p2;
		
		$s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")";
		break;
		
	case 'PCONNECT':
	case 'CONNECT':
		$host = $p1;
		$database = $p2;
		
		$s = "$dbms error: [$errno: $errmsg] in $fn('$host', ?, ?, '$database')";
		break;
		
	default:
		$s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)";
		break;
	}
	
	$class = ADODB_PEAR_ERROR_CLASS;
	$ADODB_Last_PEAR_Error = new $class($s, $errno,
		$GLOBALS['_PEAR_default_error_mode'],
		$GLOBALS['_PEAR_default_error_options'], 
		$errmsg);
		
	//print "<p>!$s</p>";
}

/**
* Returns last PEAR_Error object. This error might be for an error that
* occured several sql statements ago.
*/
function &ADODB_PEAR_Error()
{
global $ADODB_Last_PEAR_Error;

	return $ADODB_Last_PEAR_Error;
}
		
?>

Added program_files/include/adodb4/adodb-exceptions.inc.php.





































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php

/**
 * @version v4.992 10 Nov 2009  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
 * Released under both BSD license and Lesser GPL library license.
 * Whenever there is any discrepancy between the two licenses,
 * the BSD license will take precedence.
 *
 * Set tabs to 4 for best viewing.
 *
 * Latest version is available at http://php.weblogs.com
 *
 * Exception-handling code using PHP5 exceptions (try-catch-throw).
 */


if (!defined('ADODB_ERROR_HANDLER_TYPE')) define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR); 
define('ADODB_ERROR_HANDLER','adodb_throw');

class ADODB_Exception extends Exception {
var $dbms;
var $fn;
var $sql = '';
var $params = '';
var $host = '';
var $database = '';
	
	function __construct($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection)
	{
		switch($fn) {
		case 'EXECUTE':
			$this->sql = $p1;
			$this->params = $p2;
			$s = "$dbms error: [$errno: $errmsg] in $fn(\"$p1\")\n";
			break;
	
		case 'PCONNECT':
		case 'CONNECT':
			$user = $thisConnection->user;
			$s = "$dbms error: [$errno: $errmsg] in $fn($p1, '$user', '****', $p2)\n";
			break;
		default:
			$s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n";
			break;
		}
	
		$this->dbms = $dbms;
		if ($thisConnection) {
			$this->host = $thisConnection->host;
			$this->database = $thisConnection->database;
		}
		$this->fn = $fn;
		$this->msg = $errmsg;
				
		if (!is_numeric($errno)) $errno = -1;
		parent::__construct($s,$errno);
	}
}

/**
* Default Error Handler. This will be called with the following params
*
* @param $dbms		the RDBMS you are connecting to
* @param $fn		the name of the calling function (in uppercase)
* @param $errno		the native error number from the database
* @param $errmsg	the native error msg from the database
* @param $p1		$fn specific parameter - see below
* @param $P2		$fn specific parameter - see below
*/

function adodb_throw($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection)
{
global $ADODB_EXCEPTION;
	
	if (error_reporting() == 0) return; // obey @ protocol
	if (is_string($ADODB_EXCEPTION)) $errfn = $ADODB_EXCEPTION;
	else $errfn = 'ADODB_EXCEPTION';
	throw new $errfn($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection);
}


?>

Added program_files/include/adodb4/adodb-iterator.inc.php.











































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<?php

/*
  v4.992 10 Nov 2009  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  Released under both BSD license and Lesser GPL library license. 
  Whenever there is any discrepancy between the two licenses, 
  the BSD license will take precedence.
  
  Set tabs to 4.
  
  Declares the ADODB Base Class for PHP5 "ADODB_BASE_RS", and supports iteration with 
  the ADODB_Iterator class.
  
  		$rs = $db->Execute("select * from adoxyz");
		foreach($rs as $k => $v) {
			echo $k; print_r($v); echo "<br>";
		}
		
		
	Iterator code based on http://cvs.php.net/cvs.php/php-src/ext/spl/examples/cachingiterator.inc?login=2
 */
 

 class ADODB_Iterator implements Iterator {

    private $rs;

    function __construct($rs) 
	{
        $this->rs = $rs;
    }
    function rewind() 
	{
        $this->rs->MoveFirst();
    }

	function valid() 
	{
        return !$this->rs->EOF;
    }
	
    function key() 
	{
        return $this->rs->_currentRow;
    }
	
    function current() 
	{
        return $this->rs->fields;
    }
	
    function next() 
	{
        $this->rs->MoveNext();
    }
	
	function __call($func, $params)
	{
		return call_user_func_array(array($this->rs, $func), $params);
	}

	
	function hasMore()
	{
		return !$this->rs->EOF;
	}

}


class ADODB_BASE_RS implements IteratorAggregate {
    function getIterator() {
        return new ADODB_Iterator($this);
    }
	
	/* this is experimental - i don't really know what to return... */
	function __toString()
	{
		include_once(ADODB_DIR.'/toexport.inc.php');
		return _adodb_export($this,',',',',false,true);
	}
} 


?>

Added program_files/include/adodb4/adodb-lib.inc.php.















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
<?php
	
// security - hide paths
if (!defined('ADODB_DIR')) die();

global $ADODB_INCLUDED_LIB;
$ADODB_INCLUDED_LIB = 1;

/* 
 @version v4.992 10 Nov 2009 (c) 2000-2009 John Lim (jlim\@natsoft.com.my). All rights reserved.
  Released under both BSD license and Lesser GPL library license. 
  Whenever there is any discrepancy between the two licenses, 
  the BSD license will take precedence. See License.txt. 
  Set tabs to 4 for best viewing.
  
  Less commonly used functions are placed here to reduce size of adodb.inc.php. 
*/ 

function adodb_strip_order_by($sql)
{
	$rez = preg_match('/(\sORDER\s+BY\s[^)]*)/is',$sql,$arr);
	if ($arr)
		if (strpos($arr[0],'(') !== false) {
			$at = strpos($sql,$arr[0]);
			$cntin = 0;
			for ($i=$at, $max=strlen($sql); $i < $max; $i++) {
				$ch = $sql[$i];
				if ($ch == '(') {
					$cntin += 1;
				} elseif($ch == ')') {
					$cntin -= 1;
					if ($cntin < 0) {
						break;
					}
				}
			}
			$sql = substr($sql,0,$at).substr($sql,$i);
		} else
			$sql = str_replace($arr[0], '', $sql); 
	return $sql;
 }

if (false) {
	$sql = 'select * from (select a from b order by a(b),b(c) desc)';
	$sql = '(select * from abc order by 1)';
	die(adodb_strip_order_by($sql));
}

function adodb_probetypes(&$array,&$types,$probe=8)
{
// probe and guess the type
	$types = array();
	if ($probe > sizeof($array)) $max = sizeof($array);
	else $max = $probe;
	
	
	for ($j=0;$j < $max; $j++) {
		$row =& $array[$j];
		if (!$row) break;
		$i = -1;
		foreach($row as $v) {
			$i += 1;

			if (isset($types[$i]) && $types[$i]=='C') continue;
			
			//print " ($i ".$types[$i]. "$v) ";
			$v = trim($v);
			
			if (!preg_match('/^[+-]{0,1}[0-9\.]+$/',$v)) {
				$types[$i] = 'C'; // once C, always C
				
				continue;
			}
			if ($j == 0) { 
			// If empty string, we presume is character
			// test for integer for 1st row only
			// after that it is up to testing other rows to prove
			// that it is not an integer
				if (strlen($v) == 0) $types[$i] = 'C';
				if (strpos($v,'.') !== false) $types[$i] = 'N';
				else  $types[$i] = 'I';
				continue;
			}
			
			if (strpos($v,'.') !== false) $types[$i] = 'N';
			
		}
	}
	
}

function  adodb_transpose(&$arr, &$newarr, &$hdr, &$fobjs)
{
	$oldX = sizeof(reset($arr));
	$oldY = sizeof($arr);	
	
	if ($hdr) {
		$startx = 1;
		$hdr = array('Fields');
		for ($y = 0; $y < $oldY; $y++) {
			$hdr[] = $arr[$y][0];
		}
	} else
		$startx = 0;

	for ($x = $startx; $x < $oldX; $x++) {
		if ($fobjs) {
			$o = $fobjs[$x];
			$newarr[] = array($o->name);
		} else
			$newarr[] = array();
			
		for ($y = 0; $y < $oldY; $y++) {
			$newarr[$x-$startx][] = $arr[$y][$x];
		}
	}
}

// Force key to upper. 
// See also http://www.php.net/manual/en/function.array-change-key-case.php
function _array_change_key_case($an_array)
{
	if (is_array($an_array)) {
		$new_array = array();
		foreach($an_array as $key=>$value)
			$new_array[strtoupper($key)] = $value;

	   	return $new_array;
   }

	return $an_array;
}

function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc)
{
		if (count($fieldArray) == 0) return 0;
		$first = true;
		$uSet = '';
		
		if (!is_array($keyCol)) {
			$keyCol = array($keyCol);
		}
		foreach($fieldArray as $k => $v) {
			if ($v === null) {
				$v = 'NULL';
				$fieldArray[$k] = $v;
			} else if ($autoQuote && !is_numeric($v) /*and strncmp($v,"'",1) !== 0 -- sql injection risk*/ and strcasecmp($v,$zthis->null2null)!=0) {
				$v = $zthis->qstr($v);
				$fieldArray[$k] = $v;
			}
			if (in_array($k,$keyCol)) continue; // skip UPDATE if is key
			
			if ($first) {
				$first = false;			
				$uSet = "$k=$v";
			} else
				$uSet .= ",$k=$v";
		}
		 
		$where = false;
		foreach ($keyCol as $v) {
			if (isset($fieldArray[$v])) {
				if ($where) $where .= ' and '.$v.'='.$fieldArray[$v];
				else $where = $v.'='.$fieldArray[$v];
			}
		}
		
		if ($uSet && $where) {
			$update = "UPDATE $table SET $uSet WHERE $where";

			$rs = $zthis->Execute($update);
			
			
			if ($rs) {
				if ($zthis->poorAffectedRows) {
				/*
				 The Select count(*) wipes out any errors that the update would have returned. 
				http://phplens.com/lens/lensforum/msgs.php?id=5696
				*/
					if ($zthis->ErrorNo()<>0) return 0;
					
				# affected_rows == 0 if update field values identical to old values
				# for mysql - which is silly. 
			
					$cnt = $zthis->GetOne("select count(*) from $table where $where");
					if ($cnt > 0) return 1; // record already exists
				} else {
					if (($zthis->Affected_Rows()>0)) return 1;
				}
			} else
				return 0;
		}
		
	//	print "<p>Error=".$this->ErrorNo().'<p>';
		$first = true;
		foreach($fieldArray as $k => $v) {
			if ($has_autoinc && in_array($k,$keyCol)) continue; // skip autoinc col
			
			if ($first) {
				$first = false;			
				$iCols = "$k";
				$iVals = "$v";
			} else {
				$iCols .= ",$k";
				$iVals .= ",$v";
			}				
		}
		$insert = "INSERT INTO $table ($iCols) VALUES ($iVals)"; 
		$rs = $zthis->Execute($insert);
		return ($rs) ? 2 : 0;
}

// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
			$size=0, $selectAttr='',$compareFields0=true)
{
	$hasvalue = false;

	if ($multiple or is_array($defstr)) {
		if ($size==0) $size=5;
		$attr = ' multiple size="'.$size.'"';
		if (!strpos($name,'[]')) $name .= '[]';
	} else if ($size) $attr = ' size="'.$size.'"';
	else $attr ='';
	
	$s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>';
	if ($blank1stItem) 
		if (is_string($blank1stItem))  {
			$barr = explode(':',$blank1stItem);
			if (sizeof($barr) == 1) $barr[] = '';
			$s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>";
		} else $s .= "\n<option></option>";

	if ($zthis->FieldCount() > 1) $hasvalue=true;
	else $compareFields0 = true;
	
	$value = '';
    $optgroup = null;
    $firstgroup = true;
    $fieldsize = $zthis->FieldCount();
	while(!$zthis->EOF) {
		$zval = rtrim(reset($zthis->fields));

		if ($blank1stItem && $zval=="") {
			$zthis->MoveNext();
			continue;
		}

        if ($fieldsize > 1) {
			if (isset($zthis->fields[1]))
				$zval2 = rtrim($zthis->fields[1]);
			else
				$zval2 = rtrim(next($zthis->fields));
		}
		$selected = ($compareFields0) ? $zval : $zval2;
		
        $group = '';
		if ($fieldsize > 2) {
            $group = rtrim($zthis->fields[2]);
        }
/* 
        if ($optgroup != $group) {
            $optgroup = $group;
            if ($firstgroup) {
                $firstgroup = false;
                $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
            } else {
                $s .="\n</optgroup>";
                $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
            }
		}
*/
		if ($hasvalue) 
			$value = " value='".htmlspecialchars($zval2)."'";
		
		if (is_array($defstr))  {
			
			if (in_array($selected,$defstr)) 
				$s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
			else 
				$s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
		}
		else {
			if (strcasecmp($selected,$defstr)==0) 
				$s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
			else
				$s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
		}
		$zthis->MoveNext();
	} // while
	
    // closing last optgroup
    if($optgroup != null) {
        $s .= "\n</optgroup>";
	}
	return $s ."\n</select>\n";
}

// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
function _adodb_getmenu_gp(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
			$size=0, $selectAttr='',$compareFields0=true)
{
	$hasvalue = false;

	if ($multiple or is_array($defstr)) {
		if ($size==0) $size=5;
		$attr = ' multiple size="'.$size.'"';
		if (!strpos($name,'[]')) $name .= '[]';
	} else if ($size) $attr = ' size="'.$size.'"';
	else $attr ='';
	
	$s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>';
	if ($blank1stItem) 
		if (is_string($blank1stItem))  {
			$barr = explode(':',$blank1stItem);
			if (sizeof($barr) == 1) $barr[] = '';
			$s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>";
		} else $s .= "\n<option></option>";

	if ($zthis->FieldCount() > 1) $hasvalue=true;
	else $compareFields0 = true;
	
	$value = '';
    $optgroup = null;
    $firstgroup = true;
    $fieldsize = sizeof($zthis->fields);
	while(!$zthis->EOF) {
		$zval = rtrim(reset($zthis->fields));

		if ($blank1stItem && $zval=="") {
			$zthis->MoveNext();
			continue;
		}

        if ($fieldsize > 1) {
			if (isset($zthis->fields[1]))
				$zval2 = rtrim($zthis->fields[1]);
			else
				$zval2 = rtrim(next($zthis->fields));
		}
		$selected = ($compareFields0) ? $zval : $zval2;
		
        $group = '';
		if (isset($zthis->fields[2])) {
            $group = rtrim($zthis->fields[2]);
        }
 
        if ($optgroup != $group) {
            $optgroup = $group;
            if ($firstgroup) {
                $firstgroup = false;
                $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
            } else {
                $s .="\n</optgroup>";
                $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
            }
		}
	
		if ($hasvalue) 
			$value = " value='".htmlspecialchars($zval2)."'";
		
		if (is_array($defstr))  {
			
			if (in_array($selected,$defstr)) 
				$s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
			else 
				$s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
		}
		else {
			if (strcasecmp($selected,$defstr)==0) 
				$s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
			else
				$s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
		}
		$zthis->MoveNext();
	} // while
	
    // closing last optgroup
    if($optgroup != null) {
        $s .= "\n</optgroup>";
	}
	return $s ."\n</select>\n";
}


/*
	Count the number of records this sql statement will return by using
	query rewriting heuristics...
	
	Does not work with UNIONs, except with postgresql and oracle.
	
	Usage:
	
	$conn->Connect(...);
	$cnt = _adodb_getcount($conn, $sql);
	
*/
function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0) 
{
	$qryRecs = 0;
	
	 if (!empty($zthis->_nestedSQL) || preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) || 
	 	preg_match('/\s+GROUP\s+BY\s+/is',$sql) || 
		preg_match('/\s+UNION\s+/is',$sql)) {
		
		$rewritesql = adodb_strip_order_by($sql);
		
		// ok, has SELECT DISTINCT or GROUP BY so see if we can use a table alias
		// but this is only supported by oracle and postgresql...
		if ($zthis->dataProvider == 'oci8') {
			// Allow Oracle hints to be used for query optimization, Chris Wrye
			if (preg_match('#/\\*+.*?\\*\\/#', $sql, $hint)) {
				$rewritesql = "SELECT ".$hint[0]." COUNT(*) FROM (".$rewritesql.")"; 
			} else
				$rewritesql = "SELECT COUNT(*) FROM (".$rewritesql.")"; 
			
		} else if (strncmp($zthis->databaseType,'postgres',8) == 0 || strncmp($zthis->databaseType,'mysql',5) == 0)  {
			$rewritesql = "SELECT COUNT(*) FROM ($rewritesql) _ADODB_ALIAS_";
		} else {
			$rewritesql = "SELECT COUNT(*) FROM ($rewritesql) ";
		}
	} else {		
		// now replace SELECT ... FROM with SELECT COUNT(*) FROM
		$rewritesql = preg_replace(
					'/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql);
		// fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails 
		// with mssql, access and postgresql. Also a good speedup optimization - skips sorting!
		// also see http://phplens.com/lens/lensforum/msgs.php?id=12752
		$rewritesql = adodb_strip_order_by($rewritesql);
	}
	
	if (isset($rewritesql) && $rewritesql != $sql) {
		if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0];

		if ($secs2cache) {
			// we only use half the time of secs2cache because the count can quickly
			// become inaccurate if new records are added
			$qryRecs = $zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr);
			
		} else {
			$qryRecs = $zthis->GetOne($rewritesql,$inputarr);
	  	}
		if ($qryRecs !== false) return $qryRecs;
	}
	//--------------------------------------------
	// query rewrite failed - so try slower way...
	
	
	// strip off unneeded ORDER BY if no UNION
	if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql;
	else $rewritesql = $rewritesql = adodb_strip_order_by($sql); 
	
	if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0];
		
	$rstest = &$zthis->Execute($rewritesql,$inputarr);
	if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr);
	
	if ($rstest) {
	  		$qryRecs = $rstest->RecordCount();
		if ($qryRecs == -1) { 
		global $ADODB_EXTENSION;
		// some databases will return -1 on MoveLast() - change to MoveNext()
			if ($ADODB_EXTENSION) {
				while(!$rstest->EOF) {
					adodb_movenext($rstest);
				}
			} else {
				while(!$rstest->EOF) {
					$rstest->MoveNext();
				}
			}
			$qryRecs = $rstest->_currentRow;
		}
		$rstest->Close();
		if ($qryRecs == -1) return 0;
	}
	return $qryRecs;
}

/*
 	Code originally from "Cornel G" <conyg@fx.ro>

	This code might not work with SQL that has UNION in it	
	
	Also if you are using CachePageExecute(), there is a strong possibility that
	data will get out of synch. use CachePageExecute() only with tables that
	rarely change.
*/
function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page, 
						$inputarr=false, $secs2cache=0) 
{
	$atfirstpage = false;
	$atlastpage = false;
	$lastpageno=1;

	// If an invalid nrows is supplied, 
	// we assume a default value of 10 rows per page
	if (!isset($nrows) || $nrows <= 0) $nrows = 10;

	$qryRecs = false; //count records for no offset
	
	$qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache);
	$lastpageno = (int) ceil($qryRecs / $nrows);
	$zthis->_maxRecordCount = $qryRecs;
	


	// ***** Here we check whether $page is the last page or 
	// whether we are trying to retrieve 
	// a page number greater than the last page number.
	if ($page >= $lastpageno) {
		$page = $lastpageno;
		$atlastpage = true;
	}
	
	// If page number <= 1, then we are at the first page
	if (empty($page) || $page <= 1) {	
		$page = 1;
		$atfirstpage = true;
	}
	
	// We get the data we want
	$offset = $nrows * ($page-1);
	if ($secs2cache > 0) 
		$rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
	else 
		$rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);

	
	// Before returning the RecordSet, we set the pagination properties we need
	if ($rsreturn) {
		$rsreturn->_maxRecordCount = $qryRecs;
		$rsreturn->rowsPerPage = $nrows;
		$rsreturn->AbsolutePage($page);
		$rsreturn->AtFirstPage($atfirstpage);
		$rsreturn->AtLastPage($atlastpage);
		$rsreturn->LastPageNo($lastpageno);
	}
	return $rsreturn;
}

// Iván Oliva version
function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0) 
{

	$atfirstpage = false;
	$atlastpage = false;
	
	if (!isset($page) || $page <= 1) {	// If page number <= 1, then we are at the first page
		$page = 1;
		$atfirstpage = true;
	}
	if ($nrows <= 0) $nrows = 10;	// If an invalid nrows is supplied, we assume a default value of 10 rows per page
	
	// ***** Here we check whether $page is the last page or whether we are trying to retrieve a page number greater than 
	// the last page number.
	$pagecounter = $page + 1;
	$pagecounteroffset = ($pagecounter * $nrows) - $nrows;
	if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
	else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
	if ($rstest) {
		while ($rstest && $rstest->EOF && $pagecounter>0) {
			$atlastpage = true;
			$pagecounter--;
			$pagecounteroffset = $nrows * ($pagecounter - 1);
			$rstest->Close();
			if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
			else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
		}
		if ($rstest) $rstest->Close();
	}
	if ($atlastpage) {	// If we are at the last page or beyond it, we are going to retrieve it
		$page = $pagecounter;
		if ($page == 1) $atfirstpage = true;	// We have to do this again in case the last page is the same as the first
			//... page, that is, the recordset has only 1 page.
	}
	
	// We get the data we want
	$offset = $nrows * ($page-1);
	if ($secs2cache > 0) $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
	else $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
	
	// Before returning the RecordSet, we set the pagination properties we need
	if ($rsreturn) {
		$rsreturn->rowsPerPage = $nrows;
		$rsreturn->AbsolutePage($page);
		$rsreturn->AtFirstPage($atfirstpage);
		$rsreturn->AtLastPage($atlastpage);
	}
	return $rsreturn;
}

function _adodb_getupdatesql(&$zthis,&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=2)
{
	global $ADODB_QUOTE_FIELDNAMES;

		if (!$rs) {
			printf(ADODB_BAD_RS,'GetUpdateSQL');
			return false;
		}
	
		$fieldUpdatedCount = 0;
		$arrFields = _array_change_key_case($arrFields);

		$hasnumeric = isset($rs->fields[0]);
		$setFields = '';
		
		// Loop through all of the fields in the recordset
		for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
			// Get the field from the recordset
			$field = $rs->FetchField($i);

			// If the recordset field is one
			// of the fields passed in then process.
			$upperfname = strtoupper($field->name);
			if (adodb_key_exists($upperfname,$arrFields,$force)) {
				
				// If the existing field value in the recordset
				// is different from the value passed in then
				// go ahead and append the field name and new value to
				// the update query.
				
				if ($hasnumeric) $val = $rs->fields[$i];
				else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname];
				else if (isset($rs->fields[$field->name])) $val =  $rs->fields[$field->name];
				else if (isset($rs->fields[strtolower($upperfname)])) $val =  $rs->fields[strtolower($upperfname)];
				else $val = '';
				
			
				if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) {
					// Set the counter for the number of fields that will be updated.
					$fieldUpdatedCount++;

					// Based on the datatype of the field
					// Format the value properly for the database
					$type = $rs->MetaType($field->type);
						

					if ($type == 'null') {
						$type = 'C';
					}
					
					if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES))
						$fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;
					else
						$fnameq = $upperfname;
					
					
                // is_null requires php 4.0.4
                //********************************************************//
                if (is_null($arrFields[$upperfname])
					|| (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
                    || $arrFields[$upperfname] === $zthis->null2null
                    )
                {
                    switch ($force) {

                        //case 0:
                        //    //Ignore empty values. This is allready handled in "adodb_key_exists" function.
                        //break;

                        case 1:
                            //Set null
                            $setFields .= $field->name . " = null, ";
                        break;
							
                        case 2:
                            //Set empty
                            $arrFields[$upperfname] = "";
                            $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
                        break;
						default:
                        case 3:
                            //Set the value that was given in array, so you can give both null and empty values
                            if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
                                $setFields .= $field->name . " = null, ";
                            } else {
                                $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
                            }
                        break;
                    }
                //********************************************************//
                } else {
						//we do this so each driver can customize the sql for
						//DB specific column types. 
						//Oracle needs BLOB types to be handled with a returning clause
						//postgres has special needs as well
						$setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,
														  $arrFields, $magicq);
					}
				}
			}
		}

		// If there were any modified fields then build the rest of the update query.
		if ($fieldUpdatedCount > 0 || $forceUpdate) {
					// Get the table name from the existing query.
			if (!empty($rs->tableName)) $tableName = $rs->tableName;
			else {
				preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName);
				$tableName = $tableName[1];
			}
			// Get the full where clause excluding the word "WHERE" from
			// the existing query.
			preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause);
			
			$discard = false;
			// not a good hack, improvements?
			if ($whereClause) {
			#var_dump($whereClause);
				if (preg_match('/\s(ORDER\s.*)/is', $whereClause[1], $discard));
				else if (preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard));
				else if (preg_match('/\s(FOR UPDATE.*)/is', $whereClause[1], $discard));
				else preg_match('/\s.*(\) WHERE .*)/is', $whereClause[1], $discard); # see http://sourceforge.net/tracker/index.php?func=detail&aid=1379638&group_id=42718&atid=433976
			} else
				$whereClause = array(false,false);
				
			if ($discard)
				$whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1]));
			
			$sql = 'UPDATE '.$tableName.' SET '.substr($setFields, 0, -2);
			if (strlen($whereClause[1]) > 0) 
				$sql .= ' WHERE '.$whereClause[1];

			return $sql;

		} else {
			return false;
	}
}

function adodb_key_exists($key, &$arr,$force=2)
{
	if ($force<=0) {
		// the following is the old behaviour where null or empty fields are ignored
		return (!empty($arr[$key])) || (isset($arr[$key]) && strlen($arr[$key])>0);
	}

	if (isset($arr[$key])) return true;
	## null check below
	if (ADODB_PHPVER >= 0x4010) return array_key_exists($key,$arr);
	return false;
}

/**
 * There is a special case of this function for the oci8 driver.
 * The proper way to handle an insert w/ a blob in oracle requires
 * a returning clause with bind variables and a descriptor blob.
 * 
 * 
 */
function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
{
static $cacheRS = false;
static $cacheSig = 0;
static $cacheCols;
	global $ADODB_QUOTE_FIELDNAMES;

	$tableName = '';
	$values = '';
	$fields = '';
	$recordSet = null;
	$arrFields = _array_change_key_case($arrFields);
	$fieldInsertedCount = 0;
	
	if (is_string($rs)) {
		//ok we have a table name
		//try and get the column info ourself.
		$tableName = $rs;			
	
		//we need an object for the recordSet
		//because we have to call MetaType.
		//php can't do a $rsclass::MetaType()
		$rsclass = $zthis->rsPrefix.$zthis->databaseType;
		$recordSet = new $rsclass(-1,$zthis->fetchMode);
		$recordSet->connection = &$zthis;
		
		if (is_string($cacheRS) && $cacheRS == $rs) {
			$columns =& $cacheCols;
		} else {
			$columns = $zthis->MetaColumns( $tableName );
			$cacheRS = $tableName;
			$cacheCols = $columns;
		}
	} else if (is_subclass_of($rs, 'adorecordset')) {
		if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS == $rs->insertSig) {
			$columns =& $cacheCols;
		} else {
			for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) 
				$columns[] = $rs->FetchField($i);
			$cacheRS = $cacheSig;
			$cacheCols = $columns;
			$rs->insertSig = $cacheSig++;
		}
		$recordSet =& $rs;
	
	} else {
		printf(ADODB_BAD_RS,'GetInsertSQL');
		return false;
	}

	// Loop through all of the fields in the recordset
	foreach( $columns as $field ) { 
		$upperfname = strtoupper($field->name);
		if (adodb_key_exists($upperfname,$arrFields,$force)) {
			$bad = false;
			if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES))
				$fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;
			else
				$fnameq = $upperfname;
			
			$type = $recordSet->MetaType($field->type);
			
            /********************************************************/
            if (is_null($arrFields[$upperfname])
                || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
                || $arrFields[$upperfname] === $zthis->null2null
				)
               {
                    switch ($force) {

                        case 0: // we must always set null if missing
							$bad = true;
							break;
							
                        case 1:
                            $values  .= "null, ";
                        break;
		
                        case 2:
                            //Set empty
                            $arrFields[$upperfname] = "";
                            $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,$arrFields, $magicq);
                        break;

						default:
                        case 3:
                            //Set the value that was given in array, so you can give both null and empty values
							if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) { 
								$values  .= "null, ";
							} else {
                        		$values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields, $magicq);
             				}
              			break;
             		} // switch

            /*********************************************************/
			} else {
				//we do this so each driver can customize the sql for
				//DB specific column types. 
				//Oracle needs BLOB types to be handled with a returning clause
				//postgres has special needs as well
				$values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,
											   $arrFields, $magicq);
			}
			
			if ($bad) continue;
			// Set the counter for the number of fields that will be inserted.
			$fieldInsertedCount++;
			
			
			// Get the name of the fields to insert
			$fields .= $fnameq . ", ";
		}
	}


	// If there were any inserted fields then build the rest of the insert query.
	if ($fieldInsertedCount <= 0)  return false;
	
	// Get the table name from the existing query.
	if (!$tableName) {
		if (!empty($rs->tableName)) $tableName = $rs->tableName;
		else if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName))
			$tableName = $tableName[1];
		else 
			return false;
	}		

	// Strip off the comma and space on the end of both the fields
	// and their values.
	$fields = substr($fields, 0, -2);
	$values = substr($values, 0, -2);

	// Append the fields and their values to the insert query.
	return 'INSERT INTO '.$tableName.' ( '.$fields.' ) VALUES ( '.$values.' )';
}


/**
 * This private method is used to help construct
 * the update/sql which is generated by GetInsertSQL and GetUpdateSQL.
 * It handles the string construction of 1 column -> sql string based on
 * the column type.  We want to do 'safe' handling of BLOBs
 * 
 * @param string the type of sql we are trying to create
 *                'I' or 'U'. 
 * @param string column data type from the db::MetaType() method  
 * @param string the column name
 * @param array the column value
 * 
 * @return string
 * 
 */
function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFields, $magicq) 
{
    $sql = '';
    
    // Based on the datatype of the field
    // Format the value properly for the database
    switch($type) {
    case 'B':
        //in order to handle Blobs correctly, we need
        //to do some magic for Oracle

        //we need to create a new descriptor to handle 
        //this properly
        if (!empty($zthis->hasReturningInto)) {
            if ($action == 'I') {
                $sql = 'empty_blob(), ';
            } else {
                $sql = $fnameq. '=empty_blob(), ';
            }
            //add the variable to the returning clause array
            //so the user can build this later in
            //case they want to add more to it
            $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
        } else if (empty($arrFields[$fname])){
            if ($action == 'I') {
                $sql = 'empty_blob(), ';
            } else {
                $sql = $fnameq. '=empty_blob(), ';
            }            
        } else {
            //this is to maintain compatibility
            //with older adodb versions.
            $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
        }
        break;

    case "X":
        //we need to do some more magic here for long variables
        //to handle these correctly in oracle.

        //create a safe bind var name
        //to avoid conflicts w/ dupes.
       if (!empty($zthis->hasReturningInto)) {
            if ($action == 'I') {
                $sql = ':xx'.$fname.'xx, ';                
            } else {
                $sql = $fnameq.'=:xx'.$fname.'xx, ';
            }
            //add the variable to the returning clause array
            //so the user can build this later in
            //case they want to add more to it
            $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
        } else {
            //this is to maintain compatibility
            //with older adodb versions.
            $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
        }            
        break;
        
    default:
        $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq,  $arrFields, $magicq,false);
        break;
    }
    
    return $sql;
}    
	
function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq, $recurse=true) 
{

	if ($recurse) {
		switch($zthis->dataProvider)  {
		case 'postgres':
			if ($type == 'L') $type = 'C';
			break;
		case 'oci8':
			return _adodb_column_sql_oci8($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq);
			
		}
	}
		
	switch($type) {
		case "C":
		case "X":
		case 'B':
			$val = $zthis->qstr($arrFields[$fname],$magicq);
			break;

		case "D":
			$val = $zthis->DBDate($arrFields[$fname]);
			break;
		
		case "T":
			$val = $zthis->DBTimeStamp($arrFields[$fname]);
            break;

		case "N":
		    $val = $arrFields[$fname];
			if (!is_numeric($val)) $val = str_replace(',', '.', (float)$val);
			break;

		case "I":
		case "R":
		    $val = $arrFields[$fname];
			if (!is_numeric($val)) $val = (integer) $val;
		    break;

		default:
			$val = str_replace(array("'"," ","("),"",$arrFields[$fname]); // basic sql injection defence
			if (empty($val)) $val = '0';
			break;
	}

	if ($action == 'I') return $val . ", ";
	
	
	return $fnameq . "=" . $val  . ", ";
	
}



function _adodb_debug_execute(&$zthis, $sql, $inputarr)
{
	$ss = '';
	if ($inputarr) {
		foreach($inputarr as $kk=>$vv) {
			if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
			if (is_null($vv)) $ss .= "($kk=>null) ";
			else $ss .= "($kk=>'$vv') ";
		}
		$ss = "[ $ss ]";
	}
	$sqlTxt = is_array($sql) ? $sql[0] : $sql;
	/*str_replace(', ','##1#__^LF',is_array($sql) ? $sql[0] : $sql);
	$sqlTxt = str_replace(',',', ',$sqlTxt);
	$sqlTxt = str_replace('##1#__^LF', ', ' ,$sqlTxt);
	*/
	// check if running from browser or command-line
	$inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
	
	$dbt = $zthis->databaseType;
	if (isset($zthis->dsnType)) $dbt .= '-'.$zthis->dsnType;
	if ($inBrowser) {
		if ($ss) {
			$ss = '<code>'.htmlspecialchars($ss).'</code>';
		}
		if ($zthis->debug === -1)
			ADOConnection::outp( "<br />\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<br />\n",false);
		else 
			ADOConnection::outp( "<hr />\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr />\n",false);
	} else {
		ADOConnection::outp("-----\n($dbt): ".$sqlTxt."\n-----\n",false);
	}

	$qID = $zthis->_query($sql,$inputarr);
	
	/* 
		Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
		because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion
	*/
	if ($zthis->databaseType == 'mssql') { 
	// ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6
		if($emsg = $zthis->ErrorMsg()) {
			if ($err = $zthis->ErrorNo()) ADOConnection::outp($err.': '.$emsg);
		}
	} else if (!$qID) {
		ADOConnection::outp($zthis->ErrorNo() .': '. $zthis->ErrorMsg());
	}
	
	if ($zthis->debug === 99) _adodb_backtrace(true,9999,2);
	return $qID;
}

# pretty print the debug_backtrace function
function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0)
{
	if (!function_exists('debug_backtrace')) return '';
	 
	$html =  (isset($_SERVER['HTTP_USER_AGENT']));
	$fmt =  ($html) ? "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s";

	$MAXSTRLEN = 128;

	$s = ($html) ? '<pre align=left>' : '';
	
	if (is_array($printOrArr)) $traceArr = $printOrArr;
	else $traceArr = debug_backtrace();
	array_shift($traceArr);
	array_shift($traceArr);
	$tabs = sizeof($traceArr)-2;
	
	foreach ($traceArr as $arr) {
		if ($skippy) {$skippy -= 1; continue;}
		$levels -= 1;
		if ($levels < 0) break;
		
		$args = array();
		for ($i=0; $i < $tabs; $i++) $s .=  ($html) ? ' &nbsp; ' : "\t";
		$tabs -= 1;
		if ($html) $s .= '<font face="Courier New,Courier">';
		if (isset($arr['class'])) $s .= $arr['class'].'.';
		if (isset($arr['args']))
		 foreach($arr['args'] as $v) {
			if (is_null($v)) $args[] = 'null';
			else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
			else if (is_object($v)) $args[] = 'Object:'.get_class($v);
			else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
			else {
				$v = (string) @$v;
				$str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
				if (strlen($v) > $MAXSTRLEN) $str .= '...';
				$args[] = $str;
			}
		}
		$s .= $arr['function'].'('.implode(', ',$args).')';
		
		
		$s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file']));
			
		$s .= "\n";
	}	
	if ($html) $s .= '</pre>';
	if ($printOrArr) print $s;
	
	return $s;
}
/*
function _adodb_find_from($sql) 
{

	$sql = str_replace(array("\n","\r"), ' ', $sql);
	$charCount = strlen($sql);
	
	$inString = false;
	$quote = '';
	$parentheseCount = 0;
	$prevChars = '';
	$nextChars = '';
	

	for($i = 0; $i < $charCount; $i++) {

    	$char = substr($sql,$i,1);
	    $prevChars = substr($sql,0,$i);
    	$nextChars = substr($sql,$i+1);

		if((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === false) {
			$quote = $char;
			$inString = true;
		}

		elseif((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === true && $quote == $char) {
			$quote = "";
			$inString = false;
		}

		elseif($char == "(" && $inString === false)
			$parentheseCount++;

		elseif($char == ")" && $inString === false && $parentheseCount > 0)
			$parentheseCount--;

		elseif($parentheseCount <= 0 && $inString === false && $char == " " && strtoupper(substr($prevChars,-5,5)) == " FROM")
			return $i;

	}
}
*/

?>

Added program_files/include/adodb4/adodb-memcache.lib.inc.php.































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
<?php

// security - hide paths
if (!defined('ADODB_DIR')) die();

global $ADODB_INCLUDED_MEMCACHE;
$ADODB_INCLUDED_MEMCACHE = 1;

global $ADODB_INCLUDED_CSV;
if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');

/* 

  v4.992 10 Nov 2009  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  Released under both BSD license and Lesser GPL library license. 
  Whenever there is any discrepancy between the two licenses, 
  the BSD license will take precedence. See License.txt. 
  Set tabs to 4 for best viewing.
  
  Latest version is available at http://adodb.sourceforge.net

Usage:
  
$db = NewADOConnection($driver);
$db->memCache = true; /// should we use memCache instead of caching in files
$db->memCacheHost = array($ip1, $ip2, $ip3);
$db->memCachePort = 11211; /// this is default memCache port
$db->memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib)

$db->Connect(...);
$db->CacheExecute($sql);

  Note the memcache class is shared by all connections, is created during the first call to Connect/PConnect.
  
  Class instance is stored in $ADODB_CACHE
*/

	class ADODB_Cache_MemCache {
		var $createdir = false; // create caching directory structure?
		
		//-----------------------------
		// memcache specific variables
		
		var $hosts;	// array of hosts
		var $port = 11211;
		var $compress = false; // memcache compression with zlib
		
		var $_connected = false;
		var $_memcache = false;
		
		function ADODB_Cache_MemCache(&$obj)
		{
			$this->hosts = $obj->memCacheHost;
			$this->port = $obj->memCachePort;
			$this->compress = $obj->memCacheCompress;
		}
		
		// implement as lazy connection. The connection only occurs on CacheExecute call
		function connect(&$err)
		{
			if (!function_exists('memcache_pconnect')) {
				$err = 'Memcache module PECL extension not found!';
				return false;
			}

			$memcache = new MemCache;
			
			if (!is_array($this->hosts)) $this->hosts = array($this->hosts);
		
			$failcnt = 0;
			foreach($this->hosts as $host) {
				if (!@$memcache->addServer($host,$this->port,true)) {
					$failcnt += 1;
				}
			}
			if ($failcnt == sizeof($this->hosts)) {
				$err = 'Can\'t connect to any memcache server';
				return false;
			}
			$this->_connected = true;
			$this->_memcache = $memcache;

			return true;
		}
		
		// returns true or false. true if successful save
		function writecache($filename, $contents,$debug, $secs2cache)
		{
			if (!$this->_connected) {
				$err = '';
				if (!$this->connect($err) && $debug) ADOConnection::outp($err);
			}
			if (!$this->_memcache) return false;
			
			if (!$this->_memcache->set($filename, $contents, $this->compress, $secs2cache)) {
				if ($debug) ADOConnection::outp(" Failed to save data at the memcached server!<br>\n");
				return false;
			}
			
			return true;
		}
		
		// returns a recordset
		function &readcache($filename, &$err, $secs2cache, $rsClass)
		{
			$false = false;
			if (!$this->_connected) $this->connect($err);
			if (!$this->_memcache) return $false;
			
			$rs = $this->_memcache->get($filename);
			if (!$rs) {
				$err = 'Item with such key doesn\'t exists on the memcached server.';
				return $false;
			}
	
			// hack, should actually use _csv2rs
			$rs = explode("\n", $rs);
            unset($rs[0]);
            $rs = join("\n", $rs);
            $rs = unserialize($rs);
			if (! is_object($rs)) {
				$err = 'Unable to unserialize $rs';		
				return $false;
			}
			
			if ($rs->timeCreated == 0) return $rs; // apparently have been reports that timeCreated was set to 0 somewhere
			$tdiff = intval($rs->timeCreated+$secs2cache - time());
			if ($tdiff <= 2) {
				switch($tdiff) {
					case 2: 
						if ((rand() & 15) == 0) {
							$err = "Timeout 2";
							return $false;
						}
						break;
					case 1:
						if ((rand() & 3) == 0) {
							$err = "Timeout 1";
							return $false;
						}
						break;
					default: 
						$err = "Timeout 0";
						return $false;
				}
			}
			return $rs;
		}
	
		function flushall($debug=false)
		{
			if (!$this->_connected) {
				$err = '';
				if (!$this->connect($err) && $debug) ADOConnection::outp($err);
			}
			if (!$this->_memcache) return false;
			
			$del = $this->_memcache->flush();
			
			if ($debug) 
				if (!$del) ADOConnection::outp("flushall: failed!<br>\n");
				else ADOConnection::outp("flushall: succeeded!<br>\n");
				
			return $del;
		}
		
		function flushcache($filename, $debug=false)
		{
			if (!$this->_connected) {
  				$err = '';
  				if (!$this->connect($err) && $debug) ADOConnection::outp($err); 
			} 
			if (!$this->_memcache) return false;
			
			$del = $this->_memcache->delete($filename);
			
			if ($debug) 
				if (!$del) ADOConnection::outp("flushcache: $key entry doesn't exist on memcached server!<br>\n");
				else ADOConnection::outp("flushcache: $key entry flushed from memcached server!<br>\n");
				
			return $del;
		}
		
		// not used for memcache
		function createdir($dir, $hash) 
		{
			return true;
		}
	}

?>

Added program_files/include/adodb4/adodb-pager.inc.php.





































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
<?php

/*
	v4.992 10 Nov 2009  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
	  Released under both BSD license and Lesser GPL library license. 
	  Whenever there is any discrepancy between the two licenses, 
	  the BSD license will take precedence. 
	  Set tabs to 4 for best viewing.

  	This class provides recordset pagination with 
	First/Prev/Next/Last links. 
	
	Feel free to modify this class for your own use as
	it is very basic. To learn how to use it, see the 
	example in adodb/tests/testpaging.php.
	
	"Pablo Costa" <pablo@cbsp.com.br> implemented Render_PageLinks().
	
	Please note, this class is entirely unsupported, 
	and no free support requests except for bug reports
	will be entertained by the author.

*/
class ADODB_Pager {
	var $id; 	// unique id for pager (defaults to 'adodb')
	var $db; 	// ADODB connection object
	var $sql; 	// sql used
	var $rs;	// recordset generated
	var $curr_page;	// current page number before Render() called, calculated in constructor
	var $rows;		// number of rows per page
    var $linksPerPage=10; // number of links per page in navigation bar
    var $showPageLinks; 

	var $gridAttributes = 'width=100% border=1 bgcolor=white';
	
	// Localize text strings here
	var $first = '<code>|&lt;</code>';
	var $prev = '<code>&lt;&lt;</code>';
	var $next = '<code>>></code>';
	var $last = '<code>>|</code>';
	var $moreLinks = '...';
	var $startLinks = '...';
	var $gridHeader = false;
	var $htmlSpecialChars = true;
	var $page = 'Page';
	var $linkSelectedColor = 'red';
	var $cache = 0;  #secs to cache with CachePageExecute()
	
	//----------------------------------------------
	// constructor
	//
	// $db	adodb connection object
	// $sql	sql statement
	// $id	optional id to identify which pager, 
	//		if you have multiple on 1 page. 
	//		$id should be only be [a-z0-9]*
	//
	function ADODB_Pager(&$db,$sql,$id = 'adodb', $showPageLinks = false)
	{
	global $PHP_SELF;
	
		$curr_page = $id.'_curr_page';
		$PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS attacks
		
		$this->sql = $sql;
		$this->id = $id;
		$this->db = $db;
		$this->showPageLinks = $showPageLinks;
		
		$next_page = $id.'_next_page';	
		
		if (isset($_GET[$next_page])) {
			$_SESSION[$curr_page] = (integer) $_GET[$next_page];
		}
		if (empty($_SESSION[$curr_page])) $_SESSION[$curr_page] = 1; ## at first page
		
		$this->curr_page = $_SESSION[$curr_page];
		
	}
	
	//---------------------------
	// Display link to first page
	function Render_First($anchor=true)
	{
	global $PHP_SELF;
		if ($anchor) {
	?>
		<a href="<?php echo $PHP_SELF,'?',$this->id;?>_next_page=1"><?php echo $this->first;?></a> &nbsp; 
	<?php
		} else {
			print "$this->first &nbsp; ";
		}
	}
	
	//--------------------------
	// Display link to next page
	function render_next($anchor=true)
	{
	global $PHP_SELF;
	
		if ($anchor) {
		?>
		<a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() + 1 ?>"><?php echo $this->next;?></a> &nbsp; 
		<?php
		} else {
			print "$this->next &nbsp; ";
		}
	}
	
	//------------------
	// Link to last page
	// 
	// for better performance with large recordsets, you can set
	// $this->db->pageExecuteCountRows = false, which disables
	// last page counting.
	function render_last($anchor=true)
	{
	global $PHP_SELF;
	
		if (!$this->db->pageExecuteCountRows) return;
		
		if ($anchor) {
		?>
			<a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->LastPageNo() ?>"><?php echo $this->last;?></a> &nbsp; 
		<?php
		} else {
			print "$this->last &nbsp; ";
		}
	}
	
	//---------------------------------------------------
	// original code by "Pablo Costa" <pablo@cbsp.com.br> 
        function render_pagelinks()
        {
        global $PHP_SELF;
            $pages        = $this->rs->LastPageNo();
            $linksperpage = $this->linksPerPage ? $this->linksPerPage : $pages;
            for($i=1; $i <= $pages; $i+=$linksperpage)
            {
                if($this->rs->AbsolutePage() >= $i)
                {
                    $start = $i;
                }
            }
			$numbers = '';
            $end = $start+$linksperpage-1;
			$link = $this->id . "_next_page";
            if($end > $pages) $end = $pages;
			
			
			if ($this->startLinks && $start > 1) {
				$pos = $start - 1;
				$numbers .= "<a href=$PHP_SELF?$link=$pos>$this->startLinks</a>  ";
            } 
			
			for($i=$start; $i <= $end; $i++) {
                if ($this->rs->AbsolutePage() == $i)
                    $numbers .= "<font color=$this->linkSelectedColor><b>$i</b></font>  ";
                else 
                     $numbers .= "<a href=$PHP_SELF?$link=$i>$i</a>  ";
            
            }
			if ($this->moreLinks && $end < $pages) 
				$numbers .= "<a href=$PHP_SELF?$link=$i>$this->moreLinks</a>  ";
            print $numbers . ' &nbsp; ';
        }
	// Link to previous page
	function render_prev($anchor=true)
	{
	global $PHP_SELF;
		if ($anchor) {
	?>
		<a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() - 1 ?>"><?php echo $this->prev;?></a> &nbsp; 
	<?php 
		} else {
			print "$this->prev &nbsp; ";
		}
	}
	
	//--------------------------------------------------------
	// Simply rendering of grid. You should override this for
	// better control over the format of the grid
	//
	// We use output buffering to keep code clean and readable.
	function RenderGrid()
	{
	global $gSQLBlockRows; // used by rs2html to indicate how many rows to display
		include_once(ADODB_DIR.'/tohtml.inc.php');
		ob_start();
		$gSQLBlockRows = $this->rows;
		rs2html($this->rs,$this->gridAttributes,$this->gridHeader,$this->htmlSpecialChars);
		$s = ob_get_contents();
		ob_end_clean();
		return $s;
	}
	
	//-------------------------------------------------------
	// Navigation bar
	//
	// we use output buffering to keep the code easy to read.
	function RenderNav()
	{
		ob_start();
		if (!$this->rs->AtFirstPage()) {
			$this->Render_First();
			$this->Render_Prev();
		} else {
			$this->Render_First(false);
			$this->Render_Prev(false);
		}
        if ($this->showPageLinks){
            $this->Render_PageLinks();
        }
		if (!$this->rs->AtLastPage()) {
			$this->Render_Next();
			$this->Render_Last();
		} else {
			$this->Render_Next(false);
			$this->Render_Last(false);
		}
		$s = ob_get_contents();
		ob_end_clean();
		return $s;
	}
	
	//-------------------
	// This is the footer
	function RenderPageCount()
	{
		if (!$this->db->pageExecuteCountRows) return '';
		$lastPage = $this->rs->LastPageNo();
		if ($lastPage == -1) $lastPage = 1; // check for empty rs.
		if ($this->curr_page > $lastPage) $this->curr_page = 1;
		return "<font size=-1>$this->page ".$this->curr_page."/".$lastPage."</font>";
	}
	
	//-----------------------------------
	// Call this class to draw everything.
	function Render($rows=10)
	{
	global $ADODB_COUNTRECS;
	
		$this->rows = $rows;
		
		if ($this->db->dataProvider == 'informix') $this->db->cursorType = IFX_SCROLL;
		
		$savec = $ADODB_COUNTRECS;
		if ($this->db->pageExecuteCountRows) $ADODB_COUNTRECS = true;
		if ($this->cache)
			$rs = &$this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page);
		else
			$rs = &$this->db->PageExecute($this->sql,$rows,$this->curr_page);
		$ADODB_COUNTRECS = $savec;
		
		$this->rs = &$rs;
		if (!$rs) {
			print "<h3>Query failed: $this->sql</h3>";
			return;
		}
		
		if (!$rs->EOF && (!$rs->AtFirstPage() || !$rs->AtLastPage())) 
			$header = $this->RenderNav();
		else
			$header = "&nbsp;";
		
		$grid = $this->RenderGrid();
		$footer = $this->RenderPageCount();
		
		$this->RenderLayout($header,$grid,$footer);
		
		$rs->Close();
		$this->rs = false;
	}
	
	//------------------------------------------------------
	// override this to control overall layout and formating
	function RenderLayout($header,$grid,$footer,$attributes='border=1 bgcolor=beige')
	{
		echo "<table ".$attributes."><tr><td>",
				$header,
			"</td></tr><tr><td>",
				$grid,
			"</td></tr><tr><td>",
				$footer,
			"</td></tr></table>";
	}
}


?>

Added program_files/include/adodb4/adodb-pear.inc.php.













































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
<?php
/** 
 * @version v4.992 10 Nov 2009 (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
 * Released under both BSD license and Lesser GPL library license. 
 * Whenever there is any discrepancy between the two licenses, 
 * the BSD license will take precedence. 
 *
 * Set tabs to 4 for best viewing.
 * 
 * PEAR DB Emulation Layer for ADODB.
 *
 * The following code is modelled on PEAR DB code by Stig Bakken <ssb@fast.no>								   |
 * and Tomas V.V.Cox <cox@idecnet.com>.	Portions (c)1997-2002 The PHP Group.
 */

 /*
 We support:
 
 DB_Common
 ---------
 	query - returns PEAR_Error on error
	limitQuery - return PEAR_Error on error
	prepare - does not return PEAR_Error on error
	execute - does not return PEAR_Error on error
	setFetchMode - supports ASSOC and ORDERED
	errorNative
	quote
	nextID
	disconnect
	
	getOne
	getAssoc
	getRow
	getCol
	getAll
	
 DB_Result
 ---------
 	numRows - returns -1 if not supported
	numCols
	fetchInto - does not support passing of fetchmode
	fetchRows - does not support passing of fetchmode
	free
 */
 
define('ADODB_PEAR',dirname(__FILE__));
include_once "PEAR.php";
include_once ADODB_PEAR."/adodb-errorpear.inc.php";
include_once ADODB_PEAR."/adodb.inc.php";

if (!defined('DB_OK')) {
define("DB_OK",	1);
define("DB_ERROR",-1);

// autoExecute constants
define('DB_AUTOQUERY_INSERT', 1);
define('DB_AUTOQUERY_UPDATE', 2);

/**
 * This is a special constant that tells DB the user hasn't specified
 * any particular get mode, so the default should be used.
 */

define('DB_FETCHMODE_DEFAULT', 0);

/**
 * Column data indexed by numbers, ordered from 0 and up
 */

define('DB_FETCHMODE_ORDERED', 1);

/**
 * Column data indexed by column names
 */

define('DB_FETCHMODE_ASSOC', 2);

/* for compatibility */

define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED);
define('DB_GETMODE_ASSOC',   DB_FETCHMODE_ASSOC);

/**
 * these are constants for the tableInfo-function
 * they are bitwised or'ed. so if there are more constants to be defined
 * in the future, adjust DB_TABLEINFO_FULL accordingly
 */

define('DB_TABLEINFO_ORDER', 1);
define('DB_TABLEINFO_ORDERTABLE', 2);
define('DB_TABLEINFO_FULL', 3);
}

/**
 * The main "DB" class is simply a container class with some static
 * methods for creating DB objects as well as some utility functions
 * common to all parts of DB.
 *
 */

class DB
{
	/**
	 * Create a new DB object for the specified database type
	 *
	 * @param $type string database type, for example "mysql"
	 *
	 * @return object a newly created DB object, or a DB error code on
	 * error
	 */

	function &factory($type)
	{
		include_once(ADODB_DIR."/drivers/adodb-$type.inc.php");
		$obj = &NewADOConnection($type);
		if (!is_object($obj)) $obj =& new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
		return $obj;
	}

	/**
	 * Create a new DB object and connect to the specified database
	 *
	 * @param $dsn mixed "data source name", see the DB::parseDSN
	 * method for a description of the dsn format.  Can also be
	 * specified as an array of the format returned by DB::parseDSN.
	 *
	 * @param $options mixed if boolean (or scalar), tells whether
	 * this connection should be persistent (for backends that support
	 * this).  This parameter can also be an array of options, see
	 * DB_common::setOption for more information on connection
	 * options.
	 *
	 * @return object a newly created DB connection object, or a DB
	 * error object on error
	 *
	 * @see DB::parseDSN
	 * @see DB::isError
	 */
	function &connect($dsn, $options = false)
	{
		if (is_array($dsn)) {
			$dsninfo = $dsn;
		} else {
			$dsninfo = DB::parseDSN($dsn);
		}
		switch ($dsninfo["phptype"]) {
			case 'pgsql': 	$type = 'postgres7'; break;
			case 'ifx':		$type = 'informix9'; break;
			default: 		$type = $dsninfo["phptype"]; break;
		}

		if (is_array($options) && isset($options["debug"]) &&
			$options["debug"] >= 2) {
			// expose php errors with sufficient debug level
			 @include_once("adodb-$type.inc.php");
		} else {
			 @include_once("adodb-$type.inc.php");
		}

		@$obj =& NewADOConnection($type);
		if (!is_object($obj)) {
			$obj =& new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
			return $obj;
		}
		if (is_array($options)) {
			foreach($options as $k => $v) {
				switch(strtolower($k)) {
				case 'persist':
				case 'persistent': 	$persist = $v; break;
				#ibase
				case 'dialect': 	$obj->dialect = $v; break;
				case 'charset':		$obj->charset = $v; break;
				case 'buffers':		$obj->buffers = $v; break;
				#ado
				case 'charpage':	$obj->charPage = $v; break;
				#mysql
				case 'clientflags': $obj->clientFlags = $v; break;
				}
			}
		} else {
		   	$persist = false;
		}

		if (isset($dsninfo['socket'])) $dsninfo['hostspec'] .= ':'.$dsninfo['socket'];
		else if (isset($dsninfo['port'])) $dsninfo['hostspec'] .= ':'.$dsninfo['port'];
		
		if($persist) $ok = $obj->PConnect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
		else  $ok = $obj->Connect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
		
		if (!$ok) $obj = ADODB_PEAR_Error();
		return $obj;
	}

	/**
	 * Return the DB API version
	 *
	 * @return int the DB API version number
	 */
	function apiVersion()
	{
		return 2;
	}

	/**
	 * Tell whether a result code from a DB method is an error
	 *
	 * @param $value int result code
	 *
	 * @return bool whether $value is an error
	 */
	function isError($value)
	{
		if (!is_object($value)) return false;
		$class = strtolower(get_class($value));
		return $class == 'pear_error' || is_subclass_of($value, 'pear_error') || 
				$class == 'db_error' || is_subclass_of($value, 'db_error');
	}


	/**
	 * Tell whether a result code from a DB method is a warning.
	 * Warnings differ from errors in that they are generated by DB,
	 * and are not fatal.
	 *
	 * @param $value mixed result value
	 *
	 * @return bool whether $value is a warning
	 */
	function isWarning($value)
	{
		return false;
		/*
		return is_object($value) &&
			(get_class( $value ) == "db_warning" ||
			 is_subclass_of($value, "db_warning"));*/
	}

	/**
	 * Parse a data source name
	 *
	 * @param $dsn string Data Source Name to be parsed
	 *
	 * @return array an associative array with the following keys:
	 *
	 *  phptype: Database backend used in PHP (mysql, odbc etc.)
	 *  dbsyntax: Database used with regards to SQL syntax etc.
	 *  protocol: Communication protocol to use (tcp, unix etc.)
	 *  hostspec: Host specification (hostname[:port])
	 *  database: Database to use on the DBMS server
	 *  username: User name for login
	 *  password: Password for login
	 *
	 * The format of the supplied DSN is in its fullest form:
	 *
	 *  phptype(dbsyntax)://username:password@protocol+hostspec/database
	 *
	 * Most variations are allowed:
	 *
	 *  phptype://username:password@protocol+hostspec:110//usr/db_file.db
	 *  phptype://username:password@hostspec/database_name
	 *  phptype://username:password@hostspec
	 *  phptype://username@hostspec
	 *  phptype://hostspec/database
	 *  phptype://hostspec
	 *  phptype(dbsyntax)
	 *  phptype
	 *
	 * @author Tomas V.V.Cox <cox@idecnet.com>
	 */
	function parseDSN($dsn)
	{
		if (is_array($dsn)) {
			return $dsn;
		}

		$parsed = array(
			'phptype'  => false,
			'dbsyntax' => false,
			'protocol' => false,
			'hostspec' => false,
			'database' => false,
			'username' => false,
			'password' => false
		);

		// Find phptype and dbsyntax
		if (($pos = strpos($dsn, '://')) !== false) {
			$str = substr($dsn, 0, $pos);
			$dsn = substr($dsn, $pos + 3);
		} else {
			$str = $dsn;
			$dsn = NULL;
		}

		// Get phptype and dbsyntax
		// $str => phptype(dbsyntax)
		if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
			$parsed['phptype'] = $arr[1];
			$parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : $arr[2];
		} else {
			$parsed['phptype'] = $str;
			$parsed['dbsyntax'] = $str;
		}

		if (empty($dsn)) {
			return $parsed;
		}

		// Get (if found): username and password
		// $dsn => username:password@protocol+hostspec/database
		if (($at = strpos($dsn,'@')) !== false) {
			$str = substr($dsn, 0, $at);
			$dsn = substr($dsn, $at + 1);
			if (($pos = strpos($str, ':')) !== false) {
				$parsed['username'] = urldecode(substr($str, 0, $pos));
				$parsed['password'] = urldecode(substr($str, $pos + 1));
			} else {
				$parsed['username'] = urldecode($str);
			}
		}

		// Find protocol and hostspec
		// $dsn => protocol+hostspec/database
		if (($pos=strpos($dsn, '/')) !== false) {
			$str = substr($dsn, 0, $pos);
			$dsn = substr($dsn, $pos + 1);
		} else {
			$str = $dsn;
			$dsn = NULL;
		}

		// Get protocol + hostspec
		// $str => protocol+hostspec
		if (($pos=strpos($str, '+')) !== false) {
			$parsed['protocol'] = substr($str, 0, $pos);
			$parsed['hostspec'] = urldecode(substr($str, $pos + 1));
		} else {
			$parsed['hostspec'] = urldecode($str);
		}

		// Get dabase if any
		// $dsn => database
		if (!empty($dsn)) {
			$parsed['database'] = $dsn;
		}

		return $parsed;
	}

	/**
	 * Load a PHP database extension if it is not loaded already.
	 *
	 * @access public
	 *
	 * @param $name the base name of the extension (without the .so or
	 * .dll suffix)
	 *
	 * @return bool true if the extension was already or successfully
	 * loaded, false if it could not be loaded
	 */
	function assertExtension($name)
	{
		if (!extension_loaded($name)) {
			$dlext = (strncmp(PHP_OS,'WIN',3) === 0) ? '.dll' : '.so';
			@dl($name . $dlext);
		}
		if (!extension_loaded($name)) {
			return false;
		}
		return true;
	}
}

?>

Added program_files/include/adodb4/adodb-perf.inc.php.

































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
<?php
/* 
v4.992 10 Nov 2009  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  Released under both BSD license and Lesser GPL library license. 
  Whenever there is any discrepancy between the two licenses, 
  the BSD license will take precedence. See License.txt. 
  Set tabs to 4 for best viewing.
  
  Latest version is available at http://adodb.sourceforge.net
  
  Library for basic performance monitoring and tuning.
  
  My apologies if you see code mixed with presentation. The presentation suits
  my needs. If you want to separate code from presentation, be my guest. Patches
  are welcome.
  
*/

if (!defined('ADODB_DIR')) include_once(dirname(__FILE__).'/adodb.inc.php');
include_once(ADODB_DIR.'/tohtml.inc.php');

global $ADODB_PERF_MIN;
$ADODB_PERF_MIN = 0.05; // log only if >= minimum number of secs to run

define( 'ADODB_OPT_HIGH', 2);
define( 'ADODB_OPT_LOW', 1);

// returns in K the memory of current process, or 0 if not known
function adodb_getmem()
{
	if (function_exists('memory_get_usage'))
		return (integer) ((memory_get_usage()+512)/1024);
	
	$pid = getmypid();
	
	if ( strncmp(strtoupper(PHP_OS),'WIN',3)==0) {
		$output = array();
	
		exec('tasklist /FI "PID eq ' . $pid. '" /FO LIST', $output); 
		return substr($output[5], strpos($output[5], ':') + 1);
	} 
	
	/* Hopefully UNIX */
	exec("ps --pid $pid --no-headers -o%mem,size", $output);
	if (sizeof($output) == 0) return 0;
	
	$memarr = explode(' ',$output[0]);
	if (sizeof($memarr)>=2) return (integer) $memarr[1];
	
	return 0;
}

// avoids localization problems where , is used instead of .
function adodb_round($n,$prec)
{
	return number_format($n, $prec, '.', '');
}

/* return microtime value as a float */
function adodb_microtime()
{
	$t = microtime();
	$t = explode(' ',$t);
	return (float)$t[1]+ (float)$t[0];
}

/* sql code timing */
function& adodb_log_sql(&$connx,$sql,$inputarr)
{
    $perf_table = adodb_perf::table();
	$connx->fnExecute = false;
	$t0 = microtime();
	$rs =& $connx->Execute($sql,$inputarr);
	$t1 = microtime();

	if (!empty($connx->_logsql) && (empty($connx->_logsqlErrors) || !$rs)) {
	global $ADODB_LOG_CONN;
	
		if (!empty($ADODB_LOG_CONN)) {
			$conn = &$ADODB_LOG_CONN;
			if ($conn->databaseType != $connx->databaseType)
				$prefix = '/*dbx='.$connx->databaseType .'*/ ';
			else
				$prefix = '';
		} else {
			$conn =& $connx;
			$prefix = '';
		}
		
		$conn->_logsql = false; // disable logsql error simulation
		$dbT = $conn->databaseType;
		
		$a0 = split(' ',$t0);
		$a0 = (float)$a0[1]+(float)$a0[0];
		
		$a1 = split(' ',$t1);
		$a1 = (float)$a1[1]+(float)$a1[0];
		
		$time = $a1 - $a0;
	
		if (!$rs) {
			$errM = $connx->ErrorMsg();
			$errN = $connx->ErrorNo();
			$conn->lastInsID = 0;
			$tracer = substr('ERROR: '.htmlspecialchars($errM),0,250);
		} else {
			$tracer = '';
			$errM = '';
			$errN = 0;
			$dbg = $conn->debug;
			$conn->debug = false;
			if (!is_object($rs) || $rs->dataProvider == 'empty') 
				$conn->_affected = $conn->affected_rows(true);
			$conn->lastInsID = @$conn->Insert_ID();
			$conn->debug = $dbg;
		}
		if (isset($_SERVER['HTTP_HOST'])) {
			$tracer .= '<br>'.$_SERVER['HTTP_HOST'];
			if (isset($_SERVER['PHP_SELF'])) $tracer .= htmlspecialchars($_SERVER['PHP_SELF']);
		} else 
			if (isset($_SERVER['PHP_SELF'])) $tracer .= '<br>'.htmlspecialchars($_SERVER['PHP_SELF']);
		//$tracer .= (string) adodb_backtrace(false);
		
		$tracer = (string) substr($tracer,0,500);
		
		if (is_array($inputarr)) {
			if (is_array(reset($inputarr))) $params = 'Array sizeof='.sizeof($inputarr);
			else {
				// Quote string parameters so we can see them in the
				// performance stats. This helps spot disabled indexes.
				$xar_params = $inputarr;
				foreach ($xar_params as $xar_param_key => $xar_param) {
					if (gettype($xar_param) == 'string')
					$xar_params[$xar_param_key] = '"' . $xar_param . '"';
				}
				$params = implode(', ', $xar_params);
				if (strlen($params) >= 3000) $params = substr($params, 0, 3000);
			}
		} else {
			$params = '';
		}
		
		if (is_array($sql)) $sql = $sql[0];
		if ($prefix) $sql = $prefix.$sql;
		$arr = array('b'=>strlen($sql).'.'.crc32($sql),
					'c'=>substr($sql,0,3900), 'd'=>$params,'e'=>$tracer,'f'=>adodb_round($time,6));
		//var_dump($arr);
		$saved = $conn->debug;
		$conn->debug = 0;
		
		$d = $conn->sysTimeStamp;
		if (empty($d)) $d = date("'Y-m-d H:i:s'");
		if ($conn->dataProvider == 'oci8' && $dbT != 'oci8po') {
			$isql = "insert into $perf_table values($d,:b,:c,:d,:e,:f)";
		} else if ($dbT == 'odbc_mssql' || $dbT == 'informix' || strncmp($dbT,'odbtp',4)==0) {
			$timer = $arr['f'];
			if ($dbT == 'informix') $sql2 = substr($sql2,0,230);

			$sql1 = $conn->qstr($arr['b']);
			$sql2 = $conn->qstr($arr['c']);
			$params = $conn->qstr($arr['d']);
			$tracer = $conn->qstr($arr['e']);
			
			$isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values($d,$sql1,$sql2,$params,$tracer,$timer)";
			if ($dbT == 'informix') $isql = str_replace(chr(10),' ',$isql);
			$arr = false;
		} else {
			if ($dbT == 'db2') $arr['f'] = (float) $arr['f'];
			$isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values( $d,?,?,?,?,?)";
		}
		global $ADODB_PERF_MIN;
		if ($errN != 0 || $time >= $ADODB_PERF_MIN) {
			$ok = $conn->Execute($isql,$arr);
		} else {
			$ok = true;
		}
		$conn->debug = $saved;
		
		if ($ok) {
			$conn->_logsql = true; 
		} else {
			$err2 = $conn->ErrorMsg();
			$conn->_logsql = true; // enable logsql error simulation
			$perf =& NewPerfMonitor($conn);
			if ($perf) {
				if ($perf->CreateLogTable()) $ok = $conn->Execute($isql,$arr);
			} else {
				$ok = $conn->Execute("create table $perf_table (
				created varchar(50),
				sql0 varchar(250), 
				sql1 varchar(4000),
				params varchar(3000),
				tracer varchar(500),
				timer decimal(16,6))");
			}
			if (!$ok) {
				ADOConnection::outp( "<p><b>LOGSQL Insert Failed</b>: $isql<br>$err2</p>");
				$conn->_logsql = false;
			}
		}
		$connx->_errorMsg = $errM;
		$connx->_errorCode = $errN;
	} 
	$connx->fnExecute = 'adodb_log_sql';
	return $rs;
}

	
/*
The settings data structure is an associative array that database parameter per element.

Each database parameter element in the array is itself an array consisting of:

0: category code, used to group related db parameters
1: either
	a. sql string to retrieve value, eg. "select value from v\$parameter where name='db_block_size'", 
	b. array holding sql string and field to look for, e.g. array('show variables','table_cache'),
	c. a string prefixed by =, then a PHP method of the class is invoked, 
		e.g. to invoke $this->GetIndexValue(), set this array element to '=GetIndexValue',
2: description of the database parameter
*/

class adodb_perf {
	var $conn;
	var $color = '#F0F0F0';
	var $table = '<table border=1 bgcolor=white>';
	var $titles = '<tr><td><b>Parameter</b></td><td><b>Value</b></td><td><b>Description</b></td></tr>';
	var $warnRatio = 90;
	var $tablesSQL = false;
	var $cliFormat = "%32s => %s \r\n";
	var $sql1 = 'sql1';  // used for casting sql1 to text for mssql
	var $explain = true;
	var $helpurl = "<a href=http://phplens.com/adodb/reference.functions.fnexecute.and.fncacheexecute.properties.html#logsql>LogSQL help</a>";
	var $createTableSQL = false;
	var $maxLength = 2000;
	
    // Sets the tablename to be used            
    function table($newtable = false)
    {
        static $_table;

        if (!empty($newtable))  $_table = $newtable;
		if (empty($_table)) $_table = 'adodb_logsql';
        return $_table;
    }

	// returns array with info to calculate CPU Load
	function _CPULoad()
	{
/*

cpu  524152 2662 2515228 336057010
cpu0 264339 1408 1257951 168025827
cpu1 259813 1254 1257277 168031181
page 622307 25475680
swap 24 1891
intr 890153570 868093576 6 0 4 4 0 6 1 2 0 0 0 124 0 8098760 2 13961053 0 0 0 0 0 0 0 0 0 0 0 0 0 16 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
disk_io: (3,0):(3144904,54369,610378,3090535,50936192) (3,1):(3630212,54097,633016,3576115,50951320)
ctxt 66155838
btime 1062315585
processes 69293

*/
		// Algorithm is taken from
		// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/example__obtaining_raw_performance_data.asp
		if (strncmp(PHP_OS,'WIN',3)==0) {
			if (PHP_VERSION == '5.0.0') return false;
			if (PHP_VERSION == '5.0.1') return false;
			if (PHP_VERSION == '5.0.2') return false;
			if (PHP_VERSION == '5.0.3') return false;
			if (PHP_VERSION == '4.3.10') return false; # see http://bugs.php.net/bug.php?id=31737
			
			@$c = new COM("WinMgmts:{impersonationLevel=impersonate}!Win32_PerfRawData_PerfOS_Processor.Name='_Total'");
			if (!$c) return false;
			
			$info[0] = $c->PercentProcessorTime;
			$info[1] = 0;
			$info[2] = 0;
			$info[3] = $c->TimeStamp_Sys100NS;
			//print_r($info);
			return $info;
		}
		
		// Algorithm - Steve Blinch (BlitzAffe Online, http://www.blitzaffe.com)
		$statfile = '/proc/stat';
		if (!file_exists($statfile)) return false;
		
		$fd = fopen($statfile,"r");
		if (!$fd) return false;
		
		$statinfo = explode("\n",fgets($fd, 1024));
		fclose($fd);
		foreach($statinfo as $line) {
			$info = explode(" ",$line);
			if($info[0]=="cpu") {
				array_shift($info);  // pop off "cpu"
				if(!$info[0]) array_shift($info); // pop off blank space (if any)
				return $info;
			}
		}
		
		return false;
		
	}
	
	/* NOT IMPLEMENTED */
	function MemInfo()
	{
		/*

        total:    used:    free:  shared: buffers:  cached:
Mem:  1055289344 917299200 137990144        0 165437440 599773184
Swap: 2146775040 11055104 2135719936
MemTotal:      1030556 kB
MemFree:        134756 kB
MemShared:           0 kB
Buffers:        161560 kB
Cached:         581384 kB
SwapCached:       4332 kB
Active:         494468 kB
Inact_dirty:    322856 kB
Inact_clean:     24256 kB
Inact_target:   168316 kB
HighTotal:      131064 kB
HighFree:         1024 kB
LowTotal:       899492 kB
LowFree:        133732 kB
SwapTotal:     2096460 kB
SwapFree:      2085664 kB
Committed_AS:   348732 kB
		*/
	}
	
	
	/*
		Remember that this is client load, not db server load!
	*/
	var $_lastLoad;
	function CPULoad()
	{
		$info = $this->_CPULoad();
		if (!$info) return false;
			
		if (empty($this->_lastLoad)) {
			sleep(1);
			$this->_lastLoad = $info;
			$info = $this->_CPULoad();
		}
		
		$last = $this->_lastLoad;
		$this->_lastLoad = $info;
		
		$d_user = $info[0] - $last[0];
		$d_nice = $info[1] - $last[1];
		$d_system = $info[2] - $last[2];
		$d_idle = $info[3] - $last[3];
		
		//printf("Delta - User: %f  Nice: %f  System: %f  Idle: %f<br>",$d_user,$d_nice,$d_system,$d_idle);

		if (strncmp(PHP_OS,'WIN',3)==0) {
			if ($d_idle < 1) $d_idle = 1;
			return 100*(1-$d_user/$d_idle);
		}else {
			$total=$d_user+$d_nice+$d_system+$d_idle;
			if ($total<1) $total=1;
			return 100*($d_user+$d_nice+$d_system)/$total; 
		}
	}
	
	function Tracer($sql)
	{
        $perf_table = adodb_perf::table();
		$saveE = $this->conn->fnExecute;
		$this->conn->fnExecute = false;
		
		global $ADODB_FETCH_MODE;
		$save = $ADODB_FETCH_MODE;
		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
		if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
				
		$sqlq = $this->conn->qstr($sql);
		$arr = $this->conn->GetArray(
"select count(*),tracer 
	from $perf_table where sql1=$sqlq 
	group by tracer
	order by 1 desc");
		$s = '';
		if ($arr) {
			$s .= '<h3>Scripts Affected</h3>';
			foreach($arr as $k) {
				$s .= sprintf("%4d",$k[0]).' &nbsp; '.strip_tags($k[1]).'<br>';
			}
		}
		
		if (isset($savem)) $this->conn->SetFetchMode($savem);
		$ADODB_CACHE_MODE = $save;
		$this->conn->fnExecute = $saveE;
		return $s;
	}

	/* 
		Explain Plan for $sql.
		If only a snippet of the $sql is passed in, then $partial will hold the crc32 of the 
			actual sql.
	*/
	function Explain($sql,$partial=false)
	{	
		return false;
	}
	
	function InvalidSQL($numsql = 10)
	{
	
		if (isset($_GET['sql'])) return;
		$s = '<h3>Invalid SQL</h3>';
		$saveE = $this->conn->fnExecute;
		$this->conn->fnExecute = false;
        $perf_table = adodb_perf::table();
		$rs =& $this->conn->SelectLimit("select distinct count(*),sql1,tracer as error_msg from $perf_table where tracer like 'ERROR:%' group by sql1,tracer order by 1 desc",$numsql);//,$numsql);
		$this->conn->fnExecute = $saveE;
		if ($rs) {
			$s .= rs2html($rs,false,false,false,false);
		} else
			return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
		
		return $s;
	}

	
	/*
		This script identifies the longest running SQL
	*/	
	function _SuspiciousSQL($numsql = 10)
	{
		global $ADODB_FETCH_MODE;
		
            $perf_table = adodb_perf::table();
			$saveE = $this->conn->fnExecute;
			$this->conn->fnExecute = false;
			
			if (isset($_GET['exps']) && isset($_GET['sql'])) {
				$partial = !empty($_GET['part']);
				echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
			}
			
			if (isset($_GET['sql'])) return;
			$sql1 = $this->sql1;
			
			$save = $ADODB_FETCH_MODE;
			$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
			if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
			//$this->conn->debug=1;
			$rs =& $this->conn->SelectLimit(
			"select avg(timer) as avg_timer,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
				from $perf_table
				where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT')
				and (tracer is null or tracer not like 'ERROR:%')
				group by sql1
				order by 1 desc",$numsql);
			if (isset($savem)) $this->conn->SetFetchMode($savem);
			$ADODB_FETCH_MODE = $save;
			$this->conn->fnExecute = $saveE;
			
			if (!$rs) return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
			$s = "<h3>Suspicious SQL</h3>
<font size=1>The following SQL have high average execution times</font><br>
<table border=1 bgcolor=white><tr><td><b>Avg Time</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
			$max = $this->maxLength;
			while (!$rs->EOF) {
				$sql = $rs->fields[1];
				$raw = urlencode($sql);
				if (strlen($raw)>$max-100) {
					$sql2 = substr($sql,0,$max-500);
					$raw = urlencode($sql2).'&part='.crc32($sql);
				}
				$prefix = "<a target=sql".rand()." href=\"?hidem=1&exps=1&sql=".$raw."&x#explain\">";
				$suffix = "</a>";
				if ($this->explain == false || strlen($prefix)>$max) {
					$suffix = ' ... <i>String too long for GET parameter: '.strlen($prefix).'</i>';
					$prefix = '';
				}
				$s .= "<tr><td>".adodb_round($rs->fields[0],6)."<td align=right>".$rs->fields[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
					"<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
				$rs->MoveNext();
			}
			return $s."</table>";
		
	}
	
	function CheckMemory()
	{
		return '';
	}
	
	
	function SuspiciousSQL($numsql=10)
	{
		return adodb_perf::_SuspiciousSQL($numsql);
	}

	function ExpensiveSQL($numsql=10)
	{
		return adodb_perf::_ExpensiveSQL($numsql);
	}

	
	/*
		This reports the percentage of load on the instance due to the most 
		expensive few SQL statements. Tuning these statements can often 
		make huge improvements in overall system performance. 
	*/
	function _ExpensiveSQL($numsql = 10)
	{
		global $ADODB_FETCH_MODE;
		
            $perf_table = adodb_perf::table();
			$saveE = $this->conn->fnExecute;
			$this->conn->fnExecute = false;
			
			if (isset($_GET['expe']) && isset($_GET['sql'])) {
				$partial = !empty($_GET['part']);
				echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
			}
			
			if (isset($_GET['sql'])) return;
			
			$sql1 = $this->sql1;
			$save = $ADODB_FETCH_MODE;
			$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
			if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
			
			$rs =& $this->conn->SelectLimit(
			"select sum(timer) as total,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
				from $perf_table
				where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5))  not in ('DROP ','INSER','COMMI','CREAT')
				and (tracer is null or tracer not like 'ERROR:%')
				group by sql1
				having count(*)>1
				order by 1 desc",$numsql);
			if (isset($savem)) $this->conn->SetFetchMode($savem);
			$this->conn->fnExecute = $saveE;
			$ADODB_FETCH_MODE = $save;
			if (!$rs) return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
			$s = "<h3>Expensive SQL</h3>
<font size=1>Tuning the following SQL could reduce the server load substantially</font><br>
<table border=1 bgcolor=white><tr><td><b>Load</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
			$max = $this->maxLength;
			while (!$rs->EOF) {
				$sql = $rs->fields[1];
				$raw = urlencode($sql);
				if (strlen($raw)>$max-100) {
					$sql2 = substr($sql,0,$max-500);
					$raw = urlencode($sql2).'&part='.crc32($sql);
				}
				$prefix = "<a target=sqle".rand()." href=\"?hidem=1&expe=1&sql=".$raw."&x#explain\">";
				$suffix = "</a>";
				if($this->explain == false || strlen($prefix>$max)) {
					$prefix = '';
					$suffix = '';
				}
				$s .= "<tr><td>".adodb_round($rs->fields[0],6)."<td align=right>".$rs->fields[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
					"<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
				$rs->MoveNext();
			}
			return $s."</table>";
	}
	
	/*
		Raw function to return parameter value from $settings.
	*/
	function DBParameter($param)
	{
		if (empty($this->settings[$param])) return false;
		$sql = $this->settings[$param][1];
		return $this->_DBParameter($sql);
	}
	
	/*
		Raw function returning array of poll paramters
	*/
	function &PollParameters()
	{
		$arr[0] = (float)$this->DBParameter('data cache hit ratio');
		$arr[1] = (float)$this->DBParameter('data reads');
		$arr[2] = (float)$this->DBParameter('data writes');
		$arr[3] = (integer) $this->DBParameter('current connections');
		return $arr;
	}
	
	/*
		Low-level Get Database Parameter
	*/
	function _DBParameter($sql)
	{
		$savelog = $this->conn->LogSQL(false);
		if (is_array($sql)) {
		global $ADODB_FETCH_MODE;
		
			$sql1 = $sql[0];
			$key = $sql[1];
			if (sizeof($sql)>2) $pos = $sql[2];
			else $pos = 1;
			if (sizeof($sql)>3) $coef = $sql[3];
			else $coef = false;
			$ret = false;
			$save = $ADODB_FETCH_MODE;
			$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
			if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
			
			$rs = $this->conn->Execute($sql1);
			
			if (isset($savem)) $this->conn->SetFetchMode($savem);
			$ADODB_FETCH_MODE = $save;
			if ($rs) {
				while (!$rs->EOF) {
					$keyf = reset($rs->fields);
					if (trim($keyf) == $key) {
						$ret = $rs->fields[$pos];
						if ($coef) $ret *= $coef;
						break;
					}
					$rs->MoveNext();
				}
				$rs->Close();
			}
			$this->conn->LogSQL($savelog);
			return $ret;
		} else {
			if (strncmp($sql,'=',1) == 0) {
				$fn = substr($sql,1);
				return $this->$fn();
			}
			$sql = str_replace('$DATABASE',$this->conn->database,$sql);
			$ret = $this->conn->GetOne($sql);
			$this->conn->LogSQL($savelog);
			
			return $ret;
		}
	}
	
	/*
		Warn if cache ratio falls below threshold. Displayed in "Description" column.
	*/
	function WarnCacheRatio($val)
	{
		if ($val < $this->warnRatio) 
			 return '<font color=red><b>Cache ratio should be at least '.$this->warnRatio.'%</b></font>';
		else return '';
	}
	
	function clearsql()
	{
		$perf_table = adodb_perf::table();
		$this->conn->Execute("delete from $perf_table where created<".$this->conn->sysTimeStamp);
	}
	
	/***********************************************************************************************/
	//                                    HIGH LEVEL UI FUNCTIONS
	/***********************************************************************************************/
	
	
	function UI($pollsecs=5)
	{
	global $ADODB_LOG_CONN;
	
    $perf_table = adodb_perf::table();
	$conn = $this->conn;
	
	$app = $conn->host;
	if ($conn->host && $conn->database) $app .= ', db=';
	$app .= $conn->database;
	
	if ($app) $app .= ', ';
	$savelog = $this->conn->LogSQL(false);	
	$info = $conn->ServerInfo();
	if (isset($_GET['clearsql'])) {
		$this->clearsql();
	}
	$this->conn->LogSQL($savelog);
	
	// magic quotes
	
	if (isset($_GET['sql']) && get_magic_quotes_gpc()) {
		$_GET['sql'] = $_GET['sql'] = str_replace(array("\\'",'\"'),array("'",'"'),$_GET['sql']);
	}
	
	if (!isset($_SESSION['ADODB_PERF_SQL'])) $nsql = $_SESSION['ADODB_PERF_SQL'] = 10;
	else  $nsql = $_SESSION['ADODB_PERF_SQL'];
	
	$app .= $info['description'];
	
	
	if (isset($_GET['do'])) $do = $_GET['do'];
	else if (isset($_POST['do'])) $do = $_POST['do'];
	 else if (isset($_GET['sql'])) $do = 'viewsql';
	 else $do = 'stats';
	 
	if (isset($_GET['nsql'])) {
		if ($_GET['nsql'] > 0) $nsql = $_SESSION['ADODB_PERF_SQL'] = (integer) $_GET['nsql'];
	}
	echo "<title>ADOdb Performance Monitor on $app</title><body bgcolor=white>";
	if ($do == 'viewsql') $form = "<td><form># SQL:<input type=hidden value=viewsql name=do> <input type=text size=4 name=nsql value=$nsql><input type=submit value=Go></td></form>";
	else $form = "<td>&nbsp;</td>";
	
	$allowsql = !defined('ADODB_PERF_NO_RUN_SQL');
	global $ADODB_PERF_MIN;
	$app .= " (Min sql timing \$ADODB_PERF_MIN=$ADODB_PERF_MIN secs)";
	
	if  (empty($_GET['hidem']))
	echo "<table border=1 width=100% bgcolor=lightyellow><tr><td colspan=2>
	<b><a href=http://adodb.sourceforge.net/?perf=1>ADOdb</a> Performance Monitor</b> <font size=1>for $app</font></tr><tr><td>
	<a href=?do=stats><b>Performance Stats</b></a> &nbsp; <a href=?do=viewsql><b>View SQL</b></a>
	 &nbsp; <a href=?do=tables><b>View Tables</b></a> &nbsp; <a href=?do=poll><b>Poll Stats</b></a>",
	 $allowsql ? ' &nbsp; <a href=?do=dosql><b>Run SQL</b></a>' : '',
	 "$form",
	 "</tr></table>";

	 
	 	switch ($do) {
		default:
		case 'stats':
		
			if (empty($ADODB_LOG_CONN))
				echo "<p>&nbsp; <a href=\"?do=viewsql&clearsql=1\">Clear SQL Log</a><br>";
			echo $this->HealthCheck();
			//$this->conn->debug=1;
			echo $this->CheckMemory();
			global $ADODB_LOG_CONN;
			break;
		case 'poll':
			$self = htmlspecialchars($_SERVER['PHP_SELF']);
			echo "<iframe width=720 height=80% 
				src=\"{$self}?do=poll2&hidem=1\"></iframe>";
			break;
		case 'poll2':
			echo "<pre>";
			$this->Poll($pollsecs);
			break;
		
		case 'dosql':
			if (!$allowsql) break;
			
			$this->DoSQLForm();
			break;
		case 'viewsql':
			if (empty($_GET['hidem']))
				echo "&nbsp; <a href=\"?do=viewsql&clearsql=1\">Clear SQL Log</a><br>";
			echo($this->SuspiciousSQL($nsql));
			echo($this->ExpensiveSQL($nsql));
			echo($this->InvalidSQL($nsql));
			break;
		case 'tables': 
			echo $this->Tables(); break;
		}
		global $ADODB_vers;
		echo "<p><div align=center><font size=1>$ADODB_vers Sponsored by <a href=http://phplens.com/>phpLens</a></font></div>";
	}
	
	/*
		Runs in infinite loop, returning real-time statistics
	*/
	function Poll($secs=5)
	{
		$this->conn->fnExecute = false;
		//$this->conn->debug=1;
		if ($secs <= 1) $secs = 1;
		echo "Accumulating statistics, every $secs seconds...\n";flush();
		$arro =& $this->PollParameters();
		$cnt = 0;
		set_time_limit(0);
		sleep($secs);
		while (1) {

			$arr =& $this->PollParameters();
			
			$hits   = sprintf('%2.2f',$arr[0]);
			$reads  = sprintf('%12.4f',($arr[1]-$arro[1])/$secs);
			$writes = sprintf('%12.4f',($arr[2]-$arro[2])/$secs);
			$sess = sprintf('%5d',$arr[3]);
			
			$load = $this->CPULoad();
			if ($load !== false) {
				$oslabel = 'WS-CPU%';
				$osval = sprintf(" %2.1f  ",(float) $load);
			}else {
				$oslabel = '';
				$osval = '';
			}
			if ($cnt % 10 == 0) echo " Time   ".$oslabel."   Hit%   Sess           Reads/s          Writes/s\n"; 
			$cnt += 1;
			echo date('H:i:s').'  '.$osval."$hits  $sess $reads $writes\n";
			flush();
			
			if (connection_aborted()) return;
			
			sleep($secs);
			$arro = $arr;
		}
	}
	
	/*
		Returns basic health check in a command line interface
	*/
	function HealthCheckCLI()
	{
		return $this->HealthCheck(true);
	}
	
		
	/*
		Returns basic health check as HTML
	*/
	function HealthCheck($cli=false)
	{
		$saveE = $this->conn->fnExecute;
		$this->conn->fnExecute = false;	
		if ($cli) $html = '';
		else $html = $this->table.'<tr><td colspan=3><h3>'.$this->conn->databaseType.'</h3></td></tr>'.$this->titles;
		
		$oldc = false;
		$bgc = '';
		foreach($this->settings as $name => $arr) {
			if ($arr === false) break;
			
			if (!is_string($name)) {
				if ($cli) $html .= " -- $arr -- \n";
				else $html .= "<tr bgcolor=$this->color><td colspan=3><i>$arr</i> &nbsp;</td></tr>";
				continue;
			}
			
			if (!is_array($arr)) break;
			$category = $arr[0];
			$how = $arr[1];
			if (sizeof($arr)>2) $desc = $arr[2];
			else $desc = ' &nbsp; ';
			
			
			if ($category == 'HIDE') continue;
			
			$val = $this->_DBParameter($how);
			
			if ($desc && strncmp($desc,"=",1) === 0) {
				$fn = substr($desc,1);
				$desc = $this->$fn($val);
			}
			
			if ($val === false) {
				$m = $this->conn->ErrorMsg();
				$val = "Error: $m"; 
			} else {
				if (is_numeric($val) && $val >= 256*1024) {
					if ($val % (1024*1024) == 0) {
						$val /= (1024*1024);
						$val .= 'M';
					} else if ($val % 1024 == 0) {
						$val /= 1024;
						$val .= 'K';
					}
					//$val = htmlspecialchars($val);
				}
			}
			if ($category != $oldc) {
				$oldc = $category;
				//$bgc = ($bgc == ' bgcolor='.$this->color) ? ' bgcolor=white' : ' bgcolor='.$this->color;
			}
			if (strlen($desc)==0) $desc = '&nbsp;';
			if (strlen($val)==0) $val = '&nbsp;';
			if ($cli) {
				$html  .= str_replace('&nbsp;','',sprintf($this->cliFormat,strip_tags($name),strip_tags($val),strip_tags($desc)));
				
			}else {
				$html .= "<tr$bgc><td>".$name.'</td><td>'.$val.'</td><td>'.$desc."</td></tr>\n";
			}
		}
		
		if (!$cli) $html .= "</table>\n";
		$this->conn->fnExecute = $saveE;
			
		return $html;	
	}
	
	function Tables($orderby='1')
	{
		if (!$this->tablesSQL) return false;
		
		$savelog = $this->conn->LogSQL(false);
		$rs = $this->conn->Execute($this->tablesSQL.' order by '.$orderby);
		$this->conn->LogSQL($savelog);
		$html = rs2html($rs,false,false,false,false);
		return $html;
	}
	

	function CreateLogTable()
	{
		if (!$this->createTableSQL) return false;
		
		$table = $this->table();
		$sql = str_replace('adodb_logsql',$table,$this->createTableSQL);
		$savelog = $this->conn->LogSQL(false);
		$ok = $this->conn->Execute($sql);
		$this->conn->LogSQL($savelog);
		return ($ok) ? true : false;
	}
	
	function DoSQLForm()
	{
		$PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']);
		$sql = isset($_REQUEST['sql']) ? $_REQUEST['sql'] : '';

		if (isset($_SESSION['phplens_sqlrows'])) $rows = $_SESSION['phplens_sqlrows'];
		else $rows = 3;
		
		if (isset($_REQUEST['SMALLER'])) {
			$rows /= 2;
			if ($rows < 3) $rows = 3;
			$_SESSION['phplens_sqlrows'] = $rows;
		}
		if (isset($_REQUEST['BIGGER'])) {
			$rows *= 2;
			$_SESSION['phplens_sqlrows'] = $rows;
		}
		
?>

<form method="POST" action="<?php echo $PHP_SELF ?>">
<table><tr>
<td> Form size: <input type="submit" value=" &lt; " name="SMALLER"><input type="submit" value=" &gt; &gt; " name="BIGGER">
</td>
<td align=right>
<input type="submit" value=" Run SQL Below " name="RUN"><input type=hidden name=do value=dosql>
</td></tr>
  <tr>
  <td colspan=2><textarea rows=<?php print $rows; ?> name="sql" cols="80"><?php print htmlspecialchars($sql) ?></textarea>
  </td>
  </tr>
 </table>
</form>

<?php
		if (!isset($_REQUEST['sql'])) return;
		
		$sql = $this->undomq(trim($sql));
		if (substr($sql,strlen($sql)-1) === ';') {
			$print = true;
			$sqla = $this->SplitSQL($sql);
		} else  {
			$print = false;
			$sqla = array($sql);
		}
		foreach($sqla as $sqls) {

			if (!$sqls) continue;
			
			if ($print) {
				print "<p>".htmlspecialchars($sqls)."</p>";
				flush();
			}
			$savelog = $this->conn->LogSQL(false);
			$rs = $this->conn->Execute($sqls);
			$this->conn->LogSQL($savelog);
			if ($rs && is_object($rs) && !$rs->EOF) {
				rs2html($rs);
				while ($rs->NextRecordSet()) {
					print "<table width=98% bgcolor=#C0C0FF><tr><td>&nbsp;</td></tr></table>";
					rs2html($rs);
				}
			} else {
				$e1 = (integer) $this->conn->ErrorNo();
				$e2 = $this->conn->ErrorMsg();
				if (($e1) || ($e2)) {
					if (empty($e1)) $e1 = '-1'; // postgresql fix
					print ' &nbsp; '.$e1.': '.$e2;
				} else {
					print "<p>No Recordset returned<br></p>";
				}
			}
		} // foreach
	}
	
	function SplitSQL($sql)
	{
		$arr = explode(';',$sql);
		return $arr;
	}
	
	function undomq($m) 
	{
	if (get_magic_quotes_gpc()) {
		// undo the damage
		$m = str_replace('\\\\','\\',$m);
		$m = str_replace('\"','"',$m);
		$m = str_replace('\\\'','\'',$m);
	}
	return $m;
}

    
   /************************************************************************/
   
    /** 
     * Reorganise multiple table-indices/statistics/..
     * OptimizeMode could be given by last Parameter
     * 
     * @example
     *      <pre>
     *          optimizeTables( 'tableA');
     *      </pre>
     *      <pre>
     *          optimizeTables( 'tableA', 'tableB', 'tableC');
     *      </pre>
     *      <pre>
     *          optimizeTables( 'tableA', 'tableB', ADODB_OPT_LOW);
     *      </pre>
     * 
     * @param string table name of the table to optimize
     * @param int mode optimization-mode
     *      <code>ADODB_OPT_HIGH</code> for full optimization 
     *      <code>ADODB_OPT_LOW</code> for CPU-less optimization
     *      Default is LOW <code>ADODB_OPT_LOW</code> 
     * @author Markus Staab
     * @return Returns <code>true</code> on success and <code>false</code> on error
     */
    function OptimizeTables()
    {
        $args = func_get_args();
        $numArgs = func_num_args();
        
        if ( $numArgs == 0) return false;
        
        $mode = ADODB_OPT_LOW; 
        $lastArg = $args[ $numArgs - 1];
        if ( !is_string($lastArg)) {
            $mode = $lastArg;
            unset( $args[ $numArgs - 1]);
        }
        
        foreach( $args as $table) {
            $this->optimizeTable( $table, $mode);
        }
	}

    /** 
     * Reorganise the table-indices/statistics/.. depending on the given mode.
     * Default Implementation throws an error.
     * 
     * @param string table name of the table to optimize
     * @param int mode optimization-mode
     *      <code>ADODB_OPT_HIGH</code> for full optimization 
     *      <code>ADODB_OPT_LOW</code> for CPU-less optimization
     *      Default is LOW <code>ADODB_OPT_LOW</code> 
     * @author Markus Staab
     * @return Returns <code>true</code> on success and <code>false</code> on error
     */
    function OptimizeTable( $table, $mode = ADODB_OPT_LOW) 
    {
        ADOConnection::outp( sprintf( "<p>%s: '%s' not implemented for driver '%s'</p>", __CLASS__, __FUNCTION__, $this->conn->databaseType));
        return false;
    }
    
    /** 
     * Reorganise current database.
     * Default implementation loops over all <code>MetaTables()</code> and 
     * optimize each using <code>optmizeTable()</code>
     * 
     * @author Markus Staab
     * @return Returns <code>true</code> on success and <code>false</code> on error
     */
    function optimizeDatabase() 
    {
        $conn = $this->conn;
        if ( !$conn) return false;
        
        $tables = $conn->MetaTables( 'TABLES');
        if ( !$tables ) return false;

        foreach( $tables as $table) {
            if ( !$this->optimizeTable( $table)) {
                return false;
            }
        }
      
        return true;
    }
    // end hack 
}

?>

Added program_files/include/adodb4/adodb-php4.inc.php.

































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

/*
  v4.992 10 Nov 2009  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  Released under both BSD license and Lesser GPL library license. 
  Whenever there is any discrepancy between the two licenses, 
  the BSD license will take precedence.
  
  Set tabs to 4.
*/


class ADODB_BASE_RS {
}

?>

Added program_files/include/adodb4/adodb-time.inc.php.



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
<?php
/**
ADOdb Date Library, part of the ADOdb abstraction library
Download: http://phplens.com/phpeverywhere/

PHP native date functions use integer timestamps for computations.
Because of this, dates are restricted to the years 1901-2038 on Unix 
and 1970-2038 on Windows due to integer overflow for dates beyond 
those years. This library overcomes these limitations by replacing the 
native function's signed integers (normally 32-bits) with PHP floating 
point numbers (normally 64-bits).

Dates from 100 A.D. to 3000 A.D. and later
have been tested. The minimum is 100 A.D. as <100 will invoke the
2 => 4 digit year conversion. The maximum is billions of years in the 
future, but this is a theoretical limit as the computation of that year 
would take too long with the current implementation of adodb_mktime().

This library replaces native functions as follows:

<pre>	
	getdate()  with  adodb_getdate()
	date()     with  adodb_date() 
	gmdate()   with  adodb_gmdate()
	mktime()   with  adodb_mktime()
	gmmktime() with  adodb_gmmktime()
	strftime() with  adodb_strftime()
	strftime() with  adodb_gmstrftime()
</pre>
	
The parameters are identical, except that adodb_date() accepts a subset
of date()'s field formats. Mktime() will convert from local time to GMT, 
and date() will convert from GMT to local time, but daylight savings is 
not handled currently.

This library is independant of the rest of ADOdb, and can be used
as standalone code.

PERFORMANCE

For high speed, this library uses the native date functions where
possible, and only switches to PHP code when the dates fall outside 
the 32-bit signed integer range.

GREGORIAN CORRECTION

Pope Gregory shortened October of A.D. 1582 by ten days. Thursday, 
October 4, 1582 (Julian) was followed immediately by Friday, October 15, 
1582 (Gregorian). 

Since 0.06, we handle this correctly, so:

adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582) 
	== 24 * 3600 (1 day)

=============================================================================

COPYRIGHT

(c) 2003-2005 John Lim and released under BSD-style license except for code by 
jackbbs, which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year
and originally found at http://www.php.net/manual/en/function.mktime.php

=============================================================================

BUG REPORTS

These should be posted to the ADOdb forums at

	http://phplens.com/lens/lensforum/topics.php?id=4

=============================================================================

FUNCTION DESCRIPTIONS


** FUNCTION adodb_getdate($date=false)

Returns an array containing date information, as getdate(), but supports
dates greater than 1901 to 2038. The local date/time format is derived from a 
heuristic the first time adodb_getdate is called. 
	 
	 
** FUNCTION adodb_date($fmt, $timestamp = false)

Convert a timestamp to a formatted local date. If $timestamp is not defined, the
current timestamp is used. Unlike the function date(), it supports dates
outside the 1901 to 2038 range.

The format fields that adodb_date supports:

<pre>
	a - "am" or "pm" 
	A - "AM" or "PM" 
	d - day of the month, 2 digits with leading zeros; i.e. "01" to "31" 
	D - day of the week, textual, 3 letters; e.g. "Fri" 
	F - month, textual, long; e.g. "January" 
	g - hour, 12-hour format without leading zeros; i.e. "1" to "12" 
	G - hour, 24-hour format without leading zeros; i.e. "0" to "23" 
	h - hour, 12-hour format; i.e. "01" to "12" 
	H - hour, 24-hour format; i.e. "00" to "23" 
	i - minutes; i.e. "00" to "59" 
	j - day of the month without leading zeros; i.e. "1" to "31" 
	l (lowercase 'L') - day of the week, textual, long; e.g. "Friday"  
	L - boolean for whether it is a leap year; i.e. "0" or "1" 
	m - month; i.e. "01" to "12" 
	M - month, textual, 3 letters; e.g. "Jan" 
	n - month without leading zeros; i.e. "1" to "12" 
	O - Difference to Greenwich time in hours; e.g. "+0200" 
	Q - Quarter, as in 1, 2, 3, 4 
	r - RFC 2822 formatted date; e.g. "Thu, 21 Dec 2000 16:01:07 +0200" 
	s - seconds; i.e. "00" to "59" 
	S - English ordinal suffix for the day of the month, 2 characters; 
	   			i.e. "st", "nd", "rd" or "th" 
	t - number of days in the given month; i.e. "28" to "31"
	T - Timezone setting of this machine; e.g. "EST" or "MDT" 
	U - seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)  
	w - day of the week, numeric, i.e. "0" (Sunday) to "6" (Saturday) 
	Y - year, 4 digits; e.g. "1999" 
	y - year, 2 digits; e.g. "99" 
	z - day of the year; i.e. "0" to "365" 
	Z - timezone offset in seconds (i.e. "-43200" to "43200"). 
	   			The offset for timezones west of UTC is always negative, 
				and for those east of UTC is always positive. 
</pre>

Unsupported:
<pre>
	B - Swatch Internet time 
	I (capital i) - "1" if Daylight Savings Time, "0" otherwise.
	W - ISO-8601 week number of year, weeks starting on Monday 

</pre>


** FUNCTION adodb_date2($fmt, $isoDateString = false)
Same as adodb_date, but 2nd parameter accepts iso date, eg.

  adodb_date2('d-M-Y H:i','2003-12-25 13:01:34');

  
** FUNCTION adodb_gmdate($fmt, $timestamp = false)

Convert a timestamp to a formatted GMT date. If $timestamp is not defined, the
current timestamp is used. Unlike the function date(), it supports dates
outside the 1901 to 2038 range.


** FUNCTION adodb_mktime($hr, $min, $sec[, $month, $day, $year])

Converts a local date to a unix timestamp.  Unlike the function mktime(), it supports
dates outside the 1901 to 2038 range. All parameters are optional.


** FUNCTION adodb_gmmktime($hr, $min, $sec [, $month, $day, $year])

Converts a gmt date to a unix timestamp.  Unlike the function gmmktime(), it supports
dates outside the 1901 to 2038 range. Differs from gmmktime() in that all parameters
are currently compulsory.

** FUNCTION adodb_gmstrftime($fmt, $timestamp = false)
Convert a timestamp to a formatted GMT date.

** FUNCTION adodb_strftime($fmt, $timestamp = false)

Convert a timestamp to a formatted local date. Internally converts $fmt into 
adodb_date format, then echo result.

For best results, you can define the local date format yourself. Define a global
variable $ADODB_DATE_LOCALE which is an array, 1st element is date format using
adodb_date syntax, and 2nd element is the time format, also in adodb_date syntax.

    eg. $ADODB_DATE_LOCALE = array('d/m/Y','H:i:s');
	
	Supported format codes:

<pre>
	%a - abbreviated weekday name according to the current locale 
	%A - full weekday name according to the current locale 
	%b - abbreviated month name according to the current locale 
	%B - full month name according to the current locale 
	%c - preferred date and time representation for the current locale 
	%d - day of the month as a decimal number (range 01 to 31) 
	%D - same as %m/%d/%y 
	%e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31') 
	%h - same as %b
	%H - hour as a decimal number using a 24-hour clock (range 00 to 23) 
	%I - hour as a decimal number using a 12-hour clock (range 01 to 12) 
	%m - month as a decimal number (range 01 to 12) 
	%M - minute as a decimal number 
	%n - newline character 
	%p - either `am' or `pm' according to the given time value, or the corresponding strings for the current locale 
	%r - time in a.m. and p.m. notation 
	%R - time in 24 hour notation 
	%S - second as a decimal number 
	%t - tab character 
	%T - current time, equal to %H:%M:%S 
	%x - preferred date representation for the current locale without the time 
	%X - preferred time representation for the current locale without the date 
	%y - year as a decimal number without a century (range 00 to 99) 
	%Y - year as a decimal number including the century 
	%Z - time zone or name or abbreviation 
	%% - a literal `%' character 
</pre>	

	Unsupported codes:
<pre>
	%C - century number (the year divided by 100 and truncated to an integer, range 00 to 99) 
	%g - like %G, but without the century. 
	%G - The 4-digit year corresponding to the ISO week number (see %V). 
	     This has the same format and value as %Y, except that if the ISO week number belongs 
		 to the previous or next year, that year is used instead. 
	%j - day of the year as a decimal number (range 001 to 366) 
	%u - weekday as a decimal number [1,7], with 1 representing Monday 
	%U - week number of the current year as a decimal number, starting 
	    with the first Sunday as the first day of the first week 
	%V - The ISO 8601:1988 week number of the current year as a decimal number, 
	     range 01 to 53, where week 1 is the first week that has at least 4 days in the 
		 current year, and with Monday as the first day of the week. (Use %G or %g for 
		 the year component that corresponds to the week number for the specified timestamp.) 
	%w - day of the week as a decimal, Sunday being 0 
	%W - week number of the current year as a decimal number, starting with the 
	     first Monday as the first day of the first week 
</pre>

=============================================================================

NOTES

Useful url for generating test timestamps:
	http://www.4webhelp.net/us/timestamp.php

Possible future optimizations include 

a. Using an algorithm similar to Plauger's in "The Standard C Library" 
(page 428, xttotm.c _Ttotm() function). Plauger's algorithm will not 
work outside 32-bit signed range, so i decided not to implement it.

b. Implement daylight savings, which looks awfully complicated, see
	http://webexhibits.org/daylightsaving/


CHANGELOG

- 11 Feb 2008 0.33
* Bug in 0.32 fix for hour handling. Fixed.

- 1 Feb 2008 0.32
* Now adodb_mktime(0,0,0,12+$m,20,2040) works properly. 

- 10 Jan 2008 0.31
* Now adodb_mktime(0,0,0,24,1,2037) works correctly.

- 15 July 2007 0.30
Added PHP 5.2.0 compatability fixes. 
 * gmtime behaviour for 1970 has changed. We use the actual date if it is between 1970 to 2038 to get the
 * timezone, otherwise we use the current year as the baseline to retrieve the timezone.
 * Also the timezone's in php 5.2.* support historical data better, eg. if timezone today was +8, but 
   in 1970 it was +7:30, then php 5.2 return +7:30, while this library will use +8.
 * 
 
- 19 March 2006 0.24
Changed strftime() locale detection, because some locales prepend the day of week to the date when %c is used.

- 10 Feb 2006 0.23
PHP5 compat: when we detect PHP5, the RFC2822 format for gmt 0000hrs is changed from -0000 to +0000. 
	In PHP4, we will still use -0000 for 100% compat with PHP4.

- 08 Sept 2005 0.22
In adodb_date2(), $is_gmt not supported properly. Fixed.

- 18 July  2005 0.21
In PHP 4.3.11, the 'r' format has changed. Leading 0 in day is added. Changed for compat.
Added support for negative months in adodb_mktime().

- 24 Feb 2005 0.20
Added limited strftime/gmstrftime support. x10 improvement in performance of adodb_date().

- 21 Dec 2004 0.17
In adodb_getdate(), the timestamp was accidentally converted to gmt when $is_gmt is false. 
Also adodb_mktime(0,0,0) did not work properly. Both fixed thx Mauro.

- 17 Nov 2004 0.16
Removed intval typecast in adodb_mktime() for secs, allowing:
	 adodb_mktime(0,0,0 + 2236672153,1,1,1934);
Suggested by Ryan.

- 18 July 2004 0.15
All params in adodb_mktime were formerly compulsory. Now only the hour, min, secs is compulsory. 
This brings it more in line with mktime (still not identical).

- 23 June 2004 0.14

Allow you to define your own daylights savings function, adodb_daylight_sv.
If the function is defined (somewhere in an include), then you can correct for daylights savings.

In this example, we apply daylights savings in June or July, adding one hour. This is extremely
unrealistic as it does not take into account time-zone, geographic location, current year.

function adodb_daylight_sv(&$arr, $is_gmt)
{
	if ($is_gmt) return;
	$m = $arr['mon'];
	if ($m == 6 || $m == 7) $arr['hours'] += 1;
}

This is only called by adodb_date() and not by adodb_mktime(). 

The format of $arr is
Array ( 
   [seconds] => 0 
   [minutes] => 0 
   [hours] => 0 
   [mday] => 1      # day of month, eg 1st day of the month
   [mon] => 2       # month (eg. Feb)
   [year] => 2102 
   [yday] => 31     # days in current year
   [leap] =>        # true if leap year
   [ndays] => 28    # no of days in current month
   ) 
   

- 28 Apr 2004 0.13
Fixed adodb_date to properly support $is_gmt. Thx to Dimitar Angelov.

- 20 Mar 2004 0.12
Fixed month calculation error in adodb_date. 2102-June-01 appeared as 2102-May-32.

- 26 Oct 2003 0.11
Because of daylight savings problems (some systems apply daylight savings to 
January!!!), changed adodb_get_gmt_diff() to ignore daylight savings.

- 9 Aug 2003 0.10
Fixed bug with dates after 2038. 
See http://phplens.com/lens/lensforum/msgs.php?id=6980

- 1 July 2003 0.09
Added support for Q (Quarter).
Added adodb_date2(), which accepts ISO date in 2nd param

- 3 March 2003 0.08
Added support for 'S' adodb_date() format char. Added constant ADODB_ALLOW_NEGATIVE_TS
if you want PHP to handle negative timestamps between 1901 to 1969.

- 27 Feb 2003 0.07
All negative numbers handled by adodb now because of RH 7.3+ problems.
See http://bugs.php.net/bug.php?id=20048&edit=2

- 4 Feb 2003 0.06
Fixed a typo, 1852 changed to 1582! This means that pre-1852 dates
are now correctly handled.

- 29 Jan 2003 0.05

Leap year checking differs under Julian calendar (pre 1582). Also
leap year code optimized by checking for most common case first.

We also handle month overflow correctly in mktime (eg month set to 13).

Day overflow for less than one month's days is supported.

- 28 Jan 2003 0.04

Gregorian correction handled. In PHP5, we might throw an error if 
mktime uses invalid dates around 5-14 Oct 1582. Released with ADOdb 3.10.
Added limbo 5-14 Oct 1582 check, when we set to 15 Oct 1582.

- 27 Jan 2003 0.03

Fixed some more month problems due to gmt issues. Added constant ADODB_DATE_VERSION.
Fixed calculation of days since start of year for <1970. 

- 27 Jan 2003 0.02

Changed _adodb_getdate() to inline leap year checking for better performance.
Fixed problem with time-zones west of GMT +0000.

- 24 Jan 2003 0.01

First implementation.
*/


/* Initialization */

/*
	Version Number
*/
define('ADODB_DATE_VERSION',0.33);

$ADODB_DATETIME_CLASS = (PHP_VERSION >= 5.2);

/*
	This code was originally for windows. But apparently this problem happens 
	also with Linux, RH 7.3 and later!
	
	glibc-2.2.5-34 and greater has been changed to return -1 for dates <
	1970.  This used to work.  The problem exists with RedHat 7.3 and 8.0
	echo (mktime(0, 0, 0, 1, 1, 1960));  // prints -1
	
	References:
	 http://bugs.php.net/bug.php?id=20048&edit=2
	 http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html
*/

if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1);

function adodb_date_test_date($y1,$m,$d=13)
{
	$h = round(rand()% 24);
	$t = adodb_mktime($h,0,0,$m,$d,$y1);
	$rez = adodb_date('Y-n-j H:i:s',$t);
	if ($h == 0) $h = '00';
	else if ($h < 10) $h = '0'.$h;	
	if ("$y1-$m-$d $h:00:00" != $rez) {
		print "<b>$y1 error, expected=$y1-$m-$d $h:00:00, adodb=$rez</b><br>";
		return false;
	}
	return true;
}

function adodb_date_test_strftime($fmt)
{
	$s1 = strftime($fmt);
	$s2 = adodb_strftime($fmt);
	
	if ($s1 == $s2) return true;
	
	echo "error for $fmt,  strftime=$s1, adodb=$s2<br>";
	return false;
}

/**
	 Test Suite
*/		
function adodb_date_test()
{
	
	for ($m=-24; $m<=24; $m++)
		echo "$m :",adodb_date('d-m-Y',adodb_mktime(0,0,0,1+$m,20,2040)),"<br>";
	
	error_reporting(E_ALL);
	print "<h4>Testing adodb_date and adodb_mktime. version=".ADODB_DATE_VERSION.' PHP='.PHP_VERSION."</h4>";
	@set_time_limit(0);
	$fail = false;
	
	// This flag disables calling of PHP native functions, so we can properly test the code
	if (!defined('ADODB_TEST_DATES')) define('ADODB_TEST_DATES',1);
	
	$t = time();
	
	
	$fmt = 'Y-m-d H:i:s';
	echo '<pre>';
	echo 'adodb: ',adodb_date($fmt,$t),'<br>';
	echo 'php  : ',date($fmt,$t),'<br>';
	echo '</pre>';
	
	adodb_date_test_strftime('%Y %m %x %X');
	adodb_date_test_strftime("%A %d %B %Y");
	adodb_date_test_strftime("%H %M S");
	
	$t = adodb_mktime(0,0,0);
	if (!(adodb_date('Y-m-d') == date('Y-m-d'))) print 'Error in '.adodb_mktime(0,0,0).'<br>';
	
	$t = adodb_mktime(0,0,0,6,1,2102);
	if (!(adodb_date('Y-m-d',$t) == '2102-06-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>';
	
	$t = adodb_mktime(0,0,0,2,1,2102);
	if (!(adodb_date('Y-m-d',$t) == '2102-02-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>';
	
	
	print "<p>Testing gregorian <=> julian conversion<p>";
	$t = adodb_mktime(0,0,0,10,11,1492);
	//http://www.holidayorigins.com/html/columbus_day.html - Friday check
	if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in Columbus landing<br>';
	
	$t = adodb_mktime(0,0,0,2,29,1500);
	if (!(adodb_date('Y-m-d',$t) == '1500-02-29')) print 'Error in julian leap years<br>';
	
	$t = adodb_mktime(0,0,0,2,29,1700);
	if (!(adodb_date('Y-m-d',$t) == '1700-03-01')) print 'Error in gregorian leap years<br>';
	
	print  adodb_mktime(0,0,0,10,4,1582).' ';
	print adodb_mktime(0,0,0,10,15,1582);
	$diff = (adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582));
	if ($diff != 3600*24) print " <b>Error in gregorian correction = ".($diff/3600/24)." days </b><br>";
		
	print " 15 Oct 1582, Fri=".(adodb_dow(1582,10,15) == 5 ? 'Fri' : '<b>Error</b>')."<br>";
	print " 4 Oct 1582, Thu=".(adodb_dow(1582,10,4) == 4 ? 'Thu' : '<b>Error</b>')."<br>";
	
	print "<p>Testing overflow<p>";
	
	$t = adodb_mktime(0,0,0,3,33,1965);
	if (!(adodb_date('Y-m-d',$t) == '1965-04-02')) print 'Error in day overflow 1 <br>';
	$t = adodb_mktime(0,0,0,4,33,1971);
	if (!(adodb_date('Y-m-d',$t) == '1971-05-03')) print 'Error in day overflow 2 <br>';
	$t = adodb_mktime(0,0,0,1,60,1965);
	if (!(adodb_date('Y-m-d',$t) == '1965-03-01')) print 'Error in day overflow 3 '.adodb_date('Y-m-d',$t).' <br>';
	$t = adodb_mktime(0,0,0,12,32,1965);
	if (!(adodb_date('Y-m-d',$t) == '1966-01-01')) print 'Error in day overflow 4 '.adodb_date('Y-m-d',$t).' <br>';
	$t = adodb_mktime(0,0,0,12,63,1965);
	if (!(adodb_date('Y-m-d',$t) == '1966-02-01')) print 'Error in day overflow 5 '.adodb_date('Y-m-d',$t).' <br>';
	$t = adodb_mktime(0,0,0,13,3,1965);
	if (!(adodb_date('Y-m-d',$t) == '1966-01-03')) print 'Error in mth overflow 1 <br>';
	
	print "Testing 2-digit => 4-digit year conversion<p>";
	if (adodb_year_digit_check(00) != 2000) print "Err 2-digit 2000<br>";
	if (adodb_year_digit_check(10) != 2010) print "Err 2-digit 2010<br>";
	if (adodb_year_digit_check(20) != 2020) print "Err 2-digit 2020<br>";
	if (adodb_year_digit_check(30) != 2030) print "Err 2-digit 2030<br>";
	if (adodb_year_digit_check(40) != 1940) print "Err 2-digit 1940<br>";
	if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950<br>";
	if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990<br>";
	
	// Test string formating
	print "<p>Testing date formating</p>";
	
	$fmt = '\d\a\t\e T Y-m-d H:i:s a A d D F g G h H i j l L m M n O \R\F\C2822 r s t U w y Y z Z 2003';
	$s1 = date($fmt,0);
	$s2 = adodb_date($fmt,0);
	if ($s1 != $s2) {
		print " date() 0 failed<br>$s1<br>$s2<br>";
	}
	flush();
	for ($i=100; --$i > 0; ) {

		$ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000);
		$s1 = date($fmt,$ts);
		$s2 = adodb_date($fmt,$ts);
		//print "$s1 <br>$s2 <p>";
		$pos = strcmp($s1,$s2);

		if (($s1) != ($s2)) {
			for ($j=0,$k=strlen($s1); $j < $k; $j++) {
				if ($s1[$j] != $s2[$j]) {
					print substr($s1,$j).' ';
					break;
				}
			}
			print "<b>Error date(): $ts<br><pre> 
&nbsp; \"$s1\" (date len=".strlen($s1).")
&nbsp; \"$s2\" (adodb_date len=".strlen($s2).")</b></pre><br>";
			$fail = true;
		}
		
		$a1 = getdate($ts);
		$a2 = adodb_getdate($ts);
		$rez = array_diff($a1,$a2);
		if (sizeof($rez)>0) {
			print "<b>Error getdate() $ts</b><br>";
				print_r($a1);
			print "<br>";
				print_r($a2);
			print "<p>";
			$fail = true;
		}
	}
	
	// Test generation of dates outside 1901-2038
	print "<p>Testing random dates between 100 and 4000</p>";
	adodb_date_test_date(100,1);
	for ($i=100; --$i >= 0;) {
		$y1 = 100+rand(0,1970-100);
		$m = rand(1,12);
		adodb_date_test_date($y1,$m);
		
		$y1 = 3000-rand(0,3000-1970);
		adodb_date_test_date($y1,$m);
	}
	print '<p>';
	$start = 1960+rand(0,10);
	$yrs = 12;
	$i = 365.25*86400*($start-1970);
	$offset = 36000+rand(10000,60000);
	$max = 365*$yrs*86400;
	$lastyear = 0;
	
	// we generate a timestamp, convert it to a date, and convert it back to a timestamp
	// and check if the roundtrip broke the original timestamp value.
	print "Testing $start to ".($start+$yrs).", or $max seconds, offset=$offset: ";
	$cnt = 0;
	for ($max += $i; $i < $max; $i += $offset) {
		$ret = adodb_date('m,d,Y,H,i,s',$i);
		$arr = explode(',',$ret);
		if ($lastyear != $arr[2]) {
			$lastyear = $arr[2];
			print " $lastyear ";
			flush();
		}
		$newi = adodb_mktime($arr[3],$arr[4],$arr[5],$arr[0],$arr[1],$arr[2]);
		if ($i != $newi) {
			print "Error at $i, adodb_mktime returned $newi ($ret)";
			$fail = true;
			break;
		}
		$cnt += 1;
	}
	echo "Tested $cnt dates<br>";
	if (!$fail) print "<p>Passed !</p>";
	else print "<p><b>Failed</b> :-(</p>";
}

/**
	Returns day of week, 0 = Sunday,... 6=Saturday. 
	Algorithm from PEAR::Date_Calc
*/
function adodb_dow($year, $month, $day)
{
/*
Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and 
proclaimed that from that time onwards 3 days would be dropped from the calendar 
every 400 years.

Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian). 
*/
	if ($year <= 1582) {
		if ($year < 1582 || 
			($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3;
		 else
			$greg_correction = 0;
	} else
		$greg_correction = 0;
	
	if($month > 2)
	    $month -= 2;
	else {
	    $month += 10;
	    $year--;
	}
	
	$day =  floor((13 * $month - 1) / 5) +
	        $day + ($year % 100) +
	        floor(($year % 100) / 4) +
	        floor(($year / 100) / 4) - 2 *
	        floor($year / 100) + 77 + $greg_correction;
	
	return $day - 7 * floor($day / 7);
}


/**
 Checks for leap year, returns true if it is. No 2-digit year check. Also 
 handles julian calendar correctly.
*/
function _adodb_is_leap_year($year) 
{
	if ($year % 4 != 0) return false;
	
	if ($year % 400 == 0) {
		return true;
	// if gregorian calendar (>1582), century not-divisible by 400 is not leap
	} else if ($year > 1582 && $year % 100 == 0 ) {
		return false;
	} 
	
	return true;
}


/**
 checks for leap year, returns true if it is. Has 2-digit year check
*/
function adodb_is_leap_year($year) 
{
	return  _adodb_is_leap_year(adodb_year_digit_check($year));
}

/**
	Fix 2-digit years. Works for any century.
 	Assumes that if 2-digit is more than 30 years in future, then previous century.
*/
function adodb_year_digit_check($y) 
{
	if ($y < 100) {
	
		$yr = (integer) date("Y");
		$century = (integer) ($yr /100);
		
		if ($yr%100 > 50) {
			$c1 = $century + 1;
			$c0 = $century;
		} else {
			$c1 = $century;
			$c0 = $century - 1;
		}
		$c1 *= 100;
		// if 2-digit year is less than 30 years in future, set it to this century
		// otherwise if more than 30 years in future, then we set 2-digit year to the prev century.
		if (($y + $c1) < $yr+30) $y = $y + $c1;
		else $y = $y + $c0*100;
	}
	return $y;
}

function adodb_get_gmt_diff_ts($ts) 
{
	if (0 <= $ts && $ts <= 0x7FFFFFFF) { // check if number in 32-bit signed range) {
		$arr = getdate($ts);
		$y = $arr['year'];
		$m = $arr['mon'];
		$d = $arr['mday'];
		return adodb_get_gmt_diff($y,$m,$d);	
	} else {
		return adodb_get_gmt_diff(false,false,false);
	}
	
}

/**
 get local time zone offset from GMT. Does not handle historical timezones before 1970.
*/
function adodb_get_gmt_diff($y,$m,$d) 
{
static $TZ,$tzo;
global $ADODB_DATETIME_CLASS;

	if (!defined('ADODB_TEST_DATES')) $y = false;
	else if ($y < 1970 || $y >= 2038) $y = false;

	if ($ADODB_DATETIME_CLASS && $y !== false) {
		$dt = new DateTime();
		$dt->setISODate($y,$m,$d);
		if (empty($tzo)) {
			$tzo = new DateTimeZone(date_default_timezone_get());
		#	$tzt = timezone_transitions_get( $tzo );
		}
		return -$tzo->getOffset($dt);
	} else {
		if (isset($TZ)) return $TZ;
		$y = date('Y');
		$TZ = mktime(0,0,0,12,2,$y,0) - gmmktime(0,0,0,12,2,$y,0);
	}
	
	return $TZ;
}

/**
	Returns an array with date info.
*/
function adodb_getdate($d=false,$fast=false)
{
	if ($d === false) return getdate();
	if (!defined('ADODB_TEST_DATES')) {
		if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
			if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
				return @getdate($d);
		}
	}
	return _adodb_getdate($d);
}

/*
// generate $YRS table for _adodb_getdate()
function adodb_date_gentable($out=true)
{

	for ($i=1970; $i >= 1600; $i-=10) {
		$s = adodb_gmmktime(0,0,0,1,1,$i);
		echo "$i => $s,<br>";	
	}
}
adodb_date_gentable();

for ($i=1970; $i > 1500; $i--) {

echo "<hr />$i ";
	adodb_date_test_date($i,1,1);
}

*/


$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
	
function adodb_validdate($y,$m,$d)
{
global $_month_table_normal,$_month_table_leaf;

	if (_adodb_is_leap_year($y)) $marr = $_month_table_leaf;
	else $marr = $_month_table_normal;
	
	if ($m > 12 || $m < 1) return false;
	
	if ($d > 31 || $d < 1) return false;
	
	if ($marr[$m] < $d) return false;
	
	if ($y < 1000 && $y > 3000) return false;
	
	return true;
}

/**
	Low-level function that returns the getdate() array. We have a special
	$fast flag, which if set to true, will return fewer array values,
	and is much faster as it does not calculate dow, etc.
*/
function _adodb_getdate($origd=false,$fast=false,$is_gmt=false)
{
static $YRS;
global $_month_table_normal,$_month_table_leaf;

	$d =  $origd - ($is_gmt ? 0 : adodb_get_gmt_diff_ts($origd));
	$_day_power = 86400;
	$_hour_power = 3600;
	$_min_power = 60;
	
	if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction 
	
	$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
	$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
	
	$d366 = $_day_power * 366;
	$d365 = $_day_power * 365;
	
	if ($d < 0) {
		
		if (empty($YRS)) $YRS = array(
			1970 => 0,
			1960 => -315619200,
			1950 => -631152000,
			1940 => -946771200,
			1930 => -1262304000,
			1920 => -1577923200,
			1910 => -1893456000,
			1900 => -2208988800,
			1890 => -2524521600,
			1880 => -2840140800,
			1870 => -3155673600,
			1860 => -3471292800,
			1850 => -3786825600,
			1840 => -4102444800,
			1830 => -4417977600,
			1820 => -4733596800,
			1810 => -5049129600,
			1800 => -5364662400,
			1790 => -5680195200,
			1780 => -5995814400,
			1770 => -6311347200,
			1760 => -6626966400,
			1750 => -6942499200,
			1740 => -7258118400,
			1730 => -7573651200,
			1720 => -7889270400,
			1710 => -8204803200,
			1700 => -8520336000,
			1690 => -8835868800,
			1680 => -9151488000,
			1670 => -9467020800,
			1660 => -9782640000,
			1650 => -10098172800,
			1640 => -10413792000,
			1630 => -10729324800,
			1620 => -11044944000,
			1610 => -11360476800,
			1600 => -11676096000);

		if ($is_gmt) $origd = $d;
		// The valid range of a 32bit signed timestamp is typically from 
		// Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT
		//
		
		# old algorithm iterates through all years. new algorithm does it in
		# 10 year blocks
		
		/*
		# old algo
		for ($a = 1970 ; --$a >= 0;) {
			$lastd = $d;
			
			if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
			else $d += $d365;
			
			if ($d >= 0) {
				$year = $a;
				break;
			}
		}
		*/
		
		$lastsecs = 0;
		$lastyear = 1970;
		foreach($YRS as $year => $secs) {
			if ($d >= $secs) {
				$a = $lastyear;
				break;
			}
			$lastsecs = $secs;
			$lastyear = $year;
		}
		
		$d -= $lastsecs;
		if (!isset($a)) $a = $lastyear;
		
		//echo ' yr=',$a,' ', $d,'.';
		
		for (; --$a >= 0;) {
			$lastd = $d;
			
			if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
			else $d += $d365;
			
			if ($d >= 0) {
				$year = $a;
				break;
			}
		}
		/**/
		
		$secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd;
		
		$d = $lastd;
		$mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
		for ($a = 13 ; --$a > 0;) {
			$lastd = $d;
			$d += $mtab[$a] * $_day_power;
			if ($d >= 0) {
				$month = $a;
				$ndays = $mtab[$a];
				break;
			}
		}
		
		$d = $lastd;
		$day = $ndays + ceil(($d+1) / ($_day_power));

		$d += ($ndays - $day+1)* $_day_power;
		$hour = floor($d/$_hour_power);
	
	} else {
		for ($a = 1970 ;; $a++) {
			$lastd = $d;
			
			if ($leaf = _adodb_is_leap_year($a)) $d -= $d366;
			else $d -= $d365;
			if ($d < 0) {
				$year = $a;
				break;
			}
		}
		$secsInYear = $lastd;
		$d = $lastd;
		$mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
		for ($a = 1 ; $a <= 12; $a++) {
			$lastd = $d;
			$d -= $mtab[$a] * $_day_power;
			if ($d < 0) {
				$month = $a;
				$ndays = $mtab[$a];
				break;
			}
		}
		$d = $lastd;
		$day = ceil(($d+1) / $_day_power);
		$d = $d - ($day-1) * $_day_power;
		$hour = floor($d /$_hour_power);
	}
	
	$d -= $hour * $_hour_power;
	$min = floor($d/$_min_power);
	$secs = $d - $min * $_min_power;
	if ($fast) {
		return array(
		'seconds' => $secs,
		'minutes' => $min,
		'hours' => $hour,
		'mday' => $day,
		'mon' => $month,
		'year' => $year,
		'yday' => floor($secsInYear/$_day_power),
		'leap' => $leaf,
		'ndays' => $ndays
		);
	}
	
	
	$dow = adodb_dow($year,$month,$day);

	return array(
		'seconds' => $secs,
		'minutes' => $min,
		'hours' => $hour,
		'mday' => $day,
		'wday' => $dow,
		'mon' => $month,
		'year' => $year,
		'yday' => floor($secsInYear/$_day_power),
		'weekday' => gmdate('l',$_day_power*(3+$dow)),
		'month' => gmdate('F',mktime(0,0,0,$month,2,1971)),
		0 => $origd
	);
}
/*
		if ($isphp5)
				$dates .= sprintf('%s%04d',($gmt<=0)?'+':'-',abs($gmt)/36); 
			else
				$dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); 
			break;*/
function adodb_tz_offset($gmt,$isphp5)
{
	$zhrs = abs($gmt)/3600;
	$hrs = floor($zhrs);
	if ($isphp5) 
		return sprintf('%s%02d%02d',($gmt<=0)?'+':'-',floor($zhrs),($zhrs-$hrs)*60); 
	else
		return sprintf('%s%02d%02d',($gmt<0)?'+':'-',floor($zhrs),($zhrs-$hrs)*60); 
}


function adodb_gmdate($fmt,$d=false)
{
	return adodb_date($fmt,$d,true);
}

// accepts unix timestamp and iso date format in $d
function adodb_date2($fmt, $d=false, $is_gmt=false)
{
	if ($d !== false) {
		if (!preg_match( 
			"|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 
			($d), $rr)) return adodb_date($fmt,false,$is_gmt);

		if ($rr[1] <= 100 && $rr[2]<= 1) return adodb_date($fmt,false,$is_gmt);
	
		// h-m-s-MM-DD-YY
		if (!isset($rr[5])) $d = adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1],false,$is_gmt);
		else $d = @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1],false,$is_gmt);
	}
	
	return adodb_date($fmt,$d,$is_gmt);
}


/**
	Return formatted date based on timestamp $d
*/
function adodb_date($fmt,$d=false,$is_gmt=false)
{
static $daylight;
global $ADODB_DATETIME_CLASS;

	if ($d === false) return ($is_gmt)? @gmdate($fmt): @date($fmt);
	if (!defined('ADODB_TEST_DATES')) {
		if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
			if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
				return ($is_gmt)? @gmdate($fmt,$d): @date($fmt,$d);

		}
	}
	$_day_power = 86400;
	
	$arr = _adodb_getdate($d,true,$is_gmt);
	
	if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv');
	if ($daylight) adodb_daylight_sv($arr, $is_gmt);
	
	$year = $arr['year'];
	$month = $arr['mon'];
	$day = $arr['mday'];
	$hour = $arr['hours'];
	$min = $arr['minutes'];
	$secs = $arr['seconds'];
	
	$max = strlen($fmt);
	$dates = '';
	
	$isphp5 = PHP_VERSION >= 5;
	
	/*
		at this point, we have the following integer vars to manipulate:
		$year, $month, $day, $hour, $min, $secs
	*/
	for ($i=0; $i < $max; $i++) {
		switch($fmt[$i]) {
		case 'T': 
			if ($ADODB_DATETIME_CLASS) {
				$dt = new DateTime();
				$dt->SetDate($year,$month,$day);
				$dates .= $dt->Format('T');
			} else
				$dates .= date('T');
			break;
		// YEAR
		case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
		case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
		
			// 4.3.11 uses '04 Jun 2004'
			// 4.3.8 uses  ' 4 Jun 2004'
			$dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', '		
				. ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';
			
			if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour; 
			
			if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min;
			
			if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs;
			
			$gmt = adodb_get_gmt_diff($year,$month,$day);
			
			$dates .= ' '.adodb_tz_offset($gmt,$isphp5);
			break;
			
		case 'Y': $dates .= $year; break;
		case 'y': $dates .= substr($year,strlen($year)-2,2); break;
		// MONTH
		case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break;
		case 'Q': $dates .= ($month+3)>>2; break;
		case 'n': $dates .= $month; break;
		case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break;
		case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break;
		// DAY
		case 't': $dates .= $arr['ndays']; break;
		case 'z': $dates .= $arr['yday']; break;
		case 'w': $dates .= adodb_dow($year,$month,$day); break;
		case 'l': $dates .= gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break;
		case 'D': $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break;
		case 'j': $dates .= $day; break;
		case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break;
		case 'S': 
			$d10 = $day % 10;
			if ($d10 == 1) $dates .= 'st';
			else if ($d10 == 2 && $day != 12) $dates .= 'nd';
			else if ($d10 == 3) $dates .= 'rd';
			else $dates .= 'th';
			break;
			
		// HOUR
		case 'Z':
			$dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff($year,$month,$day); break;
		case 'O': 
			$gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff($year,$month,$day);
			
			$dates .= adodb_tz_offset($gmt,$isphp5);
			break;
			
		case 'H': 
			if ($hour < 10) $dates .= '0'.$hour; 
			else $dates .= $hour; 
			break;
		case 'h': 
			if ($hour > 12) $hh = $hour - 12; 
			else {
				if ($hour == 0) $hh = '12'; 
				else $hh = $hour;
			}
			
			if ($hh < 10) $dates .= '0'.$hh;
			else $dates .= $hh;
			break;
			
		case 'G': 
			$dates .= $hour;
			break;
			
		case 'g':
			if ($hour > 12) $hh = $hour - 12; 
			else {
				if ($hour == 0) $hh = '12'; 
				else $hh = $hour; 
			}
			$dates .= $hh;
			break;
		// MINUTES
		case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break;
		// SECONDS
		case 'U': $dates .= $d; break;
		case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break;
		// AM/PM
		// Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
		case 'a':
			if ($hour>=12) $dates .= 'pm';
			else $dates .= 'am';
			break;
		case 'A':
			if ($hour>=12) $dates .= 'PM';
			else $dates .= 'AM';
			break;
		default:
			$dates .= $fmt[$i]; break;
		// ESCAPE
		case "\\": 
			$i++;
			if ($i < $max) $dates .= $fmt[$i];
			break;
		}
	}
	return $dates;
}

/**
	Returns a timestamp given a GMT/UTC time. 
	Note that $is_dst is not implemented and is ignored.
*/
function adodb_gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false)
{
	return adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true);
}

/**
	Return a timestamp given a local time. Originally by jackbbs.
	Note that $is_dst is not implemented and is ignored.
	
	Not a very fast algorithm - O(n) operation. Could be optimized to O(1).
*/
function adodb_mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false) 
{
	if (!defined('ADODB_TEST_DATES')) {

		if ($mon === false) {
			return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec);
		}
		
		// for windows, we don't check 1970 because with timezone differences, 
		// 1 Jan 1970 could generate negative timestamp, which is illegal
		$usephpfns = (1971 < $year && $year < 2038
			|| !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && $year < 2038)
			); 
			
		
		if ($usephpfns && ($year + $mon/12+$day/365.25+$hr/(24*365.25) >= 2038)) $usephpfns = false;
			
		if ($usephpfns) {
				return $is_gmt ?
					@gmmktime($hr,$min,$sec,$mon,$day,$year):
					@mktime($hr,$min,$sec,$mon,$day,$year);
		}
	}
	
	$gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff($year,$mon,$day);

	/*
	# disabled because some people place large values in $sec.
	# however we need it for $mon because we use an array...
	$hr = intval($hr);
	$min = intval($min);
	$sec = intval($sec);
	*/
	$mon = intval($mon);
	$day = intval($day);
	$year = intval($year);
	
	
	$year = adodb_year_digit_check($year);

	if ($mon > 12) {
		$y = floor(($mon-1)/ 12);
		$year += $y;
		$mon -= $y*12;
	} else if ($mon < 1) {
		$y = ceil((1-$mon) / 12);
		$year -= $y;
		$mon += $y*12;
	}
	
	$_day_power = 86400;
	$_hour_power = 3600;
	$_min_power = 60;
	
	$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
	$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
	
	$_total_date = 0;
	if ($year >= 1970) {
		for ($a = 1970 ; $a <= $year; $a++) {
			$leaf = _adodb_is_leap_year($a);
			if ($leaf == true) {
				$loop_table = $_month_table_leaf;
				$_add_date = 366;
			} else {
				$loop_table = $_month_table_normal;
				$_add_date = 365;
			}
			if ($a < $year) { 
				$_total_date += $_add_date;
			} else {
				for($b=1;$b<$mon;$b++) {
					$_total_date += $loop_table[$b];
				}
			}
		}
		$_total_date +=$day-1;
		$ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different;
	
	} else {
		for ($a = 1969 ; $a >= $year; $a--) {
			$leaf = _adodb_is_leap_year($a);
			if ($leaf == true) {
				$loop_table = $_month_table_leaf;
				$_add_date = 366;
			} else {
				$loop_table = $_month_table_normal;
				$_add_date = 365;
			}
			if ($a > $year) { $_total_date += $_add_date;
			} else {
				for($b=12;$b>$mon;$b--) {
					$_total_date += $loop_table[$b];
				}
			}
		}
		$_total_date += $loop_table[$mon] - $day;
		
		$_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
		$_day_time = $_day_power - $_day_time;
		$ret = -( $_total_date * $_day_power + $_day_time - $gmt_different);
		if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction
		else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582.
	} 
	//print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret;
	return $ret;
}

function adodb_gmstrftime($fmt, $ts=false)
{
	return adodb_strftime($fmt,$ts,true);
}

// hack - convert to adodb_date
function adodb_strftime($fmt, $ts=false,$is_gmt=false)
{
global $ADODB_DATE_LOCALE;

	if (!defined('ADODB_TEST_DATES')) {
		if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
			if (!defined('ADODB_NO_NEGATIVE_TS') || $ts >= 0) // if windows, must be +ve integer
				return ($is_gmt)? @gmstrftime($fmt,$ts): @strftime($fmt,$ts);

		}
	}
	
	if (empty($ADODB_DATE_LOCALE)) {
	/*
		$tstr = strtoupper(gmstrftime('%c',31366800)); // 30 Dec 1970, 1 am
		$sep = substr($tstr,2,1);
		$hasAM = strrpos($tstr,'M') !== false;
	*/
		# see http://phplens.com/lens/lensforum/msgs.php?id=14865 for reasoning, and changelog for version 0.24
		$dstr = gmstrftime('%x',31366800); // 30 Dec 1970, 1 am
		$sep = substr($dstr,2,1);
		$tstr = strtoupper(gmstrftime('%X',31366800)); // 30 Dec 1970, 1 am
		$hasAM = strrpos($tstr,'M') !== false;
		
		$ADODB_DATE_LOCALE = array();
		$ADODB_DATE_LOCALE[] =  strncmp($tstr,'30',2) == 0 ? 'd'.$sep.'m'.$sep.'y' : 'm'.$sep.'d'.$sep.'y';	
		$ADODB_DATE_LOCALE[]  = ($hasAM) ? 'h:i:s a' : 'H:i:s';
			
	}
	$inpct = false;
	$fmtdate = '';
	for ($i=0,$max = strlen($fmt); $i < $max; $i++) {
		$ch = $fmt[$i];
		if ($ch == '%') {
			if ($inpct) {
				$fmtdate .= '%';
				$inpct = false;
			} else
				$inpct = true;
		} else if ($inpct) {
		
			$inpct = false;
			switch($ch) {
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
			case 'E':
			case 'O':
				/* ignore format modifiers */
				$inpct = true; 
				break;
				
			case 'a': $fmtdate .= 'D'; break;
			case 'A': $fmtdate .= 'l'; break;
			case 'h':
			case 'b': $fmtdate .= 'M'; break;
			case 'B': $fmtdate .= 'F'; break;
			case 'c': $fmtdate .= $ADODB_DATE_LOCALE[0].$ADODB_DATE_LOCALE[1]; break;
			case 'C': $fmtdate .= '\C?'; break; // century
			case 'd': $fmtdate .= 'd'; break;
			case 'D': $fmtdate .= 'm/d/y'; break;
			case 'e': $fmtdate .= 'j'; break;
			case 'g': $fmtdate .= '\g?'; break; //?
			case 'G': $fmtdate .= '\G?'; break; //?
			case 'H': $fmtdate .= 'H'; break;
			case 'I': $fmtdate .= 'h'; break;
			case 'j': $fmtdate .= '?z'; $parsej = true; break; // wrong as j=1-based, z=0-basd
			case 'm': $fmtdate .= 'm'; break;
			case 'M': $fmtdate .= 'i'; break;
			case 'n': $fmtdate .= "\n"; break;
			case 'p': $fmtdate .= 'a'; break;
			case 'r': $fmtdate .= 'h:i:s a'; break;
			case 'R': $fmtdate .= 'H:i:s'; break;
			case 'S': $fmtdate .= 's'; break;
			case 't': $fmtdate .= "\t"; break;
			case 'T': $fmtdate .= 'H:i:s'; break;
			case 'u': $fmtdate .= '?u'; $parseu = true; break; // wrong strftime=1-based, date=0-based
			case 'U': $fmtdate .= '?U'; $parseU = true; break;// wrong strftime=1-based, date=0-based
			case 'x': $fmtdate .= $ADODB_DATE_LOCALE[0]; break;
			case 'X': $fmtdate .= $ADODB_DATE_LOCALE[1]; break;
			case 'w': $fmtdate .= '?w'; $parseu = true; break; // wrong strftime=1-based, date=0-based
			case 'W': $fmtdate .= '?W'; $parseU = true; break;// wrong strftime=1-based, date=0-based
			case 'y': $fmtdate .= 'y'; break;
			case 'Y': $fmtdate .= 'Y'; break;
			case 'Z': $fmtdate .= 'T'; break;
			}
		} else if (('A' <= ($ch) && ($ch) <= 'Z' ) || ('a' <= ($ch) && ($ch) <= 'z' ))
			$fmtdate .= "\\".$ch;
		else
			$fmtdate .= $ch;
	}
	//echo "fmt=",$fmtdate,"<br>";
	if ($ts === false) $ts = time();
	$ret = adodb_date($fmtdate, $ts, $is_gmt);
	return $ret;
}

?>

Added program_files/include/adodb4/adodb-time.zip.

cannot compute difference between binary files

Added program_files/include/adodb4/adodb-xmlschema.inc.php.



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
<?php
// Copyright (c) 2004 ars Cognita Inc., all rights reserved
/* ******************************************************************************
    Released under both BSD license and Lesser GPL library license. 
 	Whenever there is any discrepancy between the two licenses, 
 	the BSD license will take precedence. 
*******************************************************************************/
/**
 * xmlschema is a class that allows the user to quickly and easily
 * build a database on any ADOdb-supported platform using a simple
 * XML schema.
 *
 * Last Editor: $Author: jlim $
 * @author Richard Tango-Lowy & Dan Cech
 * @version $Revision: 1.12 $
 *
 * @package axmls
 * @tutorial getting_started.pkg
 */
 
function _file_get_contents($file) 
{
 	if (function_exists('file_get_contents')) return file_get_contents($file);
	
	$f = fopen($file,'r');
	if (!$f) return '';
	$t = '';
	
	while ($s = fread($f,100000)) $t .= $s;
	fclose($f);
	return $t;
}


/**
* Debug on or off
*/
if( !defined( 'XMLS_DEBUG' ) ) {
	define( 'XMLS_DEBUG', FALSE );
}

/**
* Default prefix key
*/
if( !defined( 'XMLS_PREFIX' ) ) {
	define( 'XMLS_PREFIX', '%%P' );
}

/**
* Maximum length allowed for object prefix
*/
if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
	define( 'XMLS_PREFIX_MAXLEN', 10 );
}

/**
* Execute SQL inline as it is generated
*/
if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
	define( 'XMLS_EXECUTE_INLINE', FALSE );
}

/**
* Continue SQL Execution if an error occurs?
*/
if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
	define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
}

/**
* Current Schema Version
*/
if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
	define( 'XMLS_SCHEMA_VERSION', '0.2' );
}

/**
* Default Schema Version.  Used for Schemas without an explicit version set.
*/
if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
	define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
}

/**
* Default Schema Version.  Used for Schemas without an explicit version set.
*/
if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
	define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
}

/**
* Include the main ADODB library
*/
if( !defined( '_ADODB_LAYER' ) ) {
	require( 'adodb.inc.php' );
	require( 'adodb-datadict.inc.php' );
}

/**
* Abstract DB Object. This class provides basic methods for database objects, such
* as tables and indexes.
*
* @package axmls
* @access private
*/
class dbObject {
	
	/**
	* var object Parent
	*/
	var $parent;
	
	/**
	* var string current element
	*/
	var $currentElement;
	
	/**
	* NOP
	*/
	function dbObject( &$parent, $attributes = NULL ) {
		$this->parent =& $parent;
	}
	
	/**
	* XML Callback to process start elements
	*
	* @access private
	*/
	function _tag_open( &$parser, $tag, $attributes ) {
		
	}
	
	/**
	* XML Callback to process CDATA elements
	*
	* @access private
	*/
	function _tag_cdata( &$parser, $cdata ) {
		
	}
	
	/**
	* XML Callback to process end elements
	*
	* @access private
	*/
	function _tag_close( &$parser, $tag ) {
		
	}
	
	function create() {
		return array();
	}
	
	/**
	* Destroys the object
	*/
	function destroy() {
		unset( $this );
	}
	
	/**
	* Checks whether the specified RDBMS is supported by the current
	* database object or its ranking ancestor.
	*
	* @param string $platform RDBMS platform name (from ADODB platform list).
	* @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
	*/
	function supportedPlatform( $platform = NULL ) {
		return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE;
	}
	
	/**
	* Returns the prefix set by the ranking ancestor of the database object.
	*
	* @param string $name Prefix string.
	* @return string Prefix.
	*/
	function prefix( $name = '' ) {
		return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name;
	}
	
	/**
	* Extracts a field ID from the specified field.
	*
	* @param string $field Field.
	* @return string Field ID.
	*/
	function FieldID( $field ) {
		return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
	}
}

/**
* Creates a table object in ADOdb's datadict format
*
* This class stores information about a database table. As charactaristics
* of the table are loaded from the external source, methods and properties
* of this class are used to build up the table description in ADOdb's
* datadict format.
*
* @package axmls
* @access private
*/
class dbTable extends dbObject {
	
	/**
	* @var string Table name
	*/
	var $name;
	
	/**
	* @var array Field specifier: Meta-information about each field
	*/
	var $fields = array();
	
	/**
	* @var array List of table indexes.
	*/
	var $indexes = array();
	
	/**
	* @var array Table options: Table-level options
	*/
	var $opts = array();
	
	/**
	* @var string Field index: Keeps track of which field is currently being processed
	*/
	var $current_field;
	
	/**
	* @var boolean Mark table for destruction
	* @access private
	*/
	var $drop_table;
	
	/**
	* @var boolean Mark field for destruction (not yet implemented)
	* @access private
	*/
	var $drop_field = array();
	
	/**
	* Iniitializes a new table object.
	*
	* @param string $prefix DB Object prefix
	* @param array $attributes Array of table attributes.
	*/
	function dbTable( &$parent, $attributes = NULL ) {
		$this->parent =& $parent;
		$this->name = $this->prefix($attributes['NAME']);
	}
	
	/**
	* XML Callback to process start elements. Elements currently 
	* processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT. 
	*
	* @access private
	*/
	function _tag_open( &$parser, $tag, $attributes ) {
		$this->currentElement = strtoupper( $tag );
		
		switch( $this->currentElement ) {
			case 'INDEX':
				if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
					xml_set_object( $parser, $this->addIndex( $attributes ) );
				}
				break;
			case 'DATA':
				if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
					xml_set_object( $parser, $this->addData( $attributes ) );
				}
				break;
			case 'DROP':
				$this->drop();
				break;
			case 'FIELD':
				// Add a field
				$fieldName = $attributes['NAME'];
				$fieldType = $attributes['TYPE'];
				$fieldSize = isset( $attributes['SIZE'] ) ? $attributes['SIZE'] : NULL;
				$fieldOpts = isset( $attributes['OPTS'] ) ? $attributes['OPTS'] : NULL;
				
				$this->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts );
				break;
			case 'KEY':
			case 'NOTNULL':
			case 'AUTOINCREMENT':
				// Add a field option
				$this->addFieldOpt( $this->current_field, $this->currentElement );
				break;
			case 'DEFAULT':
				// Add a field option to the table object
				
				// Work around ADOdb datadict issue that misinterprets empty strings.
				if( $attributes['VALUE'] == '' ) {
					$attributes['VALUE'] = " '' ";
				}
				
				$this->addFieldOpt( $this->current_field, $this->currentElement, $attributes['VALUE'] );
				break;
			case 'DEFDATE':
			case 'DEFTIMESTAMP':
				// Add a field option to the table object
				$this->addFieldOpt( $this->current_field, $this->currentElement );
				break;
			default:
				// print_r( array( $tag, $attributes ) );
		}
	}
	
	/**
	* XML Callback to process CDATA elements
	*
	* @access private
	*/
	function _tag_cdata( &$parser, $cdata ) {
		switch( $this->currentElement ) {
			// Table constraint
			case 'CONSTRAINT':
				if( isset( $this->current_field ) ) {
					$this->addFieldOpt( $this->current_field, $this->currentElement, $cdata );
				} else {
					$this->addTableOpt( $cdata );
				}
				break;
			// Table option
			case 'OPT':
				$this->addTableOpt( $cdata );
				break;
			default:
				
		}
	}
	
	/**
	* XML Callback to process end elements
	*
	* @access private
	*/
	function _tag_close( &$parser, $tag ) {
		$this->currentElement = '';
		
		switch( strtoupper( $tag ) ) {
			case 'TABLE':
				$this->parent->addSQL( $this->create( $this->parent ) );
				xml_set_object( $parser, $this->parent );
				$this->destroy();
				break;
			case 'FIELD':
				unset($this->current_field);
				break;

		}
	}
	
	/**
	* Adds an index to a table object
	*
	* @param array $attributes Index attributes
	* @return object dbIndex object
	*/
	function &addIndex( $attributes ) {
		$name = strtoupper( $attributes['NAME'] );
		$this->indexes[$name] =& new dbIndex( $this, $attributes );
		return $this->indexes[$name];
	}
	
	/**
	* Adds data to a table object
	*
	* @param array $attributes Data attributes
	* @return object dbData object
	*/
	function &addData( $attributes ) {
		if( !isset( $this->data ) ) {
			$this->data =& new dbData( $this, $attributes );
		}
		return $this->data;
	}
	
	/**
	* Adds a field to a table object
	*
	* $name is the name of the table to which the field should be added. 
	* $type is an ADODB datadict field type. The following field types
	* are supported as of ADODB 3.40:
	* 	- C:  varchar
	*	- X:  CLOB (character large object) or largest varchar size
	*	   if CLOB is not supported
	*	- C2: Multibyte varchar
	*	- X2: Multibyte CLOB
	*	- B:  BLOB (binary large object)
	*	- D:  Date (some databases do not support this, and we return a datetime type)
	*	- T:  Datetime or Timestamp
	*	- L:  Integer field suitable for storing booleans (0 or 1)
	*	- I:  Integer (mapped to I4)
	*	- I1: 1-byte integer
	*	- I2: 2-byte integer
	*	- I4: 4-byte integer
	*	- I8: 8-byte integer
	*	- F:  Floating point number
	*	- N:  Numeric or decimal number
	*
	* @param string $name Name of the table to which the field will be added.
	* @param string $type	ADODB datadict field type.
	* @param string $size	Field size
	* @param array $opts	Field options array
	* @return array Field specifier array
	*/
	function addField( $name, $type, $size = NULL, $opts = NULL ) {
		$field_id = $this->FieldID( $name );
		
		// Set the field index so we know where we are
		$this->current_field = $field_id;
		
		// Set the field name (required)
		$this->fields[$field_id]['NAME'] = $name;
		
		// Set the field type (required)
		$this->fields[$field_id]['TYPE'] = $type;
		
		// Set the field size (optional)
		if( isset( $size ) ) {
			$this->fields[$field_id]['SIZE'] = $size;
		}
		
		// Set the field options
		if( isset( $opts ) ) {
			$this->fields[$field_id]['OPTS'][] = $opts;
		}
	}
	
	/**
	* Adds a field option to the current field specifier
	*
	* This method adds a field option allowed by the ADOdb datadict 
	* and appends it to the given field.
	*
	* @param string $field	Field name
	* @param string $opt ADOdb field option
	* @param mixed $value Field option value
	* @return array Field specifier array
	*/
	function addFieldOpt( $field, $opt, $value = NULL ) {
		if( !isset( $value ) ) {
			$this->fields[$this->FieldID( $field )]['OPTS'][] = $opt;
		// Add the option and value
		} else {
			$this->fields[$this->FieldID( $field )]['OPTS'][] = array( $opt => $value );
		}
	}
	
	/**
	* Adds an option to the table
	*
	* This method takes a comma-separated list of table-level options
	* and appends them to the table object.
	*
	* @param string $opt Table option
	* @return array Options
	*/
	function addTableOpt( $opt ) {
		$this->opts[] = $opt;
		
		return $this->opts;
	}
	
	/**
	* Generates the SQL that will create the table in the database
	*
	* @param object $xmls adoSchema object
	* @return array Array containing table creation SQL
	*/
	function create( &$xmls ) {
		$sql = array();
		
		// drop any existing indexes
		if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( $this->name ) ) ) {
			foreach( $legacy_indexes as $index => $index_details ) {
				$sql[] = $xmls->dict->DropIndexSQL( $index, $this->name );
			}
		}
		
		// remove fields to be dropped from table object
		foreach( $this->drop_field as $field ) {
			unset( $this->fields[$field] );
		}
		
		// if table exists
		if( is_array( $legacy_fields = $xmls->dict->MetaColumns( $this->name ) ) ) {
			// drop table
			if( $this->drop_table ) {
				$sql[] = $xmls->dict->DropTableSQL( $this->name );
				
				return $sql;
			}
			
			// drop any existing fields not in schema
			foreach( $legacy_fields as $field_id => $field ) {
				if( !isset( $this->fields[$field_id] ) ) {
					$sql[] = $xmls->dict->DropColumnSQL( $this->name, '`'.$field->name.'`' );
				}
			}
		// if table doesn't exist
		} else {
			if( $this->drop_table ) {
				return $sql;
			}
			
			$legacy_fields = array();
		}
		
		// Loop through the field specifier array, building the associative array for the field options
		$fldarray = array();
		
		foreach( $this->fields as $field_id => $finfo ) {
			// Set an empty size if it isn't supplied
			if( !isset( $finfo['SIZE'] ) ) {
				$finfo['SIZE'] = '';
			}
			
			// Initialize the field array with the type and size
			$fldarray[$field_id] = array(
				'NAME' => $finfo['NAME'],
				'TYPE' => $finfo['TYPE'],
				'SIZE' => $finfo['SIZE']
			);
			
			// Loop through the options array and add the field options. 
			if( isset( $finfo['OPTS'] ) ) {
				foreach( $finfo['OPTS'] as $opt ) {
					// Option has an argument.
					if( is_array( $opt ) ) {
						$key = key( $opt );
						$value = $opt[key( $opt )];
						@$fldarray[$field_id][$key] .= $value;
					// Option doesn't have arguments
					} else {
						$fldarray[$field_id][$opt] = $opt;
					}
				}
			}
		}
		
		if( empty( $legacy_fields ) ) {
			// Create the new table
			$sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
			logMsg( end( $sql ), 'Generated CreateTableSQL' );
		} else {
			// Upgrade an existing table
			logMsg( "Upgrading {$this->name} using '{$xmls->upgrade}'" );
			switch( $xmls->upgrade ) {
				// Use ChangeTableSQL
				case 'ALTER':
					logMsg( 'Generated ChangeTableSQL (ALTERing table)' );
					$sql[] = $xmls->dict->ChangeTableSQL( $this->name, $fldarray, $this->opts );
					break;
				case 'REPLACE':
					logMsg( 'Doing upgrade REPLACE (testing)' );
					$sql[] = $xmls->dict->DropTableSQL( $this->name );
					$sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
					break;
				// ignore table
				default:
					return array();
			}
		}
		
		foreach( $this->indexes as $index ) {
			$sql[] = $index->create( $xmls );
		}
		
		if( isset( $this->data ) ) {
			$sql[] = $this->data->create( $xmls );
		}
		
		return $sql;
	}
	
	/**
	* Marks a field or table for destruction
	*/
	function drop() {
		if( isset( $this->current_field ) ) {
			// Drop the current field
			logMsg( "Dropping field '{$this->current_field}' from table '{$this->name}'" );
			// $this->drop_field[$this->current_field] = $xmls->dict->DropColumnSQL( $this->name, $this->current_field );
			$this->drop_field[$this->current_field] = $this->current_field;
		} else {
			// Drop the current table
			logMsg( "Dropping table '{$this->name}'" );
			// $this->drop_table = $xmls->dict->DropTableSQL( $this->name );
			$this->drop_table = TRUE;
		}
	}
}

/**
* Creates an index object in ADOdb's datadict format
*
* This class stores information about a database index. As charactaristics
* of the index are loaded from the external source, methods and properties
* of this class are used to build up the index description in ADOdb's
* datadict format.
*
* @package axmls
* @access private
*/
class dbIndex extends dbObject {
	
	/**
	* @var string	Index name
	*/
	var $name;
	
	/**
	* @var array	Index options: Index-level options
	*/
	var $opts = array();
	
	/**
	* @var array	Indexed fields: Table columns included in this index
	*/
	var $columns = array();
	
	/**
	* @var boolean Mark index for destruction
	* @access private
	*/
	var $drop = FALSE;
	
	/**
	* Initializes the new dbIndex object.
	*
	* @param object $parent Parent object
	* @param array $attributes Attributes
	*
	* @internal
	*/
	function dbIndex( &$parent, $attributes = NULL ) {
		$this->parent =& $parent;
		
		$this->name = $this->prefix ($attributes['NAME']);
	}
	
	/**
	* XML Callback to process start elements
	*
	* Processes XML opening tags. 
	* Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH. 
	*
	* @access private
	*/
	function _tag_open( &$parser, $tag, $attributes ) {
		$this->currentElement = strtoupper( $tag );
		
		switch( $this->currentElement ) {
			case 'DROP':
				$this->drop();
				break;
			case 'CLUSTERED':
			case 'BITMAP':
			case 'UNIQUE':
			case 'FULLTEXT':
			case 'HASH':
				// Add index Option
				$this->addIndexOpt( $this->currentElement );
				break;
			default:
				// print_r( array( $tag, $attributes ) );
		}
	}
	
	/**
	* XML Callback to process CDATA elements
	*
	* Processes XML cdata.
	*
	* @access private
	*/
	function _tag_cdata( &$parser, $cdata ) {
		switch( $this->currentElement ) {
			// Index field name
			case 'COL':
				$this->addField( $cdata );
				break;
			default:
				
		}
	}
	
	/**
	* XML Callback to process end elements
	*
	* @access private
	*/
	function _tag_close( &$parser, $tag ) {
		$this->currentElement = '';
		
		switch( strtoupper( $tag ) ) {
			case 'INDEX':
				xml_set_object( $parser, $this->parent );
				break;
		}
	}
	
	/**
	* Adds a field to the index
	*
	* @param string $name Field name
	* @return string Field list
	*/
	function addField( $name ) {
		$this->columns[$this->FieldID( $name )] = $name;
		
		// Return the field list
		return $this->columns;
	}
	
	/**
	* Adds options to the index
	*
	* @param string $opt Comma-separated list of index options.
	* @return string Option list
	*/
	function addIndexOpt( $opt ) {
		$this->opts[] = $opt;
		
		// Return the options list
		return $this->opts;
	}
	
	/**
	* Generates the SQL that will create the index in the database
	*
	* @param object $xmls adoSchema object
	* @return array Array containing index creation SQL
	*/
	function create( &$xmls ) {
		if( $this->drop ) {
			return NULL;
		}
		
		// eliminate any columns that aren't in the table
		foreach( $this->columns as $id => $col ) {
			if( !isset( $this->parent->fields[$id] ) ) {
				unset( $this->columns[$id] );
			}
		}
		
		return $xmls->dict->CreateIndexSQL( $this->name, $this->parent->name, $this->columns, $this->opts );
	}
	
	/**
	* Marks an index for destruction
	*/
	function drop() {
		$this->drop = TRUE;
	}
}

/**
* Creates a data object in ADOdb's datadict format
*
* This class stores information about table data.
*
* @package axmls
* @access private
*/
class dbData extends dbObject {
	
	var $data = array();
	
	var $row;
	
	/**
	* Initializes the new dbIndex object.
	*
	* @param object $parent Parent object
	* @param array $attributes Attributes
	*
	* @internal
	*/
	function dbData( &$parent, $attributes = NULL ) {
		$this->parent =& $parent;
	}
	
	/**
	* XML Callback to process start elements
	*
	* Processes XML opening tags. 
	* Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH. 
	*
	* @access private
	*/
	function _tag_open( &$parser, $tag, $attributes ) {
		$this->currentElement = strtoupper( $tag );
		
		switch( $this->currentElement ) {
			case 'ROW':
				$this->row = count( $this->data );
				$this->data[$this->row] = array();
				break;
			case 'F':
				$this->addField($attributes);
			default:
				// print_r( array( $tag, $attributes ) );
		}
	}
	
	/**
	* XML Callback to process CDATA elements
	*
	* Processes XML cdata.
	*
	* @access private
	*/
	function _tag_cdata( &$parser, $cdata ) {
		switch( $this->currentElement ) {
			// Index field name
			case 'F':
				$this->addData( $cdata );
				break;
			default:
				
		}
	}
	
	/**
	* XML Callback to process end elements
	*
	* @access private
	*/
	function _tag_close( &$parser, $tag ) {
		$this->currentElement = '';
		
		switch( strtoupper( $tag ) ) {
			case 'DATA':
				xml_set_object( $parser, $this->parent );
				break;
		}
	}
	
	/**
	* Adds a field to the index
	*
	* @param string $name Field name
	* @return string Field list
	*/
	function addField( $attributes ) {
		if( isset( $attributes['NAME'] ) ) {
			$name = $attributes['NAME'];
		} else {
			$name = count($this->data[$this->row]);
		}
		
		// Set the field index so we know where we are
		$this->current_field = $this->FieldID( $name );
	}
	
	/**
	* Adds options to the index
	*
	* @param string $opt Comma-separated list of index options.
	* @return string Option list
	*/
	function addData( $cdata ) {
		if( !isset( $this->data[$this->row] ) ) {
			$this->data[$this->row] = array();
		}
		
		if( !isset( $this->data[$this->row][$this->current_field] ) ) {
			$this->data[$this->row][$this->current_field] = '';
		}
		
		$this->data[$this->row][$this->current_field] .= $cdata;
	}
	
	/**
	* Generates the SQL that will create the index in the database
	*
	* @param object $xmls adoSchema object
	* @return array Array containing index creation SQL
	*/
	function create( &$xmls ) {
		$table = $xmls->dict->TableName($this->parent->name);
		$table_field_count = count($this->parent->fields);
		$sql = array();
		
		// eliminate any columns that aren't in the table
		foreach( $this->data as $row ) {
			$table_fields = $this->parent->fields;
			$fields = array();
			
			foreach( $row as $field_id => $field_data ) {
				if( !array_key_exists( $field_id, $table_fields ) ) {
					if( is_numeric( $field_id ) ) {
						$field_id = reset( array_keys( $table_fields ) );
					} else {
						continue;
					}
				}
				
				$name = $table_fields[$field_id]['NAME'];
				
				switch( $table_fields[$field_id]['TYPE'] ) {
					case 'C':
					case 'C2':
					case 'X':
					case 'X2':
						$fields[$name] = $xmls->db->qstr( $field_data );
						break;
					case 'I':
					case 'I1':
					case 'I2':
					case 'I4':
					case 'I8':
						$fields[$name] = intval($field_data);
						break;
					default:
						$fields[$name] = $field_data;
				}
				
				unset($table_fields[$field_id]);
			}
			
			// check that at least 1 column is specified
			if( empty( $fields ) ) {
				continue;
			}
			
			// check that no required columns are missing
			if( count( $fields ) < $table_field_count ) {
				foreach( $table_fields as $field ) {
					if (isset( $field['OPTS'] ))
						if( ( in_array( 'NOTNULL', $field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 'AUTOINCREMENT', $field['OPTS'] ) ) {
							continue(2);
						}
				}
			}
			
			$sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
		}
		
		return $sql;
	}
}

/**
* Creates the SQL to execute a list of provided SQL queries
*
* @package axmls
* @access private
*/
class dbQuerySet extends dbObject {
	
	/**
	* @var array	List of SQL queries
	*/
	var $queries = array();
	
	/**
	* @var string	String used to build of a query line by line
	*/
	var $query;
	
	/**
	* @var string	Query prefix key
	*/
	var $prefixKey = '';
	
	/**
	* @var boolean	Auto prefix enable (TRUE)
	*/
	var $prefixMethod = 'AUTO';
	
	/**
	* Initializes the query set.
	*
	* @param object $parent Parent object
	* @param array $attributes Attributes
	*/
	function dbQuerySet( &$parent, $attributes = NULL ) {
		$this->parent =& $parent;
			
		// Overrides the manual prefix key
		if( isset( $attributes['KEY'] ) ) {
			$this->prefixKey = $attributes['KEY'];
		}
		
		$prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : '';
		
		// Enables or disables automatic prefix prepending
		switch( $prefixMethod ) {
			case 'AUTO':
				$this->prefixMethod = 'AUTO';
				break;
			case 'MANUAL':
				$this->prefixMethod = 'MANUAL';
				break;
			case 'NONE':
				$this->prefixMethod = 'NONE';
				break;
		}
	}
	
	/**
	* XML Callback to process start elements. Elements currently 
	* processed are: QUERY. 
	*
	* @access private
	*/
	function _tag_open( &$parser, $tag, $attributes ) {
		$this->currentElement = strtoupper( $tag );
		
		switch( $this->currentElement ) {
			case 'QUERY':
				// Create a new query in a SQL queryset.
				// Ignore this query set if a platform is specified and it's different than the 
				// current connection platform.
				if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
					$this->newQuery();
				} else {
					$this->discardQuery();
				}
				break;
			default:
				// print_r( array( $tag, $attributes ) );
		}
	}
	
	/**
	* XML Callback to process CDATA elements
	*/
	function _tag_cdata( &$parser, $cdata ) {
		switch( $this->currentElement ) {
			// Line of queryset SQL data
			case 'QUERY':
				$this->buildQuery( $cdata );
				break;
			default:
				
		}
	}
	
	/**
	* XML Callback to process end elements
	*
	* @access private
	*/
	function _tag_close( &$parser, $tag ) {
		$this->currentElement = '';
		
		switch( strtoupper( $tag ) ) {
			case 'QUERY':
				// Add the finished query to the open query set.
				$this->addQuery();
				break;
			case 'SQL':
				$this->parent->addSQL( $this->create( $this->parent ) );
				xml_set_object( $parser, $this->parent );
				$this->destroy();
				break;
			default:
				
		}
	}
	
	/**
	* Re-initializes the query.
	*
	* @return boolean TRUE
	*/
	function newQuery() {
		$this->query = '';
		
		return TRUE;
	}
	
	/**
	* Discards the existing query.
	*
	* @return boolean TRUE
	*/
	function discardQuery() {
		unset( $this->query );
		
		return TRUE;
	}
	
	/** 
	* Appends a line to a query that is being built line by line
	*
	* @param string $data Line of SQL data or NULL to initialize a new query
	* @return string SQL query string.
	*/
	function buildQuery( $sql = NULL ) {
		if( !isset( $this->query ) OR empty( $sql ) ) {
			return FALSE;
		}
		
		$this->query .= $sql;
		
		return $this->query;
	}
	
	/**
	* Adds a completed query to the query list
	*
	* @return string	SQL of added query
	*/
	function addQuery() {
		if( !isset( $this->query ) ) {
			return FALSE;
		}
		
		$this->queries[] = $return = trim($this->query);
		
		unset( $this->query );
		
		return $return;
	}
	
	/**
	* Creates and returns the current query set
	*
	* @param object $xmls adoSchema object
	* @return array Query set
	*/
	function create( &$xmls ) {
		foreach( $this->queries as $id => $query ) {
			switch( $this->prefixMethod ) {
				case 'AUTO':
					// Enable auto prefix replacement
					
					// Process object prefix.
					// Evaluate SQL statements to prepend prefix to objects
					$query = $this->prefixQuery( '/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
					$query = $this->prefixQuery( '/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
					$query = $this->prefixQuery( '/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
					
					// SELECT statements aren't working yet
					#$data = preg_replace( '/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 $prefix\2 \3", $data );
					
				case 'MANUAL':
					// If prefixKey is set and has a value then we use it to override the default constant XMLS_PREFIX.
					// If prefixKey is not set, we use the default constant XMLS_PREFIX
					if( isset( $this->prefixKey ) AND( $this->prefixKey !== '' ) ) {
						// Enable prefix override
						$query = str_replace( $this->prefixKey, $xmls->objectPrefix, $query );
					} else {
						// Use default replacement
						$query = str_replace( XMLS_PREFIX , $xmls->objectPrefix, $query );
					}
			}
			
			$this->queries[$id] = trim( $query );
		}
		
		// Return the query set array
		return $this->queries;
	}
	
	/**
	* Rebuilds the query with the prefix attached to any objects
	*
	* @param string $regex Regex used to add prefix
	* @param string $query SQL query string
	* @param string $prefix Prefix to be appended to tables, indices, etc.
	* @return string Prefixed SQL query string.
	*/
	function prefixQuery( $regex, $query, $prefix = NULL ) {
		if( !isset( $prefix ) ) {
			return $query;
		}
		
		if( preg_match( $regex, $query, $match ) ) {
			$preamble = $match[1];
			$postamble = $match[5];
			$objectList = explode( ',', $match[3] );
			// $prefix = $prefix . '_';
			
			$prefixedList = '';
			
			foreach( $objectList as $object ) {
				if( $prefixedList !== '' ) {
					$prefixedList .= ', ';
				}
				
				$prefixedList .= $prefix . trim( $object );
			}
			
			$query = $preamble . ' ' . $prefixedList . ' ' . $postamble;
		}
		
		return $query;
	}
}

/**
* Loads and parses an XML file, creating an array of "ready-to-run" SQL statements
* 
* This class is used to load and parse the XML file, to create an array of SQL statements
* that can be used to build a database, and to build the database using the SQL array.
*
* @tutorial getting_started.pkg
*
* @author Richard Tango-Lowy & Dan Cech
* @version $Revision: 1.12 $
*
* @package axmls
*/
class adoSchema {
	
	/**
	* @var array	Array containing SQL queries to generate all objects
	* @access private
	*/
	var $sqlArray;
	
	/**
	* @var object	ADOdb connection object
	* @access private
	*/
	var $db;
	
	/**
	* @var object	ADOdb Data Dictionary
	* @access private
	*/
	var $dict;
	
	/**
	* @var string Current XML element
	* @access private
	*/
	var $currentElement = '';
	
	/**
	* @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database
	* @access private
	*/
	var $upgrade = '';
	
	/**
	* @var string Optional object prefix
	* @access private
	*/
	var $objectPrefix = '';
	
	/**
	* @var long	Original Magic Quotes Runtime value
	* @access private
	*/
	var $mgq;
	
	/**
	* @var long	System debug
	* @access private
	*/
	var $debug;
	
	/**
	* @var string Regular expression to find schema version
	* @access private
	*/
	var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
	
	/**
	* @var string Current schema version
	* @access private
	*/
	var $schemaVersion;
	
	/**
	* @var int	Success of last Schema execution
	*/
	var $success;
	
	/**
	* @var bool	Execute SQL inline as it is generated
	*/
	var $executeInline;
	
	/**
	* @var bool	Continue SQL execution if errors occur
	*/
	var $continueOnError;
	
	/**
	* Creates an adoSchema object
	*
	* Creating an adoSchema object is the first step in processing an XML schema.
	* The only parameter is an ADOdb database connection object, which must already
	* have been created.
	*
	* @param object $db ADOdb database connection object.
	*/
	function adoSchema( &$db ) {
		// Initialize the environment
		$this->mgq = get_magic_quotes_runtime();
		set_magic_quotes_runtime(0);
		
		$this->db =& $db;
		$this->debug = $this->db->debug;
		$this->dict = NewDataDictionary( $this->db );
		$this->sqlArray = array();
		$this->schemaVersion = XMLS_SCHEMA_VERSION;
		$this->executeInline( XMLS_EXECUTE_INLINE );
		$this->continueOnError( XMLS_CONTINUE_ON_ERROR );
		$this->setUpgradeMethod();
	}
	
	/**
	* Sets the method to be used for upgrading an existing database
	*
	* Use this method to specify how existing database objects should be upgraded.
	* The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to
	* alter each database object directly, REPLACE attempts to rebuild each object
	* from scratch, BEST attempts to determine the best upgrade method for each
	* object, and NONE disables upgrading.
	*
	* This method is not yet used by AXMLS, but exists for backward compatibility.
	* The ALTER method is automatically assumed when the adoSchema object is
	* instantiated; other upgrade methods are not currently supported.
	*
	* @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
	* @returns string Upgrade method used
	*/
	function SetUpgradeMethod( $method = '' ) {
		if( !is_string( $method ) ) {
			return FALSE;
		}
		
		$method = strtoupper( $method );
		
		// Handle the upgrade methods
		switch( $method ) {
			case 'ALTER':
				$this->upgrade = $method;
				break;
			case 'REPLACE':
				$this->upgrade = $method;
				break;
			case 'BEST':
				$this->upgrade = 'ALTER';
				break;
			case 'NONE':
				$this->upgrade = 'NONE';
				break;
			default:
				// Use default if no legitimate method is passed.
				$this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD;
		}
		
		return $this->upgrade;
	}
	
	/**
	* Enables/disables inline SQL execution.
	*
	* Call this method to enable or disable inline execution of the schema. If the mode is set to TRUE (inline execution),
	* AXMLS applies the SQL to the database immediately as each schema entity is parsed. If the mode
	* is set to FALSE (post execution), AXMLS parses the entire schema and you will need to call adoSchema::ExecuteSchema()
	* to apply the schema to the database.
	*
	* @param bool $mode execute
	* @return bool current execution mode
	*
	* @see ParseSchema(), ExecuteSchema()
	*/
	function ExecuteInline( $mode = NULL ) {
		if( is_bool( $mode ) ) {
			$this->executeInline = $mode;
		}
		
		return $this->executeInline;
	}
	
	/**
	* Enables/disables SQL continue on error.
	*
	* Call this method to enable or disable continuation of SQL execution if an error occurs.
	* If the mode is set to TRUE (continue), AXMLS will continue to apply SQL to the database, even if an error occurs.
	* If the mode is set to FALSE (halt), AXMLS will halt execution of generated sql if an error occurs, though parsing
	* of the schema will continue.
	*
	* @param bool $mode execute
	* @return bool current continueOnError mode
	*
	* @see addSQL(), ExecuteSchema()
	*/
	function ContinueOnError( $mode = NULL ) {
		if( is_bool( $mode ) ) {
			$this->continueOnError = $mode;
		}
		
		return $this->continueOnError;
	}
	
	/**
	* Loads an XML schema from a file and converts it to SQL.
	*
	* Call this method to load the specified schema (see the DTD for the proper format) from
	* the filesystem and generate the SQL necessary to create the database described. 
	* @see ParseSchemaString()
	*
	* @param string $file Name of XML schema file.
	* @param bool $returnSchema Return schema rather than parsing.
	* @return array Array of SQL queries, ready to execute
	*/
	function ParseSchema( $filename, $returnSchema = FALSE ) {
		return $this->ParseSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
	}
	
	/**
	* Loads an XML schema from a file and converts it to SQL.
	*
	* Call this method to load the specified schema from a file (see the DTD for the proper format) 
	* and generate the SQL necessary to create the database described by the schema.
	*
	* @param string $file Name of XML schema file.
	* @param bool $returnSchema Return schema rather than parsing.
	* @return array Array of SQL queries, ready to execute.
	*
	* @deprecated Replaced by adoSchema::ParseSchema() and adoSchema::ParseSchemaString()
	* @see ParseSchema(), ParseSchemaString()
	*/
	function ParseSchemaFile( $filename, $returnSchema = FALSE ) {
		// Open the file
		if( !($fp = fopen( $filename, 'r' )) ) {
			// die( 'Unable to open file' );
			return FALSE;
		}
		
		// do version detection here
		if( $this->SchemaFileVersion( $filename ) != $this->schemaVersion ) {
			return FALSE;
		}
		
		if ( $returnSchema )
		{
			$xmlstring = '';
			while( $data = fread( $fp, 100000 ) ) {
				$xmlstring .= $data;
			}
			return $xmlstring;
		}
		
		$this->success = 2;
		
		$xmlParser = $this->create_parser();
		
		// Process the file
		while( $data = fread( $fp, 4096 ) ) {
			if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) {
				die( sprintf(
					"XML error: %s at line %d",
					xml_error_string( xml_get_error_code( $xmlParser) ),
					xml_get_current_line_number( $xmlParser)
				) );
			}
		}
		
		xml_parser_free( $xmlParser );
		
		return $this->sqlArray;
	}
	
	/**
	* Converts an XML schema string to SQL.
	*
	* Call this method to parse a string containing an XML schema (see the DTD for the proper format)
	* and generate the SQL necessary to create the database described by the schema. 
	* @see ParseSchema()
	*
	* @param string $xmlstring XML schema string.
	* @param bool $returnSchema Return schema rather than parsing.
	* @return array Array of SQL queries, ready to execute.
	*/
	function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) {
		if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
			return FALSE;
		}
		
		// do version detection here
		if( $this->SchemaStringVersion( $xmlstring ) != $this->schemaVersion ) {
			return FALSE;
		}
		
		if ( $returnSchema )
		{
			return $xmlstring;
		}
		
		$this->success = 2;
		
		$xmlParser = $this->create_parser();
		
		if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
			die( sprintf(
				"XML error: %s at line %d",
				xml_error_string( xml_get_error_code( $xmlParser) ),
				xml_get_current_line_number( $xmlParser)
			) );
		}
		
		xml_parser_free( $xmlParser );
		
		return $this->sqlArray;
	}
	
	/**
	* Loads an XML schema from a file and converts it to uninstallation SQL.
	*
	* Call this method to load the specified schema (see the DTD for the proper format) from
	* the filesystem and generate the SQL necessary to remove the database described.
	* @see RemoveSchemaString()
	*
	* @param string $file Name of XML schema file.
	* @param bool $returnSchema Return schema rather than parsing.
	* @return array Array of SQL queries, ready to execute
	*/
	function RemoveSchema( $filename, $returnSchema = FALSE ) {
		return $this->RemoveSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
	}
	
	/**
	* Converts an XML schema string to uninstallation SQL.
	*
	* Call this method to parse a string containing an XML schema (see the DTD for the proper format)
	* and generate the SQL necessary to uninstall the database described by the schema. 
	* @see RemoveSchema()
	*
	* @param string $schema XML schema string.
	* @param bool $returnSchema Return schema rather than parsing.
	* @return array Array of SQL queries, ready to execute.
	*/
	function RemoveSchemaString( $schema, $returnSchema = FALSE ) {
		
		// grab current version
		if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
			return FALSE;
		}
		
		return $this->ParseSchemaString( $this->TransformSchema( $schema, 'remove-' . $version), $returnSchema );
	}
	
	/**
	* Applies the current XML schema to the database (post execution).
	*
	* Call this method to apply the current schema (generally created by calling 
	* ParseSchema() or ParseSchemaString() ) to the database (creating the tables, indexes, 
	* and executing other SQL specified in the schema) after parsing.
	* @see ParseSchema(), ParseSchemaString(), ExecuteInline()
	*
	* @param array $sqlArray Array of SQL statements that will be applied rather than
	*		the current schema.
	* @param boolean $continueOnErr Continue to apply the schema even if an error occurs.
	* @returns integer 0 if failure, 1 if errors, 2 if successful.
	*/
	function ExecuteSchema( $sqlArray = NULL, $continueOnErr =  NULL ) {
		if( !is_bool( $continueOnErr ) ) {
			$continueOnErr = $this->ContinueOnError();
		}
		
		if( !isset( $sqlArray ) ) {
			$sqlArray = $this->sqlArray;
		}
		
		if( !is_array( $sqlArray ) ) {
			$this->success = 0;
		} else {
			$this->success = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr );
		}
		
		return $this->success;
	}
	
	/**
	* Returns the current SQL array. 
	*
	* Call this method to fetch the array of SQL queries resulting from 
	* ParseSchema() or ParseSchemaString(). 
	*
	* @param string $format Format: HTML, TEXT, or NONE (PHP array)
	* @return array Array of SQL statements or FALSE if an error occurs
	*/
	function PrintSQL( $format = 'NONE' ) {
		$sqlArray = null;
		return $this->getSQL( $format, $sqlArray );
	}
	
	/**
	* Saves the current SQL array to the local filesystem as a list of SQL queries.
	*
	* Call this method to save the array of SQL queries (generally resulting from a
	* parsed XML schema) to the filesystem.
	*
	* @param string $filename Path and name where the file should be saved.
	* @return boolean TRUE if save is successful, else FALSE. 
	*/
	function SaveSQL( $filename = './schema.sql' ) {
		
		if( !isset( $sqlArray ) ) {
			$sqlArray = $this->sqlArray;
		}
		if( !isset( $sqlArray ) ) {
			return FALSE;
		}
		
		$fp = fopen( $filename, "w" );
		
		foreach( $sqlArray as $key => $query ) {
			fwrite( $fp, $query . ";\n" );
		}
		fclose( $fp );
	}
	
	/**
	* Create an xml parser
	*
	* @return object PHP XML parser object
	*
	* @access private
	*/
	function &create_parser() {
		// Create the parser
		$xmlParser = xml_parser_create();
		xml_set_object( $xmlParser, $this );
		
		// Initialize the XML callback functions
		xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' );
		xml_set_character_data_handler( $xmlParser, '_tag_cdata' );
		
		return $xmlParser;
	}
	
	/**
	* XML Callback to process start elements
	*
	* @access private
	*/
	function _tag_open( &$parser, $tag, $attributes ) {
		switch( strtoupper( $tag ) ) {
			case 'TABLE':
				$this->obj = new dbTable( $this, $attributes );
				xml_set_object( $parser, $this->obj );
				break;
			case 'SQL':
				if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
					$this->obj = new dbQuerySet( $this, $attributes );
					xml_set_object( $parser, $this->obj );
				}
				break;
			default:
				// print_r( array( $tag, $attributes ) );
		}
		
	}
	
	/**
	* XML Callback to process CDATA elements
	*
	* @access private
	*/
	function _tag_cdata( &$parser, $cdata ) {
	}
	
	/**
	* XML Callback to process end elements
	*
	* @access private
	* @internal
	*/
	function _tag_close( &$parser, $tag ) {
		
	}
	
	/**
	* Converts an XML schema string to the specified DTD version.
	*
	* Call this method to convert a string containing an XML schema to a different AXMLS
	* DTD version. For instance, to convert a schema created for an pre-1.0 version for 
	* AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version 
	* parameter is specified, the schema will be converted to the current DTD version. 
	* If the newFile parameter is provided, the converted schema will be written to the specified
	* file.
	* @see ConvertSchemaFile()
	*
	* @param string $schema String containing XML schema that will be converted.
	* @param string $newVersion DTD version to convert to.
	* @param string $newFile File name of (converted) output file.
	* @return string Converted XML schema or FALSE if an error occurs.
	*/
	function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) {
		
		// grab current version
		if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
			return FALSE;
		}
		
		if( !isset ($newVersion) ) {
			$newVersion = $this->schemaVersion;
		}
		
		if( $version == $newVersion ) {
			$result = $schema;
		} else {
			$result = $this->TransformSchema( $schema, 'convert-' . $version . '-' . $newVersion);
		}
		
		if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
			fwrite( $fp, $result );
			fclose( $fp );
		}
		
		return $result;
	}
	
	// compat for pre-4.3 - jlim
	function _file_get_contents($path)
	{
		if (function_exists('file_get_contents')) return file_get_contents($path);
		return join('',file($path));
	}
	
	/**
	* Converts an XML schema file to the specified DTD version.
	*
	* Call this method to convert the specified XML schema file to a different AXMLS
	* DTD version. For instance, to convert a schema created for an pre-1.0 version for 
	* AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version 
	* parameter is specified, the schema will be converted to the current DTD version. 
	* If the newFile parameter is provided, the converted schema will be written to the specified
	* file.
	* @see ConvertSchemaString()
	*
	* @param string $filename Name of XML schema file that will be converted.
	* @param string $newVersion DTD version to convert to.
	* @param string $newFile File name of (converted) output file.
	* @return string Converted XML schema or FALSE if an error occurs.
	*/
	function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) {
		
		// grab current version
		if( !( $version = $this->SchemaFileVersion( $filename ) ) ) {
			return FALSE;
		}
		
		if( !isset ($newVersion) ) {
			$newVersion = $this->schemaVersion;
		}
		
		if( $version == $newVersion ) {
			$result = _file_get_contents( $filename );
			
			// remove unicode BOM if present
			if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) {
				$result = substr( $result, 3 );
			}
		} else {
			$result = $this->TransformSchema( $filename, 'convert-' . $version . '-' . $newVersion, 'file' );
		}
		
		if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
			fwrite( $fp, $result );
			fclose( $fp );
		}
		
		return $result;
	}
	
	function TransformSchema( $schema, $xsl, $schematype='string' )
	{
		// Fail if XSLT extension is not available
		if( ! function_exists( 'xslt_create' ) ) {
			return FALSE;
		}
		
		$xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl';
		
		// look for xsl
		if( !is_readable( $xsl_file ) ) {
			return FALSE;
		}
		
		switch( $schematype )
		{
			case 'file':
				if( !is_readable( $schema ) ) {
					return FALSE;
				}
				
				$schema = _file_get_contents( $schema );
				break;
			case 'string':
			default:
				if( !is_string( $schema ) ) {
					return FALSE;
				}
		}
		
		$arguments = array (
			'/_xml' => $schema,
			'/_xsl' => _file_get_contents( $xsl_file )
		);
		
		// create an XSLT processor
		$xh = xslt_create ();
		
		// set error handler
		xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler'));
		
		// process the schema
		$result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments); 
		
		xslt_free ($xh);
		
		return $result;
	}
	
	/**
	* Processes XSLT transformation errors
	*
	* @param object $parser XML parser object
	* @param integer $errno Error number
	* @param integer $level Error level
	* @param array $fields Error information fields
	*
	* @access private
	*/
	function xslt_error_handler( $parser, $errno, $level, $fields ) {
		if( is_array( $fields ) ) {
			$msg = array(
				'Message Type' => ucfirst( $fields['msgtype'] ),
				'Message Code' => $fields['code'],
				'Message' => $fields['msg'],
				'Error Number' => $errno,
				'Level' => $level
			);
			
			switch( $fields['URI'] ) {
				case 'arg:/_xml':
					$msg['Input'] = 'XML';
					break;
				case 'arg:/_xsl':
					$msg['Input'] = 'XSL';
					break;
				default:
					$msg['Input'] = $fields['URI'];
			}
			
			$msg['Line'] = $fields['line'];
		} else {
			$msg = array(
				'Message Type' => 'Error',
				'Error Number' => $errno,
				'Level' => $level,
				'Fields' => var_export( $fields, TRUE )
			);
		}
		
		$error_details = $msg['Message Type'] . ' in XSLT Transformation' . "\n"
					   . '<table>' . "\n";
		
		foreach( $msg as $label => $details ) {
			$error_details .= '<tr><td><b>' . $label . ': </b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n";
		}
		
		$error_details .= '</table>';
		
		trigger_error( $error_details, E_USER_ERROR );
	}
	
	/**
	* Returns the AXMLS Schema Version of the requested XML schema file.
	*
	* Call this method to obtain the AXMLS DTD version of the requested XML schema file.
	* @see SchemaStringVersion()
	*
	* @param string $filename AXMLS schema file
	* @return string Schema version number or FALSE on error
	*/
	function SchemaFileVersion( $filename ) {
		// Open the file
		if( !($fp = fopen( $filename, 'r' )) ) {
			// die( 'Unable to open file' );
			return FALSE;
		}
		
		// Process the file
		while( $data = fread( $fp, 4096 ) ) {
			if( preg_match( $this->versionRegex, $data, $matches ) ) {
				return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
			}
		}
		
		return FALSE;
	}
	
	/**
	* Returns the AXMLS Schema Version of the provided XML schema string.
	*
	* Call this method to obtain the AXMLS DTD version of the provided XML schema string.
	* @see SchemaFileVersion()
	*
	* @param string $xmlstring XML schema string
	* @return string Schema version number or FALSE on error
	*/
	function SchemaStringVersion( $xmlstring ) {
		if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
			return FALSE;
		}
		
		if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) {
			return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
		}
		
		return FALSE;
	}
	
	/**
	* Extracts an XML schema from an existing database.
	*
	* Call this method to create an XML schema string from an existing database.
	* If the data parameter is set to TRUE, AXMLS will include the data from the database
	* in the schema. 
	*
	* @param boolean $data Include data in schema dump
	* @return string Generated XML schema
	*/
	function ExtractSchema( $data = FALSE ) {
		$old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM );
		
		$schema = '<?xml version="1.0"?>' . "\n"
				. '<schema version="' . $this->schemaVersion . '">' . "\n";
		
		if( is_array( $tables = $this->db->MetaTables( 'TABLES' ) ) ) {
			foreach( $tables as $table ) {
				$schema .= '	<table name="' . $table . '">' . "\n";
				
				// grab details from database
				$rs = $this->db->Execute( 'SELECT * FROM ' . $table . ' WHERE 1=1' );
				$fields = $this->db->MetaColumns( $table );
				$indexes = $this->db->MetaIndexes( $table );
				
				if( is_array( $fields ) ) {
					foreach( $fields as $details ) {
						$extra = '';
						$content = array();
						
						if( $details->max_length > 0 ) {
							$extra .= ' size="' . $details->max_length . '"';
						}
						
						if( $details->primary_key ) {
							$content[] = '<KEY/>';
						} elseif( $details->not_null ) {
							$content[] = '<NOTNULL/>';
						}
						
						if( $details->has_default ) {
							$content[] = '<DEFAULT value="' . $details->default_value . '"/>';
						}
						
						if( $details->auto_increment ) {
							$content[] = '<AUTOINCREMENT/>';
						}
						
						// this stops the creation of 'R' columns,
						// AUTOINCREMENT is used to create auto columns
						$details->primary_key = 0;
						$type = $rs->MetaType( $details );
						
						$schema .= '		<field name="' . $details->name . '" type="' . $type . '"' . $extra . '>';
						
						if( !empty( $content ) ) {
							$schema .= "\n			" . implode( "\n			", $content ) . "\n		";
						}
						
						$schema .= '</field>' . "\n";
					}
				}
				
				if( is_array( $indexes ) ) {
					foreach( $indexes as $index => $details ) {
						$schema .= '		<index name="' . $index . '">' . "\n";
						
						if( $details['unique'] ) {
							$schema .= '			<UNIQUE/>' . "\n";
						}
						
						foreach( $details['columns'] as $column ) {
							$schema .= '			<col>' . $column . '</col>' . "\n";
						}
						
						$schema .= '		</index>' . "\n";
					}
				}
				
				if( $data ) {
					$rs = $this->db->Execute( 'SELECT * FROM ' . $table );
					
					if( is_object( $rs ) ) {
						$schema .= '		<data>' . "\n";
						
						while( $row = $rs->FetchRow() ) {
							foreach( $row as $key => $val ) {
								$row[$key] = htmlentities($val);
							}
							
							$schema .= '			<row><f>' . implode( '</f><f>', $row ) . '</f></row>' . "\n";
						}
						
						$schema .= '		</data>' . "\n";
					}
				}
				
				$schema .= '	</table>' . "\n";
			}
		}
		
		$this->db->SetFetchMode( $old_mode );
		
		$schema .= '</schema>';
		return $schema;
	}
	
	/**
	* Sets a prefix for database objects
	*
	* Call this method to set a standard prefix that will be prepended to all database tables 
	* and indices when the schema is parsed. Calling setPrefix with no arguments clears the prefix.
	*
	* @param string $prefix Prefix that will be prepended.
	* @param boolean $underscore If TRUE, automatically append an underscore character to the prefix.
	* @return boolean TRUE if successful, else FALSE
	*/
	function SetPrefix( $prefix = '', $underscore = TRUE ) {
		switch( TRUE ) {
			// clear prefix
			case empty( $prefix ):
				logMsg( 'Cleared prefix' );
				$this->objectPrefix = '';
				return TRUE;
			// prefix too long
			case strlen( $prefix ) > XMLS_PREFIX_MAXLEN:
			// prefix contains invalid characters
			case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ):
				logMsg( 'Invalid prefix: ' . $prefix );
				return FALSE;
		}
		
		if( $underscore AND substr( $prefix, -1 ) != '_' ) {
			$prefix .= '_';
		}
		
		// prefix valid
		logMsg( 'Set prefix: ' . $prefix );
		$this->objectPrefix = $prefix;
		return TRUE;
	}
	
	/**
	* Returns an object name with the current prefix prepended.
	*
	* @param string	$name Name
	* @return string	Prefixed name
	*
	* @access private
	*/
	function prefix( $name = '' ) {
		// if prefix is set
		if( !empty( $this->objectPrefix ) ) {
			// Prepend the object prefix to the table name
			// prepend after quote if used
			return preg_replace( '/^(`?)(.+)$/', '$1' . $this->objectPrefix . '$2', $name );
		}
		
		// No prefix set. Use name provided.
		return $name;
	}
	
	/**
	* Checks if element references a specific platform
	*
	* @param string $platform Requested platform
	* @returns boolean TRUE if platform check succeeds
	*
	* @access private
	*/
	function supportedPlatform( $platform = NULL ) {
		$regex = '/^(\w*\|)*' . $this->db->databaseType . '(\|\w*)*$/';
		
		if( !isset( $platform ) OR preg_match( $regex, $platform ) ) {
			logMsg( "Platform $platform is supported" );
			return TRUE;
		} else {
			logMsg( "Platform $platform is NOT supported" );
			return FALSE;
		}
	}
	
	/**
	* Clears the array of generated SQL.
	*
	* @access private
	*/
	function clearSQL() {
		$this->sqlArray = array();
	}
	
	/**
	* Adds SQL into the SQL array.
	*
	* @param mixed $sql SQL to Add
	* @return boolean TRUE if successful, else FALSE.
	*
	* @access private
	*/	
	function addSQL( $sql = NULL ) {
		if( is_array( $sql ) ) {
			foreach( $sql as $line ) {
				$this->addSQL( $line );
			}
			
			return TRUE;
		}
		
		if( is_string( $sql ) ) {
			$this->sqlArray[] = $sql;
			
			// if executeInline is enabled, and either no errors have occurred or continueOnError is enabled, execute SQL.
			if( $this->ExecuteInline() && ( $this->success == 2 || $this->ContinueOnError() ) ) {
				$saved = $this->db->debug;
				$this->db->debug = $this->debug;
				$ok = $this->db->Execute( $sql );
				$this->db->debug = $saved;
				
				if( !$ok ) {
					if( $this->debug ) {
						ADOConnection::outp( $this->db->ErrorMsg() );
					}
					
					$this->success = 1;
				}
			}
			
			return TRUE;
		}
		
		return FALSE;
	}
	
	/**
	* Gets the SQL array in the specified format.
	*
	* @param string $format Format
	* @return mixed SQL
	*	
	* @access private
	*/
	function getSQL( $format = NULL, $sqlArray = NULL ) {
		if( !is_array( $sqlArray ) ) {
			$sqlArray = $this->sqlArray;
		}
		
		if( !is_array( $sqlArray ) ) {
			return FALSE;
		}
		
		switch( strtolower( $format ) ) {
			case 'string':
			case 'text':
				return !empty( $sqlArray ) ? implode( ";\n\n", $sqlArray ) . ';' : '';
			case'html':
				return !empty( $sqlArray ) ? nl2br( htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : '';
		}
		
		return $this->sqlArray;
	}
	
	/**
	* Destroys an adoSchema object.
	*
	* Call this method to clean up after an adoSchema object that is no longer in use.
	* @deprecated adoSchema now cleans up automatically.
	*/
	function Destroy() {
		set_magic_quotes_runtime( $this->mgq );
		unset( $this );
	}
}

/**
* Message logging function
*
* @access private
*/
function logMsg( $msg, $title = NULL, $force = FALSE ) {
	if( XMLS_DEBUG or $force ) {
		echo '<pre>';
		
		if( isset( $title ) ) {
			echo '<h3>' . htmlentities( $title ) . '</h3>';
		}
		
		if( is_object( $this ) ) {
			echo '[' . get_class( $this ) . '] ';
		}
		
		print_r( $msg );
		
		echo '</pre>';
	}
}
?>

Added program_files/include/adodb4/adodb-xmlschema03.inc.php.







































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
<?php
// Copyright (c) 2004-2005 ars Cognita Inc., all rights reserved
/* ******************************************************************************
    Released under both BSD license and Lesser GPL library license. 
 	Whenever there is any discrepancy between the two licenses, 
 	the BSD license will take precedence. 
*******************************************************************************/
/**
 * xmlschema is a class that allows the user to quickly and easily
 * build a database on any ADOdb-supported platform using a simple
 * XML schema.
 *
 * Last Editor: $Author: jlim $
 * @author Richard Tango-Lowy & Dan Cech
 * @version $Revision: 1.62 $
 *
 * @package axmls
 * @tutorial getting_started.pkg
 */
 
function _file_get_contents($file) 
{
 	if (function_exists('file_get_contents')) return file_get_contents($file);
	
	$f = fopen($file,'r');
	if (!$f) return '';
	$t = '';
	
	while ($s = fread($f,100000)) $t .= $s;
	fclose($f);
	return $t;
}


/**
* Debug on or off
*/
if( !defined( 'XMLS_DEBUG' ) ) {
	define( 'XMLS_DEBUG', FALSE );
}

/**
* Default prefix key
*/
if( !defined( 'XMLS_PREFIX' ) ) {
	define( 'XMLS_PREFIX', '%%P' );
}

/**
* Maximum length allowed for object prefix
*/
if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
	define( 'XMLS_PREFIX_MAXLEN', 10 );
}

/**
* Execute SQL inline as it is generated
*/
if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
	define( 'XMLS_EXECUTE_INLINE', FALSE );
}

/**
* Continue SQL Execution if an error occurs?
*/
if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
	define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
}

/**
* Current Schema Version
*/
if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
	define( 'XMLS_SCHEMA_VERSION', '0.3' );
}

/**
* Default Schema Version.  Used for Schemas without an explicit version set.
*/
if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
	define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
}

/**
* How to handle data rows that already exist in a database during and upgrade.
* Options are INSERT (attempts to insert duplicate rows), UPDATE (updates existing
* rows) and IGNORE (ignores existing rows).
*/
if( !defined( 'XMLS_MODE_INSERT' ) ) {
	define( 'XMLS_MODE_INSERT', 0 );
}
if( !defined( 'XMLS_MODE_UPDATE' ) ) {
	define( 'XMLS_MODE_UPDATE', 1 );
}
if( !defined( 'XMLS_MODE_IGNORE' ) ) {
	define( 'XMLS_MODE_IGNORE', 2 );
}
if( !defined( 'XMLS_EXISTING_DATA' ) ) {
	define( 'XMLS_EXISTING_DATA', XMLS_MODE_INSERT );
}

/**
* Default Schema Version.  Used for Schemas without an explicit version set.
*/
if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
	define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
}

/**
* Include the main ADODB library
*/
if( !defined( '_ADODB_LAYER' ) ) {
	require( 'adodb.inc.php' );
	require( 'adodb-datadict.inc.php' );
}

/**
* Abstract DB Object. This class provides basic methods for database objects, such
* as tables and indexes.
*
* @package axmls
* @access private
*/
class dbObject {
	
	/**
	* var object Parent
	*/
	var $parent;
	
	/**
	* var string current element
	*/
	var $currentElement;
	
	/**
	* NOP
	*/
	function dbObject( &$parent, $attributes = NULL ) {
		$this->parent =& $parent;
	}
	
	/**
	* XML Callback to process start elements
	*
	* @access private
	*/
	function _tag_open( &$parser, $tag, $attributes ) {
		
	}
	
	/**
	* XML Callback to process CDATA elements
	*
	* @access private
	*/
	function _tag_cdata( &$parser, $cdata ) {
		
	}
	
	/**
	* XML Callback to process end elements
	*
	* @access private
	*/
	function _tag_close( &$parser, $tag ) {
		
	}
	
	function create() {
		return array();
	}
	
	/**
	* Destroys the object
	*/
	function destroy() {
		unset( $this );
	}
	
	/**
	* Checks whether the specified RDBMS is supported by the current
	* database object or its ranking ancestor.
	*
	* @param string $platform RDBMS platform name (from ADODB platform list).
	* @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
	*/
	function supportedPlatform( $platform = NULL ) {
		return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE;
	}
	
	/**
	* Returns the prefix set by the ranking ancestor of the database object.
	*
	* @param string $name Prefix string.
	* @return string Prefix.
	*/
	function prefix( $name = '' ) {
		return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name;
	}
	
	/**
	* Extracts a field ID from the specified field.
	*
	* @param string $field Field.
	* @return string Field ID.
	*/
	function FieldID( $field ) {
		return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
	}
}

/**
* Creates a table object in ADOdb's datadict format
*
* This class stores information about a database table. As charactaristics
* of the table are loaded from the external source, methods and properties
* of this class are used to build up the table description in ADOdb's
* datadict format.
*
* @package axmls
* @access private
*/
class dbTable extends dbObject {
	
	/**
	* @var string Table name
	*/
	var $name;
	
	/**
	* @var array Field specifier: Meta-information about each field
	*/
	var $fields = array();
	
	/**
	* @var array List of table indexes.
	*/
	var $indexes = array();
	
	/**
	* @var array Table options: Table-level options
	*/
	var $opts = array();
	
	/**
	* @var string Field index: Keeps track of which field is currently being processed
	*/
	var $current_field;
	
	/**
	* @var boolean Mark table for destruction
	* @access private
	*/
	var $drop_table;
	
	/**
	* @var boolean Mark field for destruction (not yet implemented)
	* @access private
	*/
	var $drop_field = array();
	
	/**
	* @var array Platform-specific options
	* @access private
	*/
	var $currentPlatform = true;
	
	
	/**
	* Iniitializes a new table object.
	*
	* @param string $prefix DB Object prefix
	* @param array $attributes Array of table attributes.
	*/
	function dbTable( &$parent, $attributes = NULL ) {
		$this->parent =& $parent;
		$this->name = $this->prefix($attributes['NAME']);
	}
	
	/**
	* XML Callback to process start elements. Elements currently 
	* processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT. 
	*
	* @access private
	*/
	function _tag_open( &$parser, $tag, $attributes ) {
		$this->currentElement = strtoupper( $tag );
		
		switch( $this->currentElement ) {
			case 'INDEX':
				if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
					xml_set_object( $parser, $this->addIndex( $attributes ) );
				}
				break;
			case 'DATA':
				if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
					xml_set_object( $parser, $this->addData( $attributes ) );
				}
				break;
			case 'DROP':
				$this->drop();
				break;
			case 'FIELD':
				// Add a field
				$fieldName = $attributes['NAME'];
				$fieldType = $attributes['TYPE'];
				$fieldSize = isset( $attributes['SIZE'] ) ? $attributes['SIZE'] : NULL;
				$fieldOpts = !empty( $attributes['OPTS'] ) ? $attributes['OPTS'] : NULL;
				
				$this->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts );
				break;
			case 'KEY':
			case 'NOTNULL':
			case 'AUTOINCREMENT':
			case 'DEFDATE':
			case 'DEFTIMESTAMP':
			case 'UNSIGNED':
				// Add a field option
				$this->addFieldOpt( $this->current_field, $this->currentElement );
				break;
			case 'DEFAULT':
				// Add a field option to the table object
				
				// Work around ADOdb datadict issue that misinterprets empty strings.
				if( $attributes['VALUE'] == '' ) {
					$attributes['VALUE'] = " '' ";
				}
				
				$this->addFieldOpt( $this->current_field, $this->currentElement, $attributes['VALUE'] );
				break;
			case 'OPT':
			case 'CONSTRAINT':
				// Accept platform-specific options
				$this->currentPlatform = ( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) );
				break;
			default:
				// print_r( array( $tag, $attributes ) );
		}
	}
	
	/**
	* XML Callback to process CDATA elements
	*
	* @access private
	*/
	function _tag_cdata( &$parser, $cdata ) {
		switch( $this->currentElement ) {
			// Table/field constraint
			case 'CONSTRAINT':
				if( isset( $this->current_field ) ) {
					$this->addFieldOpt( $this->current_field, $this->currentElement, $cdata );
				} else {
					$this->addTableOpt( $cdata );
				}
				break;
			// Table/field option
			case 'OPT':
				if( isset( $this->current_field ) ) {
					$this->addFieldOpt( $this->current_field, $cdata );
				} else {
				$this->addTableOpt( $cdata );
				}
				break;
			default:
				
		}
	}
	
	/**
	* XML Callback to process end elements
	*
	* @access private
	*/
	function _tag_close( &$parser, $tag ) {
		$this->currentElement = '';
		
		switch( strtoupper( $tag ) ) {
			case 'TABLE':
				$this->parent->addSQL( $this->create( $this->parent ) );
				xml_set_object( $parser, $this->parent );
				$this->destroy();
				break;
			case 'FIELD':
				unset($this->current_field);
				break;
			case 'OPT':
			case 'CONSTRAINT':
				$this->currentPlatform = true;
				break;
			default:

		}
	}
	
	/**
	* Adds an index to a table object
	*
	* @param array $attributes Index attributes
	* @return object dbIndex object
	*/
	function &addIndex( $attributes ) {
		$name = strtoupper( $attributes['NAME'] );
		$this->indexes[$name] =& new dbIndex( $this, $attributes );
		return $this->indexes[$name];
	}
	
	/**
	* Adds data to a table object
	*
	* @param array $attributes Data attributes
	* @return object dbData object
	*/
	function &addData( $attributes ) {
		if( !isset( $this->data ) ) {
			$this->data =& new dbData( $this, $attributes );
		}
		return $this->data;
	}
	
	/**
	* Adds a field to a table object
	*
	* $name is the name of the table to which the field should be added. 
	* $type is an ADODB datadict field type. The following field types
	* are supported as of ADODB 3.40:
	* 	- C:  varchar
	*	- X:  CLOB (character large object) or largest varchar size
	*	   if CLOB is not supported
	*	- C2: Multibyte varchar
	*	- X2: Multibyte CLOB
	*	- B:  BLOB (binary large object)
	*	- D:  Date (some databases do not support this, and we return a datetime type)
	*	- T:  Datetime or Timestamp
	*	- L:  Integer field suitable for storing booleans (0 or 1)
	*	- I:  Integer (mapped to I4)
	*	- I1: 1-byte integer
	*	- I2: 2-byte integer
	*	- I4: 4-byte integer
	*	- I8: 8-byte integer
	*	- F:  Floating point number
	*	- N:  Numeric or decimal number
	*
	* @param string $name Name of the table to which the field will be added.
	* @param string $type	ADODB datadict field type.
	* @param string $size	Field size
	* @param array $opts	Field options array
	* @return array Field specifier array
	*/
	function addField( $name, $type, $size = NULL, $opts = NULL ) {
		$field_id = $this->FieldID( $name );
		
		// Set the field index so we know where we are
		$this->current_field = $field_id;
		
		// Set the field name (required)
		$this->fields[$field_id]['NAME'] = $name;
		
		// Set the field type (required)
		$this->fields[$field_id]['TYPE'] = $type;
		
		// Set the field size (optional)
		if( isset( $size ) ) {
			$this->fields[$field_id]['SIZE'] = $size;
		}
		
		// Set the field options
		if( isset( $opts ) ) {
			$this->fields[$field_id]['OPTS'] = array($opts);
		} else {
			$this->fields[$field_id]['OPTS'] = array();
		}
	}
	
	/**
	* Adds a field option to the current field specifier
	*
	* This method adds a field option allowed by the ADOdb datadict 
	* and appends it to the given field.
	*
	* @param string $field	Field name
	* @param string $opt ADOdb field option
	* @param mixed $value Field option value
	* @return array Field specifier array
	*/
	function addFieldOpt( $field, $opt, $value = NULL ) {
		if( $this->currentPlatform ) {
		if( !isset( $value ) ) {
			$this->fields[$this->FieldID( $field )]['OPTS'][] = $opt;
		// Add the option and value
		} else {
			$this->fields[$this->FieldID( $field )]['OPTS'][] = array( $opt => $value );
		}
	}
	}
	
	/**
	* Adds an option to the table
	*
	* This method takes a comma-separated list of table-level options
	* and appends them to the table object.
	*
	* @param string $opt Table option
	* @return array Options
	*/
	function addTableOpt( $opt ) {
		if( $this->currentPlatform ) {
		$this->opts[] = $opt;
		}
		return $this->opts;
	}
	
	/**
	* Generates the SQL that will create the table in the database
	*
	* @param object $xmls adoSchema object
	* @return array Array containing table creation SQL
	*/
	function create( &$xmls ) {
		$sql = array();
		
		// drop any existing indexes
		if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( $this->name ) ) ) {
			foreach( $legacy_indexes as $index => $index_details ) {
				$sql[] = $xmls->dict->DropIndexSQL( $index, $this->name );
			}
		}
		
		// remove fields to be dropped from table object
		foreach( $this->drop_field as $field ) {
			unset( $this->fields[$field] );
		}
		
		// if table exists
		if( is_array( $legacy_fields = $xmls->dict->MetaColumns( $this->name ) ) ) {
			// drop table
			if( $this->drop_table ) {
				$sql[] = $xmls->dict->DropTableSQL( $this->name );
				
				return $sql;
			}
			
			// drop any existing fields not in schema
			foreach( $legacy_fields as $field_id => $field ) {
				if( !isset( $this->fields[$field_id] ) ) {
					$sql[] = $xmls->dict->DropColumnSQL( $this->name, $field->name );
				}
			}
		// if table doesn't exist
		} else {
			if( $this->drop_table ) {
				return $sql;
			}
			
			$legacy_fields = array();
		}
		
		// Loop through the field specifier array, building the associative array for the field options
		$fldarray = array();
		
		foreach( $this->fields as $field_id => $finfo ) {
			// Set an empty size if it isn't supplied
			if( !isset( $finfo['SIZE'] ) ) {
				$finfo['SIZE'] = '';
			}
			
			// Initialize the field array with the type and size
			$fldarray[$field_id] = array(
				'NAME' => $finfo['NAME'],
				'TYPE' => $finfo['TYPE'],
				'SIZE' => $finfo['SIZE']
			);
			
			// Loop through the options array and add the field options. 
			if( isset( $finfo['OPTS'] ) ) {
				foreach( $finfo['OPTS'] as $opt ) {
					// Option has an argument.
					if( is_array( $opt ) ) {
						$key = key( $opt );
						$value = $opt[key( $opt )];
						@$fldarray[$field_id][$key] .= $value;
					// Option doesn't have arguments
					} else {
						$fldarray[$field_id][$opt] = $opt;
					}
				}
			}
		}
		
		if( empty( $legacy_fields ) ) {
			// Create the new table
			$sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
			logMsg( end( $sql ), 'Generated CreateTableSQL' );
		} else {
			// Upgrade an existing table
			logMsg( "Upgrading {$this->name} using '{$xmls->upgrade}'" );
			switch( $xmls->upgrade ) {
				// Use ChangeTableSQL
				case 'ALTER':
					logMsg( 'Generated ChangeTableSQL (ALTERing table)' );
					$sql[] = $xmls->dict->ChangeTableSQL( $this->name, $fldarray, $this->opts );
					break;
				case 'REPLACE':
					logMsg( 'Doing upgrade REPLACE (testing)' );
					$sql[] = $xmls->dict->DropTableSQL( $this->name );
					$sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
					break;
				// ignore table
				default:
					return array();
			}
		}
		
		foreach( $this->indexes as $index ) {
			$sql[] = $index->create( $xmls );
		}
		
		if( isset( $this->data ) ) {
			$sql[] = $this->data->create( $xmls );
		}
		
		return $sql;
	}
	
	/**
	* Marks a field or table for destruction
	*/
	function drop() {
		if( isset( $this->current_field ) ) {
			// Drop the current field
			logMsg( "Dropping field '{$this->current_field}' from table '{$this->name}'" );
			// $this->drop_field[$this->current_field] = $xmls->dict->DropColumnSQL( $this->name, $this->current_field );
			$this->drop_field[$this->current_field] = $this->current_field;
		} else {
			// Drop the current table
			logMsg( "Dropping table '{$this->name}'" );
			// $this->drop_table = $xmls->dict->DropTableSQL( $this->name );
			$this->drop_table = TRUE;
		}
	}
}

/**
* Creates an index object in ADOdb's datadict format
*
* This class stores information about a database index. As charactaristics
* of the index are loaded from the external source, methods and properties
* of this class are used to build up the index description in ADOdb's
* datadict format.
*
* @package axmls
* @access private
*/
class dbIndex extends dbObject {
	
	/**
	* @var string	Index name
	*/
	var $name;
	
	/**
	* @var array	Index options: Index-level options
	*/
	var $opts = array();
	
	/**
	* @var array	Indexed fields: Table columns included in this index
	*/
	var $columns = array();
	
	/**
	* @var boolean Mark index for destruction
	* @access private
	*/
	var $drop = FALSE;
	
	/**
	* Initializes the new dbIndex object.
	*
	* @param object $parent Parent object
	* @param array $attributes Attributes
	*
	* @internal
	*/
	function dbIndex( &$parent, $attributes = NULL ) {
		$this->parent =& $parent;
		
		$this->name = $this->prefix ($attributes['NAME']);
	}
	
	/**
	* XML Callback to process start elements
	*
	* Processes XML opening tags. 
	* Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH. 
	*
	* @access private
	*/
	function _tag_open( &$parser, $tag, $attributes ) {
		$this->currentElement = strtoupper( $tag );
		
		switch( $this->currentElement ) {
			case 'DROP':
				$this->drop();
				break;
			case 'CLUSTERED':
			case 'BITMAP':
			case 'UNIQUE':
			case 'FULLTEXT':
			case 'HASH':
				// Add index Option
				$this->addIndexOpt( $this->currentElement );
				break;
			default:
				// print_r( array( $tag, $attributes ) );
		}
	}
	
	/**
	* XML Callback to process CDATA elements
	*
	* Processes XML cdata.
	*
	* @access private
	*/
	function _tag_cdata( &$parser, $cdata ) {
		switch( $this->currentElement ) {
			// Index field name
			case 'COL':
				$this->addField( $cdata );
				break;
			default:
				
		}
	}
	
	/**
	* XML Callback to process end elements
	*
	* @access private
	*/
	function _tag_close( &$parser, $tag ) {
		$this->currentElement = '';
		
		switch( strtoupper( $tag ) ) {
			case 'INDEX':
				xml_set_object( $parser, $this->parent );
				break;
		}
	}
	
	/**
	* Adds a field to the index
	*
	* @param string $name Field name
	* @return string Field list
	*/
	function addField( $name ) {
		$this->columns[$this->FieldID( $name )] = $name;
		
		// Return the field list
		return $this->columns;
	}
	
	/**
	* Adds options to the index
	*
	* @param string $opt Comma-separated list of index options.
	* @return string Option list
	*/
	function addIndexOpt( $opt ) {
		$this->opts[] = $opt;
		
		// Return the options list
		return $this->opts;
	}
	
	/**
	* Generates the SQL that will create the index in the database
	*
	* @param object $xmls adoSchema object
	* @return array Array containing index creation SQL
	*/
	function create( &$xmls ) {
		if( $this->drop ) {
			return NULL;
		}
		
		// eliminate any columns that aren't in the table
		foreach( $this->columns as $id => $col ) {
			if( !isset( $this->parent->fields[$id] ) ) {
				unset( $this->columns[$id] );
			}
		}
		
		return $xmls->dict->CreateIndexSQL( $this->name, $this->parent->name, $this->columns, $this->opts );
	}
	
	/**
	* Marks an index for destruction
	*/
	function drop() {
		$this->drop = TRUE;
	}
}

/**
* Creates a data object in ADOdb's datadict format
*
* This class stores information about table data, and is called
* when we need to load field data into a table.
*
* @package axmls
* @access private
*/
class dbData extends dbObject {
	
	var $data = array();
	
	var $row;
	
	/**
	* Initializes the new dbData object.
	*
	* @param object $parent Parent object
	* @param array $attributes Attributes
	*
	* @internal
	*/
	function dbData( &$parent, $attributes = NULL ) {
		$this->parent =& $parent;
	}
	
	/**
	* XML Callback to process start elements
	*
	* Processes XML opening tags. 
	* Elements currently processed are: ROW and F (field). 
	*
	* @access private
	*/
	function _tag_open( &$parser, $tag, $attributes ) {
		$this->currentElement = strtoupper( $tag );
		
		switch( $this->currentElement ) {
			case 'ROW':
				$this->row = count( $this->data );
				$this->data[$this->row] = array();
				break;
			case 'F':
				$this->addField($attributes);
			default:
				// print_r( array( $tag, $attributes ) );
		}
	}
	
	/**
	* XML Callback to process CDATA elements
	*
	* Processes XML cdata.
	*
	* @access private
	*/
	function _tag_cdata( &$parser, $cdata ) {
		switch( $this->currentElement ) {
			// Index field name
			case 'F':
				$this->addData( $cdata );
				break;
			default:
				
		}
	}
	
	/**
	* XML Callback to process end elements
	*
	* @access private
	*/
	function _tag_close( &$parser, $tag ) {
		$this->currentElement = '';
		
		switch( strtoupper( $tag ) ) {
			case 'DATA':
				xml_set_object( $parser, $this->parent );
				break;
		}
	}
	
	/**
	* Adds a field to the insert
	*
	* @param string $name Field name
	* @return string Field list
	*/
	function addField( $attributes ) {
		// check we're in a valid row
		if( !isset( $this->row ) || !isset( $this->data[$this->row] ) ) {
			return;
		}
		
		// Set the field index so we know where we are
		if( isset( $attributes['NAME'] ) ) {
			$this->current_field = $this->FieldID( $attributes['NAME'] );
		} else {
			$this->current_field = count( $this->data[$this->row] );
		}
		
		// initialise data
		if( !isset( $this->data[$this->row][$this->current_field] ) ) {
			$this->data[$this->row][$this->current_field] = '';
		}
	}
	
	/**
	* Adds options to the index
	*
	* @param string $opt Comma-separated list of index options.
	* @return string Option list
	*/
	function addData( $cdata ) {
		// check we're in a valid field
		if ( isset( $this->data[$this->row][$this->current_field] ) ) {
			// add data to field
			$this->data[$this->row][$this->current_field] .= $cdata;
		}
	}
	
	/**
	* Generates the SQL that will add/update the data in the database
	*
	* @param object $xmls adoSchema object
	* @return array Array containing index creation SQL
	*/
	function create( &$xmls ) {
		$table = $xmls->dict->TableName($this->parent->name);
		$table_field_count = count($this->parent->fields);
		$tables = $xmls->db->MetaTables(); 
		$sql = array();
		
		$ukeys = $xmls->db->MetaPrimaryKeys( $table );
		if( !empty( $this->parent->indexes ) and !empty( $ukeys ) ) {
			foreach( $this->parent->indexes as $indexObj ) {
				if( !in_array( $indexObj->name, $ukeys ) ) $ukeys[] = $indexObj->name;
			}
		}
		
		// eliminate any columns that aren't in the table
		foreach( $this->data as $row ) {
			$table_fields = $this->parent->fields;
			$fields = array();
			$rawfields = array(); // Need to keep some of the unprocessed data on hand.
			
			foreach( $row as $field_id => $field_data ) {
				if( !array_key_exists( $field_id, $table_fields ) ) {
					if( is_numeric( $field_id ) ) {
						$field_id = reset( array_keys( $table_fields ) );
					} else {
						continue;
					}
				}
				
				$name = $table_fields[$field_id]['NAME'];
				
				switch( $table_fields[$field_id]['TYPE'] ) {
					case 'I':
					case 'I1':
					case 'I2':
					case 'I4':
					case 'I8':
						$fields[$name] = intval($field_data);
						break;
					case 'C':
					case 'C2':
					case 'X':
					case 'X2':
					default:
						$fields[$name] = $xmls->db->qstr( $field_data );
						$rawfields[$name] = $field_data;
				}
				
				unset($table_fields[$field_id]);
				
			}
			
			// check that at least 1 column is specified
			if( empty( $fields ) ) {
				continue;
			}
			
			// check that no required columns are missing
			if( count( $fields ) < $table_field_count ) {
				foreach( $table_fields as $field ) {
					if( isset( $field['OPTS'] ) and ( in_array( 'NOTNULL', $field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 'AUTOINCREMENT', $field['OPTS'] ) ) {
							continue(2);
						}
				}
			}
			
			// The rest of this method deals with updating existing data records.
			
			if( !in_array( $table, $tables ) or ( $mode = $xmls->existingData() ) == XMLS_MODE_INSERT ) {
				// Table doesn't yet exist, so it's safe to insert.
				logMsg( "$table doesn't exist, inserting or mode is INSERT" );
			$sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
				continue;
		}
		
			// Prepare to test for potential violations. Get primary keys and unique indexes
			$mfields = array_merge( $fields, $rawfields );
			$keyFields = array_intersect( $ukeys, array_keys( $mfields ) );
			
			if( empty( $ukeys ) or count( $keyFields ) == 0 ) {
				// No unique keys in schema, so safe to insert
				logMsg( "Either schema or data has no unique keys, so safe to insert" );
				$sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
				continue;
			}
			
			// Select record containing matching unique keys.
			$where = '';
			foreach( $ukeys as $key ) {
				if( isset( $mfields[$key] ) and $mfields[$key] ) {
					if( $where ) $where .= ' AND ';
					$where .= $key . ' = ' . $xmls->db->qstr( $mfields[$key] );
				}
			}
			$records = $xmls->db->Execute( 'SELECT * FROM ' . $table . ' WHERE ' . $where );
			switch( $records->RecordCount() ) {
				case 0:
					// No matching record, so safe to insert.
					logMsg( "No matching records. Inserting new row with unique data" );
					$sql[] = $xmls->db->GetInsertSQL( $records, $mfields );
					break;
				case 1:
					// Exactly one matching record, so we can update if the mode permits.
					logMsg( "One matching record..." );
					if( $mode == XMLS_MODE_UPDATE ) {
						logMsg( "...Updating existing row from unique data" );
						$sql[] = $xmls->db->GetUpdateSQL( $records, $mfields );
					}
					break;
				default:
					// More than one matching record; the result is ambiguous, so we must ignore the row.
					logMsg( "More than one matching record. Ignoring row." );
			}
		}
		return $sql;
	}
}

/**
* Creates the SQL to execute a list of provided SQL queries
*
* @package axmls
* @access private
*/
class dbQuerySet extends dbObject {
	
	/**
	* @var array	List of SQL queries
	*/
	var $queries = array();
	
	/**
	* @var string	String used to build of a query line by line
	*/
	var $query;
	
	/**
	* @var string	Query prefix key
	*/
	var $prefixKey = '';
	
	/**
	* @var boolean	Auto prefix enable (TRUE)
	*/
	var $prefixMethod = 'AUTO';
	
	/**
	* Initializes the query set.
	*
	* @param object $parent Parent object
	* @param array $attributes Attributes
	*/
	function dbQuerySet( &$parent, $attributes = NULL ) {
		$this->parent =& $parent;
			
		// Overrides the manual prefix key
		if( isset( $attributes['KEY'] ) ) {
			$this->prefixKey = $attributes['KEY'];
		}
		
		$prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : '';
		
		// Enables or disables automatic prefix prepending
		switch( $prefixMethod ) {
			case 'AUTO':
				$this->prefixMethod = 'AUTO';
				break;
			case 'MANUAL':
				$this->prefixMethod = 'MANUAL';
				break;
			case 'NONE':
				$this->prefixMethod = 'NONE';
				break;
		}
	}
	
	/**
	* XML Callback to process start elements. Elements currently 
	* processed are: QUERY. 
	*
	* @access private
	*/
	function _tag_open( &$parser, $tag, $attributes ) {
		$this->currentElement = strtoupper( $tag );
		
		switch( $this->currentElement ) {
			case 'QUERY':
				// Create a new query in a SQL queryset.
				// Ignore this query set if a platform is specified and it's different than the 
				// current connection platform.
				if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
					$this->newQuery();
				} else {
					$this->discardQuery();
				}
				break;
			default:
				// print_r( array( $tag, $attributes ) );
		}
	}
	
	/**
	* XML Callback to process CDATA elements
	*/
	function _tag_cdata( &$parser, $cdata ) {
		switch( $this->currentElement ) {
			// Line of queryset SQL data
			case 'QUERY':
				$this->buildQuery( $cdata );
				break;
			default:
				
		}
	}
	
	/**
	* XML Callback to process end elements
	*
	* @access private
	*/
	function _tag_close( &$parser, $tag ) {
		$this->currentElement = '';
		
		switch( strtoupper( $tag ) ) {
			case 'QUERY':
				// Add the finished query to the open query set.
				$this->addQuery();
				break;
			case 'SQL':
				$this->parent->addSQL( $this->create( $this->parent ) );
				xml_set_object( $parser, $this->parent );
				$this->destroy();
				break;
			default:
				
		}
	}
	
	/**
	* Re-initializes the query.
	*
	* @return boolean TRUE
	*/
	function newQuery() {
		$this->query = '';
		
		return TRUE;
	}
	
	/**
	* Discards the existing query.
	*
	* @return boolean TRUE
	*/
	function discardQuery() {
		unset( $this->query );
		
		return TRUE;
	}
	
	/** 
	* Appends a line to a query that is being built line by line
	*
	* @param string $data Line of SQL data or NULL to initialize a new query
	* @return string SQL query string.
	*/
	function buildQuery( $sql = NULL ) {
		if( !isset( $this->query ) OR empty( $sql ) ) {
			return FALSE;
		}
		
		$this->query .= $sql;
		
		return $this->query;
	}
	
	/**
	* Adds a completed query to the query list
	*
	* @return string	SQL of added query
	*/
	function addQuery() {
		if( !isset( $this->query ) ) {
			return FALSE;
		}
		
		$this->queries[] = $return = trim($this->query);
		
		unset( $this->query );
		
		return $return;
	}
	
	/**
	* Creates and returns the current query set
	*
	* @param object $xmls adoSchema object
	* @return array Query set
	*/
	function create( &$xmls ) {
		foreach( $this->queries as $id => $query ) {
			switch( $this->prefixMethod ) {
				case 'AUTO':
					// Enable auto prefix replacement
					
					// Process object prefix.
					// Evaluate SQL statements to prepend prefix to objects
					$query = $this->prefixQuery( '/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
					$query = $this->prefixQuery( '/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
					$query = $this->prefixQuery( '/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
					
					// SELECT statements aren't working yet
					#$data = preg_replace( '/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 $prefix\2 \3", $data );
					
				case 'MANUAL':
					// If prefixKey is set and has a value then we use it to override the default constant XMLS_PREFIX.
					// If prefixKey is not set, we use the default constant XMLS_PREFIX
					if( isset( $this->prefixKey ) AND( $this->prefixKey !== '' ) ) {
						// Enable prefix override
						$query = str_replace( $this->prefixKey, $xmls->objectPrefix, $query );
					} else {
						// Use default replacement
						$query = str_replace( XMLS_PREFIX , $xmls->objectPrefix, $query );
					}
			}
			
			$this->queries[$id] = trim( $query );
		}
		
		// Return the query set array
		return $this->queries;
	}
	
	/**
	* Rebuilds the query with the prefix attached to any objects
	*
	* @param string $regex Regex used to add prefix
	* @param string $query SQL query string
	* @param string $prefix Prefix to be appended to tables, indices, etc.
	* @return string Prefixed SQL query string.
	*/
	function prefixQuery( $regex, $query, $prefix = NULL ) {
		if( !isset( $prefix ) ) {
			return $query;
		}
		
		if( preg_match( $regex, $query, $match ) ) {
			$preamble = $match[1];
			$postamble = $match[5];
			$objectList = explode( ',', $match[3] );
			// $prefix = $prefix . '_';
			
			$prefixedList = '';
			
			foreach( $objectList as $object ) {
				if( $prefixedList !== '' ) {
					$prefixedList .= ', ';
				}
				
				$prefixedList .= $prefix . trim( $object );
			}
			
			$query = $preamble . ' ' . $prefixedList . ' ' . $postamble;
		}
		
		return $query;
	}
}

/**
* Loads and parses an XML file, creating an array of "ready-to-run" SQL statements
* 
* This class is used to load and parse the XML file, to create an array of SQL statements
* that can be used to build a database, and to build the database using the SQL array.
*
* @tutorial getting_started.pkg
*
* @author Richard Tango-Lowy & Dan Cech
* @version $Revision: 1.62 $
*
* @package axmls
*/
class adoSchema {
	
	/**
	* @var array	Array containing SQL queries to generate all objects
	* @access private
	*/
	var $sqlArray;
	
	/**
	* @var object	ADOdb connection object
	* @access private
	*/
	var $db;
	
	/**
	* @var object	ADOdb Data Dictionary
	* @access private
	*/
	var $dict;
	
	/**
	* @var string Current XML element
	* @access private
	*/
	var $currentElement = '';
	
	/**
	* @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database
	* @access private
	*/
	var $upgrade = '';
	
	/**
	* @var string Optional object prefix
	* @access private
	*/
	var $objectPrefix = '';
	
	/**
	* @var long	Original Magic Quotes Runtime value
	* @access private
	*/
	var $mgq;
	
	/**
	* @var long	System debug
	* @access private
	*/
	var $debug;
	
	/**
	* @var string Regular expression to find schema version
	* @access private
	*/
	var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
	
	/**
	* @var string Current schema version
	* @access private
	*/
	var $schemaVersion;
	
	/**
	* @var int	Success of last Schema execution
	*/
	var $success;
	
	/**
	* @var bool	Execute SQL inline as it is generated
	*/
	var $executeInline;
	
	/**
	* @var bool	Continue SQL execution if errors occur
	*/
	var $continueOnError;
	
	/**
	* @var int	How to handle existing data rows (insert, update, or ignore)
	*/
	var $existingData;
	
	/**
	* Creates an adoSchema object
	*
	* Creating an adoSchema object is the first step in processing an XML schema.
	* The only parameter is an ADOdb database connection object, which must already
	* have been created.
	*
	* @param object $db ADOdb database connection object.
	*/
	function adoSchema( &$db ) {
		// Initialize the environment
		$this->mgq = get_magic_quotes_runtime();
		set_magic_quotes_runtime(0);
		
		$this->db =& $db;
		$this->debug = $this->db->debug;
		$this->dict = NewDataDictionary( $this->db );
		$this->sqlArray = array();
		$this->schemaVersion = XMLS_SCHEMA_VERSION;
		$this->executeInline( XMLS_EXECUTE_INLINE );
		$this->continueOnError( XMLS_CONTINUE_ON_ERROR );
		$this->existingData( XMLS_EXISTING_DATA );
		$this->setUpgradeMethod();
	}
	
	/**
	* Sets the method to be used for upgrading an existing database
	*
	* Use this method to specify how existing database objects should be upgraded.
	* The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to
	* alter each database object directly, REPLACE attempts to rebuild each object
	* from scratch, BEST attempts to determine the best upgrade method for each
	* object, and NONE disables upgrading.
	*
	* This method is not yet used by AXMLS, but exists for backward compatibility.
	* The ALTER method is automatically assumed when the adoSchema object is
	* instantiated; other upgrade methods are not currently supported.
	*
	* @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
	* @returns string Upgrade method used
	*/
	function SetUpgradeMethod( $method = '' ) {
		if( !is_string( $method ) ) {
			return FALSE;
		}
		
		$method = strtoupper( $method );
		
		// Handle the upgrade methods