گرویتی فرم فارسی - Version 2.3.0

Version Description



  • *
Download this release

Release Info

Developer hannanstd
Plugin Icon 128x128 گرویتی فرم فارسی
Version 2.3.0
Comparing to
See all releases

Code changes from version 2.1.6 to 2.3.0

Files changed (56) hide show
  1. assets/css/admin.rtl.css +0 -69
  2. assets/css/font-admin.css +27 -0
  3. assets/css/font-face-shabnam.css +7 -0
  4. assets/css/font-face-vazir.css +7 -0
  5. assets/css/font-face-yekan.css +7 -0
  6. assets/css/font.droidsans.css +0 -16
  7. assets/css/font.yekan.css +0 -29
  8. assets/css/print.rtl.css +0 -1
  9. assets/css/rtl-admin.css +127 -0
  10. assets/css/rtl-print.css +13 -0
  11. assets/fonts/BYekan.eot +0 -0
  12. assets/fonts/BYekan.ttf +0 -0
  13. assets/fonts/BYekan.woff +0 -0
  14. assets/fonts/LICENSE +51 -0
  15. assets/fonts/Shabnam.eot +0 -0
  16. assets/fonts/Shabnam.ttf +0 -0
  17. assets/fonts/Shabnam.woff +0 -0
  18. assets/fonts/Shabnam.woff2 +0 -0
  19. assets/fonts/Vazir.eot +0 -0
  20. assets/fonts/Vazir.ttf +0 -0
  21. assets/fonts/Vazir.woff +0 -0
  22. assets/fonts/Vazir.woff2 +0 -0
  23. assets/images/Gravity_Forms_fa.png +0 -0
  24. assets/images/logo.png +0 -0
  25. assets/js/iran-cities-full.js +0 -0
  26. assets/js/iran-cities-full.min.js +0 -0
  27. assets/js/{jalali.date.picker.js → jalali-datepicker.js} +0 -0
  28. assets/js/melli-code.js +0 -539
  29. assets/js/melli-code.min.js +0 -1
  30. assets/js/national_id.js +546 -0
  31. assets/js/national_id.min.js +1 -0
  32. assets/js/shamsi_chart.js +0 -0
  33. includes/{class-iran-cities.php → class-address.php} +97 -101
  34. includes/class-admin.php +131 -0
  35. includes/class-core.php +198 -0
  36. includes/class-currencies.php +71 -0
  37. includes/class-deprecated.php +657 -0
  38. includes/class-jalali-date.php +133 -252
  39. includes/class-live-preview.php +148 -142
  40. includes/class-melli-code.php +0 -434
  41. includes/class-merge-tag.php +672 -0
  42. includes/class-multi-page-navi.php +167 -0
  43. includes/class-multipage-navigation.php +0 -160
  44. includes/class-national-id.php +434 -0
  45. includes/class-news-letter.php +0 -50
  46. includes/class-payments.php +499 -0
  47. includes/class-post-content-merge-tags.php +0 -249
  48. includes/class-pre-submission.php +0 -194
  49. includes/class-settings.php +418 -0
  50. includes/class-snippets.php +62 -73
  51. includes/class-subtotal-calc.php +0 -245
  52. includes/class-transaction-id.php +58 -0
  53. includes/class-wpp-gravity-forms.php +0 -116
  54. includes/lib/jalali.php +755 -0
  55. includes/lib/nusoap-php5.3.php +8484 -0
  56. includes/lib/nusoap-php7.php +7208 -0
assets/css/admin.rtl.css DELETED
@@ -1,69 +0,0 @@
1
- #gf_merge_tag_list a{
2
- font-family:tahoma !important;
3
- }
4
- #toplevel_page_gf_edit_forms a,#toplevel_page_gf_edit_forms .wp-menu-name,.newform_notice,.gatewayset p,.gatewayset td,h1,h2,h3,h4,h5,h6,h2 span,h3 span,label,#no-fields span,.group-header,#gf_form_toolbar a,.gform_tabs a,td a,td a strong,td strong a,th,.add-new-h2,.button,.stat b,.gresults-chart-wrapper *,div.gresults-results-filter-section-label,div.gresults-results-field-label,#gresults-results td,#gresults-results th,#gresults-results tr,h2 a{
5
- font-weight:normal !important;
6
- }
7
- h4,h5,h6 {
8
- font-size:16px !important;
9
- }
10
- .group-header {
11
- font-size:16px !important;
12
- font-weight:normal !important;
13
- }
14
- .row-title,#toplevel_page_gf_edit_forms .wp-menu-name,.newform_notice{
15
- font-size:16px !important;
16
- }
17
- a.gf_toolbar_active ,.gform_tabs a,label{
18
- font-size:13px !important;
19
- }
20
- div.gf_entry_detail_pagination {
21
- top:-10px !important;
22
- }
23
- #TB_ajaxContent,#TB_title {
24
- text-align:right !important;
25
- }
26
- #gresults-results{
27
- margin-right:0px !important;
28
- margin-left:300px !important;
29
- }
30
- div#gf_nofield_1_instructions, div#gf_nofield_2_instructions, div#gf_nofield_3_instructions, div#gf_nofield_4_instructions, div#gf_nofield_5_instructions {
31
- background-image: url("../images/Gravity_Forms_fa.png") !important;
32
- }
33
- .gf_nofield_3_instructions_copy_bottom {
34
- margin-left:-163px !important;
35
- }
36
- .gf_nofield_4_instructions_copy_bottom {
37
- margin-top:13px !important;
38
- margin-left:-220px !important;
39
- }
40
- #gf_user_form .left_header ,.metaname , .metavalue{
41
- float:right !important;
42
- }
43
- .gf_dashboard_form_title_header{
44
- text-align:right !important;
45
- }
46
- .gf_dashboard_view td i{
47
- font-style:normal !important;
48
- }
49
- .gfur-form-select {
50
- margin-right:415px !important;
51
- }
52
- optgroup {
53
- font-style:normal !important;
54
- }
55
- .choice_with_value_and_price label {
56
- margin: 0 60px 0 0 !important;
57
- padding-left: 26px !important;
58
- }
59
- .choice_with_price .gfield_choice_header_label ,.choice_with_value .gfield_choice_header_label {
60
- margin: 0 69px 0 99px !important;
61
- }
62
- .ui-tabs .ui-tabs-nav li {
63
- margin-left: 0.2em !important;
64
- margin-right: 0 !important;
65
- float: right !important;
66
- }
67
- div#gf_nofield_1_instructions span, div#gf_nofield_2_instructions span, div#gf_nofield_3_instructions span, div#gf_nofield_4_instructions span, div#gf_nofield_5_instructions span {
68
- line-height: 2.5rem !important;
69
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/css/font-admin.css ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *, body, html {
2
+ font-family: tahoma, serif;
3
+ }
4
+
5
+ input, li, ul, select, textarea, #gf_merge_tag_list a {
6
+ font-family: tahoma, serif !important;
7
+ }
8
+
9
+ #toplevel_page_gf_edit_forms a,
10
+ #toplevel_page_gf_edit_forms .wp-menu-name,
11
+ .newform_notice, .gatewayset p,
12
+ .gatewayset td, h1, h2, h3, h4, h5, h6, h2 span, h3 span, label,
13
+ #no-fields span, .group-header, #gf_form_toolbar a, .gform_tabs a, td a, td a strong, td strong a, th,
14
+ .add-new-h2, .button, .stat b, .gresults-chart-wrapper *, div.gresults-results-filter-section-label,
15
+ div.gresults-results-field-label, #gresults-results td, #gresults-results th, #gresults-results tr, h2 a,
16
+ .field_hover div.gf-pagebreak-container div.gf-pagebreak-text-main span,
17
+ .field_selected div.gf-pagebreak-container div.gf-pagebreak-text-main span,
18
+ .gf-pagebreak-text-after,
19
+ .gf-pagebreak-text-before, div.gf-pagebreak-text-main span,
20
+ .field_type li input, .add-buttons-title,
21
+ .field_type li input, .add-buttons-title,
22
+ .entry-detail-view td, .entry-detail-view td *,
23
+ .gf_dashboard_view td i,
24
+ .gforms_settings_wrap td, .gforms_settings_wrap th, .gforms_settings_wrap th strong, .gforms_settings_wrap td strong,
25
+ #entry_list_form tbody *{
26
+ font-family: GFPersian, serif !important;
27
+ }
assets/css/font-face-shabnam.css ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ @font-face {
2
+ font-family: 'GFPersian';
3
+ src: url('../fonts/Shabnam.eot');
4
+ src: url('../fonts/Shabnam.woff') format('woff'), url('../fonts/Shabnam.ttf') format('truetype');
5
+ font-weight: normal;
6
+ font-style: normal;
7
+ }
assets/css/font-face-vazir.css ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ @font-face {
2
+ font-family: 'GFPersian';
3
+ src: url('../fonts/Vazir.eot');
4
+ src: url('../fonts/Vazir.woff') format('woff'), url('../fonts/Vazir.ttf') format('truetype');
5
+ font-weight: normal;
6
+ font-style: normal;
7
+ }
assets/css/font-face-yekan.css ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ @font-face {
2
+ font-family: 'GFPersian';
3
+ src: url('../fonts/BYekan.eot');
4
+ src: url('../fonts/BYekan.woff') format('woff'), url('../fonts/BYekan.ttf') format('truetype');
5
+ font-weight: normal;
6
+ font-style: normal;
7
+ }
assets/css/font.droidsans.css DELETED
@@ -1,16 +0,0 @@
1
- #toplevel_page_gf_edit_forms a,#toplevel_page_gf_edit_forms .wp-menu-name,.newform_notice,.gatewayset p,.gatewayset td,h1,h2,h3,h4,h5,h6,h2 span,h3 span,label,#no-fields span,.group-header,#gf_form_toolbar a,.gform_tabs a,td a,td a strong,td strong a,th,.add-new-h2,.button,.stat b,.gresults-chart-wrapper *,div.gresults-results-filter-section-label,div.gresults-results-field-label,#gresults-results td,#gresults-results th,#gresults-results tr,h2 a{
2
- font-family:DroidNaskh !important;
3
- font-weight:normal !important;
4
- }
5
- .field_hover div.gf-pagebreak-container div.gf-pagebreak-text-main span, .field_selected div.gf-pagebreak-container div.gf-pagebreak-text-main span ,.gf-pagebreak-text-after, .gf-pagebreak-text-before,div.gf-pagebreak-text-main span{
6
- font-family:DroidNaskh !important;
7
- }
8
- .field_type li input,.add-buttons-title{
9
- font-family:DroidNaskh !important;
10
- }
11
- .field_type li input,.add-buttons-title{
12
- font-family:DroidNaskh !important;
13
- }
14
- .gf_dashboard_view td i{
15
- font-family:DroidNaskh !important;
16
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/css/font.yekan.css DELETED
@@ -1,29 +0,0 @@
1
- @font-face {
2
- font-family: 'BYekan';
3
- src: url('../fonts/BYekan.eot');
4
- src: url('../fonts/BYekan.woff') format('woff'), url('../fonts/BYekan.ttf') format('truetype');
5
- font-weight: normal;
6
- font-style: normal;
7
- }
8
- *,body,html {
9
- font-family:tahoma;
10
- }
11
- input,li,ul,select,textarea,#gf_merge_tag_list a{
12
- font-family:tahoma !important;
13
- }
14
- #toplevel_page_gf_edit_forms a,#toplevel_page_gf_edit_forms .wp-menu-name,.newform_notice,.gatewayset p,.gatewayset td,h1,h2,h3,h4,h5,h6,h2 span,h3 span,label,#no-fields span,.group-header,#gf_form_toolbar a,.gform_tabs a,td a,td a strong,td strong a,th,.add-new-h2,.button,.stat b,.gresults-chart-wrapper *,div.gresults-results-filter-section-label,div.gresults-results-field-label,#gresults-results td,#gresults-results th,#gresults-results tr,h2 a{
15
- font-family:BYekan !important;
16
- font-weight:normal !important;
17
- }
18
- .field_hover div.gf-pagebreak-container div.gf-pagebreak-text-main span, .field_selected div.gf-pagebreak-container div.gf-pagebreak-text-main span ,.gf-pagebreak-text-after, .gf-pagebreak-text-before,div.gf-pagebreak-text-main span{
19
- font-family:BYekan !important;
20
- }
21
- .field_type li input,.add-buttons-title{
22
- font-family:BYekan !important;
23
- }
24
- .field_type li input,.add-buttons-title{
25
- font-family:BYekan !important;
26
- }
27
- .gf_dashboard_view td i{
28
- font-family:BYekan !important;
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/css/print.rtl.css DELETED
@@ -1 +0,0 @@
1
- *,html,body,table,thead,tr,th,td,div {direction: rtl !important;text-align: right !important;font-family:Tahoma !important;}
 
assets/css/rtl-admin.css ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #gf_merge_tag_list a {
2
+ font-family: tahoma, serif !important;
3
+ }
4
+
5
+ #toplevel_page_gf_edit_forms a, #toplevel_page_gf_edit_forms .wp-menu-name, .newform_notice, .gatewayset p, .gatewayset td, h1, h2, h3, h4, h5, h6, h2 span, h3 span, label, #no-fields span, .group-header, #gf_form_toolbar a, .gform_tabs a, td a, td a strong, td strong a, th, .add-new-h2, .button, .stat b, .gresults-chart-wrapper *, div.gresults-results-filter-section-label, div.gresults-results-field-label, #gresults-results td, #gresults-results th, #gresults-results tr, h2 a {
6
+ font-weight: normal !important;
7
+ }
8
+
9
+ h4, h5, h6 {
10
+ font-size: 16px !important;
11
+ }
12
+
13
+ .group-header {
14
+ font-size: 16px !important;
15
+ font-weight: normal !important;
16
+ }
17
+
18
+ .row-title, #toplevel_page_gf_edit_forms .wp-menu-name, .newform_notice {
19
+ font-size: 16px !important;
20
+ }
21
+
22
+ a.gf_toolbar_active, .gform_tabs a, label {
23
+ font-size: 13px !important;
24
+ }
25
+
26
+ div.gf_entry_detail_pagination {
27
+ top: -10px !important;
28
+ }
29
+
30
+ #TB_ajaxContent, #TB_title {
31
+ text-align: right !important;
32
+ }
33
+
34
+ #gresults-results {
35
+ margin-right: 0px !important;
36
+ margin-left: 300px !important;
37
+ }
38
+
39
+ div#gf_nofield_1_instructions, div#gf_nofield_2_instructions, div#gf_nofield_3_instructions, div#gf_nofield_4_instructions, div#gf_nofield_5_instructions {
40
+ background-image: url("../images/Gravity_Forms_fa.png") !important;
41
+ }
42
+
43
+ .gf_nofield_3_instructions_copy_bottom {
44
+ margin-left: -163px !important;
45
+ }
46
+
47
+ .gf_nofield_4_instructions_copy_bottom {
48
+ margin-top: 13px !important;
49
+ margin-left: -220px !important;
50
+ }
51
+
52
+ #gf_user_form .left_header, .metaname, .metavalue {
53
+ float: right !important;
54
+ }
55
+
56
+ .gf_dashboard_form_title_header {
57
+ text-align: right !important;
58
+ }
59
+
60
+ .gf_dashboard_view td i {
61
+ font-style: normal !important;
62
+ }
63
+
64
+ .gfur-form-select {
65
+ margin-right: 415px !important;
66
+ }
67
+
68
+ optgroup {
69
+ font-style: normal !important;
70
+ }
71
+
72
+ .choice_with_value_and_price label {
73
+ margin: 0 60px 0 0 !important;
74
+ padding-left: 26px !important;
75
+ }
76
+
77
+ .choice_with_price .gfield_choice_header_label, .choice_with_value .gfield_choice_header_label {
78
+ margin: 0 69px 0 99px !important;
79
+ }
80
+
81
+ .ui-tabs .ui-tabs-nav li {
82
+ margin-left: 0.2em !important;
83
+ margin-right: 0 !important;
84
+ float: right !important;
85
+ }
86
+
87
+ div#gf_nofield_1_instructions span, div#gf_nofield_2_instructions span, div#gf_nofield_3_instructions span, div#gf_nofield_4_instructions span, div#gf_nofield_5_instructions span {
88
+ line-height: 2.5rem !important;
89
+ }
90
+
91
+ .calculation_setting .gf_calculation_buttons input, html[dir="rtl"] body.wp-admin .calculation_setting .gf_calculation_buttons input,
92
+ .calculation_setting textarea, html[dir="rtl"] body.wp-admin .calculation_setting textarea,
93
+ .css_class_setting input, html[dir="rtl"] body.wp-admin .css_class_setting input,
94
+ .prepopulate_field_setting input, html[dir="rtl"] body.wp-admin .prepopulate_field_setting input,
95
+ #form_page_querystring {
96
+ direction: ltr !important;
97
+ text-align: left !important;
98
+ }
99
+
100
+ .mt-gform_notification_message, .mt-form_confirmation_message {
101
+ margin-right: -30px !important;
102
+ }
103
+
104
+ .entry-detail-view td ul {
105
+ padding-right: 15px;
106
+ }
107
+
108
+ #entry_filters {
109
+ float: right;
110
+ }
111
+
112
+ #entry_search_button {
113
+ float: left;
114
+ }
115
+
116
+ #entry_list_form .subsubsub {
117
+ float: right !important;
118
+ clear: both;
119
+ }
120
+
121
+ #edit_payment_status_details * {
122
+ font-size: 12px !important;
123
+ }
124
+
125
+ #notes .actions input.button {
126
+ width: 100px !important;
127
+ }
assets/css/rtl-print.css ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *, html, body, table, thead, tr, th, td, div {
2
+ direction: rtl !important;
3
+ text-align: right !important;
4
+ font-family: Tahoma, serif;
5
+ }
6
+ ul {
7
+ padding-right: 10px !important;
8
+ }
9
+
10
+ div.note-avatar {
11
+ margin-left: 15px;
12
+ float: right;
13
+ }
assets/fonts/BYekan.eot CHANGED
File without changes
assets/fonts/BYekan.ttf CHANGED
File without changes
assets/fonts/BYekan.woff CHANGED
File without changes
assets/fonts/LICENSE ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Changes by Saber Rastikerdar are in public domain.
2
+ Glyphs and data from Roboto font are licensed under the Apache License, Version 2.0.
3
+
4
+ Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
5
+
6
+ Bitstream Vera Fonts Copyright
7
+ ------------------------------
8
+
9
+ Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
10
+ a trademark of Bitstream, Inc.
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of the fonts accompanying this license ("Fonts") and associated
14
+ documentation files (the "Font Software"), to reproduce and distribute the
15
+ Font Software, including without limitation the rights to use, copy, merge,
16
+ publish, distribute, and/or sell copies of the Font Software, and to permit
17
+ persons to whom the Font Software is furnished to do so, subject to the
18
+ following conditions:
19
+
20
+ The above copyright and trademark notices and this permission notice shall
21
+ be included in all copies of one or more of the Font Software typefaces.
22
+
23
+ The Font Software may be modified, altered, or added to, and in particular
24
+ the designs of glyphs or characters in the Fonts may be modified and
25
+ additional glyphs or characters may be added to the Fonts, only if the fonts
26
+ are renamed to names not containing either the words "Bitstream" or the word
27
+ "Vera".
28
+
29
+ This License becomes null and void to the extent applicable to Fonts or Font
30
+ Software that has been modified and is distributed under the "Bitstream
31
+ Vera" names.
32
+
33
+ The Font Software may be sold as part of a larger software package but no
34
+ copy of one or more of the Font Software typefaces may be sold by itself.
35
+
36
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
37
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
38
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
39
+ TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
40
+ FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
41
+ ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
42
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
43
+ THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
44
+ FONT SOFTWARE.
45
+
46
+ Except as contained in this notice, the names of Gnome, the Gnome
47
+ Foundation, and Bitstream Inc., shall not be used in advertising or
48
+ otherwise to promote the sale, use or other dealings in this Font Software
49
+ without prior written authorization from the Gnome Foundation or Bitstream
50
+ Inc., respectively. For further information, contact: fonts at gnome dot
51
+ org.
assets/fonts/Shabnam.eot ADDED
Binary file
assets/fonts/Shabnam.ttf ADDED
Binary file
assets/fonts/Shabnam.woff ADDED
Binary file
assets/fonts/Shabnam.woff2 ADDED
Binary file
assets/fonts/Vazir.eot ADDED
Binary file
assets/fonts/Vazir.ttf ADDED
Binary file
assets/fonts/Vazir.woff ADDED
Binary file
assets/fonts/Vazir.woff2 ADDED
Binary file
assets/images/Gravity_Forms_fa.png CHANGED
File without changes
assets/images/logo.png ADDED
Binary file
assets/js/iran-cities-full.js CHANGED
File without changes
assets/js/iran-cities-full.min.js CHANGED
File without changes
assets/js/{jalali.date.picker.js → jalali-datepicker.js} RENAMED
File without changes
assets/js/melli-code.js DELETED
@@ -1,539 +0,0 @@
1
- function cityName_by_melliCode_hannanstd (code){
2
- if (code == "169")cityN = "استان آذربایجان شرقی - شهر آذر شهر";
3
- if (code == "170")cityN = "استان آذربایجان شرقی - شهر اسکو";
4
- if (code == "149" || code == "150")cityN = "استان آذربایجان شرقی - شهر اهر";
5
- if (code == "171")cityN = "استان آذربایجان شرقی - شهر بستان آباد";
6
- if (code == "168")cityN = "استان آذربایجان شرقی - شهر بناب";
7
- if (code == "136" || code == "137" || code == "138")cityN = "استان آذربایجان شرقی - شهر تبریز";
8
- if (code == "545")cityN = "استان آذربایجان شرقی - شهر ترکمانچای";
9
- if (code == "505")cityN = "استان آذربایجان شرقی - شهر جلفا";
10
- if (code == "636")cityN = "استان آذربایجان شرقی - شهر چاروایماق";
11
- if (code == "164" || code == "165")cityN = "استان آذربایجان شرقی - شهر سراب";
12
- if (code == "172")cityN = "استان آذربایجان شرقی - شهر شبستر";
13
- if (code == "623")cityN = "استان آذربایجان شرقی - شهر صوفیان";
14
- if (code == "506")cityN = "استان آذربایجان شرقی - شهر عجب شیر";
15
- if (code == "519")cityN = "استان آذربایجان شرقی - شهر کلیبر";
16
- if (code == "154" || code == "155")cityN = "استان آذربایجان شرقی - شهر مراغه";
17
- if (code == "567")cityN = "استان آذربایجان شرقی - شهر ورزقان";
18
- if (code == "173")cityN = "استان آذربایجان شرقی - شهر هریس";
19
- if (code == "159" || code == "160")cityN = "استان آذربایجان شرقی - شهر هشترود";
20
- if (code == "604")cityN = "استان آذربایجان شرقی - شهر هوراند";
21
- if (code == "274" || code == "275")cityN = "استان آذربایجان غربی - شهر ارومیه";
22
- if (code == "295")cityN = "استان آذربایجان غربی - شهر اشنویه";
23
- if (code == "637")cityN = "استان آذربایجان غربی - شهر انزل";
24
- if (code == "292")cityN = "استان آذربایجان غربی - شهر بوکان";
25
- if (code == "492")cityN = "استان آذربایجان غربی - شهر پلدشت";
26
- if (code == "289")cityN = "استان آذربایجان غربی - شهر پیرانشهر";
27
- if (code == "677")cityN = "استان آذربایجان غربی - شهر تخت سلیمان";
28
- if (code == "294")cityN = "استان آذربایجان غربی - شهر تکاب";
29
- if (code == "493")cityN = "استان آذربایجان غربی - شهر چایپاره";
30
- if (code == "279" || code == "280")cityN = "استان آذربایجان غربی - شهر خوی";
31
- if (code == "288")cityN = "استان آذربایجان غربی - شهر سردشت";
32
- if (code == "284" || code == "285")cityN = "استان آذربایجان غربی - شهر سلماس";
33
- if (code == "638")cityN = "استان آذربایجان غربی - شهر سیلوانه";
34
- if (code == "291")cityN = "استان آذربایجان غربی - شهر سیه چشمه(چالدران)";
35
- if (code == "640")cityN = "استان آذربایجان غربی - شهر شوط";
36
- if (code == "293")cityN = "استان آذربایجان غربی - شهر شاهین دژ";
37
- if (code == "675")cityN = "استان آذربایجان غربی - شهر کشاورز";
38
- if (code == "282" || code == "283")cityN = "استان آذربایجان غربی - شهر ماکو";
39
- if (code == "286" || code == "287")cityN = "استان آذربایجان غربی - شهر مهاباد";
40
- if (code == "296" || code == "297")cityN = "استان آذربایجان غربی - شهر میاندوآب";
41
- if (code == "290")cityN = "استان آذربایجان غربی - شهر نقده";
42
- if (code == "400" || code == "401")cityN = "استان همدان - شهر اسدآباد";
43
- if (code == "404" || code == "405")cityN = "استان همدان - شهر بهار";
44
- if (code == "397")cityN = "استان همدان - شهر تویسرکان";
45
- if (code == "398" || code == "399")cityN = "استان همدان - شهر رزن";
46
- if (code == "647")cityN = "استان همدان - شهر شراء و پیشخوار";
47
- if (code == "502")cityN = "استان همدان - شهر فامنین";
48
- if (code == "584")cityN = "استان همدان - شهر قلقل رود";
49
- if (code == "402" || code == "403")cityN = "استان همدان - شهر کبودرآهنگ";
50
- if (code == "392" || code == "393")cityN = "استان همدان - شهر ملایر";
51
- if (code == "395" || code == "396")cityN = "استان همدان - شهر نهاوند";
52
- if (code == "386" || code == "387")cityN = "استان همدان - شهر همدان";
53
- if (code == "503")cityN = "استان یزد - شهر ابرکوه";
54
- if (code == "444")cityN = "استان یزد - شهر اردکان";
55
- if (code == "551")cityN = "استان یزد - شهر اشکذر";
56
- if (code == "447")cityN = "استان یزد - شهر بافق";
57
- if (code == "561")cityN = "استان یزد - شهر بهاباد";
58
- if (code == "445")cityN = "استان یزد - شهر تفت";
59
- if (code == "718")cityN = "استان یزد - شهر دستگردان";
60
- if (code == "083")cityN = "استان یزد - شهر طبس";
61
- if (code == "446")cityN = "استان یزد - شهر مهریز";
62
- if (code == "448")cityN = "استان یزد - شهر میبد";
63
- if (code == "552")cityN = "استان یزد - شهر نیر";
64
- if (code == "543")cityN = "استان یزد - شهر هرات و مروست";
65
- if (code == "442" || code == "443")cityN = "استان یزد - شهر یزد";
66
- if (code == "051")cityN = "استان مرکزی - شهر آشتیان";
67
- if (code == "052" || code == "053")cityN = "استان مرکزی - شهر اراک";
68
- if (code == "058")cityN = "استان مرکزی - شهر تفرش";
69
- if (code == "055")cityN = "استان مرکزی - شهر خمین";
70
- if (code == "617")cityN = "استان مرکزی - شهر خنداب";
71
- if (code == "057")cityN = "استان مرکزی - شهر دلیجان";
72
- if (code == "618")cityN = "استان مرکزی - شهر زرند مرکزی";
73
- if (code == "059" || code == "060")cityN = "استان مرکزی - شهر ساوه";
74
- if (code == "061" || code == "062")cityN = "استان مرکزی - شهر سربند";
75
- if (code == "544")cityN = "استان مرکزی - شهر فراهان";
76
- if (code == "056")cityN = "استان مرکزی - شهر محلات";
77
- if (code == "571")cityN = "استان مرکزی - شهر وفس";
78
- if (code == "593")cityN = "استان مرکزی - شهر هندودر";
79
- if (code == "667")cityN = "استان هرمزگان - شهر ابوموسی";
80
- if (code == "348")cityN = "استان هرمزگان - شهر بستک";
81
- if (code == "586")cityN = "استان هرمزگان - شهر بشاگرد";
82
- if (code == "338" || code == "339")cityN = "استان هرمزگان - شهر بندرعباس";
83
- if (code == "343" || code == "344")cityN = "استان هرمزگان - شهر بندرلنگه";
84
- if (code == "346")cityN = "استان هرمزگان - شهر جاسک";
85
- if (code == "337")cityN = "استان هرمزگان - شهر حاجی آباد";
86
- if (code == "554")cityN = "استان هرمزگان - شهر خمیر";
87
- if (code == "469")cityN = "استان هرمزگان - شهر رودان";
88
- if (code == "537")cityN = "استان هرمزگان - شهر فین";
89
- if (code == "345")cityN = "استان هرمزگان - شهر قشم";
90
- if (code == "470")cityN = "استان هرمزگان - شهر گاوبندی";
91
- if (code == "341" || code == "342")cityN = "استان هرمزگان - شهر میناب";
92
- if (code == "483" || code == "484")cityN = "استان لرستان - شهر ازنا";
93
- if (code == "557")cityN = "استان لرستان - شهر اشترینان";
94
- if (code == "418")cityN = "استان لرستان - شهر الشتر";
95
- if (code == "416" || code == "417")cityN = "استان لرستان - شهر الیگودرز";
96
- if (code == "412" || code == "413")cityN = "استان لرستان - شهر بروجرد";
97
- if (code == "592")cityN = "استان لرستان - شهر پاپی";
98
- if (code == "612")cityN = "استان لرستان - شهر چغلوندی";
99
- if (code == "613")cityN = "استان لرستان - شهر چگنی";
100
- if (code == "406" || code == "407")cityN = "استان لرستان - شهر خرم آباد";
101
- if (code == "421")cityN = "استان لرستان - شهر دورود";
102
- if (code == "598")cityN = "استان لرستان - شهر رومشکان";
103
- if (code == "419")cityN = "استان لرستان - شهر کوهدشت";
104
- if (code == "385")cityN = "استان لرستان - شهر ملاوی(پلدختر)";
105
- if (code == "420")cityN = "استان لرستان - شهر نورآباد(دلفان)";
106
- if (code == "528")cityN = "استان لرستان - شهر ویسیان";
107
- if (code == "213" || code == "214")cityN = "استان مازندران - شهر آمل";
108
- if (code == "205" || code == "206")cityN = "استان مازندران - شهر بابل";
109
- if (code == "498")cityN = "استان مازندران - شهر بابل";
110
- if (code == "568")cityN = "استان مازندران - شهر بندپی";
111
- if (code == "711")cityN = "استان مازندران - شهر بندپی شرقی";
112
- if (code == "217" || code == "218")cityN = "استان مازندران - شهر بهشهر";
113
- if (code == "221")cityN = "استان مازندران - شهر تنکابن";
114
- if (code == "582")cityN = "استان مازندران - شهر جویبار";
115
- if (code == "483")cityN = "استان مازندران - شهر چالوس";
116
- if (code == "625")cityN = "استان مازندران - شهر چمستان";
117
- if (code == "576")cityN = "استان مازندران - شهر چهاردانگه";
118
- if (code == "578")cityN = "استان مازندران - شهر دودانگه";
119
- if (code == "227")cityN = "استان مازندران - شهر رامسر";
120
- if (code == "208" || code == "209")cityN = "استان مازندران - شهر ساری";
121
- if (code == "225")cityN = "استان مازندران - شهر سوادکوه";
122
- if (code == "577")cityN = "استان مازندران - شهر شیرگاه";
123
- if (code == "712")cityN = "استان مازندران - شهر عباس آباد";
124
- if (code == "215" || code == "216")cityN = "استان مازندران - شهر قائمشهر";
125
- if (code == "626")cityN = "استان مازندران - شهر کجور";
126
- if (code == "627")cityN = "استان مازندران - شهر کلاردشت";
127
- if (code == "579")cityN = "استان مازندران - شهر گلوگاه";
128
- if (code == "713")cityN = "استان مازندران - شهر میاندورود";
129
- if (code == "499")cityN = "استان مازندران - شهر نکاء";
130
- if (code == "222")cityN = "استان مازندران - شهر نور";
131
- if (code == "219" || code == "220")cityN = "استان مازندران - شهر نوشهر";
132
- if (code == "500" || code == "501")cityN = "استان مازندران - شهر هراز و محمودآباد";
133
- if (code == "623")cityN = "استان گلستان - شهر آزادشهر";
134
- if (code == "497")cityN = "استان گلستان - شهر آق قلا";
135
- if (code == "223")cityN = "استان گلستان - شهر بندرترکمن";
136
- if (code == "689")cityN = "استان گلستان - شهر بندرگز";
137
- if (code == "487")cityN = "استان گلستان - شهر رامیان";
138
- if (code == "226")cityN = "استان گلستان - شهر علی آباد";
139
- if (code == "224")cityN = "استان گلستان - شهر کردکوی";
140
- if (code == "386")cityN = "استان گلستان - شهر کلاله";
141
- if (code == "211" || code == "212")cityN = "استان گلستان - شهر گرگان";
142
- if (code == "628")cityN = "استان گلستان - شهر گمیشان";
143
- if (code == "202" || code == "203")cityN = "استان گلستان - شهر گنبد کاووس";
144
- if (code == "531")cityN = "استان گلستان - شهر مراوه تپه";
145
- if (code == "288")cityN = "استان گلستان - شهر مینودشت";
146
- if (code == "261")cityN = "استان گیلان - شهر آستارا";
147
- if (code == "273")cityN = "استان گیلان - شهر آستانه";
148
- if (code == "630")cityN = "استان گیلان - شهر املش";
149
- if (code == "264")cityN = "استان گیلان - شهر بندرانزلی";
150
- if (code == "518")cityN = "استان گیلان - شهر خمام";
151
- if (code == "631")cityN = "استان گیلان - شهر رحیم آباد";
152
- if (code == "258" || code == "259")cityN = "استان گیلان - شهر رشت";
153
- if (code == "570")cityN = "استان گیلان - شهر رضوانشهر";
154
- if (code == "265")cityN = "استان گیلان - شهر رودبار";
155
- if (code == "268" || code == "269")cityN = "استان گیلان - شهر رودسر";
156
- if (code == "653")cityN = "استان گیلان - شهر سنگر";
157
- if (code == "517")cityN = "استان گیلان - شهر سیاهکل";
158
- if (code == "569")cityN = "استان گیلان - شهر شفت";
159
- if (code == "267")cityN = "استان گیلان - شهر صومعه سرا";
160
- if (code == "262" || code == "263")cityN = "استان گیلان - شهر طالش";
161
- if (code == "593")cityN = "استان گیلان - شهر عمارلو";
162
- if (code == "266")cityN = "استان گیلان - شهر فومن";
163
- if (code == "693")cityN = "استان گیلان - شهر کوچصفهان";
164
- if (code == "271" || code == "272")cityN = "استان گیلان - شهر لاهیجان";
165
- if (code == "694")cityN = "استان گیلان - شهر لشت نشاء";
166
- if (code == "270")cityN = "استان گیلان - شهر لنگرود";
167
- if (code == "516")cityN = "استان گیلان - شهر ماسال و شاندرمن";
168
- if (code == "333" || code == "334")cityN = "استان کرمانشاه - شهر اسلام آباد";
169
- if (code == "691")cityN = "استان کرمانشاه - شهر باینگان";
170
- if (code == "322" || code == "323")cityN = "استان کرمانشاه - شهر پاوه";
171
- if (code == "595")cityN = "استان کرمانشاه - شهر ثلاث باباجانی";
172
- if (code == "395")cityN = "استان کرمانشاه - شهر جوانرود";
173
- if (code == "641")cityN = "استان کرمانشاه - شهر حمیل";
174
- if (code == "596")cityN = "استان کرمانشاه - شهر روانسر";
175
- if (code == "336")cityN = "استان کرمانشاه - شهر سرپل ذهاب";
176
- if (code == "335")cityN = "استان کرمانشاه - شهر سنقر";
177
- if (code == "496")cityN = "استان کرمانشاه - شهر صحنه";
178
- if (code == "337")cityN = "استان کرمانشاه - شهر قصرشیرین";
179
- if (code == "324" || code == "325")cityN = "استان کرمانشاه - شهر کرمانشاه";
180
- if (code == "394")cityN = "استان کرمانشاه - شهر کرند";
181
- if (code == "330")cityN = "استان کرمانشاه - شهر کنگاور";
182
- if (code == "332")cityN = "استان کرمانشاه - شهر گیلانغرب";
183
- if (code == "331")cityN = "استان کرمانشاه - شهر هرسین";
184
- if (code == "687")cityN = "استان کهکیلویه و بویراحمد - شهر باشت";
185
- if (code == "422" || code == "423")cityN = "استان کهکیلویه و بویراحمد - شهر بویراحمد(یاسوج)";
186
- if (code == "599")cityN = "استان کهکیلویه و بویراحمد - شهر بهمنی";
187
- if (code == "600")cityN = "استان کهکیلویه و بویراحمد - شهر چاروسا";
188
- if (code == "688")cityN = "استان کهکیلویه و بویراحمد - شهر دروهان";
189
- if (code == "424" || code == "425")cityN = "استان کهکیلویه و بویراحمد - شهر کهکیلویه(دهدشت)";
190
- if (code == "426")cityN = "استان کهکیلویه و بویراحمد - شهر گچساران(دوگنبدان)";
191
- if (code == "550")cityN = "استان کهکیلویه و بویراحمد - شهر لنده";
192
- if (code == "697")cityN = "استان کهکیلویه و بویراحمد - شهر مارگون";
193
- if (code == "384")cityN = "استان کردستان - شهر بانه";
194
- if (code == "377" || code == "378")cityN = "استان کردستان - شهر بیجار";
195
- if (code == "558")cityN = "استان کردستان - شهر دهگلان";
196
- if (code == "385")cityN = "استان کردستان - شهر دیواندره";
197
- if (code == "646")cityN = "استان کردستان - شهر سروآباد";
198
- if (code == "375" || code == "376")cityN = "استان کردستان - شهر سقز";
199
- if (code == "372" || code == "373")cityN = "استان کردستان - شهر سنندج";
200
- if (code == "379" || code == "380")cityN = "استان کردستان - شهر قروه";
201
- if (code == "383")cityN = "استان کردستان - شهر کامیاران";
202
- if (code == "674")cityN = "استان کردستان - شهر کرانی";
203
- if (code == "381" || code == "382")cityN = "استان کردستان - شهر مریوان";
204
- if (code == "676")cityN = "استان کردستان - شهر نمشیر";
205
- if (code == "722")cityN = "استان کرمان - شهر ارزونیه";
206
- if (code == "542")cityN = "استان کرمان - شهر انار";
207
- if (code == "312" || code == "313")cityN = "استان کرمان - شهر بافت";
208
- if (code == "317")cityN = "استان کرمان - شهر بردسیر";
209
- if (code == "310" || code == "311")cityN = "استان کرمان - شهر بم";
210
- if (code == "302" || code == "303")cityN = "استان کرمان - شهر جیرفت";
211
- if (code == "583")cityN = "استان کرمان - شهر رابر";
212
- if (code == "321")cityN = "استان کرمان - شهر راور";
213
- if (code == "382")cityN = "استان کرمان - شهر راین";
214
- if (code == "304" || code == "305")cityN = "استان کرمان - شهر رفسنجان";
215
- if (code == "536")cityN = "استان کرمان - شهر رودبار کهنوج";
216
- if (code == "605")cityN = "استان کرمان - شهر ریگان";
217
- if (code == "308" || code == "309")cityN = "استان کرمان - شهر زرند";
218
- if (code == "306" || code == "307")cityN = "استان کرمان - شهر سیرجان";
219
- if (code == "319")cityN = "استان کرمان - شهر شهداد";
220
- if (code == "313" || code == "314")cityN = "استان کرمان - شهر شهربابک";
221
- if (code == "606")cityN = "استان کرمان - شهر عنبرآباد";
222
- if (code == "320")cityN = "استان کرمان - شهر فهرج";
223
- if (code == "698")cityN = "استان کرمان - شهر قلعه گنج";
224
- if (code == "298" || code == "299")cityN = "استان کرمان - شهر کرمان";
225
- if (code == "535")cityN = "استان کرمان - شهر کوهبنان";
226
- if (code == "315" || code == "316")cityN = "استان کرمان - شهر کهنوج";
227
- if (code == "318")cityN = "استان کرمان - شهر گلباف";
228
- if (code == "607")cityN = "استان کرمان - شهر ماهان";
229
- if (code == "608")cityN = "استان کرمان - شهر منوجان";
230
- if (code == "508")cityN = "استان قزوین - شهر آبیک";
231
- if (code == "538")cityN = "استان قزوین - شهر آوج";
232
- if (code == "728")cityN = "استان قزوین - شهر البرز";
233
- if (code == "509")cityN = "استان قزوین - شهر بوئین زهرا";
234
- if (code == "438" || code == "439")cityN = "استان قزوین - شهر تاکستان";
235
- if (code == "580")cityN = "استان قزوین - شهر رودبار الموت";
236
- if (code == "590")cityN = "استان قزوین - شهر رودبار شهرستان";
237
- if (code == "559")cityN = "استان قزوین - شهر ضیاءآباد";
238
- if (code == "588")cityN = "استان قزوین - شهر طارم سفلی";
239
- if (code == "431" || code == "432")cityN = "استان قزوین - شهر قزوین";
240
- if (code == "037" || code == "038")cityN = "استان قم - شهر قم";
241
- if (code == "702")cityN = "استان قم - شهر کهک";
242
- if (code == "240" || code == "241")cityN = "استان فارس - شهر آباده";
243
- if (code == "670")cityN = "استان فارس - شهر آباده طشک";
244
- if (code == "648")cityN = "استان فارس - شهر ارسنجان";
245
- if (code == "252")cityN = "استان فارس - شهر استهبان";
246
- if (code == "678")cityN = "استان فارس - شهر اشکنان";
247
- if (code == "253")cityN = "استان فارس - شهر اقلید";
248
- if (code == "649")cityN = "استان فارس - شهر اوز";
249
- if (code == "513")cityN = "استان فارس - شهر بوانات";
250
- if (code == "546")cityN = "استان فارس - شهر بیضا";
251
- if (code == "671")cityN = "استان فارس - شهر جویم";
252
- if (code == "246" || code == "247")cityN = "استان فارس - شهر جهرم";
253
- if (code == "654")cityN = "استان فارس - شهر حاجی آباد(زرین دشت)";
254
- if (code == "548")cityN = "استان فارس - شهر خرامه";
255
- if (code == "547")cityN = "استان فارس - شهر خشت و کمارج";
256
- if (code == "655")cityN = "استان فارس - شهر خفر";
257
- if (code == "248" || code == "249")cityN = "استان فارس - شهر داراب";
258
- if (code == "253")cityN = "استان فارس - شهر سپیدان";
259
- if (code == "514")cityN = "استان فارس - شهر سروستان";
260
- if (code == "665")cityN = "استان فارس - شهر سعادت آباد";
261
- if (code == "673")cityN = "استان فارس - شهر شیبکوه";
262
- if (code == "228" || code == "229" || code == "230")cityN = "استان فارس - شهر شیراز";
263
- if (code == "679")cityN = "استان فارس - شهر فراشبند";
264
- if (code == "256" || code == "257")cityN = "استان فارس - شهر فسا";
265
- if (code == "244" || code == "245")cityN = "استان فارس - شهر فیروزآباد";
266
- if (code == "681")cityN = "استان فارس - شهر قنقری(خرم بید)";
267
- if (code == "723")cityN = "استان فارس - شهر قیروکارزین";
268
- if (code == "236" || code == "237")cityN = "استان فارس - شهر کازرون";
269
- if (code == "683")cityN = "استان فارس - شهر کوار";
270
- if (code == "656")cityN = "استان فارس - شهر کراش";
271
- if (code == "250" || code == "251")cityN = "استان فارس - شهر لارستان";
272
- if (code == "515")cityN = "استان فارس - شهر لامرد";
273
- if (code == "242" || code == "243")cityN = "استان فارس - شهر مرودشت";
274
- if (code == "238" || code == "239")cityN = "استان فارس - شهر ممسنی";
275
- if (code == "657")cityN = "استان فارس - شهر مهر";
276
- if (code == "255")cityN = "استان فارس - شهر نی ریز";
277
- if (code == "684")cityN = "استان سمنان - شهر ایوانکی";
278
- if (code == "700")cityN = "استان سمنان - شهر بسطام";
279
- if (code == "642")cityN = "استان سمنان - شهر بیارجمند";
280
- if (code == "457")cityN = "استان سمنان - شهر دامغان";
281
- if (code == "456")cityN = "استان سمنان - شهر سمنان";
282
- if (code == "458" || code == "459")cityN = "استان سمنان - شهر شاهرود";
283
- if (code == "460")cityN = "استان سمنان - شهر گرمسار";
284
- if (code == "530")cityN = "استان سمنان - شهر مهدیشهر";
285
- if (code == "520")cityN = "استان سمنان - شهر میامی";
286
- if (code == "358" || code == "359")cityN = "استان سیستان و بلوچستان - شهر ایرانشهر";
287
- if (code == "682")cityN = "استان سیستان و بلوچستان - شهر بزمان";
288
- if (code == "703")cityN = "استان سیستان و بلوچستان - شهر بمپور";
289
- if (code == "364" || code == "365")cityN = "استان سیستان و بلوچستان - شهر چابهار";
290
- if (code == "371")cityN = "استان سیستان و بلوچستان - شهر خاش";
291
- if (code == "701")cityN = "استان سیستان و بلوچستان - شهر دشتیاری";
292
- if (code == "720")cityN = "استان سیستان و بلوچستان - شهر راسک";
293
- if (code == "366" || code == "367")cityN = "استان سیستان و بلوچستان - شهر زابل";
294
- if (code == "704")cityN = "استان سیستان و بلوچستان - شهر زابلی";
295
- if (code == "361" || code == "362")cityN = "استان سیستان و بلوچستان - شهر زاهدان";
296
- if (code == "369" || code == "370")cityN = "استان سیستان و بلوچستان - شهر سراوان";
297
- if (code == "635")cityN = "استان سیستان و بلوچستان - شهر سرباز";
298
- if (code == "668")cityN = "استان سیستان و بلوچستان - شهر سیب و سوران";
299
- if (code == "533")cityN = "استان سیستان و بلوچستان - شهر شهرکی و ناروئی(زهک)";
300
- if (code == "705")cityN = "استان سیستان و بلوچستان - شهر شیب آب";
301
- if (code == "699")cityN = "استان سیستان و بلوچستان - شهر فنوج";
302
- if (code == "669")cityN = "استان سیستان و بلوچستان - شهر قصرقند";
303
- if (code == "725")cityN = "استان سیستان و بلوچستان - شهر کنارک";
304
- if (code == "597")cityN = "استان سیستان و بلوچستان - شهر لاشار(اسپکه)";
305
- if (code == "611")cityN = "استان سیستان و بلوچستان - شهر میرجاوه";
306
- if (code == "525")cityN = "استان سیستان و بلوچستان - شهر نیک شهر";
307
- if (code == "181")cityN = "استان خوزستان - شهر آبادان";
308
- if (code == "527")cityN = "استان خوزستان - شهر آغاجاری";
309
- if (code == "585")cityN = "استان خوزستان - شهر اروندکنار";
310
- if (code == "685")cityN = "استان خوزستان - شهر امیدیه";
311
- if (code == "663")cityN = "استان خوزستان - شهر اندیکا";
312
- if (code == "192" || code == "193")cityN = "استان خوزستان - شهر اندیمشک";
313
- if (code == "174" || code == "175")cityN = "استان خوزستان - شهر اهواز";
314
- if (code == "183" || code == "184")cityN = "استان خوزستان - شهر ایذه";
315
- if (code == "481")cityN = "استان خوزستان - شهر باغ ملک";
316
- if (code == "706")cityN = "استان خوزستان - شهر بندر امام خمینی";
317
- if (code == "194" || code == "195")cityN = "استان خوزستان - شهر بندرماهشهر";
318
- if (code == "185" || code == "186")cityN = "استان خوزستان - شهر بهبهان";
319
- if (code == "182")cityN = "استان خوزستان - شهر خرمشهر";
320
- if (code == "199" || code == "200")cityN = "استان خوزستان - شهر دزفول";
321
- if (code == "198")cityN = "استان خوزستان - شهر دشت آزادگان";
322
- if (code == "662")cityN = "استان خوزستان - شهر رامشیر";
323
- if (code == "190" || code == "191")cityN = "استان خوزستان - شهر رامهرمز";
324
- if (code == "692")cityN = "استان خوزستان - شهر سردشت";
325
- if (code == "189")cityN = "استان خوزستان - شهر شادگان";
326
- if (code == "707")cityN = "استان خوزستان - شهر شاوور";
327
- if (code == "526")cityN = "استان خوزستان - شهر شوش";
328
- if (code == "187" || code == "188")cityN = "استان خوزستان - شهر شوشتر";
329
- if (code == "729")cityN = "استان خوزستان - شهر گتوند";
330
- if (code == "730")cityN = "استان خوزستان - شهر لالی";
331
- if (code == "196" || code == "197")cityN = "استان خوزستان - شهر مسجدسلیمان";
332
- if (code == "661")cityN = "استان خوزستان - شهر هندیجان";
333
- if (code == "680")cityN = "استان خوزستان - شهر هویزه";
334
- if (code == "643")cityN = "استان خراسان رضوی - شهر احمدآباد";
335
- if (code == "562")cityN = "استان خراسان رضوی - شهر بجستان";
336
- if (code == "572")cityN = "استان خراسان رضوی - شهر بردسکن";
337
- if (code == "074")cityN = "استان خراسان رضوی - شهر تایباد";
338
- if (code == "644")cityN = "استان خراسان رضوی - شهر تخت جلگه";
339
- if (code == "072" || code == "073")cityN = "استان خراسان رضوی - شهر تربت جام";
340
- if (code == "069" || code == "070")cityN = "استان خراسان رضوی - شهر تربت حیدریه";
341
- if (code == "521")cityN = "استان خراسان رضوی - شهر جغتای";
342
- if (code == "573")cityN = "استان خراسان رضوی - شهر جوین";
343
- if (code == "522")cityN = "استان خراسان رضوی - شهر چناران";
344
- if (code == "724")cityN = "استان خراسان رضوی - شهر خلیل آباد";
345
- if (code == "076")cityN = "استان خراسان رضوی - شهر خواف";
346
- if (code == "077")cityN = "استان خراسان رضوی - شهر درگز";
347
- if (code == "650")cityN = "استان خراسان رضوی - شهر رشتخوار";
348
- if (code == "574")cityN = "استان خراسان رضوی - شهر زبرخان";
349
- if (code == "078" || code == "079")cityN = "استان خراسان رضوی - شهر سبزوار";
350
- if (code == "081")cityN = "استان خراسان رضوی - شهر سرخس";
351
- if (code == "084")cityN = "استان خراسان رضوی - شهر فریمان";
352
- if (code == "651")cityN = "استان خراسان رضوی - شهر فیض آباد";
353
- if (code == "086" || code == "087")cityN = "استان خراسان رضوی - شهر قوچان";
354
- if (code == "089" || code == "090")cityN = "استان خراسان رضوی - شهر کاشمر";
355
- if (code == "553")cityN = "استان خراسان رضوی - شهر کلات";
356
- if (code == "091")cityN = "استان خراسان رضوی - شهر گناباد";
357
- if (code == "092" || code == "093" || code == "094")cityN = "استان خراسان رضوی - شهر مشهد";
358
- if (code == "097")cityN = "استان خراسان رضوی - شهر مشهد منطقه2";
359
- if (code == "098")cityN = "استان خراسان رضوی - شهر مشهد منطقه3";
360
- if (code == "096")cityN = "استان خراسان رضوی - شهر مشهد منطقه1";
361
- if (code == "105" || code == "106")cityN = "استان خراسان رضوی - شهر نیشابور";
362
- if (code == "063")cityN = "استان خراسان شمالی - شهر اسفراین";
363
- if (code == "067" || code == "068")cityN = "استان خراسان شمالی - شهر بجنورد";
364
- if (code == "075")cityN = "استان خراسان شمالی - شهر جاجرم";
365
- if (code == "591")cityN = "استان خراسان شمالی - شهر رازوجرکلان";
366
- if (code == "082")cityN = "استان خراسان شمالی - شهر شیروان";
367
- if (code == "635")cityN = "استان خراسان شمالی - شهر فاروج";
368
- if (code == "524")cityN = "استان خراسان شمالی - شهر مانه و سملقان";
369
- if (code == "468")cityN = "استان چهارمحال و بختیاری - شهر اردل";
370
- if (code == "465")cityN = "استان چهارمحال و بختیاری - شهر بروجن";
371
- if (code == "461" || code == "462")cityN = "استان چهارمحال و بختیاری - شهر شهرکرد";
372
- if (code == "467")cityN = "استان چهارمحال و بختیاری - شهر فارسان";
373
- if (code == "555")cityN = "استان چهارمحال و بختیاری - شهر کوهرنگ";
374
- if (code == "633")cityN = "استان چهارمحال و بختیاری - شهر کیار";
375
- if (code == "629")cityN = "استان چهارمحال و بختیاری - شهر گندمان";
376
- if (code == "466")cityN = "استان چهارمحال و بختیاری - شهر لردگان";
377
- if (code == "696")cityN = "استان چهارمحال و بختیاری - شهر میانکوه";
378
- if (code == "721")cityN = "استان خراسان جنوبی - شهر بشرویه";
379
- if (code == "064" || code == "065")cityN = "استان خراسان جنوبی - شهر بیرجند";
380
- if (code == "523")cityN = "استان خراسان جنوبی - شهر درمیان";
381
- if (code == "652")cityN = "استان خراسان جنوبی - شهر زیرکوه";
382
- if (code == "719")cityN = "استان خراسان جنوبی - شهر سرایان";
383
- if (code == "716")cityN = "استان خراسان جنوبی - شهر سربیشه";
384
- if (code == "085")cityN = "استان خراسان جنوبی - شهر فردوس";
385
- if (code == "088")cityN = "استان خراسان جنوبی - شهر قائنات";
386
- if (code == "563")cityN = "استان خراسان جنوبی - شهر نهبندان";
387
- if (code == "529")cityN = "استان بوشهر - شهر بندر دیلم";
388
- if (code == "353")cityN = "استان بوشهر - شهر بندر گناوه";
389
- if (code == "349" || code == "350")cityN = "استان بوشهر - شهر بوشهر";
390
- if (code == "355")cityN = "استان بوشهر - شهر تنگستان";
391
- if (code == "609")cityN = "استان بوشهر - شهر جم";
392
- if (code == "351" || code == "352")cityN = "استان بوشهر - شهر دشتستان";
393
- if (code == "354")cityN = "استان بوشهر - شهر دشتی";
394
- if (code == "732")cityN = "استان بوشهر - شهر دلوار";
395
- if (code == "357")cityN = "استان بوشهر - شهر دیر";
396
- if (code == "532")cityN = "استان بوشهر - شهر سعد آباد";
397
- if (code == "610")cityN = "استان بوشهر - شهر شبانکاره";
398
- if (code == "356")cityN = "استان بوشهر - شهر کنگان";
399
- if (code == "556")cityN = "استان تهران - شهر اسلامشهر";
400
- if (code == "658")cityN = "استان تهران - شهر پاکدشت";
401
- if (code == "001" || code == "002" || code == "003" || code == "004" || code == "005" || code == "006" || code == "007" || code == "008")cityN = "استان تهران - شهر تهران مرکزی";
402
- if (code == "011")cityN = "استان تهران - شهر تهران جنوب";
403
- if (code == "020")cityN = "استان تهران - شهر تهران شرق";
404
- if (code == "025")cityN = "استان تهران - شهر تهرانشمال";
405
- if (code == "015")cityN = "استان تهران - شهر تهران غرب";
406
- if (code == "043")cityN = "استان تهران - شهر دماوند";
407
- if (code == "666")cityN = "استان تهران - شهر رباط کریم";
408
- if (code == "489")cityN = "استان تهران - شهر ساوجبلاغ";
409
- if (code == "044" || code == "045")cityN = "استان تهران - شهر شمیران";
410
- if (code == "048" || code == "049")cityN = "استان تهران - شهر شهرری";
411
- if (code == "490" || code == "491")cityN = "استان تهران - شهر شهریار";
412
- if (code == "695")cityN = "استان تهران - شهر طالقان";
413
- if (code == "659")cityN = "استان تهران - شهر فیروزکوه";
414
- if (code == "031" || code == "032")cityN = "استان تهران - شهر کرج";
415
- if (code == "664")cityN = "استان تهران - شهر کهریزک";
416
- if (code == "717")cityN = "استان تهران - شهر نظرآباد";
417
- if (code == "041" || code == "042")cityN = "استان تهران - شهر ورامین";
418
- if (code == "471" || code == "472")cityN = " امور خارجه - امور خارجه";
419
- if (code == "454")cityN = "استان ایلام - شهر آبدانان";
420
- if (code == "581")cityN = "استان ایلام - شهر ارکوازی(ملکشاهی)";
421
- if (code == "449" || code == "450")cityN = "استان ایلام - شهر ایلام";
422
- if (code == "616")cityN = "استان ایلام - شهر ایوان";
423
- if (code == "534")cityN = "استان ایلام - شهر بدره";
424
- if (code == "455")cityN = "استان ایلام - شهر دره شهر";
425
- if (code == "451")cityN = "استان ایلام - شهر دهلران";
426
- if (code == "726")cityN = "استان ایلام - شهر زرین آباد";
427
- if (code == "634")cityN = "استان ایلام - شهر شیروان لومار";
428
- if (code == "453")cityN = "استان ایلام - شهر شیروان و چرداول";
429
- if (code == "727")cityN = "استان ایلام - شهر موسیان";
430
- if (code == "452")cityN = "استان ایلام - شهر مهران";
431
- if (code == "145" || code == "146")cityN = "استان اردبیل - شهر اردبیل";
432
- if (code == "731")cityN = "استان اردبیل - شهر ارشق";
433
- if (code == "690")cityN = "استان اردبیل - شهر انگوت";
434
- if (code == "601")cityN = "استان اردبیل - شهر بیله سوار";
435
- if (code == "504")cityN = "استان اردبیل - شهر پارس آباد";
436
- if (code == "163")cityN = "استان اردبیل - شهر خلخال";
437
- if (code == "714")cityN = "استان اردبیل - شهر خورش رستم";
438
- if (code == "715")cityN = "استان اردبیل - شهر سرعین";
439
- if (code == "566")cityN = "استان اردبیل - شهر سنجبد(کوثر)";
440
- if (code == "166" || code == "167")cityN = "استان اردبیل - شهر مشکین شهر";
441
- if (code == "161" || code == "162")cityN = "استان اردبیل - شهر مغان";
442
- if (code == "686")cityN = "استان اردبیل - شهر نمین";
443
- if (code == "603")cityN = "استان اردبیل - شهر نیر";
444
- if (code == "619")cityN = "استان اصفهان - شهر آران و بیدگل";
445
- if (code == "118")cityN = "استان اصفهان - شهر اردستان";
446
- if (code == "127" || code == "128" || code == "129")cityN = "استان اصفهان - شهر اصفهان";
447
- if (code == "620")cityN = "استان اصفهان - شهر باغ بهادران";
448
- if (code == "621")cityN = "استان اصفهان - شهر بوئین و میاندشت";
449
- if (code == "549")cityN = "استان اصفهان - شهر تیران و کرون";
450
- if (code == "564")cityN = "استان اصفهان - شهر جرقویه";
451
- if (code == "575")cityN = "استان اصفهان - شهر چادگان";
452
- if (code == "113" || code == "114")cityN = "استان اصفهان - شهر خمینی شهر";
453
- if (code == "122")cityN = "استان اصفهان - شهر خوانسار";
454
- if (code == "540")cityN = "استان اصفهان - شهر خور و بیابانک";
455
- if (code == "660")cityN = "استان اصفهان - شهر دولت آباد";
456
- if (code == "120")cityN = "استان اصفهان - شهر سمیرم";
457
- if (code == "512")cityN = "استان اصفهان - شهر سمیرم سفلی (دهاقان)";
458
- if (code == "510" || code == "511")cityN = "استان اصفهان - شهر شاهین شهر";
459
- if (code == "119")cityN = "استان اصفهان - شهر شهرضا";
460
- if (code == "115")cityN = "استان اصفهان - شهر فریدن";
461
- if (code == "112")cityN = "استان اصفهان - شهر فریدونشهر";
462
- if (code == "110" || code == "111")cityN = "استان اصفهان - شهر فلاورجان";
463
- if (code == "125" || code == "126")cityN = "استان اصفهان - شهر کاشان";
464
- if (code == "565")cityN = "استان اصفهان - شهر کوهپایه";
465
- if (code == "121")cityN = "استان اصفهان - شهر گلپایگان";
466
- if (code == "116" || code == "117")cityN = "استان اصفهان - شهر لنجان(زرینشهر)";
467
- if (code == "541")cityN = "استان اصفهان - شهر مبارکه";
468
- if (code == "622")cityN = "استان اصفهان - شهر میمه";
469
- if (code == "124")cityN = "استان اصفهان - شهر نائین";
470
- if (code == "108" || code == "109")cityN = "استان اصفهان - شهر نجف آباد";
471
- if (code == "123")cityN = "استان اصفهان - شهر نطنز";
472
- if (code == "427" || code == "428")cityN = "استان زنجان - شهر زنجان";
473
- if (code == "507")cityN = "استان آذربایجان شرقی - شهر ملکان";
474
- if (code == "158")cityN = "استان آذربایجان شرقی - شهر مرند";
475
- if (code == "152" || code == "153")cityN = "استان آذربایجان شرقی - شهر میانه";
476
- if (code == "615")cityN = "استان قزوین - شهر ابهر و خرمدره";
477
- return cityN;
478
- }
479
-
480
- function melli_code_function(melli_code , field_id , message1 , message2 , message3 , is_seperate , show_city ) {
481
-
482
- document.getElementById("city_" + field_id).innerHTML = '';
483
-
484
- if (melli_code.value == '')
485
- return false;
486
-
487
- melli_code.value = melli_code.value.replace("-", "").replace("-", "");
488
-
489
- if (melli_code.value.length == 8)
490
- melli_code.value = '00' + melli_code.value;
491
-
492
- if (melli_code.value.length == 9)
493
- melli_code.value = '0' + melli_code.value;
494
-
495
- if (isNaN(melli_code.value)) {
496
- document.getElementById("city_" + field_id).innerHTML = message1;
497
- return false;
498
- }
499
-
500
- if (melli_code.value.length > 10 || melli_code.value.length < 8) {
501
- document.getElementById("city_" + field_id).innerHTML = message2;
502
- return false;
503
- }
504
-
505
- var pre_check = ["0000000000", "1111111111", "2222222222", "3333333333", "4444444444", "5555555555", "6666666666", "7777777777", "8888888888", "9999999999"];
506
- var indexOf = pre_check.indexOf(melli_code.value);
507
- if (indexOf != '-1') {
508
- document.getElementById("city_" + field_id).innerHTML = message3;
509
- return false;
510
- }
511
-
512
- city = melli_code.value.substring(0, 3);
513
- c = parseInt(melli_code.value.charAt(9));
514
- n = parseInt(melli_code.value.charAt(0)) * 10 +
515
- parseInt(melli_code.value.charAt(1)) * 9 +
516
- parseInt(melli_code.value.charAt(2)) * 8 +
517
- parseInt(melli_code.value.charAt(3)) * 7 +
518
- parseInt(melli_code.value.charAt(4)) * 6 +
519
- parseInt(melli_code.value.charAt(5)) * 5 +
520
- parseInt(melli_code.value.charAt(6)) * 4 +
521
- parseInt(melli_code.value.charAt(7)) * 3 +
522
- parseInt(melli_code.value.charAt(8)) * 2;
523
- r = n - parseInt(n / 11) * 11;
524
-
525
- if ((r == 0 && r == c) || (r == 1 && c == 1) || (r > 1 && c == 11 - r)) {
526
- if(is_seperate) {
527
- if (melli_code.value.length == 10)
528
- melli_code.value = melli_code.value.substring(0, 3) + "-" + melli_code.value.substring(3, 9) + "-" + melli_code.value.substring(9, 10);
529
- }
530
- if(show_city) {
531
- document.getElementById("city_" + field_id).innerHTML = cityName_by_melliCode_hannanstd(city);
532
- return true;
533
- }
534
- }
535
- else {
536
- document.getElementById("city_" + field_id).innerHTML = message3;
537
- return false;
538
- }
539
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/js/melli-code.min.js DELETED
@@ -1 +0,0 @@
1
- function cityName_by_melliCode_hannanstd(t){return"169"==t&&(cityN="استان آذربایجان شرقی - شهر آذر شهر"),"170"==t&&(cityN="استان آذربایجان شرقی - شهر اسکو"),("149"==t||"150"==t)&&(cityN="استان آذربایجان شرقی - شهر اهر"),"171"==t&&(cityN="استان آذربایجان شرقی - شهر بستان آباد"),"168"==t&&(cityN="استان آذربایجان شرقی - شهر بناب"),("136"==t||"137"==t||"138"==t)&&(cityN="استان آذربایجان شرقی - شهر تبریز"),"545"==t&&(cityN="استان آذربایجان شرقی - شهر ترکمانچای"),"505"==t&&(cityN="استان آذربایجان شرقی - شهر جلفا"),"636"==t&&(cityN="استان آذربایجان شرقی - شهر چاروایماق"),("164"==t||"165"==t)&&(cityN="استان آذربایجان شرقی - شهر سراب"),"172"==t&&(cityN="استان آذربایجان شرقی - شهر شبستر"),"623"==t&&(cityN="استان آذربایجان شرقی - شهر صوفیان"),"506"==t&&(cityN="استان آذربایجان شرقی - شهر عجب شیر"),"519"==t&&(cityN="استان آذربایجان شرقی - شهر کلیبر"),("154"==t||"155"==t)&&(cityN="استان آذربایجان شرقی - شهر مراغه"),"567"==t&&(cityN="استان آذربایجان شرقی - شهر ورزقان"),"173"==t&&(cityN="استان آذربایجان شرقی - شهر هریس"),("159"==t||"160"==t)&&(cityN="استان آذربایجان شرقی - شهر هشترود"),"604"==t&&(cityN="استان آذربایجان شرقی - شهر هوراند"),("274"==t||"275"==t)&&(cityN="استان آذربایجان غربی - شهر ارومیه"),"295"==t&&(cityN="استان آذربایجان غربی - شهر اشنویه"),"637"==t&&(cityN="استان آذربایجان غربی - شهر انزل"),"292"==t&&(cityN="استان آذربایجان غربی - شهر بوکان"),"492"==t&&(cityN="استان آذربایجان غربی - شهر پلدشت"),"289"==t&&(cityN="استان آذربایجان غربی - شهر پیرانشهر"),"677"==t&&(cityN="استان آذربایجان غربی - شهر تخت سلیمان"),"294"==t&&(cityN="استان آذربایجان غربی - شهر تکاب"),"493"==t&&(cityN="استان آذربایجان غربی - شهر چایپاره"),("279"==t||"280"==t)&&(cityN="استان آذربایجان غربی - شهر خوی"),"288"==t&&(cityN="استان آذربایجان غربی - شهر سردشت"),("284"==t||"285"==t)&&(cityN="استان آذربایجان غربی - شهر سلماس"),"638"==t&&(cityN="استان آذربایجان غربی - شهر سیلوانه"),"291"==t&&(cityN="استان آذربایجان غربی - شهر سیه چشمه(چالدران)"),"640"==t&&(cityN="استان آذربایجان غربی - شهر شوط"),"293"==t&&(cityN="استان آذربایجان غربی - شهر شاهین دژ"),"675"==t&&(cityN="استان آذربایجان غربی - شهر کشاورز"),("282"==t||"283"==t)&&(cityN="استان آذربایجان غربی - شهر ماکو"),("286"==t||"287"==t)&&(cityN="استان آذربایجان غربی - شهر مهاباد"),("296"==t||"297"==t)&&(cityN="استان آذربایجان غربی - شهر میاندوآب"),"290"==t&&(cityN="استان آذربایجان غربی - شهر نقده"),("400"==t||"401"==t)&&(cityN="استان همدان - شهر اسدآباد"),("404"==t||"405"==t)&&(cityN="استان همدان - شهر بهار"),"397"==t&&(cityN="استان همدان - شهر تویسرکان"),("398"==t||"399"==t)&&(cityN="استان همدان - شهر رزن"),"647"==t&&(cityN="استان همدان - شهر شراء و پیشخوار"),"502"==t&&(cityN="استان همدان - شهر فامنین"),"584"==t&&(cityN="استان همدان - شهر قلقل رود"),("402"==t||"403"==t)&&(cityN="استان همدان - شهر کبودرآهنگ"),("392"==t||"393"==t)&&(cityN="استان همدان - شهر ملایر"),("395"==t||"396"==t)&&(cityN="استان همدان - شهر نهاوند"),("386"==t||"387"==t)&&(cityN="استان همدان - شهر همدان"),"503"==t&&(cityN="استان یزد - شهر ابرکوه"),"444"==t&&(cityN="استان یزد - شهر اردکان"),"551"==t&&(cityN="استان یزد - شهر اشکذر"),"447"==t&&(cityN="استان یزد - شهر بافق"),"561"==t&&(cityN="استان یزد - شهر بهاباد"),"445"==t&&(cityN="استان یزد - شهر تفت"),"718"==t&&(cityN="استان یزد - شهر دستگردان"),"083"==t&&(cityN="استان یزد - شهر طبس"),"446"==t&&(cityN="استان یزد - شهر مهریز"),"448"==t&&(cityN="استان یزد - شهر میبد"),"552"==t&&(cityN="استان یزد - شهر نیر"),"543"==t&&(cityN="استان یزد - شهر هرات و مروست"),("442"==t||"443"==t)&&(cityN="استان یزد - شهر یزد"),"051"==t&&(cityN="استان مرکزی - شهر آشتیان"),("052"==t||"053"==t)&&(cityN="استان مرکزی - شهر اراک"),"058"==t&&(cityN="استان مرکزی - شهر تفرش"),"055"==t&&(cityN="استان مرکزی - شهر خمین"),"617"==t&&(cityN="استان مرکزی - شهر خنداب"),"057"==t&&(cityN="استان مرکزی - شهر دلیجان"),"618"==t&&(cityN="استان مرکزی - شهر زرند مرکزی"),("059"==t||"060"==t)&&(cityN="استان مرکزی - شهر ساوه"),("061"==t||"062"==t)&&(cityN="استان مرکزی - شهر سربند"),"544"==t&&(cityN="استان مرکزی - شهر فراهان"),"056"==t&&(cityN="استان مرکزی - شهر محلات"),"571"==t&&(cityN="استان مرکزی - شهر وفس"),"593"==t&&(cityN="استان مرکزی - شهر هندودر"),"667"==t&&(cityN="استان هرمزگان - شهر ابوموسی"),"348"==t&&(cityN="استان هرمزگان - شهر بستک"),"586"==t&&(cityN="استان هرمزگان - شهر بشاگرد"),("338"==t||"339"==t)&&(cityN="استان هرمزگان - شهر بندرعباس"),("343"==t||"344"==t)&&(cityN="استان هرمزگان - شهر بندرلنگه"),"346"==t&&(cityN="استان هرمزگان - شهر جاسک"),"337"==t&&(cityN="استان هرمزگان - شهر حاجی آباد"),"554"==t&&(cityN="استان هرمزگان - شهر خمیر"),"469"==t&&(cityN="استان هرمزگان - شهر رودان"),"537"==t&&(cityN="استان هرمزگان - شهر فین"),"345"==t&&(cityN="استان هرمزگان - شهر قشم"),"470"==t&&(cityN="استان هرمزگان - شهر گاوبندی"),("341"==t||"342"==t)&&(cityN="استان هرمزگان - شهر میناب"),("483"==t||"484"==t)&&(cityN="استان لرستان - شهر ازنا"),"557"==t&&(cityN="استان لرستان - شهر اشترینان"),"418"==t&&(cityN="استان لرستان - شهر الشتر"),("416"==t||"417"==t)&&(cityN="استان لرستان - شهر الیگودرز"),("412"==t||"413"==t)&&(cityN="استان لرستان - شهر بروجرد"),"592"==t&&(cityN="استان لرستان - شهر پاپی"),"612"==t&&(cityN="استان لرستان - شهر چغلوندی"),"613"==t&&(cityN="استان لرستان - شهر چگنی"),("406"==t||"407"==t)&&(cityN="استان لرستان - شهر خرم آباد"),"421"==t&&(cityN="استان لرستان - شهر دورود"),"598"==t&&(cityN="استان لرستان - شهر رومشکان"),"419"==t&&(cityN="استان لرستان - شهر کوهدشت"),"385"==t&&(cityN="استان لرستان - شهر ملاوی(پلدختر)"),"420"==t&&(cityN="استان لرستان - شهر نورآباد(دلفان)"),"528"==t&&(cityN="استان لرستان - شهر ویسیان"),("213"==t||"214"==t)&&(cityN="استان مازندران - شهر آمل"),("205"==t||"206"==t)&&(cityN="استان مازندران - شهر بابل"),"498"==t&&(cityN="استان مازندران - شهر بابل"),"568"==t&&(cityN="استان مازندران - شهر بندپی"),"711"==t&&(cityN="استان مازندران - شهر بندپی شرقی"),("217"==t||"218"==t)&&(cityN="استان مازندران - شهر بهشهر"),"221"==t&&(cityN="استان مازندران - شهر تنکابن"),"582"==t&&(cityN="استان مازندران - شهر جویبار"),"483"==t&&(cityN="استان مازندران - شهر چالوس"),"625"==t&&(cityN="استان مازندران - شهر چمستان"),"576"==t&&(cityN="استان مازندران - شهر چهاردانگه"),"578"==t&&(cityN="استان مازندران - شهر دودانگه"),"227"==t&&(cityN="استان مازندران - شهر رامسر"),("208"==t||"209"==t)&&(cityN="استان مازندران - شهر ساری"),"225"==t&&(cityN="استان مازندران - شهر سوادکوه"),"577"==t&&(cityN="استان مازندران - شهر شیرگاه"),"712"==t&&(cityN="استان مازندران - شهر عباس آباد"),("215"==t||"216"==t)&&(cityN="استان مازندران - شهر قائمشهر"),"626"==t&&(cityN="استان مازندران - شهر کجور"),"627"==t&&(cityN="استان مازندران - شهر کلاردشت"),"579"==t&&(cityN="استان مازندران - شهر گلوگاه"),"713"==t&&(cityN="استان مازندران - شهر میاندورود"),"499"==t&&(cityN="استان مازندران - شهر نکاء"),"222"==t&&(cityN="استان مازندران - شهر نور"),("219"==t||"220"==t)&&(cityN="استان مازندران - شهر نوشهر"),("500"==t||"501"==t)&&(cityN="استان مازندران - شهر هراز و محمودآباد"),"623"==t&&(cityN="استان گلستان - شهر آزادشهر"),"497"==t&&(cityN="استان گلستان - شهر آق قلا"),"223"==t&&(cityN="استان گلستان - شهر بندرترکمن"),"689"==t&&(cityN="استان گلستان - شهر بندرگز"),"487"==t&&(cityN="استان گلستان - شهر رامیان"),"226"==t&&(cityN="استان گلستان - شهر علی آباد"),"224"==t&&(cityN="استان گلستان - شهر کردکوی"),"386"==t&&(cityN="استان گلستان - شهر کلاله"),("211"==t||"212"==t)&&(cityN="استان گلستان - شهر گرگان"),"628"==t&&(cityN="استان گلستان - شهر گمیشان"),("202"==t||"203"==t)&&(cityN="استان گلستان - شهر گنبد کاووس"),"531"==t&&(cityN="استان گلستان - شهر مراوه تپه"),"288"==t&&(cityN="استان گلستان - شهر مینودشت"),"261"==t&&(cityN="استان گیلان - شهر آستارا"),"273"==t&&(cityN="استان گیلان - شهر آستانه"),"630"==t&&(cityN="استان گیلان - شهر املش"),"264"==t&&(cityN="استان گیلان - شهر بندرانزلی"),"518"==t&&(cityN="استان گیلان - شهر خمام"),"631"==t&&(cityN="استان گیلان - شهر رحیم آباد"),("258"==t||"259"==t)&&(cityN="استان گیلان - شهر رشت"),"570"==t&&(cityN="استان گیلان - شهر رضوانشهر"),"265"==t&&(cityN="استان گیلان - شهر رودبار"),("268"==t||"269"==t)&&(cityN="استان گیلان - شهر رودسر"),"653"==t&&(cityN="استان گیلان - شهر سنگر"),"517"==t&&(cityN="استان گیلان - شهر سیاهکل"),"569"==t&&(cityN="استان گیلان - شهر شفت"),"267"==t&&(cityN="استان گیلان - شهر صومعه سرا"),("262"==t||"263"==t)&&(cityN="استان گیلان - شهر طالش"),"593"==t&&(cityN="استان گیلان - شهر عمارلو"),"266"==t&&(cityN="استان گیلان - شهر فومن"),"693"==t&&(cityN="استان گیلان - شهر کوچصفهان"),("271"==t||"272"==t)&&(cityN="استان گیلان - شهر لاهیجان"),"694"==t&&(cityN="استان گیلان - شهر لشت نشاء"),"270"==t&&(cityN="استان گیلان - شهر لنگرود"),"516"==t&&(cityN="استان گیلان - شهر ماسال و شاندرمن"),("333"==t||"334"==t)&&(cityN="استان کرمانشاه - شهر اسلام آباد"),"691"==t&&(cityN="استان کرمانشاه - شهر باینگان"),("322"==t||"323"==t)&&(cityN="استان کرمانشاه - شهر پاوه"),"595"==t&&(cityN="استان کرمانشاه - شهر ثلاث باباجانی"),"395"==t&&(cityN="استان کرمانشاه - شهر جوانرود"),"641"==t&&(cityN="استان کرمانشاه - شهر حمیل"),"596"==t&&(cityN="استان کرمانشاه - شهر روانسر"),"336"==t&&(cityN="استان کرمانشاه - شهر سرپل ذهاب"),"335"==t&&(cityN="استان کرمانشاه - شهر سنقر"),"496"==t&&(cityN="استان کرمانشاه - شهر صحنه"),"337"==t&&(cityN="استان کرمانشاه - شهر قصرشیرین"),("324"==t||"325"==t)&&(cityN="استان کرمانشاه - شهر کرمانشاه"),"394"==t&&(cityN="استان کرمانشاه - شهر کرند"),"330"==t&&(cityN="استان کرمانشاه - شهر کنگاور"),"332"==t&&(cityN="استان کرمانشاه - شهر گیلانغرب"),"331"==t&&(cityN="استان کرمانشاه - شهر هرسین"),"687"==t&&(cityN="استان کهکیلویه و بویراحمد - شهر باشت"),("422"==t||"423"==t)&&(cityN="استان کهکیلویه و بویراحمد - شهر بویراحمد(یاسوج)"),"599"==t&&(cityN="استان کهکیلویه و بویراحمد - شهر بهمنی"),"600"==t&&(cityN="استان کهکیلویه و بویراحمد - شهر چاروسا"),"688"==t&&(cityN="استان کهکیلویه و بویراحمد - شهر دروهان"),("424"==t||"425"==t)&&(cityN="استان کهکیلویه و بویراحمد - شهر کهکیلویه(دهدشت)"),"426"==t&&(cityN="استان کهکیلویه و بویراحمد - شهر گچساران(دوگنبدان)"),"550"==t&&(cityN="استان کهکیلویه و بویراحمد - شهر لنده"),"697"==t&&(cityN="استان کهکیلویه و بویراحمد - شهر مارگون"),"384"==t&&(cityN="استان کردستان - شهر بانه"),("377"==t||"378"==t)&&(cityN="استان کردستان - شهر بیجار"),"558"==t&&(cityN="استان کردستان - شهر دهگلان"),"385"==t&&(cityN="استان کردستان - شهر دیواندره"),"646"==t&&(cityN="استان کردستان - شهر سروآباد"),("375"==t||"376"==t)&&(cityN="استان کردستان - شهر سقز"),("372"==t||"373"==t)&&(cityN="استان کردستان - شهر سنندج"),("379"==t||"380"==t)&&(cityN="استان کردستان - شهر قروه"),"383"==t&&(cityN="استان کردستان - شهر کامیاران"),"674"==t&&(cityN="استان کردستان - شهر کرانی"),("381"==t||"382"==t)&&(cityN="استان کردستان - شهر مریوان"),"676"==t&&(cityN="استان کردستان - شهر نمشیر"),"722"==t&&(cityN="استان کرمان - شهر ارزونیه"),"542"==t&&(cityN="استان کرمان - شهر انار"),("312"==t||"313"==t)&&(cityN="استان کرمان - شهر بافت"),"317"==t&&(cityN="استان کرمان - شهر بردسیر"),("310"==t||"311"==t)&&(cityN="استان کرمان - شهر بم"),("302"==t||"303"==t)&&(cityN="استان کرمان - شهر جیرفت"),"583"==t&&(cityN="استان کرمان - شهر رابر"),"321"==t&&(cityN="استان کرمان - شهر راور"),"382"==t&&(cityN="استان کرمان - شهر راین"),("304"==t||"305"==t)&&(cityN="استان کرمان - شهر رفسنجان"),"536"==t&&(cityN="استان کرمان - شهر رودبار کهنوج"),"605"==t&&(cityN="استان کرمان - شهر ریگان"),("308"==t||"309"==t)&&(cityN="استان کرمان - شهر زرند"),("306"==t||"307"==t)&&(cityN="استان کرمان - شهر سیرجان"),"319"==t&&(cityN="استان کرمان - شهر شهداد"),("313"==t||"314"==t)&&(cityN="استان کرمان - شهر شهربابک"),"606"==t&&(cityN="استان کرمان - شهر عنبرآباد"),"320"==t&&(cityN="استان کرمان - شهر فهرج"),"698"==t&&(cityN="استان کرمان - شهر قلعه گنج"),("298"==t||"299"==t)&&(cityN="استان کرمان - شهر کرمان"),"535"==t&&(cityN="استان کرمان - شهر کوهبنان"),("315"==t||"316"==t)&&(cityN="استان کرمان - شهر کهنوج"),"318"==t&&(cityN="استان کرمان - شهر گلباف"),"607"==t&&(cityN="استان کرمان - شهر ماهان"),"608"==t&&(cityN="استان کرمان - شهر منوجان"),"508"==t&&(cityN="استان قزوین - شهر آبیک"),"538"==t&&(cityN="استان قزوین - شهر آوج"),"728"==t&&(cityN="استان قزوین - شهر البرز"),"509"==t&&(cityN="استان قزوین - شهر بوئین زهرا"),("438"==t||"439"==t)&&(cityN="استان قزوین - شهر تاکستان"),"580"==t&&(cityN="استان قزوین - شهر رودبار الموت"),"590"==t&&(cityN="استان قزوین - شهر رودبار شهرستان"),"559"==t&&(cityN="استان قزوین - شهر ضیاءآباد"),"588"==t&&(cityN="استان قزوین - شهر طارم سفلی"),("431"==t||"432"==t)&&(cityN="استان قزوین - شهر قزوین"),("037"==t||"038"==t)&&(cityN="استان قم - شهر قم"),"702"==t&&(cityN="استان قم - شهر کهک"),("240"==t||"241"==t)&&(cityN="استان فارس - شهر آباده"),"670"==t&&(cityN="استان فارس - شهر آباده طشک"),"648"==t&&(cityN="استان فارس - شهر ارسنجان"),"252"==t&&(cityN="استان فارس - شهر استهبان"),"678"==t&&(cityN="استان فارس - شهر اشکنان"),"253"==t&&(cityN="استان فارس - شهر اقلید"),"649"==t&&(cityN="استان فارس - شهر اوز"),"513"==t&&(cityN="استان فارس - شهر بوانات"),"546"==t&&(cityN="استان فارس - شهر بیضا"),"671"==t&&(cityN="استان فارس - شهر جویم"),("246"==t||"247"==t)&&(cityN="استان فارس - شهر جهرم"),"654"==t&&(cityN="استان فارس - شهر حاجی آباد(زرین دشت)"),"548"==t&&(cityN="استان فارس - شهر خرامه"),"547"==t&&(cityN="استان فارس - شهر خشت و کمارج"),"655"==t&&(cityN="استان فارس - شهر خفر"),("248"==t||"249"==t)&&(cityN="استان فارس - شهر داراب"),"253"==t&&(cityN="استان فارس - شهر سپیدان"),"514"==t&&(cityN="استان فارس - شهر سروستان"),"665"==t&&(cityN="استان فارس - شهر سعادت آباد"),"673"==t&&(cityN="استان فارس - شهر شیبکوه"),("228"==t||"229"==t||"230"==t)&&(cityN="استان فارس - شهر شیراز"),"679"==t&&(cityN="استان فارس - شهر فراشبند"),("256"==t||"257"==t)&&(cityN="استان فارس - شهر فسا"),("244"==t||"245"==t)&&(cityN="استان فارس - شهر فیروزآباد"),"681"==t&&(cityN="استان فارس - شهر قنقری(خرم بید)"),"723"==t&&(cityN="استان فارس - شهر قیروکارزین"),("236"==t||"237"==t)&&(cityN="استان فارس - شهر کازرون"),"683"==t&&(cityN="استان فارس - شهر کوار"),"656"==t&&(cityN="استان فارس - شهر کراش"),("250"==t||"251"==t)&&(cityN="استان فارس - شهر لارستان"),"515"==t&&(cityN="استان فارس - شهر لامرد"),("242"==t||"243"==t)&&(cityN="استان فارس - شهر مرودشت"),("238"==t||"239"==t)&&(cityN="استان فارس - شهر ممسنی"),"657"==t&&(cityN="استان فارس - شهر مهر"),"255"==t&&(cityN="استان فارس - شهر نی ریز"),"684"==t&&(cityN="استان سمنان - شهر ایوانکی"),"700"==t&&(cityN="استان سمنان - شهر بسطام"),"642"==t&&(cityN="استان سمنان - شهر بیارجمند"),"457"==t&&(cityN="استان سمنان - شهر دامغان"),"456"==t&&(cityN="استان سمنان - شهر سمنان"),("458"==t||"459"==t)&&(cityN="استان سمنان - شهر شاهرود"),"460"==t&&(cityN="استان سمنان - شهر گرمسار"),"530"==t&&(cityN="استان سمنان - شهر مهدیشهر"),"520"==t&&(cityN="استان سمنان - شهر میامی"),("358"==t||"359"==t)&&(cityN="استان سیستان و بلوچستان - شهر ایرانشهر"),"682"==t&&(cityN="استان سیستان و بلوچستان - شهر بزمان"),"703"==t&&(cityN="استان سیستان و بلوچستان - شهر بمپور"),("364"==t||"365"==t)&&(cityN="استان سیستان و بلوچستان - شهر چابهار"),"371"==t&&(cityN="استان سیستان و بلوچستان - شهر خاش"),"701"==t&&(cityN="استان سیستان و بلوچستان - شهر دشتیاری"),"720"==t&&(cityN="استان سیستان و بلوچستان - شهر راسک"),("366"==t||"367"==t)&&(cityN="استان سیستان و بلوچستان - شهر زابل"),"704"==t&&(cityN="استان سیستان و بلوچستان - شهر زابلی"),("361"==t||"362"==t)&&(cityN="استان سیستان و بلوچستان - شهر زاهدان"),("369"==t||"370"==t)&&(cityN="استان سیستان و بلوچستان - شهر سراوان"),"635"==t&&(cityN="استان سیستان و بلوچستان - شهر سرباز"),"668"==t&&(cityN="استان سیستان و بلوچستان - شهر سیب و سوران"),"533"==t&&(cityN="استان سیستان و بلوچستان - شهر شهرکی و ناروئی(زهک)"),"705"==t&&(cityN="استان سیستان و بلوچستان - شهر شیب آب"),"699"==t&&(cityN="استان سیستان و بلوچستان - شهر فنوج"),"669"==t&&(cityN="استان سیستان و بلوچستان - شهر قصرقند"),"725"==t&&(cityN="استان سیستان و بلوچستان - شهر کنارک"),"597"==t&&(cityN="استان سیستان و بلوچستان - شهر لاشار(اسپکه)"),"611"==t&&(cityN="استان سیستان و بلوچستان - شهر میرجاوه"),"525"==t&&(cityN="استان سیستان و بلوچستان - شهر نیک شهر"),"181"==t&&(cityN="استان خوزستان - شهر آبادان"),"527"==t&&(cityN="استان خوزستان - شهر آغاجاری"),"585"==t&&(cityN="استان خوزستان - شهر اروندکنار"),"685"==t&&(cityN="استان خوزستان - شهر امیدیه"),"663"==t&&(cityN="استان خوزستان - شهر اندیکا"),("192"==t||"193"==t)&&(cityN="استان خوزستان - شهر اندیمشک"),("174"==t||"175"==t)&&(cityN="استان خوزستان - شهر اهواز"),("183"==t||"184"==t)&&(cityN="استان خوزستان - شهر ایذه"),"481"==t&&(cityN="استان خوزستان - شهر باغ ملک"),"706"==t&&(cityN="استان خوزستان - شهر بندر امام خمینی"),("194"==t||"195"==t)&&(cityN="استان خوزستان - شهر بندرماهشهر"),("185"==t||"186"==t)&&(cityN="استان خوزستان - شهر بهبهان"),"182"==t&&(cityN="استان خوزستان - شهر خرمشهر"),("199"==t||"200"==t)&&(cityN="استان خوزستان - شهر دزفول"),"198"==t&&(cityN="استان خوزستان - شهر دشت آزادگان"),"662"==t&&(cityN="استان خوزستان - شهر رامشیر"),("190"==t||"191"==t)&&(cityN="استان خوزستان - شهر رامهرمز"),"692"==t&&(cityN="استان خوزستان - شهر سردشت"),"189"==t&&(cityN="استان خوزستان - شهر شادگان"),"707"==t&&(cityN="استان خوزستان - شهر شاوور"),"526"==t&&(cityN="استان خوزستان - شهر شوش"),("187"==t||"188"==t)&&(cityN="استان خوزستان - شهر شوشتر"),"729"==t&&(cityN="استان خوزستان - شهر گتوند"),"730"==t&&(cityN="استان خوزستان - شهر لالی"),("196"==t||"197"==t)&&(cityN="استان خوزستان - شهر مسجدسلیمان"),"661"==t&&(cityN="استان خوزستان - شهر هندیجان"),"680"==t&&(cityN="استان خوزستان - شهر هویزه"),"643"==t&&(cityN="استان خراسان رضوی - شهر احمدآباد"),"562"==t&&(cityN="استان خراسان رضوی - شهر بجستان"),"572"==t&&(cityN="استان خراسان رضوی - شهر بردسکن"),"074"==t&&(cityN="استان خراسان رضوی - شهر تایباد"),"644"==t&&(cityN="استان خراسان رضوی - شهر تخت جلگه"),("072"==t||"073"==t)&&(cityN="استان خراسان رضوی - شهر تربت جام"),("069"==t||"070"==t)&&(cityN="استان خراسان رضوی - شهر تربت حیدریه"),"521"==t&&(cityN="استان خراسان رضوی - شهر جغتای"),"573"==t&&(cityN="استان خراسان رضوی - شهر جوین"),"522"==t&&(cityN="استان خراسان رضوی - شهر چناران"),"724"==t&&(cityN="استان خراسان رضوی - شهر خلیل آباد"),"076"==t&&(cityN="استان خراسان رضوی - شهر خواف"),"077"==t&&(cityN="استان خراسان رضوی - شهر درگز"),"650"==t&&(cityN="استان خراسان رضوی - شهر رشتخوار"),"574"==t&&(cityN="استان خراسان رضوی - شهر زبرخان"),("078"==t||"079"==t)&&(cityN="استان خراسان رضوی - شهر سبزوار"),"081"==t&&(cityN="استان خراسان رضوی - شهر سرخس"),"084"==t&&(cityN="استان خراسان رضوی - شهر فریمان"),"651"==t&&(cityN="استان خراسان رضوی - شهر فیض آباد"),("086"==t||"087"==t)&&(cityN="استان خراسان رضوی - شهر قوچان"),("089"==t||"090"==t)&&(cityN="استان خراسان رضوی - شهر کاشمر"),"553"==t&&(cityN="استان خراسان رضوی - شهر کلات"),"091"==t&&(cityN="استان خراسان رضوی - شهر گناباد"),("092"==t||"093"==t||"094"==t)&&(cityN="استان خراسان رضوی - شهر مشهد"),"097"==t&&(cityN="استان خراسان رضوی - شهر مشهد منطقه2"),"098"==t&&(cityN="استان خراسان رضوی - شهر مشهد منطقه3"),"096"==t&&(cityN="استان خراسان رضوی - شهر مشهد منطقه1"),("105"==t||"106"==t)&&(cityN="استان خراسان رضوی - شهر نیشابور"),"063"==t&&(cityN="استان خراسان شمالی - شهر اسفراین"),("067"==t||"068"==t)&&(cityN="استان خراسان شمالی - شهر بجنورد"),"075"==t&&(cityN="استان خراسان شمالی - شهر جاجرم"),"591"==t&&(cityN="استان خراسان شمالی - شهر رازوجرکلان"),"082"==t&&(cityN="استان خراسان شمالی - شهر شیروان"),"635"==t&&(cityN="استان خراسان شمالی - شهر فاروج"),"524"==t&&(cityN="استان خراسان شمالی - شهر مانه و سملقان"),"468"==t&&(cityN="استان چهارمحال و بختیاری - شهر اردل"),"465"==t&&(cityN="استان چهارمحال و بختیاری - شهر بروجن"),("461"==t||"462"==t)&&(cityN="استان چهارمحال و بختیاری - شهر شهرکرد"),"467"==t&&(cityN="استان چهارمحال و بختیاری - شهر فارسان"),"555"==t&&(cityN="استان چهارمحال و بختیاری - شهر کوهرنگ"),"633"==t&&(cityN="استان چهارمحال و بختیاری - شهر کیار"),"629"==t&&(cityN="استان چهارمحال و بختیاری - شهر گندمان"),"466"==t&&(cityN="استان چهارمحال و بختیاری - شهر لردگان"),"696"==t&&(cityN="استان چهارمحال و بختیاری - شهر میانکوه"),"721"==t&&(cityN="استان خراسان جنوبی - شهر بشرویه"),("064"==t||"065"==t)&&(cityN="استان خراسان جنوبی - شهر بیرجند"),"523"==t&&(cityN="استان خراسان جنوبی - شهر درمیان"),"652"==t&&(cityN="استان خراسان جنوبی - شهر زیرکوه"),"719"==t&&(cityN="استان خراسان جنوبی - شهر سرایان"),"716"==t&&(cityN="استان خراسان جنوبی - شهر سربیشه"),"085"==t&&(cityN="استان خراسان جنوبی - شهر فردوس"),"088"==t&&(cityN="استان خراسان جنوبی - شهر قائنات"),"563"==t&&(cityN="استان خراسان جنوبی - شهر نهبندان"),"529"==t&&(cityN="استان بوشهر - شهر بندر دیلم"),"353"==t&&(cityN="استان بوشهر - شهر بندر گناوه"),("349"==t||"350"==t)&&(cityN="استان بوشهر - شهر بوشهر"),"355"==t&&(cityN="استان بوشهر - شهر تنگستان"),"609"==t&&(cityN="استان بوشهر - شهر جم"),("351"==t||"352"==t)&&(cityN="استان بوشهر - شهر دشتستان"),"354"==t&&(cityN="استان بوشهر - شهر دشتی"),"732"==t&&(cityN="استان بوشهر - شهر دلوار"),"357"==t&&(cityN="استان بوشهر - شهر دیر"),"532"==t&&(cityN="استان بوشهر - شهر سعد آباد"),"610"==t&&(cityN="استان بوشهر - شهر شبانکاره"),"356"==t&&(cityN="استان بوشهر - شهر کنگان"),"556"==t&&(cityN="استان تهران - شهر اسلامشهر"),"658"==t&&(cityN="استان تهران - شهر پاکدشت"),("001"==t||"002"==t||"003"==t||"004"==t||"005"==t||"006"==t||"007"==t||"008"==t)&&(cityN="استان تهران - شهر تهران مرکزی"),"011"==t&&(cityN="استان تهران - شهر تهران جنوب"),"020"==t&&(cityN="استان تهران - شهر تهران شرق"),"025"==t&&(cityN="استان تهران - شهر تهرانشمال"),"015"==t&&(cityN="استان تهران - شهر تهران غرب"),"043"==t&&(cityN="استان تهران - شهر دماوند"),"666"==t&&(cityN="استان تهران - شهر رباط کریم"),"489"==t&&(cityN="استان تهران - شهر ساوجبلاغ"),("044"==t||"045"==t)&&(cityN="استان تهران - شهر شمیران"),("048"==t||"049"==t)&&(cityN="استان تهران - شهر شهرری"),("490"==t||"491"==t)&&(cityN="استان تهران - شهر شهریار"),"695"==t&&(cityN="استان تهران - شهر طالقان"),"659"==t&&(cityN="استان تهران - شهر فیروزکوه"),("031"==t||"032"==t)&&(cityN="استان تهران - شهر کرج"),"664"==t&&(cityN="استان تهران - شهر کهریزک"),"717"==t&&(cityN="استان تهران - شهر نظرآباد"),("041"==t||"042"==t)&&(cityN="استان تهران - شهر ورامین"),("471"==t||"472"==t)&&(cityN=" امور خارجه - امور خارجه"),"454"==t&&(cityN="استان ایلام - شهر آبدانان"),"581"==t&&(cityN="استان ایلام - شهر ارکوازی(ملکشاهی)"),("449"==t||"450"==t)&&(cityN="استان ایلام - شهر ایلام"),"616"==t&&(cityN="استان ایلام - شهر ایوان"),"534"==t&&(cityN="استان ایلام - شهر بدره"),"455"==t&&(cityN="استان ایلام - شهر دره شهر"),"451"==t&&(cityN="استان ایلام - شهر دهلران"),"726"==t&&(cityN="استان ایلام - شهر زرین آباد"),"634"==t&&(cityN="استان ایلام - شهر شیروان لومار"),"453"==t&&(cityN="استان ایلام - شهر شیروان و چرداول"),"727"==t&&(cityN="استان ایلام - شهر موسیان"),"452"==t&&(cityN="استان ایلام - شهر مهران"),("145"==t||"146"==t)&&(cityN="استان اردبیل - شهر اردبیل"),"731"==t&&(cityN="استان اردبیل - شهر ارشق"),"690"==t&&(cityN="استان اردبیل - شهر انگوت"),"601"==t&&(cityN="استان اردبیل - شهر بیله سوار"),"504"==t&&(cityN="استان اردبیل - شهر پارس آباد"),"163"==t&&(cityN="استان اردبیل - شهر خلخال"),"714"==t&&(cityN="استان اردبیل - شهر خورش رستم"),"715"==t&&(cityN="استان اردبیل - شهر سرعین"),"566"==t&&(cityN="استان اردبیل - شهر سنجبد(کوثر)"),("166"==t||"167"==t)&&(cityN="استان اردبیل - شهر مشکین شهر"),("161"==t||"162"==t)&&(cityN="استان اردبیل - شهر مغان"),"686"==t&&(cityN="استان اردبیل - شهر نمین"),"603"==t&&(cityN="استان اردبیل - شهر نیر"),"619"==t&&(cityN="استان اصفهان - شهر آران و بیدگل"),"118"==t&&(cityN="استان اصفهان - شهر اردستان"),("127"==t||"128"==t||"129"==t)&&(cityN="استان اصفهان - شهر اصفهان"),"620"==t&&(cityN="استان اصفهان - شهر باغ بهادران"),"621"==t&&(cityN="استان اصفهان - شهر بوئین و میاندشت"),"549"==t&&(cityN="استان اصفهان - شهر تیران و کرون"),"564"==t&&(cityN="استان اصفهان - شهر جرقویه"),"575"==t&&(cityN="استان اصفهان - شهر چادگان"),("113"==t||"114"==t)&&(cityN="استان اصفهان - شهر خمینی شهر"),"122"==t&&(cityN="استان اصفهان - شهر خوانسار"),"540"==t&&(cityN="استان اصفهان - شهر خور و بیابانک"),"660"==t&&(cityN="استان اصفهان - شهر دولت آباد"),"120"==t&&(cityN="استان اصفهان - شهر سمیرم"),"512"==t&&(cityN="استان اصفهان - شهر سمیرم سفلی (دهاقان)"),("510"==t||"511"==t)&&(cityN="استان اصفهان - شهر شاهین شهر"),"119"==t&&(cityN="استان اصفهان - شهر شهرضا"),"115"==t&&(cityN="استان اصفهان - شهر فریدن"),"112"==t&&(cityN="استان اصفهان - شهر فریدونشهر"),("110"==t||"111"==t)&&(cityN="استان اصفهان - شهر فلاورجان"),("125"==t||"126"==t)&&(cityN="استان اصفهان - شهر کاشان"),"565"==t&&(cityN="استان اصفهان - شهر کوهپایه"),"121"==t&&(cityN="استان اصفهان - شهر گلپایگان"),("116"==t||"117"==t)&&(cityN="استان اصفهان - شهر لنجان(زرینشهر)"),"541"==t&&(cityN="استان اصفهان - شهر مبارکه"),"622"==t&&(cityN="استان اصفهان - شهر میمه"),"124"==t&&(cityN="استان اصفهان - شهر نائین"),("108"==t||"109"==t)&&(cityN="استان اصفهان - شهر نجف آباد"),"123"==t&&(cityN="استان اصفهان - شهر نطنز"),("427"==t||"428"==t)&&(cityN="استان زنجان - شهر زنجان"),"507"==t&&(cityN="استان آذربایجان شرقی - شهر ملکان"),"158"==t&&(cityN="استان آذربایجان شرقی - شهر مرند"),("152"==t||"153"==t)&&(cityN="استان آذربایجان شرقی - شهر میانه"),"615"==t&&(cityN="استان قزوین - شهر ابهر و خرمدره"),cityN}function melli_code_function(t,i,y,N,e,a,l){if(document.getElementById("city_"+i).innerHTML="",""==t.value)return!1;if(t.value=t.value.replace("-","").replace("-",""),8==t.value.length&&(t.value="00"+t.value),9==t.value.length&&(t.value="0"+t.value),isNaN(t.value))return document.getElementById("city_"+i).innerHTML=y,!1;if(t.value.length>10||t.value.length<8)return document.getElementById("city_"+i).innerHTML=N,!1;var u=["0000000000","1111111111","2222222222","3333333333","4444444444","5555555555","6666666666","7777777777","8888888888","9999999999"],v=u.indexOf(t.value);return"-1"!=v?(document.getElementById("city_"+i).innerHTML=e,!1):(city=t.value.substring(0,3),c=parseInt(t.value.charAt(9)),n=10*parseInt(t.value.charAt(0))+9*parseInt(t.value.charAt(1))+8*parseInt(t.value.charAt(2))+7*parseInt(t.value.charAt(3))+6*parseInt(t.value.charAt(4))+5*parseInt(t.value.charAt(5))+4*parseInt(t.value.charAt(6))+3*parseInt(t.value.charAt(7))+2*parseInt(t.value.charAt(8)),r=n-11*parseInt(n/11),0==r&&r==c||1==r&&1==c||r>1&&c==11-r?(a&&10==t.value.length&&(t.value=t.value.substring(0,3)+"-"+t.value.substring(3,9)+"-"+t.value.substring(9,10)),l?(document.getElementById("city_"+i).innerHTML=cityName_by_melliCode_hannanstd(city),!0):void 0):(document.getElementById("city_"+i).innerHTML=e,!1))}
 
assets/js/national_id.js ADDED
@@ -0,0 +1,546 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * @return {string}
3
+ */
4
+ function GFPersian_National_ID_Location(code) {
5
+ var location = '';
6
+ if (code == "169") location = "استان آذربایجان شرقی - شهر آذر شهر";
7
+ if (code == "170") location = "استان آذربایجان شرقی - شهر اسکو";
8
+ if (code == "149" || code == "150") location = "استان آذربایجان شرقی - شهر اهر";
9
+ if (code == "171") location = "استان آذربایجان شرقی - شهر بستان آباد";
10
+ if (code == "168") location = "استان آذربایجان شرقی - شهر بناب";
11
+ if (code == "136" || code == "137" || code == "138") location = "استان آذربایجان شرقی - شهر تبریز";
12
+ if (code == "545") location = "استان آذربایجان شرقی - شهر ترکمانچای";
13
+ if (code == "505") location = "استان آذربایجان شرقی - شهر جلفا";
14
+ if (code == "636") location = "استان آذربایجان شرقی - شهر چاروایماق";
15
+ if (code == "164" || code == "165") location = "استان آذربایجان شرقی - شهر سراب";
16
+ if (code == "172") location = "استان آذربایجان شرقی - شهر شبستر";
17
+ if (code == "623") location = "استان آذربایجان شرقی - شهر صوفیان";
18
+ if (code == "506") location = "استان آذربایجان شرقی - شهر عجب شیر";
19
+ if (code == "519") location = "استان آذربایجان شرقی - شهر کلیبر";
20
+ if (code == "154" || code == "155") location = "استان آذربایجان شرقی - شهر مراغه";
21
+ if (code == "567") location = "استان آذربایجان شرقی - شهر ورزقان";
22
+ if (code == "173") location = "استان آذربایجان شرقی - شهر هریس";
23
+ if (code == "159" || code == "160") location = "استان آذربایجان شرقی - شهر هشترود";
24
+ if (code == "604") location = "استان آذربایجان شرقی - شهر هوراند";
25
+ if (code == "274" || code == "275") location = "استان آذربایجان غربی - شهر ارومیه";
26
+ if (code == "295") location = "استان آذربایجان غربی - شهر اشنویه";
27
+ if (code == "637") location = "استان آذربایجان غربی - شهر انزل";
28
+ if (code == "292") location = "استان آذربایجان غربی - شهر بوکان";
29
+ if (code == "492") location = "استان آذربایجان غربی - شهر پلدشت";
30
+ if (code == "289") location = "استان آذربایجان غربی - شهر پیرانشهر";
31
+ if (code == "677") location = "استان آذربایجان غربی - شهر تخت سلیمان";
32
+ if (code == "294") location = "استان آذربایجان غربی - شهر تکاب";
33
+ if (code == "493") location = "استان آذربایجان غربی - شهر چایپاره";
34
+ if (code == "279" || code == "280") location = "استان آذربایجان غربی - شهر خوی";
35
+ if (code == "288") location = "استان آذربایجان غربی - شهر سردشت";
36
+ if (code == "284" || code == "285") location = "استان آذربایجان غربی - شهر سلماس";
37
+ if (code == "638") location = "استان آذربایجان غربی - شهر سیلوانه";
38
+ if (code == "291") location = "استان آذربایجان غربی - شهر سیه چشمه(چالدران)";
39
+ if (code == "640") location = "استان آذربایجان غربی - شهر شوط";
40
+ if (code == "293") location = "استان آذربایجان غربی - شهر شاهین دژ";
41
+ if (code == "675") location = "استان آذربایجان غربی - شهر کشاورز";
42
+ if (code == "282" || code == "283") location = "استان آذربایجان غربی - شهر ماکو";
43
+ if (code == "286" || code == "287") location = "استان آذربایجان غربی - شهر مهاباد";
44
+ if (code == "296" || code == "297") location = "استان آذربایجان غربی - شهر میاندوآب";
45
+ if (code == "290") location = "استان آذربایجان غربی - شهر نقده";
46
+ if (code == "400" || code == "401") location = "استان همدان - شهر اسدآباد";
47
+ if (code == "404" || code == "405") location = "استان همدان - شهر بهار";
48
+ if (code == "397") location = "استان همدان - شهر تویسرکان";
49
+ if (code == "398" || code == "399") location = "استان همدان - شهر رزن";
50
+ if (code == "647") location = "استان همدان - شهر شراء و پیشخوار";
51
+ if (code == "502") location = "استان همدان - شهر فامنین";
52
+ if (code == "584") location = "استان همدان - شهر قلقل رود";
53
+ if (code == "402" || code == "403") location = "استان همدان - شهر کبودرآهنگ";
54
+ if (code == "392" || code == "393") location = "استان همدان - شهر ملایر";
55
+ if (code == "395" || code == "396") location = "استان همدان - شهر نهاوند";
56
+ if (code == "386" || code == "387") location = "استان همدان - شهر همدان";
57
+ if (code == "503") location = "استان یزد - شهر ابرکوه";
58
+ if (code == "444") location = "استان یزد - شهر اردکان";
59
+ if (code == "551") location = "استان یزد - شهر اشکذر";
60
+ if (code == "447") location = "استان یزد - شهر بافق";
61
+ if (code == "561") location = "استان یزد - شهر بهاباد";
62
+ if (code == "445") location = "استان یزد - شهر تفت";
63
+ if (code == "718") location = "استان یزد - شهر دستگردان";
64
+ if (code == "083") location = "استان یزد - شهر طبس";
65
+ if (code == "446") location = "استان یزد - شهر مهریز";
66
+ if (code == "448") location = "استان یزد - شهر میبد";
67
+ if (code == "552") location = "استان یزد - شهر نیر";
68
+ if (code == "543") location = "استان یزد - شهر هرات و مروست";
69
+ if (code == "442" || code == "443") location = "استان یزد - شهر یزد";
70
+ if (code == "051") location = "استان مرکزی - شهر آشتیان";
71
+ if (code == "052" || code == "053") location = "استان مرکزی - شهر اراک";
72
+ if (code == "058") location = "استان مرکزی - شهر تفرش";
73
+ if (code == "055") location = "استان مرکزی - شهر خمین";
74
+ if (code == "617") location = "استان مرکزی - شهر خنداب";
75
+ if (code == "057") location = "استان مرکزی - شهر دلیجان";
76
+ if (code == "618") location = "استان مرکزی - شهر زرند مرکزی";
77
+ if (code == "059" || code == "060") location = "استان مرکزی - شهر ساوه";
78
+ if (code == "061" || code == "062") location = "استان مرکزی - شهر سربند";
79
+ if (code == "544") location = "استان مرکزی - شهر فراهان";
80
+ if (code == "056") location = "استان مرکزی - شهر محلات";
81
+ if (code == "571") location = "استان مرکزی - شهر وفس";
82
+ if (code == "593") location = "استان مرکزی - شهر هندودر";
83
+ if (code == "667") location = "استان هرمزگان - شهر ابوموسی";
84
+ if (code == "348") location = "استان هرمزگان - شهر بستک";
85
+ if (code == "586") location = "استان هرمزگان - شهر بشاگرد";
86
+ if (code == "338" || code == "339") location = "استان هرمزگان - شهر بندرعباس";
87
+ if (code == "343" || code == "344") location = "استان هرمزگان - شهر بندرلنگه";
88
+ if (code == "346") location = "استان هرمزگان - شهر جاسک";
89
+ if (code == "337") location = "استان هرمزگان - شهر حاجی آباد";
90
+ if (code == "554") location = "استان هرمزگان - شهر خمیر";
91
+ if (code == "469") location = "استان هرمزگان - شهر رودان";
92
+ if (code == "537") location = "استان هرمزگان - شهر فین";
93
+ if (code == "345") location = "استان هرمزگان - شهر قشم";
94
+ if (code == "470") location = "استان هرمزگان - شهر گاوبندی";
95
+ if (code == "341" || code == "342") location = "استان هرمزگان - شهر میناب";
96
+ if (code == "483" || code == "484") location = "استان لرستان - شهر ازنا";
97
+ if (code == "557") location = "استان لرستان - شهر اشترینان";
98
+ if (code == "418") location = "استان لرستان - شهر الشتر";
99
+ if (code == "416" || code == "417") location = "استان لرستان - شهر الیگودرز";
100
+ if (code == "412" || code == "413") location = "استان لرستان - شهر بروجرد";
101
+ if (code == "592") location = "استان لرستان - شهر پاپی";
102
+ if (code == "612") location = "استان لرستان - شهر چغلوندی";
103
+ if (code == "613") location = "استان لرستان - شهر چگنی";
104
+ if (code == "406" || code == "407") location = "استان لرستان - شهر خرم آباد";
105
+ if (code == "421") location = "استان لرستان - شهر دورود";
106
+ if (code == "598") location = "استان لرستان - شهر رومشکان";
107
+ if (code == "419") location = "استان لرستان - شهر کوهدشت";
108
+ if (code == "385") location = "استان لرستان - شهر ملاوی(پلدختر)";
109
+ if (code == "420") location = "استان لرستان - شهر نورآباد(دلفان)";
110
+ if (code == "528") location = "استان لرستان - شهر ویسیان";
111
+ if (code == "213" || code == "214") location = "استان مازندران - شهر آمل";
112
+ if (code == "205" || code == "206") location = "استان مازندران - شهر بابل";
113
+ if (code == "498") location = "استان مازندران - شهر بابل";
114
+ if (code == "568") location = "استان مازندران - شهر بندپی";
115
+ if (code == "711") location = "استان مازندران - شهر بندپی شرقی";
116
+ if (code == "217" || code == "218") location = "استان مازندران - شهر بهشهر";
117
+ if (code == "221") location = "استان مازندران - شهر تنکابن";
118
+ if (code == "582") location = "استان مازندران - شهر جویبار";
119
+ if (code == "483") location = "استان مازندران - شهر چالوس";
120
+ if (code == "625") location = "استان مازندران - شهر چمستان";
121
+ if (code == "576") location = "استان مازندران - شهر چهاردانگه";
122
+ if (code == "578") location = "استان مازندران - شهر دودانگه";
123
+ if (code == "227") location = "استان مازندران - شهر رامسر";
124
+ if (code == "208" || code == "209") location = "استان مازندران - شهر ساری";
125
+ if (code == "225") location = "استان مازندران - شهر سوادکوه";
126
+ if (code == "577") location = "استان مازندران - شهر شیرگاه";
127
+ if (code == "712") location = "استان مازندران - شهر عباس آباد";
128
+ if (code == "215" || code == "216") location = "استان مازندران - شهر قائمشهر";
129
+ if (code == "626") location = "استان مازندران - شهر کجور";
130
+ if (code == "627") location = "استان مازندران - شهر کلاردشت";
131
+ if (code == "579") location = "استان مازندران - شهر گلوگاه";
132
+ if (code == "713") location = "استان مازندران - شهر میاندورود";
133
+ if (code == "499") location = "استان مازندران - شهر نکاء";
134
+ if (code == "222") location = "استان مازندران - شهر نور";
135
+ if (code == "219" || code == "220") location = "استان مازندران - شهر نوشهر";
136
+ if (code == "500" || code == "501") location = "استان مازندران - شهر هراز و محمودآباد";
137
+ if (code == "623") location = "استان گلستان - شهر آزادشهر";
138
+ if (code == "497") location = "استان گلستان - شهر آق قلا";
139
+ if (code == "223") location = "استان گلستان - شهر بندرترکمن";
140
+ if (code == "689") location = "استان گلستان - شهر بندرگز";
141
+ if (code == "487") location = "استان گلستان - شهر رامیان";
142
+ if (code == "226") location = "استان گلستان - شهر علی آباد";
143
+ if (code == "224") location = "استان گلستان - شهر کردکوی";
144
+ if (code == "386") location = "استان گلستان - شهر کلاله";
145
+ if (code == "211" || code == "212") location = "استان گلستان - شهر گرگان";
146
+ if (code == "628") location = "استان گلستان - شهر گمیشان";
147
+ if (code == "202" || code == "203") location = "استان گلستان - شهر گنبد کاووس";
148
+ if (code == "531") location = "استان گلستان - شهر مراوه تپه";
149
+ if (code == "288") location = "استان گلستان - شهر مینودشت";
150
+ if (code == "261") location = "استان گیلان - شهر آستارا";
151
+ if (code == "273") location = "استان گیلان - شهر آستانه";
152
+ if (code == "630") location = "استان گیلان - شهر املش";
153
+ if (code == "264") location = "استان گیلان - شهر بندرانزلی";
154
+ if (code == "518") location = "استان گیلان - شهر خمام";
155
+ if (code == "631") location = "استان گیلان - شهر رحیم آباد";
156
+ if (code == "258" || code == "259") location = "استان گیلان - شهر رشت";
157
+ if (code == "570") location = "استان گیلان - شهر رضوانشهر";
158
+ if (code == "265") location = "استان گیلان - شهر رودبار";
159
+ if (code == "268" || code == "269") location = "استان گیلان - شهر رودسر";
160
+ if (code == "653") location = "استان گیلان - شهر سنگر";
161
+ if (code == "517") location = "استان گیلان - شهر سیاهکل";
162
+ if (code == "569") location = "استان گیلان - شهر شفت";
163
+ if (code == "267") location = "استان گیلان - شهر صومعه سرا";
164
+ if (code == "262" || code == "263") location = "استان گیلان - شهر طالش";
165
+ if (code == "593") location = "استان گیلان - شهر عمارلو";
166
+ if (code == "266") location = "استان گیلان - شهر فومن";
167
+ if (code == "693") location = "استان گیلان - شهر کوچصفهان";
168
+ if (code == "271" || code == "272") location = "استان گیلان - شهر لاهیجان";
169
+ if (code == "694") location = "استان گیلان - شهر لشت نشاء";
170
+ if (code == "270") location = "استان گیلان - شهر لنگرود";
171
+ if (code == "516") location = "استان گیلان - شهر ماسال و شاندرمن";
172
+ if (code == "333" || code == "334") location = "استان کرمانشاه - شهر اسلام آباد";
173
+ if (code == "691") location = "استان کرمانشاه - شهر باینگان";
174
+ if (code == "322" || code == "323") location = "استان کرمانشاه - شهر پاوه";
175
+ if (code == "595") location = "استان کرمانشاه - شهر ثلاث باباجانی";
176
+ if (code == "395") location = "استان کرمانشاه - شهر جوانرود";
177
+ if (code == "641") location = "استان کرمانشاه - شهر حمیل";
178
+ if (code == "596") location = "استان کرمانشاه - شهر روانسر";
179
+ if (code == "336") location = "استان کرمانشاه - شهر سرپل ذهاب";
180
+ if (code == "335") location = "استان کرمانشاه - شهر سنقر";
181
+ if (code == "496") location = "استان کرمانشاه - شهر صحنه";
182
+ if (code == "337") location = "استان کرمانشاه - شهر قصرشیرین";
183
+ if (code == "324" || code == "325") location = "استان کرمانشاه - شهر کرمانشاه";
184
+ if (code == "394") location = "استان کرمانشاه - شهر کرند";
185
+ if (code == "330") location = "استان کرمانشاه - شهر کنگاور";
186
+ if (code == "332") location = "استان کرمانشاه - شهر گیلانغرب";
187
+ if (code == "331") location = "استان کرمانشاه - شهر هرسین";
188
+ if (code == "687") location = "استان کهکیلویه و بویراحمد - شهر باشت";
189
+ if (code == "422" || code == "423") location = "استان کهکیلویه و بویراحمد - شهر بویراحمد(یاسوج)";
190
+ if (code == "599") location = "استان کهکیلویه و بویراحمد - شهر بهمنی";
191
+ if (code == "600") location = "استان کهکیلویه و بویراحمد - شهر چاروسا";
192
+ if (code == "688") location = "استان کهکیلویه و بویراحمد - شهر دروهان";
193
+ if (code == "424" || code == "425") location = "استان کهکیلویه و بویراحمد - شهر کهکیلویه(دهدشت)";
194
+ if (code == "426") location = "استان کهکیلویه و بویراحمد - شهر گچساران(دوگنبدان)";
195
+ if (code == "550") location = "استان کهکیلویه و بویراحمد - شهر لنده";
196
+ if (code == "697") location = "استان کهکیلویه و بویراحمد - شهر مارگون";
197
+ if (code == "384") location = "استان کردستان - شهر بانه";
198
+ if (code == "377" || code == "378") location = "استان کردستان - شهر بیجار";
199
+ if (code == "558") location = "استان کردستان - شهر دهگلان";
200
+ if (code == "385") location = "استان کردستان - شهر دیواندره";
201
+ if (code == "646") location = "استان کردستان - شهر سروآباد";
202
+ if (code == "375" || code == "376") location = "استان کردستان - شهر سقز";
203
+ if (code == "372" || code == "373") location = "استان کردستان - شهر سنندج";
204
+ if (code == "379" || code == "380") location = "استان کردستان - شهر قروه";
205
+ if (code == "383") location = "استان کردستان - شهر کامیاران";
206
+ if (code == "674") location = "استان کردستان - شهر کرانی";
207
+ if (code == "381" || code == "382") location = "استان کردستان - شهر مریوان";
208
+ if (code == "676") location = "استان کردستان - شهر نمشیر";
209
+ if (code == "722") location = "استان کرمان - شهر ارزونیه";
210
+ if (code == "542") location = "استان کرمان - شهر انار";
211
+ if (code == "312" || code == "313") location = "استان کرمان - شهر بافت";
212
+ if (code == "317") location = "استان کرمان - شهر بردسیر";
213
+ if (code == "310" || code == "311") location = "استان کرمان - شهر بم";
214
+ if (code == "302" || code == "303") location = "استان کرمان - شهر جیرفت";
215
+ if (code == "583") location = "استان کرمان - شهر رابر";
216
+ if (code == "321") location = "استان کرمان - شهر راور";
217
+ if (code == "382") location = "استان کرمان - شهر راین";
218
+ if (code == "304" || code == "305") location = "استان کرمان - شهر رفسنجان";
219
+ if (code == "536") location = "استان کرمان - شهر رودبار کهنوج";
220
+ if (code == "605") location = "استان کرمان - شهر ریگان";
221
+ if (code == "308" || code == "309") location = "استان کرمان - شهر زرند";
222
+ if (code == "306" || code == "307") location = "استان کرمان - شهر سیرجان";
223
+ if (code == "319") location = "استان کرمان - شهر شهداد";
224
+ if (code == "313" || code == "314") location = "استان کرمان - شهر شهربابک";
225
+ if (code == "606") location = "استان کرمان - شهر عنبرآباد";
226
+ if (code == "320") location = "استان کرمان - شهر فهرج";
227
+ if (code == "698") location = "استان کرمان - شهر قلعه گنج";
228
+ if (code == "298" || code == "299") location = "استان کرمان - شهر کرمان";
229
+ if (code == "535") location = "استان کرمان - شهر کوهبنان";
230
+ if (code == "315" || code == "316") location = "استان کرمان - شهر کهنوج";
231
+ if (code == "318") location = "استان کرمان - شهر گلباف";
232
+ if (code == "607") location = "استان کرمان - شهر ماهان";
233
+ if (code == "608") location = "استان کرمان - شهر منوجان";
234
+ if (code == "508") location = "استان قزوین - شهر آبیک";
235
+ if (code == "538") location = "استان قزوین - شهر آوج";
236
+ if (code == "728") location = "استان قزوین - شهر البرز";
237
+ if (code == "509") location = "استان قزوین - شهر بوئین زهرا";
238
+ if (code == "438" || code == "439") location = "استان قزوین - شهر تاکستان";
239
+ if (code == "580") location = "استان قزوین - شهر رودبار الموت";
240
+ if (code == "590") location = "استان قزوین - شهر رودبار شهرستان";
241
+ if (code == "559") location = "استان قزوین - شهر ضیاءآباد";
242
+ if (code == "588") location = "استان قزوین - شهر طارم سفلی";
243
+ if (code == "431" || code == "432") location = "استان قزوین - شهر قزوین";
244
+ if (code == "037" || code == "038") location = "استان قم - شهر قم";
245
+ if (code == "702") location = "استان قم - شهر کهک";
246
+ if (code == "240" || code == "241") location = "استان فارس - شهر آباده";
247
+ if (code == "670") location = "استان فارس - شهر آباده طشک";
248
+ if (code == "648") location = "استان فارس - شهر ارسنجان";
249
+ if (code == "252") location = "استان فارس - شهر استهبان";
250
+ if (code == "678") location = "استان فارس - شهر اشکنان";
251
+ if (code == "253") location = "استان فارس - شهر اقلید";
252
+ if (code == "649") location = "استان فارس - شهر اوز";
253
+ if (code == "513") location = "استان فارس - شهر بوانات";
254
+ if (code == "546") location = "استان فارس - شهر بیضا";
255
+ if (code == "671") location = "استان فارس - شهر جویم";
256
+ if (code == "246" || code == "247") location = "استان فارس - شهر جهرم";
257
+ if (code == "654") location = "استان فارس - شهر حاجی آباد(زرین دشت)";
258
+ if (code == "548") location = "استان فارس - شهر خرامه";
259
+ if (code == "547") location = "استان فارس - شهر خشت و کمارج";
260
+ if (code == "655") location = "استان فارس - شهر خفر";
261
+ if (code == "248" || code == "249") location = "استان فارس - شهر داراب";
262
+ if (code == "253") location = "استان فارس - شهر سپیدان";
263
+ if (code == "514") location = "استان فارس - شهر سروستان";
264
+ if (code == "665") location = "استان فارس - شهر سعادت آباد";
265
+ if (code == "673") location = "استان فارس - شهر شیبکوه";
266
+ if (code == "228" || code == "229" || code == "230") location = "استان فارس - شهر شیراز";
267
+ if (code == "679") location = "استان فارس - شهر فراشبند";
268
+ if (code == "256" || code == "257") location = "استان فارس - شهر فسا";
269
+ if (code == "244" || code == "245") location = "استان فارس - شهر فیروزآباد";
270
+ if (code == "681") location = "استان فارس - شهر قنقری(خرم بید)";
271
+ if (code == "723") location = "استان فارس - شهر قیروکارزین";
272
+ if (code == "236" || code == "237") location = "استان فارس - شهر کازرون";
273
+ if (code == "683") location = "استان فارس - شهر کوار";
274
+ if (code == "656") location = "استان فارس - شهر کراش";
275
+ if (code == "250" || code == "251") location = "استان فارس - شهر لارستان";
276
+ if (code == "515") location = "استان فارس - شهر لامرد";
277
+ if (code == "242" || code == "243") location = "استان فارس - شهر مرودشت";
278
+ if (code == "238" || code == "239") location = "استان فارس - شهر ممسنی";
279
+ if (code == "657") location = "استان فارس - شهر مهر";
280
+ if (code == "255") location = "استان فارس - شهر نی ریز";
281
+ if (code == "684") location = "استان سمنان - شهر ایوانکی";
282
+ if (code == "700") location = "استان سمنان - شهر بسطام";
283
+ if (code == "642") location = "استان سمنان - شهر بیارجمند";
284
+ if (code == "457") location = "استان سمنان - شهر دامغان";
285
+ if (code == "456") location = "استان سمنان - شهر سمنان";
286
+ if (code == "458" || code == "459") location = "استان سمنان - شهر شاهرود";
287
+ if (code == "460") location = "استان سمنان - شهر گرمسار";
288
+ if (code == "530") location = "استان سمنان - شهر مهدیشهر";
289
+ if (code == "520") location = "استان سمنان - شهر میامی";
290
+ if (code == "358" || code == "359") location = "استان سیستان و بلوچستان - شهر ایرانشهر";
291
+ if (code == "682") location = "استان سیستان و بلوچستان - شهر بزمان";
292
+ if (code == "703") location = "استان سیستان و بلوچستان - شهر بمپور";
293
+ if (code == "364" || code == "365") location = "استان سیستان و بلوچستان - شهر چابهار";
294
+ if (code == "371") location = "استان سیستان و بلوچستان - شهر خاش";
295
+ if (code == "701") location = "استان سیستان و بلوچستان - شهر دشتیاری";
296
+ if (code == "720") location = "استان سیستان و بلوچستان - شهر راسک";
297
+ if (code == "366" || code == "367") location = "استان سیستان و بلوچستان - شهر زابل";
298
+ if (code == "704") location = "استان سیستان و بلوچستان - شهر زابلی";
299
+ if (code == "361" || code == "362") location = "استان سیستان و بلوچستان - شهر زاهدان";
300
+ if (code == "369" || code == "370") location = "استان سیستان و بلوچستان - شهر سراوان";
301
+ if (code == "635") location = "استان سیستان و بلوچستان - شهر سرباز";
302
+ if (code == "668") location = "استان سیستان و بلوچستان - شهر سیب و سوران";
303
+ if (code == "533") location = "استان سیستان و بلوچستان - شهر شهرکی و ناروئی(زهک)";
304
+ if (code == "705") location = "استان سیستان و بلوچستان - شهر شیب آب";
305
+ if (code == "699") location = "استان سیستان و بلوچستان - شهر فنوج";
306
+ if (code == "669") location = "استان سیستان و بلوچستان - شهر قصرقند";
307
+ if (code == "725") location = "استان سیستان و بلوچستان - شهر کنارک";
308
+ if (code == "597") location = "استان سیستان و بلوچستان - شهر لاشار(اسپکه)";
309
+ if (code == "611") location = "استان سیستان و بلوچستان - شهر میرجاوه";
310
+ if (code == "525") location = "استان سیستان و بلوچستان - شهر نیک شهر";
311
+ if (code == "181") location = "استان خوزستان - شهر آبادان";
312
+ if (code == "527") location = "استان خوزستان - شهر آغاجاری";
313
+ if (code == "585") location = "استان خوزستان - شهر اروندکنار";
314
+ if (code == "685") location = "استان خوزستان - شهر امیدیه";
315
+ if (code == "663") location = "استان خوزستان - شهر اندیکا";
316
+ if (code == "192" || code == "193") location = "استان خوزستان - شهر اندیمشک";
317
+ if (code == "174" || code == "175") location = "استان خوزستان - شهر اهواز";
318
+ if (code == "183" || code == "184") location = "استان خوزستان - شهر ایذه";
319
+ if (code == "481") location = "استان خوزستان - شهر باغ ملک";
320
+ if (code == "706") location = "استان خوزستان - شهر بندر امام خمینی";
321
+ if (code == "194" || code == "195") location = "استان خوزستان - شهر بندرماهشهر";
322
+ if (code == "185" || code == "186") location = "استان خوزستان - شهر بهبهان";
323
+ if (code == "182") location = "استان خوزستان - شهر خرمشهر";
324
+ if (code == "199" || code == "200") location = "استان خوزستان - شهر دزفول";
325
+ if (code == "198") location = "استان خوزستان - شهر دشت آزادگان";
326
+ if (code == "662") location = "استان خوزستان - شهر رامشیر";
327
+ if (code == "190" || code == "191") location = "استان خوزستان - شهر رامهرمز";
328
+ if (code == "692") location = "استان خوزستان - شهر سردشت";
329
+ if (code == "189") location = "استان خوزستان - شهر شادگان";
330
+ if (code == "707") location = "استان خوزستان - شهر شاوور";
331
+ if (code == "526") location = "استان خوزستان - شهر شوش";
332
+ if (code == "187" || code == "188") location = "استان خوزستان - شهر شوشتر";
333
+ if (code == "729") location = "استان خوزستان - شهر گتوند";
334
+ if (code == "730") location = "استان خوزستان - شهر لالی";
335
+ if (code == "196" || code == "197") location = "استان خوزستان - شهر مسجدسلیمان";
336
+ if (code == "661") location = "استان خوزستان - شهر هندیجان";
337
+ if (code == "680") location = "استان خوزستان - شهر هویزه";
338
+ if (code == "643") location = "استان خراسان رضوی - شهر احمدآباد";
339
+ if (code == "562") location = "استان خراسان رضوی - شهر بجستان";
340
+ if (code == "572") location = "استان خراسان رضوی - شهر بردسکن";
341
+ if (code == "074") location = "استان خراسان رضوی - شهر تایباد";
342
+ if (code == "644") location = "استان خراسان رضوی - شهر تخت جلگه";
343
+ if (code == "072" || code == "073") location = "استان خراسان رضوی - شهر تربت جام";
344
+ if (code == "069" || code == "070") location = "استان خراسان رضوی - شهر تربت حیدریه";
345
+ if (code == "521") location = "استان خراسان رضوی - شهر جغتای";
346
+ if (code == "573") location = "استان خراسان رضوی - شهر جوین";
347
+ if (code == "522") location = "استان خراسان رضوی - شهر چناران";
348
+ if (code == "724") location = "استان خراسان رضوی - شهر خلیل آباد";
349
+ if (code == "076") location = "استان خراسان رضوی - شهر خواف";
350
+ if (code == "077") location = "استان خراسان رضوی - شهر درگز";
351
+ if (code == "650") location = "استان خراسان رضوی - شهر رشتخوار";
352
+ if (code == "574") location = "استان خراسان رضوی - شهر زبرخان";
353
+ if (code == "078" || code == "079") location = "استان خراسان رضوی - شهر سبزوار";
354
+ if (code == "081") location = "استان خراسان رضوی - شهر سرخس";
355
+ if (code == "084") location = "استان خراسان رضوی - شهر فریمان";
356
+ if (code == "651") location = "استان خراسان رضوی - شهر فیض آباد";
357
+ if (code == "086" || code == "087") location = "استان خراسان رضوی - شهر قوچان";
358
+ if (code == "089" || code == "090") location = "استان خراسان رضوی - شهر کاشمر";
359
+ if (code == "553") location = "استان خراسان رضوی - شهر کلات";
360
+ if (code == "091") location = "استان خراسان رضوی - شهر گناباد";
361
+ if (code == "092" || code == "093" || code == "094") location = "استان خراسان رضوی - شهر مشهد";
362
+ if (code == "097") location = "استان خراسان رضوی - شهر مشهد منطقه2";
363
+ if (code == "098") location = "استان خراسان رضوی - شهر مشهد منطقه3";
364
+ if (code == "096") location = "استان خراسان رضوی - شهر مشهد منطقه1";
365
+ if (code == "105" || code == "106") location = "استان خراسان رضوی - شهر نیشابور";
366
+ if (code == "063") location = "استان خراسان شمالی - شهر اسفراین";
367
+ if (code == "067" || code == "068") location = "استان خراسان شمالی - شهر بجنورد";
368
+ if (code == "075") location = "استان خراسان شمالی - شهر جاجرم";
369
+ if (code == "591") location = "استان خراسان شمالی - شهر رازوجرکلان";
370
+ if (code == "082") location = "استان خراسان شمالی - شهر شیروان";
371
+ if (code == "635") location = "استان خراسان شمالی - شهر فاروج";
372
+ if (code == "524") location = "استان خراسان شمالی - شهر مانه و سملقان";
373
+ if (code == "468") location = "استان چهارمحال و بختیاری - شهر اردل";
374
+ if (code == "465") location = "استان چهارمحال و بختیاری - شهر بروجن";
375
+ if (code == "461" || code == "462") location = "استان چهارمحال و بختیاری - شهر شهرکرد";
376
+ if (code == "467") location = "استان چهارمحال و بختیاری - شهر فارسان";
377
+ if (code == "555") location = "استان چهارمحال و بختیاری - شهر کوهرنگ";
378
+ if (code == "633") location = "استان چهارمحال و بختیاری - شهر کیار";
379
+ if (code == "629") location = "استان چهارمحال و بختیاری - شهر گندمان";
380
+ if (code == "466") location = "استان چهارمحال و بختیاری - شهر لردگان";
381
+ if (code == "696") location = "استان چهارمحال و بختیاری - شهر میانکوه";
382
+ if (code == "721") location = "استان خراسان جنوبی - شهر بشرویه";
383
+ if (code == "064" || code == "065") location = "استان خراسان جنوبی - شهر بیرجند";
384
+ if (code == "523") location = "استان خراسان جنوبی - شهر درمیان";
385
+ if (code == "652") location = "استان خراسان جنوبی - شهر زیرکوه";
386
+ if (code == "719") location = "استان خراسان جنوبی - شهر سرایان";
387
+ if (code == "716") location = "استان خراسان جنوبی - شهر سربیشه";
388
+ if (code == "085") location = "استان خراسان جنوبی - شهر فردوس";
389
+ if (code == "088") location = "استان خراسان جنوبی - شهر قائنات";
390
+ if (code == "563") location = "استان خراسان جنوبی - شهر نهبندان";
391
+ if (code == "529") location = "استان بوشهر - شهر بندر دیلم";
392
+ if (code == "353") location = "استان بوشهر - شهر بندر گناوه";
393
+ if (code == "349" || code == "350") location = "استان بوشهر - شهر بوشهر";
394
+ if (code == "355") location = "استان بوشهر - شهر تنگستان";
395
+ if (code == "609") location = "استان بوشهر - شهر جم";
396
+ if (code == "351" || code == "352") location = "استان بوشهر - شهر دشتستان";
397
+ if (code == "354") location = "استان بوشهر - شهر دشتی";
398
+ if (code == "732") location = "استان بوشهر - شهر دلوار";
399
+ if (code == "357") location = "استان بوشهر - شهر دیر";
400
+ if (code == "532") location = "استان بوشهر - شهر سعد آباد";
401
+ if (code == "610") location = "استان بوشهر - شهر شبانکاره";
402
+ if (code == "356") location = "استان بوشهر - شهر کنگان";
403
+ if (code == "556") location = "استان تهران - شهر اسلامشهر";
404
+ if (code == "658") location = "استان تهران - شهر پاکدشت";
405
+ if (code == "001" || code == "002" || code == "003" || code == "004" || code == "005" || code == "006" || code == "007" || code == "008") location = "استان تهران - شهر تهران مرکزی";
406
+ if (code == "011") location = "استان تهران - شهر تهران جنوب";
407
+ if (code == "020") location = "استان تهران - شهر تهران شرق";
408
+ if (code == "025") location = "استان تهران - شهر تهرانشمال";
409
+ if (code == "015") location = "استان تهران - شهر تهران غرب";
410
+ if (code == "043") location = "استان تهران - شهر دماوند";
411
+ if (code == "666") location = "استان تهران - شهر رباط کریم";
412
+ if (code == "489") location = "استان تهران - شهر ساوجبلاغ";
413
+ if (code == "044" || code == "045") location = "استان تهران - شهر شمیران";
414
+ if (code == "048" || code == "049") location = "استان تهران - شهر شهرری";
415
+ if (code == "490" || code == "491") location = "استان تهران - شهر شهریار";
416
+ if (code == "695") location = "استان تهران - شهر طالقان";
417
+ if (code == "659") location = "استان تهران - شهر فیروزکوه";
418
+ if (code == "031" || code == "032") location = "استان تهران - شهر کرج";
419
+ if (code == "664") location = "استان تهران - شهر کهریزک";
420
+ if (code == "717") location = "استان تهران - شهر نظرآباد";
421
+ if (code == "041" || code == "042") location = "استان تهران - شهر ورامین";
422
+ if (code == "471" || code == "472") location = " امور خارجه - امور خارجه";
423
+ if (code == "454") location = "استان ایلام - شهر آبدانان";
424
+ if (code == "581") location = "استان ایلام - شهر ارکوازی(ملکشاهی)";
425
+ if (code == "449" || code == "450") location = "استان ایلام - شهر ایلام";
426
+ if (code == "616") location = "استان ایلام - شهر ایوان";
427
+ if (code == "534") location = "استان ایلام - شهر بدره";
428
+ if (code == "455") location = "استان ایلام - شهر دره شهر";
429
+ if (code == "451") location = "استان ایلام - شهر دهلران";
430
+ if (code == "726") location = "استان ایلام - شهر زرین آباد";
431
+ if (code == "634") location = "استان ایلام - شهر شیروان لومار";
432
+ if (code == "453") location = "استان ایلام - شهر شیروان و چرداول";
433
+ if (code == "727") location = "استان ایلام - شهر موسیان";
434
+ if (code == "452") location = "استان ایلام - شهر مهران";
435
+ if (code == "145" || code == "146") location = "استان اردبیل - شهر اردبیل";
436
+ if (code == "731") location = "استان اردبیل - شهر ارشق";
437
+ if (code == "690") location = "استان اردبیل - شهر انگوت";
438
+ if (code == "601") location = "استان اردبیل - شهر بیله سوار";
439
+ if (code == "504") location = "استان اردبیل - شهر پارس آباد";
440
+ if (code == "163") location = "استان اردبیل - شهر خلخال";
441
+ if (code == "714") location = "استان اردبیل - شهر خورش رستم";
442
+ if (code == "715") location = "استان اردبیل - شهر سرعین";
443
+ if (code == "566") location = "استان اردبیل - شهر سنجبد(کوثر)";
444
+ if (code == "166" || code == "167") location = "استان اردبیل - شهر مشکین شهر";
445
+ if (code == "161" || code == "162") location = "استان اردبیل - شهر مغان";
446
+ if (code == "686") location = "استان اردبیل - شهر نمین";
447
+ if (code == "603") location = "استان اردبیل - شهر نیر";
448
+ if (code == "619") location = "استان اصفهان - شهر آران و بیدگل";
449
+ if (code == "118") location = "استان اصفهان - شهر اردستان";
450
+ if (code == "127" || code == "128" || code == "129") location = "استان اصفهان - شهر اصفهان";
451
+ if (code == "620") location = "استان اصفهان - شهر باغ بهادران";
452
+ if (code == "621") location = "استان اصفهان - شهر بوئین و میاندشت";
453
+ if (code == "549") location = "استان اصفهان - شهر تیران و کرون";
454
+ if (code == "564") location = "استان اصفهان - شهر جرقویه";
455
+ if (code == "575") location = "استان اصفهان - شهر چادگان";
456
+ if (code == "113" || code == "114") location = "استان اصفهان - شهر خمینی شهر";
457
+ if (code == "122") location = "استان اصفهان - شهر خوانسار";
458
+ if (code == "540") location = "استان اصفهان - شهر خور و بیابانک";
459
+ if (code == "660") location = "استان اصفهان - شهر دولت آباد";
460
+ if (code == "120") location = "استان اصفهان - شهر سمیرم";
461
+ if (code == "512") location = "استان اصفهان - شهر سمیرم سفلی (دهاقان)";
462
+ if (code == "510" || code == "511") location = "استان اصفهان - شهر شاهین شهر";
463
+ if (code == "119") location = "استان اصفهان - شهر شهرضا";
464
+ if (code == "115") location = "استان اصفهان - شهر فریدن";
465
+ if (code == "112") location = "استان اصفهان - شهر فریدونشهر";
466
+ if (code == "110" || code == "111") location = "استان اصفهان - شهر فلاورجان";
467
+ if (code == "125" || code == "126") location = "استان اصفهان - شهر کاشان";
468
+ if (code == "565") location = "استان اصفهان - شهر کوهپایه";
469
+ if (code == "121") location = "استان اصفهان - شهر گلپایگان";
470
+ if (code == "116" || code == "117") location = "استان اصفهان - شهر لنجان(زرینشهر)";
471
+ if (code == "541") location = "استان اصفهان - شهر مبارکه";
472
+ if (code == "622") location = "استان اصفهان - شهر میمه";
473
+ if (code == "124") location = "استان اصفهان - شهر نائین";
474
+ if (code == "108" || code == "109") location = "استان اصفهان - شهر نجف آباد";
475
+ if (code == "123") location = "استان اصفهان - شهر نطنز";
476
+ if (code == "427" || code == "428") location = "استان زنجان - شهر زنجان";
477
+ if (code == "507") location = "استان آذربایجان شرقی - شهر ملکان";
478
+ if (code == "158") location = "استان آذربایجان شرقی - شهر مرند";
479
+ if (code == "152" || code == "153") location = "استان آذربایجان شرقی - شهر میانه";
480
+ if (code == "615") location = "استان قزوین - شهر ابهر و خرمدره";
481
+ return location;
482
+ }
483
+
484
+ /**
485
+ * @return {boolean}
486
+ */
487
+ function GFPersian_National_ID_Handler(national_id, field_id, message1, message2, message3, is_seperate, show_location) {
488
+
489
+ document.getElementById("ir_national_id_location_" + field_id).innerHTML = '';
490
+
491
+ if (national_id.value == '')
492
+ return false;
493
+
494
+ national_id.value = national_id.value.replace("-", "").replace("-", "");
495
+
496
+ if (isNaN(national_id.value)) {
497
+ document.getElementById("ir_national_id_location_" + field_id).innerHTML = message1;
498
+ return false;
499
+ }
500
+
501
+ if (national_id.value.length == 8)
502
+ national_id.value = '00' + national_id.value;
503
+
504
+ if (national_id.value.length == 9)
505
+ national_id.value = '0' + national_id.value;
506
+
507
+ if (national_id.value.length > 10 || national_id.value.length < 8) {
508
+ document.getElementById("ir_national_id_location_" + field_id).innerHTML = message2;
509
+ return false;
510
+ }
511
+
512
+ var pre_check = ["0000000000", "1111111111", "2222222222", "3333333333", "4444444444", "5555555555", "6666666666", "7777777777", "8888888888", "9999999999", "0123456789"];
513
+ var indexOf = pre_check.indexOf(national_id.value);
514
+ if (indexOf != '-1') {
515
+ document.getElementById("ir_national_id_location_" + field_id).innerHTML = message3;
516
+ return false;
517
+ }
518
+
519
+ var location = national_id.value.substring(0, 3);
520
+ var c = parseInt(national_id.value.charAt(9));
521
+ var n = parseInt(national_id.value.charAt(0)) * 10 +
522
+ parseInt(national_id.value.charAt(1)) * 9 +
523
+ parseInt(national_id.value.charAt(2)) * 8 +
524
+ parseInt(national_id.value.charAt(3)) * 7 +
525
+ parseInt(national_id.value.charAt(4)) * 6 +
526
+ parseInt(national_id.value.charAt(5)) * 5 +
527
+ parseInt(national_id.value.charAt(6)) * 4 +
528
+ parseInt(national_id.value.charAt(7)) * 3 +
529
+ parseInt(national_id.value.charAt(8)) * 2;
530
+ var r = n - parseInt(n / 11) * 11;
531
+
532
+ if ((r == 0 && r == c) || (r == 1 && c == 1) || (r > 1 && c == 11 - r)) {
533
+ if (is_seperate) {
534
+ if (national_id.value.length == 10)
535
+ national_id.value = national_id.value.substring(0, 3) + "-" + national_id.value.substring(3, 9) + "-" + national_id.value.substring(9, 10);
536
+ }
537
+ if (show_location) {
538
+ document.getElementById("ir_national_id_location_" + field_id).innerHTML = GFPersian_National_ID_Location(location);
539
+ return true;
540
+ }
541
+ }
542
+ else {
543
+ document.getElementById("ir_national_id_location_" + field_id).innerHTML = message3;
544
+ return false;
545
+ }
546
+ }
assets/js/national_id.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function GFPersian_National_ID_Location(e){var a="";return"169"==e&&(a="استان آذربایجان شرقی - شهر آذر شهر"),"170"==e&&(a="استان آذربایجان شرقی - شهر اسکو"),"149"!=e&&"150"!=e||(a="استان آذربایجان شرقی - شهر اهر"),"171"==e&&(a="استان آذربایجان شرقی - شهر بستان آباد"),"168"==e&&(a="استان آذربایجان شرقی - شهر بناب"),"136"!=e&&"137"!=e&&"138"!=e||(a="استان آذربایجان شرقی - شهر تبریز"),"545"==e&&(a="استان آذربایجان شرقی - شهر ترکمانچای"),"505"==e&&(a="استان آذربایجان شرقی - شهر جلفا"),"636"==e&&(a="استان آذربایجان شرقی - شهر چاروایماق"),"164"!=e&&"165"!=e||(a="استان آذربایجان شرقی - شهر سراب"),"172"==e&&(a="استان آذربایجان شرقی - شهر شبستر"),"623"==e&&(a="استان آذربایجان شرقی - شهر صوفیان"),"506"==e&&(a="استان آذربایجان شرقی - شهر عجب شیر"),"519"==e&&(a="استان آذربایجان شرقی - شهر کلیبر"),"154"!=e&&"155"!=e||(a="استان آذربایجان شرقی - شهر مراغه"),"567"==e&&(a="استان آذربایجان شرقی - شهر ورزقان"),"173"==e&&(a="استان آذربایجان شرقی - شهر هریس"),"159"!=e&&"160"!=e||(a="استان آذربایجان شرقی - شهر هشترود"),"604"==e&&(a="استان آذربایجان شرقی - شهر هوراند"),"274"!=e&&"275"!=e||(a="استان آذربایجان غربی - شهر ارومیه"),"295"==e&&(a="استان آذربایجان غربی - شهر اشنویه"),"637"==e&&(a="استان آذربایجان غربی - شهر انزل"),"292"==e&&(a="استان آذربایجان غربی - شهر بوکان"),"492"==e&&(a="استان آذربایجان غربی - شهر پلدشت"),"289"==e&&(a="استان آذربایجان غربی - شهر پیرانشهر"),"677"==e&&(a="استان آذربایجان غربی - شهر تخت سلیمان"),"294"==e&&(a="استان آذربایجان غربی - شهر تکاب"),"493"==e&&(a="استان آذربایجان غربی - شهر چایپاره"),"279"!=e&&"280"!=e||(a="استان آذربایجان غربی - شهر خوی"),"288"==e&&(a="استان آذربایجان غربی - شهر سردشت"),"284"!=e&&"285"!=e||(a="استان آذربایجان غربی - شهر سلماس"),"638"==e&&(a="استان آذربایجان غربی - شهر سیلوانه"),"291"==e&&(a="استان آذربایجان غربی - شهر سیه چشمه(چالدران)"),"640"==e&&(a="استان آذربایجان غربی - شهر شوط"),"293"==e&&(a="استان آذربایجان غربی - شهر شاهین دژ"),"675"==e&&(a="استان آذربایجان غربی - شهر کشاورز"),"282"!=e&&"283"!=e||(a="استان آذربایجان غربی - شهر ماکو"),"286"!=e&&"287"!=e||(a="استان آذربایجان غربی - شهر مهاباد"),"296"!=e&&"297"!=e||(a="استان آذربایجان غربی - شهر میاندوآب"),"290"==e&&(a="استان آذربایجان غربی - شهر نقده"),"400"!=e&&"401"!=e||(a="استان همدان - شهر اسدآباد"),"404"!=e&&"405"!=e||(a="استان همدان - شهر بهار"),"397"==e&&(a="استان همدان - شهر تویسرکان"),"398"!=e&&"399"!=e||(a="استان همدان - شهر رزن"),"647"==e&&(a="استان همدان - شهر شراء و پیشخوار"),"502"==e&&(a="استان همدان - شهر فامنین"),"584"==e&&(a="استان همدان - شهر قلقل رود"),"402"!=e&&"403"!=e||(a="استان همدان - شهر کبودرآهنگ"),"392"!=e&&"393"!=e||(a="استان همدان - شهر ملایر"),"395"!=e&&"396"!=e||(a="استان همدان - شهر نهاوند"),"386"!=e&&"387"!=e||(a="استان همدان - شهر همدان"),"503"==e&&(a="استان یزد - شهر ابرکوه"),"444"==e&&(a="استان یزد - شهر اردکان"),"551"==e&&(a="استان یزد - شهر اشکذر"),"447"==e&&(a="استان یزد - شهر بافق"),"561"==e&&(a="استان یزد - شهر بهاباد"),"445"==e&&(a="استان یزد - شهر تفت"),"718"==e&&(a="استان یزد - شهر دستگردان"),"083"==e&&(a="استان یزد - شهر طبس"),"446"==e&&(a="استان یزد - شهر مهریز"),"448"==e&&(a="استان یزد - شهر میبد"),"552"==e&&(a="استان یزد - شهر نیر"),"543"==e&&(a="استان یزد - شهر هرات و مروست"),"442"!=e&&"443"!=e||(a="استان یزد - شهر یزد"),"051"==e&&(a="استان مرکزی - شهر آشتیان"),"052"!=e&&"053"!=e||(a="استان مرکزی - شهر اراک"),"058"==e&&(a="استان مرکزی - شهر تفرش"),"055"==e&&(a="استان مرکزی - شهر خمین"),"617"==e&&(a="استان مرکزی - شهر خنداب"),"057"==e&&(a="استان مرکزی - شهر دلیجان"),"618"==e&&(a="استان مرکزی - شهر زرند مرکزی"),"059"!=e&&"060"!=e||(a="استان مرکزی - شهر ساوه"),"061"!=e&&"062"!=e||(a="استان مرکزی - شهر سربند"),"544"==e&&(a="استان مرکزی - شهر فراهان"),"056"==e&&(a="استان مرکزی - شهر محلات"),"571"==e&&(a="استان مرکزی - شهر وفس"),"593"==e&&(a="استان مرکزی - شهر هندودر"),"667"==e&&(a="استان هرمزگان - شهر ابوموسی"),"348"==e&&(a="استان هرمزگان - شهر بستک"),"586"==e&&(a="استان هرمزگان - شهر بشاگرد"),"338"!=e&&"339"!=e||(a="استان هرمزگان - شهر بندرعباس"),"343"!=e&&"344"!=e||(a="استان هرمزگان - شهر بندرلنگه"),"346"==e&&(a="استان هرمزگان - شهر جاسک"),"337"==e&&(a="استان هرمزگان - شهر حاجی آباد"),"554"==e&&(a="استان هرمزگان - شهر خمیر"),"469"==e&&(a="استان هرمزگان - شهر رودان"),"537"==e&&(a="استان هرمزگان - شهر فین"),"345"==e&&(a="استان هرمزگان - شهر قشم"),"470"==e&&(a="استان هرمزگان - شهر گاوبندی"),"341"!=e&&"342"!=e||(a="استان هرمزگان - شهر میناب"),"483"!=e&&"484"!=e||(a="استان لرستان - شهر ازنا"),"557"==e&&(a="استان لرستان - شهر اشترینان"),"418"==e&&(a="استان لرستان - شهر الشتر"),"416"!=e&&"417"!=e||(a="استان لرستان - شهر الیگودرز"),"412"!=e&&"413"!=e||(a="استان لرستان - شهر بروجرد"),"592"==e&&(a="استان لرستان - شهر پاپی"),"612"==e&&(a="استان لرستان - شهر چغلوندی"),"613"==e&&(a="استان لرستان - شهر چگنی"),"406"!=e&&"407"!=e||(a="استان لرستان - شهر خرم آباد"),"421"==e&&(a="استان لرستان - شهر دورود"),"598"==e&&(a="استان لرستان - شهر رومشکان"),"419"==e&&(a="استان لرستان - شهر کوهدشت"),"385"==e&&(a="استان لرستان - شهر ملاوی(پلدختر)"),"420"==e&&(a="استان لرستان - شهر نورآباد(دلفان)"),"528"==e&&(a="استان لرستان - شهر ویسیان"),"213"!=e&&"214"!=e||(a="استان مازندران - شهر آمل"),"205"!=e&&"206"!=e||(a="استان مازندران - شهر بابل"),"498"==e&&(a="استان مازندران - شهر بابل"),"568"==e&&(a="استان مازندران - شهر بندپی"),"711"==e&&(a="استان مازندران - شهر بندپی شرقی"),"217"!=e&&"218"!=e||(a="استان مازندران - شهر بهشهر"),"221"==e&&(a="استان مازندران - شهر تنکابن"),"582"==e&&(a="استان مازندران - شهر جویبار"),"483"==e&&(a="استان مازندران - شهر چالوس"),"625"==e&&(a="استان مازندران - شهر چمستان"),"576"==e&&(a="استان مازندران - شهر چهاردانگه"),"578"==e&&(a="استان مازندران - شهر دودانگه"),"227"==e&&(a="استان مازندران - شهر رامسر"),"208"!=e&&"209"!=e||(a="استان مازندران - شهر ساری"),"225"==e&&(a="استان مازندران - شهر سوادکوه"),"577"==e&&(a="استان مازندران - شهر شیرگاه"),"712"==e&&(a="استان مازندران - شهر عباس آباد"),"215"!=e&&"216"!=e||(a="استان مازندران - شهر قائمشهر"),"626"==e&&(a="استان مازندران - شهر کجور"),"627"==e&&(a="استان مازندران - شهر کلاردشت"),"579"==e&&(a="استان مازندران - شهر گلوگاه"),"713"==e&&(a="استان مازندران - شهر میاندورود"),"499"==e&&(a="استان مازندران - شهر نکاء"),"222"==e&&(a="استان مازندران - شهر نور"),"219"!=e&&"220"!=e||(a="استان مازندران - شهر نوشهر"),"500"!=e&&"501"!=e||(a="استان مازندران - شهر هراز و محمودآباد"),"623"==e&&(a="استان گلستان - شهر آزادشهر"),"497"==e&&(a="استان گلستان - شهر آق قلا"),"223"==e&&(a="استان گلستان - شهر بندرترکمن"),"689"==e&&(a="استان گلستان - شهر بندرگز"),"487"==e&&(a="استان گلستان - شهر رامیان"),"226"==e&&(a="استان گلستان - شهر علی آباد"),"224"==e&&(a="استان گلستان - شهر کردکوی"),"386"==e&&(a="استان گلستان - شهر کلاله"),"211"!=e&&"212"!=e||(a="استان گلستان - شهر گرگان"),"628"==e&&(a="استان گلستان - شهر گمیشان"),"202"!=e&&"203"!=e||(a="استان گلستان - شهر گنبد کاووس"),"531"==e&&(a="استان گلستان - شهر مراوه تپه"),"288"==e&&(a="استان گلستان - شهر مینودشت"),"261"==e&&(a="استان گیلان - شهر آستارا"),"273"==e&&(a="استان گیلان - شهر آستانه"),"630"==e&&(a="استان گیلان - شهر املش"),"264"==e&&(a="استان گیلان - شهر بندرانزلی"),"518"==e&&(a="استان گیلان - شهر خمام"),"631"==e&&(a="استان گیلان - شهر رحیم آباد"),"258"!=e&&"259"!=e||(a="استان گیلان - شهر رشت"),"570"==e&&(a="استان گیلان - شهر رضوانشهر"),"265"==e&&(a="استان گیلان - شهر رودبار"),"268"!=e&&"269"!=e||(a="استان گیلان - شهر رودسر"),"653"==e&&(a="استان گیلان - شهر سنگر"),"517"==e&&(a="استان گیلان - شهر سیاهکل"),"569"==e&&(a="استان گیلان - شهر شفت"),"267"==e&&(a="استان گیلان - شهر صومعه سرا"),"262"!=e&&"263"!=e||(a="استان گیلان - شهر طالش"),"593"==e&&(a="استان گیلان - شهر عمارلو"),"266"==e&&(a="استان گیلان - شهر فومن"),"693"==e&&(a="استان گیلان - شهر کوچصفهان"),"271"!=e&&"272"!=e||(a="استان گیلان - شهر لاهیجان"),"694"==e&&(a="استان گیلان - شهر لشت نشاء"),"270"==e&&(a="استان گیلان - شهر لنگرود"),"516"==e&&(a="استان گیلان - شهر ماسال و شاندرمن"),"333"!=e&&"334"!=e||(a="استان کرمانشاه - شهر اسلام آباد"),"691"==e&&(a="استان کرمانشاه - شهر باینگان"),"322"!=e&&"323"!=e||(a="استان کرمانشاه - شهر پاوه"),"595"==e&&(a="استان کرمانشاه - شهر ثلاث باباجانی"),"395"==e&&(a="استان کرمانشاه - شهر جوانرود"),"641"==e&&(a="استان کرمانشاه - شهر حمیل"),"596"==e&&(a="استان کرمانشاه - شهر روانسر"),"336"==e&&(a="استان کرمانشاه - شهر سرپل ذهاب"),"335"==e&&(a="استان کرمانشاه - شهر سنقر"),"496"==e&&(a="استان کرمانشاه - شهر صحنه"),"337"==e&&(a="استان کرمانشاه - شهر قصرشیرین"),"324"!=e&&"325"!=e||(a="استان کرمانشاه - شهر کرمانشاه"),"394"==e&&(a="استان کرمانشاه - شهر کرند"),"330"==e&&(a="استان کرمانشاه - شهر کنگاور"),"332"==e&&(a="استان کرمانشاه - شهر گیلانغرب"),"331"==e&&(a="استان کرمانشاه - شهر هرسین"),"687"==e&&(a="استان کهکیلویه و بویراحمد - شهر باشت"),"422"!=e&&"423"!=e||(a="استان کهکیلویه و بویراحمد - شهر بویراحمد(یاسوج)"),"599"==e&&(a="استان کهکیلویه و بویراحمد - شهر بهمنی"),"600"==e&&(a="استان کهکیلویه و بویراحمد - شهر چاروسا"),"688"==e&&(a="استان کهکیلویه و بویراحمد - شهر دروهان"),"424"!=e&&"425"!=e||(a="استان کهکیلویه و بویراحمد - شهر کهکیلویه(دهدشت)"),"426"==e&&(a="استان کهکیلویه و بویراحمد - شهر گچساران(دوگنبدان)"),"550"==e&&(a="استان کهکیلویه و بویراحمد - شهر لنده"),"697"==e&&(a="استان کهکیلویه و بویراحمد - شهر مارگون"),"384"==e&&(a="استان کردستان - شهر بانه"),"377"!=e&&"378"!=e||(a="استان کردستان - شهر بیجار"),"558"==e&&(a="استان کردستان - شهر دهگلان"),"385"==e&&(a="استان کردستان - شهر دیواندره"),"646"==e&&(a="استان کردستان - شهر سروآباد"),"375"!=e&&"376"!=e||(a="استان کردستان - شهر سقز"),"372"!=e&&"373"!=e||(a="استان کردستان - شهر سنندج"),"379"!=e&&"380"!=e||(a="استان کردستان - شهر قروه"),"383"==e&&(a="استان کردستان - شهر کامیاران"),"674"==e&&(a="استان کردستان - شهر کرانی"),"381"!=e&&"382"!=e||(a="استان کردستان - شهر مریوان"),"676"==e&&(a="استان کردستان - شهر نمشیر"),"722"==e&&(a="استان کرمان - شهر ارزونیه"),"542"==e&&(a="استان کرمان - شهر انار"),"312"!=e&&"313"!=e||(a="استان کرمان - شهر بافت"),"317"==e&&(a="استان کرمان - شهر بردسیر"),"310"!=e&&"311"!=e||(a="استان کرمان - شهر بم"),"302"!=e&&"303"!=e||(a="استان کرمان - شهر جیرفت"),"583"==e&&(a="استان کرمان - شهر رابر"),"321"==e&&(a="استان کرمان - شهر راور"),"382"==e&&(a="استان کرمان - شهر راین"),"304"!=e&&"305"!=e||(a="استان کرمان - شهر رفسنجان"),"536"==e&&(a="استان کرمان - شهر رودبار کهنوج"),"605"==e&&(a="استان کرمان - شهر ریگان"),"308"!=e&&"309"!=e||(a="استان کرمان - شهر زرند"),"306"!=e&&"307"!=e||(a="استان کرمان - شهر سیرجان"),"319"==e&&(a="استان کرمان - شهر شهداد"),"313"!=e&&"314"!=e||(a="استان کرمان - شهر شهربابک"),"606"==e&&(a="استان کرمان - شهر عنبرآباد"),"320"==e&&(a="استان کرمان - شهر فهرج"),"698"==e&&(a="استان کرمان - شهر قلعه گنج"),"298"!=e&&"299"!=e||(a="استان کرمان - شهر کرمان"),"535"==e&&(a="استان کرمان - شهر کوهبنان"),"315"!=e&&"316"!=e||(a="استان کرمان - شهر کهنوج"),"318"==e&&(a="استان کرمان - شهر گلباف"),"607"==e&&(a="استان کرمان - شهر ماهان"),"608"==e&&(a="استان کرمان - شهر منوجان"),"508"==e&&(a="استان قزوین - شهر آبیک"),"538"==e&&(a="استان قزوین - شهر آوج"),"728"==e&&(a="استان قزوین - شهر البرز"),"509"==e&&(a="استان قزوین - شهر بوئین زهرا"),"438"!=e&&"439"!=e||(a="استان قزوین - شهر تاکستان"),"580"==e&&(a="استان قزوین - شهر رودبار الموت"),"590"==e&&(a="استان قزوین - شهر رودبار شهرستان"),"559"==e&&(a="استان قزوین - شهر ضیاءآباد"),"588"==e&&(a="استان قزوین - شهر طارم سفلی"),"431"!=e&&"432"!=e||(a="استان قزوین - شهر قزوین"),"037"!=e&&"038"!=e||(a="استان قم - شهر قم"),"702"==e&&(a="استان قم - شهر کهک"),"240"!=e&&"241"!=e||(a="استان فارس - شهر آباده"),"670"==e&&(a="استان فارس - شهر آباده طشک"),"648"==e&&(a="استان فارس - شهر ارسنجان"),"252"==e&&(a="استان فارس - شهر استهبان"),"678"==e&&(a="استان فارس - شهر اشکنان"),"253"==e&&(a="استان فارس - شهر اقلید"),"649"==e&&(a="استان فارس - شهر اوز"),"513"==e&&(a="استان فارس - شهر بوانات"),"546"==e&&(a="استان فارس - شهر بیضا"),"671"==e&&(a="استان فارس - شهر جویم"),"246"!=e&&"247"!=e||(a="استان فارس - شهر جهرم"),"654"==e&&(a="استان فارس - شهر حاجی آباد(زرین دشت)"),"548"==e&&(a="استان فارس - شهر خرامه"),"547"==e&&(a="استان فارس - شهر خشت و کمارج"),"655"==e&&(a="استان فارس - شهر خفر"),"248"!=e&&"249"!=e||(a="استان فارس - شهر داراب"),"253"==e&&(a="استان فارس - شهر سپیدان"),"514"==e&&(a="استان فارس - شهر سروستان"),"665"==e&&(a="استان فارس - شهر سعادت آباد"),"673"==e&&(a="استان فارس - شهر شیبکوه"),"228"!=e&&"229"!=e&&"230"!=e||(a="استان فارس - شهر شیراز"),"679"==e&&(a="استان فارس - شهر فراشبند"),"256"!=e&&"257"!=e||(a="استان فارس - شهر فسا"),"244"!=e&&"245"!=e||(a="استان فارس - شهر فیروزآباد"),"681"==e&&(a="استان فارس - شهر قنقری(خرم بید)"),"723"==e&&(a="استان فارس - شهر قیروکارزین"),"236"!=e&&"237"!=e||(a="استان فارس - شهر کازرون"),"683"==e&&(a="استان فارس - شهر کوار"),"656"==e&&(a="استان فارس - شهر کراش"),"250"!=e&&"251"!=e||(a="استان فارس - شهر لارستان"),"515"==e&&(a="استان فارس - شهر لامرد"),"242"!=e&&"243"!=e||(a="استان فارس - شهر مرودشت"),"238"!=e&&"239"!=e||(a="استان فارس - شهر ممسنی"),"657"==e&&(a="استان فارس - شهر مهر"),"255"==e&&(a="استان فارس - شهر نی ریز"),"684"==e&&(a="استان سمنان - شهر ایوانکی"),"700"==e&&(a="استان سمنان - شهر بسطام"),"642"==e&&(a="استان سمنان - شهر بیارجمند"),"457"==e&&(a="استان سمنان - شهر دامغان"),"456"==e&&(a="استان سمنان - شهر سمنان"),"458"!=e&&"459"!=e||(a="استان سمنان - شهر شاهرود"),"460"==e&&(a="استان سمنان - شهر گرمسار"),"530"==e&&(a="استان سمنان - شهر مهدیشهر"),"520"==e&&(a="استان سمنان - شهر میامی"),"358"!=e&&"359"!=e||(a="استان سیستان و بلوچستان - شهر ایرانشهر"),"682"==e&&(a="استان سیستان و بلوچستان - شهر بزمان"),"703"==e&&(a="استان سیستان و بلوچستان - شهر بمپور"),"364"!=e&&"365"!=e||(a="استان سیستان و بلوچستان - شهر چابهار"),"371"==e&&(a="استان سیستان و بلوچستان - شهر خاش"),"701"==e&&(a="استان سیستان و بلوچستان - شهر دشتیاری"),"720"==e&&(a="استان سیستان و بلوچستان - شهر راسک"),"366"!=e&&"367"!=e||(a="استان سیستان و بلوچستان - شهر زابل"),"704"==e&&(a="استان سیستان و بلوچستان - شهر زابلی"),"361"!=e&&"362"!=e||(a="استان سیستان و بلوچستان - شهر زاهدان"),"369"!=e&&"370"!=e||(a="استان سیستان و بلوچستان - شهر سراوان"),"635"==e&&(a="استان سیستان و بلوچستان - شهر سرباز"),"668"==e&&(a="استان سیستان و بلوچستان - شهر سیب و سوران"),"533"==e&&(a="استان سیستان و بلوچستان - شهر شهرکی و ناروئی(زهک)"),"705"==e&&(a="استان سیستان و بلوچستان - شهر شیب آب"),"699"==e&&(a="استان سیستان و بلوچستان - شهر فنوج"),"669"==e&&(a="استان سیستان و بلوچستان - شهر قصرقند"),"725"==e&&(a="استان سیستان و بلوچستان - شهر کنارک"),"597"==e&&(a="استان سیستان و بلوچستان - شهر لاشار(اسپکه)"),"611"==e&&(a="استان سیستان و بلوچستان - شهر میرجاوه"),"525"==e&&(a="استان سیستان و بلوچستان - شهر نیک شهر"),"181"==e&&(a="استان خوزستان - شهر آبادان"),"527"==e&&(a="استان خوزستان - شهر آغاجاری"),"585"==e&&(a="استان خوزستان - شهر اروندکنار"),"685"==e&&(a="استان خوزستان - شهر امیدیه"),"663"==e&&(a="استان خوزستان - شهر اندیکا"),"192"!=e&&"193"!=e||(a="استان خوزستان - شهر اندیمشک"),"174"!=e&&"175"!=e||(a="استان خوزستان - شهر اهواز"),"183"!=e&&"184"!=e||(a="استان خوزستان - شهر ایذه"),"481"==e&&(a="استان خوزستان - شهر باغ ملک"),"706"==e&&(a="استان خوزستان - شهر بندر امام خمینی"),"194"!=e&&"195"!=e||(a="استان خوزستان - شهر بندرماهشهر"),"185"!=e&&"186"!=e||(a="استان خوزستان - شهر بهبهان"),"182"==e&&(a="استان خوزستان - شهر خرمشهر"),"199"!=e&&"200"!=e||(a="استان خوزستان - شهر دزفول"),"198"==e&&(a="استان خوزستان - شهر دشت آزادگان"),"662"==e&&(a="استان خوزستان - شهر رامشیر"),"190"!=e&&"191"!=e||(a="استان خوزستان - شهر رامهرمز"),"692"==e&&(a="استان خوزستان - شهر سردشت"),"189"==e&&(a="استان خوزستان - شهر شادگان"),"707"==e&&(a="استان خوزستان - شهر شاوور"),"526"==e&&(a="استان خوزستان - شهر شوش"),"187"!=e&&"188"!=e||(a="استان خوزستان - شهر شوشتر"),"729"==e&&(a="استان خوزستان - شهر گتوند"),"730"==e&&(a="استان خوزستان - شهر لالی"),"196"!=e&&"197"!=e||(a="استان خوزستان - شهر مسجدسلیمان"),"661"==e&&(a="استان خوزستان - شهر هندیجان"),"680"==e&&(a="استان خوزستان - شهر هویزه"),"643"==e&&(a="استان خراسان رضوی - شهر احمدآباد"),"562"==e&&(a="استان خراسان رضوی - شهر بجستان"),"572"==e&&(a="استان خراسان رضوی - شهر بردسکن"),"074"==e&&(a="استان خراسان رضوی - شهر تایباد"),"644"==e&&(a="استان خراسان رضوی - شهر تخت جلگه"),"072"!=e&&"073"!=e||(a="استان خراسان رضوی - شهر تربت جام"),"069"!=e&&"070"!=e||(a="استان خراسان رضوی - شهر تربت حیدریه"),"521"==e&&(a="استان خراسان رضوی - شهر جغتای"),"573"==e&&(a="استان خراسان رضوی - شهر جوین"),"522"==e&&(a="استان خراسان رضوی - شهر چناران"),"724"==e&&(a="استان خراسان رضوی - شهر خلیل آباد"),"076"==e&&(a="استان خراسان رضوی - شهر خواف"),"077"==e&&(a="استان خراسان رضوی - شهر درگز"),"650"==e&&(a="استان خراسان رضوی - شهر رشتخوار"),"574"==e&&(a="استان خراسان رضوی - شهر زبرخان"),"078"!=e&&"079"!=e||(a="استان خراسان رضوی - شهر سبزوار"),"081"==e&&(a="استان خراسان رضوی - شهر سرخس"),"084"==e&&(a="استان خراسان رضوی - شهر فریمان"),"651"==e&&(a="استان خراسان رضوی - شهر فیض آباد"),"086"!=e&&"087"!=e||(a="استان خراسان رضوی - شهر قوچان"),"089"!=e&&"090"!=e||(a="استان خراسان رضوی - شهر کاشمر"),"553"==e&&(a="استان خراسان رضوی - شهر کلات"),"091"==e&&(a="استان خراسان رضوی - شهر گناباد"),"092"!=e&&"093"!=e&&"094"!=e||(a="استان خراسان رضوی - شهر مشهد"),"097"==e&&(a="استان خراسان رضوی - شهر مشهد منطقه2"),"098"==e&&(a="استان خراسان رضوی - شهر مشهد منطقه3"),"096"==e&&(a="استان خراسان رضوی - شهر مشهد منطقه1"),"105"!=e&&"106"!=e||(a="استان خراسان رضوی - شهر نیشابور"),"063"==e&&(a="استان خراسان شمالی - شهر اسفراین"),"067"!=e&&"068"!=e||(a="استان خراسان شمالی - شهر بجنورد"),"075"==e&&(a="استان خراسان شمالی - شهر جاجرم"),"591"==e&&(a="استان خراسان شمالی - شهر رازوجرکلان"),"082"==e&&(a="استان خراسان شمالی - شهر شیروان"),"635"==e&&(a="استان خراسان شمالی - شهر فاروج"),"524"==e&&(a="استان خراسان شمالی - شهر مانه و سملقان"),"468"==e&&(a="استان چهارمحال و بختیاری - شهر اردل"),"465"==e&&(a="استان چهارمحال و بختیاری - شهر بروجن"),"461"!=e&&"462"!=e||(a="استان چهارمحال و بختیاری - شهر شهرکرد"),"467"==e&&(a="استان چهارمحال و بختیاری - شهر فارسان"),"555"==e&&(a="استان چهارمحال و بختیاری - شهر کوهرنگ"),"633"==e&&(a="استان چهارمحال و بختیاری - شهر کیار"),"629"==e&&(a="استان چهارمحال و بختیاری - شهر گندمان"),"466"==e&&(a="استان چهارمحال و بختیاری - شهر لردگان"),"696"==e&&(a="استان چهارمحال و بختیاری - شهر میانکوه"),"721"==e&&(a="استان خراسان جنوبی - شهر بشرویه"),"064"!=e&&"065"!=e||(a="استان خراسان جنوبی - شهر بیرجند"),"523"==e&&(a="استان خراسان جنوبی - شهر درمیان"),"652"==e&&(a="استان خراسان جنوبی - شهر زیرکوه"),"719"==e&&(a="استان خراسان جنوبی - شهر سرایان"),"716"==e&&(a="استان خراسان جنوبی - شهر سربیشه"),"085"==e&&(a="استان خراسان جنوبی - شهر فردوس"),"088"==e&&(a="استان خراسان جنوبی - شهر قائنات"),"563"==e&&(a="استان خراسان جنوبی - شهر نهبندان"),"529"==e&&(a="استان بوشهر - شهر بندر دیلم"),"353"==e&&(a="استان بوشهر - شهر بندر گناوه"),"349"!=e&&"350"!=e||(a="استان بوشهر - شهر بوشهر"),"355"==e&&(a="استان بوشهر - شهر تنگستان"),"609"==e&&(a="استان بوشهر - شهر جم"),"351"!=e&&"352"!=e||(a="استان بوشهر - شهر دشتستان"),"354"==e&&(a="استان بوشهر - شهر دشتی"),"732"==e&&(a="استان بوشهر - شهر دلوار"),"357"==e&&(a="استان بوشهر - شهر دیر"),"532"==e&&(a="استان بوشهر - شهر سعد آباد"),"610"==e&&(a="استان بوشهر - شهر شبانکاره"),"356"==e&&(a="استان بوشهر - شهر کنگان"),"556"==e&&(a="استان تهران - شهر اسلامشهر"),"658"==e&&(a="استان تهران - شهر پاکدشت"),"001"!=e&&"002"!=e&&"003"!=e&&"004"!=e&&"005"!=e&&"006"!=e&&"007"!=e&&"008"!=e||(a="استان تهران - شهر تهران مرکزی"),"011"==e&&(a="استان تهران - شهر تهران جنوب"),"020"==e&&(a="استان تهران - شهر تهران شرق"),"025"==e&&(a="استان تهران - شهر تهرانشمال"),"015"==e&&(a="استان تهران - شهر تهران غرب"),"043"==e&&(a="استان تهران - شهر دماوند"),"666"==e&&(a="استان تهران - شهر رباط کریم"),"489"==e&&(a="استان تهران - شهر ساوجبلاغ"),"044"!=e&&"045"!=e||(a="استان تهران - شهر شمیران"),"048"!=e&&"049"!=e||(a="استان تهران - شهر شهرری"),"490"!=e&&"491"!=e||(a="استان تهران - شهر شهریار"),"695"==e&&(a="استان تهران - شهر طالقان"),"659"==e&&(a="استان تهران - شهر فیروزکوه"),"031"!=e&&"032"!=e||(a="استان تهران - شهر کرج"),"664"==e&&(a="استان تهران - شهر کهریزک"),"717"==e&&(a="استان تهران - شهر نظرآباد"),"041"!=e&&"042"!=e||(a="استان تهران - شهر ورامین"),"471"!=e&&"472"!=e||(a=" امور خارجه - امور خارجه"),"454"==e&&(a="استان ایلام - شهر آبدانان"),"581"==e&&(a="استان ایلام - شهر ارکوازی(ملکشاهی)"),"449"!=e&&"450"!=e||(a="استان ایلام - شهر ایلام"),"616"==e&&(a="استان ایلام - شهر ایوان"),"534"==e&&(a="استان ایلام - شهر بدره"),"455"==e&&(a="استان ایلام - شهر دره شهر"),"451"==e&&(a="استان ایلام - شهر دهلران"),"726"==e&&(a="استان ایلام - شهر زرین آباد"),"634"==e&&(a="استان ایلام - شهر شیروان لومار"),"453"==e&&(a="استان ایلام - شهر شیروان و چرداول"),"727"==e&&(a="استان ایلام - شهر موسیان"),"452"==e&&(a="استان ایلام - شهر مهران"),"145"!=e&&"146"!=e||(a="استان اردبیل - شهر اردبیل"),"731"==e&&(a="استان اردبیل - شهر ارشق"),"690"==e&&(a="استان اردبیل - شهر انگوت"),"601"==e&&(a="استان اردبیل - شهر بیله سوار"),"504"==e&&(a="استان اردبیل - شهر پارس آباد"),"163"==e&&(a="استان اردبیل - شهر خلخال"),"714"==e&&(a="استان اردبیل - شهر خورش رستم"),"715"==e&&(a="استان اردبیل - شهر سرعین"),"566"==e&&(a="استان اردبیل - شهر سنجبد(کوثر)"),"166"!=e&&"167"!=e||(a="استان اردبیل - شهر مشکین شهر"),"161"!=e&&"162"!=e||(a="استان اردبیل - شهر مغان"),"686"==e&&(a="استان اردبیل - شهر نمین"),"603"==e&&(a="استان اردبیل - شهر نیر"),"619"==e&&(a="استان اصفهان - شهر آران و بیدگل"),"118"==e&&(a="استان اصفهان - شهر اردستان"),"127"!=e&&"128"!=e&&"129"!=e||(a="استان اصفهان - شهر اصفهان"),"620"==e&&(a="استان اصفهان - شهر باغ بهادران"),"621"==e&&(a="استان اصفهان - شهر بوئین و میاندشت"),"549"==e&&(a="استان اصفهان - شهر تیران و کرون"),"564"==e&&(a="استان اصفهان - شهر جرقویه"),"575"==e&&(a="استان اصفهان - شهر چادگان"),"113"!=e&&"114"!=e||(a="استان اصفهان - شهر خمینی شهر"),"122"==e&&(a="استان اصفهان - شهر خوانسار"),"540"==e&&(a="استان اصفهان - شهر خور و بیابانک"),"660"==e&&(a="استان اصفهان - شهر دولت آباد"),"120"==e&&(a="استان اصفهان - شهر سمیرم"),"512"==e&&(a="استان اصفهان - شهر سمیرم سفلی (دهاقان)"),"510"!=e&&"511"!=e||(a="استان اصفهان - شهر شاهین شهر"),"119"==e&&(a="استان اصفهان - شهر شهرضا"),"115"==e&&(a="استان اصفهان - شهر فریدن"),"112"==e&&(a="استان اصفهان - شهر فریدونشهر"),"110"!=e&&"111"!=e||(a="استان اصفهان - شهر فلاورجان"),"125"!=e&&"126"!=e||(a="استان اصفهان - شهر کاشان"),"565"==e&&(a="استان اصفهان - شهر کوهپایه"),"121"==e&&(a="استان اصفهان - شهر گلپایگان"),"116"!=e&&"117"!=e||(a="استان اصفهان - شهر لنجان(زرینشهر)"),"541"==e&&(a="استان اصفهان - شهر مبارکه"),"622"==e&&(a="استان اصفهان - شهر میمه"),"124"==e&&(a="استان اصفهان - شهر نائین"),"108"!=e&&"109"!=e||(a="استان اصفهان - شهر نجف آباد"),"123"==e&&(a="استان اصفهان - شهر نطنز"),"427"!=e&&"428"!=e||(a="استان زنجان - شهر زنجان"),"507"==e&&(a="استان آذربایجان شرقی - شهر ملکان"),"158"==e&&(a="استان آذربایجان شرقی - شهر مرند"),"152"!=e&&"153"!=e||(a="استان آذربایجان شرقی - شهر میانه"),"615"==e&&(a="استان قزوین - شهر ابهر و خرمدره"),a}function GFPersian_National_ID_Handler(e,a,n,t,l,r,i){if(document.getElementById("ir_national_id_location_"+a).innerHTML="",""==e.value)return!1;if(e.value=e.value.replace("-","").replace("-",""),isNaN(e.value))return document.getElementById("ir_national_id_location_"+a).innerHTML=n,!1;if(8==e.value.length&&(e.value="00"+e.value),9==e.value.length&&(e.value="0"+e.value),e.value.length>10||e.value.length<8)return document.getElementById("ir_national_id_location_"+a).innerHTML=t,!1;if("-1"!=["0000000000","1111111111","2222222222","3333333333","4444444444","5555555555","6666666666","7777777777","8888888888","9999999999","0123456789"].indexOf(e.value))return document.getElementById("ir_national_id_location_"+a).innerHTML=l,!1;var u=e.value.substring(0,3),o=parseInt(e.value.charAt(9)),_=10*parseInt(e.value.charAt(0))+9*parseInt(e.value.charAt(1))+8*parseInt(e.value.charAt(2))+7*parseInt(e.value.charAt(3))+6*parseInt(e.value.charAt(4))+5*parseInt(e.value.charAt(5))+4*parseInt(e.value.charAt(6))+3*parseInt(e.value.charAt(7))+2*parseInt(e.value.charAt(8)),v=_-11*parseInt(_/11);return 0==v&&v==o||1==v&&1==o||v>1&&o==11-v?(r&&10==e.value.length&&(e.value=e.value.substring(0,3)+"-"+e.value.substring(3,9)+"-"+e.value.substring(9,10)),i?(document.getElementById("ir_national_id_location_"+a).innerHTML=GFPersian_National_ID_Location(u),!0):void 0):(document.getElementById("ir_national_id_location_"+a).innerHTML=l,!1)}
assets/js/shamsi_chart.js CHANGED
File without changes
includes/{class-iran-cities.php → class-address.php} RENAMED
@@ -2,80 +2,91 @@
2
  exit;
3
  }
4
 
5
- class GFParsi_IranCities {
6
-
7
- public $province = array();
8
 
9
  public function __construct() {
10
- add_action( 'gform_editor_js', array( $this, 'iran_cities' ) );
11
- add_action( 'gform_field_standard_settings', array( $this, 'iran_cities_option' ), 10, 2 );
12
- add_filter( 'gform_address_types', array( $this, 'iran_address' ) );
13
- add_filter( 'gform_predefined_choices', array( $this, 'predefined_choices' ), 1 );
14
 
15
- add_filter( 'gform_field_content', array( $this, 'city_select' ), 10, 5 );
 
 
 
 
 
 
 
 
16
  add_action( 'gform_register_init_scripts', array( $this, 'init_script' ), 10, 1 );
17
  add_action( 'gform_enqueue_scripts', array( $this, 'external_js' ), 10, 2 );
18
  }
19
 
20
-
21
- public function get_province() {
22
-
23
- $this->province = array(
24
- __( 'Azarbaijan - East', 'GF_FA' ),
25
- __( 'Azarbaijan - West', 'GF_FA' ),
26
- __( 'Ardabil', 'GF_FA' ),
27
- __( 'Isfahan', 'GF_FA' ),
28
- __( 'Alborz', 'GF_FA' ),
29
- __( 'Ilam', 'GF_FA' ),
30
- __( 'Bushehr', 'GF_FA' ),
31
- __( 'Tehran', 'GF_FA' ),
32
- __( 'Chahar Mahaal and Bakhtiari', 'GF_FA' ),
33
- __( 'Khorasan - South', 'GF_FA' ),
34
- __( 'Khorasan - Razavi', 'GF_FA' ),
35
- __( 'Khorasan - North', 'GF_FA' ),
36
- __( 'Khuzestan', 'GF_FA' ),
37
- __( 'Zanjan', 'GF_FA' ),
38
- __( 'Semnan', 'GF_FA' ),
39
- __( 'Sistan and Baluchistan', 'GF_FA' ),
40
- __( 'Fars', 'GF_FA' ),
41
- __( 'Qazvin', 'GF_FA' ),
42
- __( 'Qom', 'GF_FA' ),
43
- __( 'Kurdistan', 'GF_FA' ),
44
- __( 'Kerman', 'GF_FA' ),
45
- __( 'Kermanshah', 'GF_FA' ),
46
- __( 'Kohgiluyeh and Boyer-Ahmad', 'GF_FA' ),
47
- __( 'Golestan', 'GF_FA' ),
48
- __( 'Guilan', 'GF_FA' ),
49
- __( 'Lorestan', 'GF_FA' ),
50
- __( 'Mazandaran', 'GF_FA' ),
51
- __( 'Markazi', 'GF_FA' ),
52
- __( 'Hormozgān', 'GF_FA' ),
53
- __( 'Hamadan', 'GF_FA' ),
54
- __( 'Yazd', 'GF_FA' )
55
  );
56
  }
57
 
58
- public function iran_address( $address_types ) {
59
- $this->get_province();
60
  $address_types['iran'] = array(
61
- 'label' => __( 'Iran', 'GF_FA' ),
62
- 'country' => __( 'Iran', 'GF_FA' ),
63
- 'zip_label' => __( 'Postal Code', 'GF_FA' ),
64
- 'state_label' => __( 'Province', 'GF_FA' ),
65
- 'states' => array_merge( array( '' ), $this->province )
66
  );
67
 
68
  return $address_types;
69
  }
70
 
71
- public function predefined_choices( $choices ) {
72
- $this->get_province();
73
- $states[ __( 'Provinces of Iran', 'GF_FA' ) ] = $this->province;
74
 
75
  return $choices = array_merge( $states, $choices );
76
  }
77
 
78
- public function iran_cities() { ?>
 
 
 
 
 
 
 
 
 
 
 
79
 
80
  <script type='text/javascript'>
81
  jQuery(document).ready(function ($) {
@@ -89,10 +100,10 @@ class GFParsi_IranCities {
89
  $iran_cities.remove();
90
  $address_type.after('<div id="iran_cities_div"><br>' + $iran_cities_input + '</div>');
91
  }
92
- var $iran_cities_div = $('#iran_cities_div');
93
- $iran_cities_div.hide();
94
  if ($address_type.val() === 'iran')
95
- $iran_cities_div.show();
 
 
96
  $address_type.change(function () {
97
  if ($(this).val() === 'iran')
98
  $("#iran_cities_div").slideDown();
@@ -106,26 +117,13 @@ class GFParsi_IranCities {
106
  <?php
107
  }
108
 
109
- public function iran_cities_option( $position, $form_id ) {
110
- if ( $position == 25 ) { ?>
111
- <li class="iran_cities field_setting">
112
- <input type="checkbox" id="iran_cities"
113
- onclick="SetFieldProperty('iran_cities', jQuery(this).is(':checked') ? 1 : 0);"/>
114
- <label class="inline gfield_value_label" for="iran_cities" class="inline">
115
- <?php _e( 'Activate Iran Cities', 'GF_FA' ); ?>
116
- </label>
117
- </li>
118
- <?php
119
- }
120
- }
121
-
122
- public function city_select( $content, $field, $value, $lead_id, $form_id ) {
123
 
124
  if ( $this->is_iran_cities( $field ) ) {
125
 
126
  $id = absint( $field['id'] );
127
 
128
- preg_match( '/<input(?:.*?)(name=["\']input_' . $id . '.3["\'].*?)(?:\/?)>/i', $content, $match );
129
 
130
  if ( ! empty( $match[0] ) && ! empty( $match[1] ) ) {
131
  $city_input = trim( $match[1] );
@@ -148,41 +146,41 @@ class GFParsi_IranCities {
148
  wp_dequeue_script( 'gform_iran_citeis' );
149
  wp_deregister_script( 'gform_iran_citeis' );
150
 
151
- wp_register_script( 'gform_iran_citeis', GF_PARSI_URL . 'assets/js/iran-cities-full.min.js', array(), GF_PARSI_VERSION, false );
152
  wp_enqueue_script( 'gform_iran_citeis' );
153
 
154
- add_action( 'wp_footer', array( $this, 'frontend_rtl' ) );
155
 
156
  break;
157
  }
158
  }
159
  }
160
 
 
161
 
162
- public function frontend_rtl() {
163
-
164
- $frontend_rtl = apply_filters( 'gf_persian_frontend_rtl', is_rtl() && ! is_admin() );
165
- if ( ! $frontend_rtl ) {
166
  return;
167
  }
168
  ?>
169
  <style type="text/css">
170
- html[dir="rtl"] .gform_wrapper .ginput_complex.ginput_container_address .address_city.ginput_left {
171
- float: left !important;
172
- padding-right: 16px !important;
173
- padding-left: 0px !important;
174
- }
175
-
176
- html[dir="rtl"] .gform_wrapper .ginput_complex.ginput_container_address .ginput_left:nth-of-type(2n),
177
- html[dir="rtl"] .gform_wrapper .ginput_complex.ginput_container_address .ginput_left:nth-of-type(2n+1) {
178
- padding-left: 0px !important;
179
- }
180
-
181
- html[dir="rtl"] .gform_wrapper .ginput_complex.ginput_container_address .address_state.ginput_right {
182
- float: right !important;
183
- padding-right: 0px !important;
184
- }
185
-
 
 
186
  </style>
187
  <?php
188
  }
@@ -193,15 +191,13 @@ class GFParsi_IranCities {
193
 
194
  if ( $this->is_iran_cities( $field ) ) {
195
 
196
- $field_id = $field['id'];
197
- $form_id = $form['id'];
198
- $id = $form_id . '_' . $field_id;
199
 
200
  $script = 'jQuery().ready(function($){' .
201
  '$(".has_city #input_' . $id . '_3").html(gform_iranCities(""+$(".has_city #input_' . $id . '_4").val()));' .
202
  'if ($(".has_city #input_' . $id . '_3").attr("data-selected")) {' .
203
- '$(".has_city #input_' . $id . '_3").val($(".has_city #input_' . $id . '_3").attr("data-selected"));' .
204
- '}' .
205
  '$(document.body).on("change", ".has_city #input_' . $id . '_4" ,function(){' .
206
  '$(".has_city #input_' . $id . '_3").html(gform_iranCities(""+$(".has_city #input_' . $id . '_4").val()));' .
207
  '}).on("change", ".has_city #input_' . $id . '_3" ,function(){' .
@@ -214,9 +210,9 @@ class GFParsi_IranCities {
214
  }
215
 
216
  private function is_iran_cities( $field ) {
217
- return $field['type'] == 'address' && $field['addressType'] == 'iran' && gfa_get( "iran_cities", $field ) && ! is_admin();
218
  }
219
 
220
  }
221
 
222
- new GFParsi_IranCities();
2
  exit;
3
  }
4
 
5
+ class GFPersian_Adress extends GFPersian_Core {
 
 
6
 
7
  public function __construct() {
 
 
 
 
8
 
9
+ if ( $this->option( 'address', '1' ) != '1' ) {
10
+ return;
11
+ }
12
+
13
+ add_action( 'gform_editor_js', array( $this, 'iran_cities_editor_js' ) );
14
+ add_action( 'gform_field_standard_settings', array( $this, 'iran_cities_option' ), 10, 2 );
15
+ add_filter( 'gform_address_types', array( $this, 'iran_address_type' ) );
16
+ add_filter( 'gform_predefined_choices', array( $this, 'iran_provinces_choices' ), 1 );
17
+ add_filter( 'gform_field_content', array( $this, 'iran_cities_field_type' ), 10, 5 );
18
  add_action( 'gform_register_init_scripts', array( $this, 'init_script' ), 10, 1 );
19
  add_action( 'gform_enqueue_scripts', array( $this, 'external_js' ), 10, 2 );
20
  }
21
 
22
+ public function iran_provinces() {
23
+ return array(
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
+ public function iran_address_type( $address_types ) {
59
+
60
  $address_types['iran'] = array(
61
+ 'label' => 'ایران',
62
+ 'country' => 'ایران',
63
+ 'zip_label' => 'کدپستی',
64
+ 'state_label' => 'استان',
65
+ 'states' => array_merge( array( '' ), $this->iran_provinces() )
66
  );
67
 
68
  return $address_types;
69
  }
70
 
71
+ public function iran_provinces_choices( $choices ) {
72
+
73
+ $states['استان های ایران'] = $this->iran_provinces();
74
 
75
  return $choices = array_merge( $states, $choices );
76
  }
77
 
78
+ public function iran_cities_option( $position, $form_id ) {
79
+ if ( $position == 25 ) { ?>
80
+ <li class="iran_cities field_setting">
81
+ <input type="checkbox" id="iran_cities"
82
+ onclick="SetFieldProperty('iran_cities', jQuery(this).is(':checked') ? 1 : 0);"/>
83
+ <label class="inline gfield_value_label" for="iran_cities">فعالسازی شهرهای ایران</label>
84
+ </li>
85
+ <?php
86
+ }
87
+ }
88
+
89
+ public function iran_cities_editor_js() { ?>
90
 
91
  <script type='text/javascript'>
92
  jQuery(document).ready(function ($) {
100
  $iran_cities.remove();
101
  $address_type.after('<div id="iran_cities_div"><br>' + $iran_cities_input + '</div>');
102
  }
 
 
103
  if ($address_type.val() === 'iran')
104
+ $('#iran_cities_div').show();
105
+ else
106
+ $('#iran_cities_div').hide();
107
  $address_type.change(function () {
108
  if ($(this).val() === 'iran')
109
  $("#iran_cities_div").slideDown();
117
  <?php
118
  }
119
 
120
+ public function iran_cities_field_type( $content, $field, $value, $entry_id, $form_id ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
  if ( $this->is_iran_cities( $field ) ) {
123
 
124
  $id = absint( $field['id'] );
125
 
126
+ preg_match( '/<input.*?(name=["\']input_' . $id . '.3["\'].*?)\/??>/i', $content, $match );
127
 
128
  if ( ! empty( $match[0] ) && ! empty( $match[1] ) ) {
129
  $city_input = trim( $match[1] );
146
  wp_dequeue_script( 'gform_iran_citeis' );
147
  wp_deregister_script( 'gform_iran_citeis' );
148
 
149
+ wp_register_script( 'gform_iran_citeis', GF_PERSIAN_URL . 'assets/js/iran-cities-full.min.js', array(), GF_PERSIAN_VERSION, false );
150
  wp_enqueue_script( 'gform_iran_citeis' );
151
 
152
+ add_action( 'gform_enqueue_scripts', array( $this, 'frontend_rtl' ), 999, 1 );
153
 
154
  break;
155
  }
156
  }
157
  }
158
 
159
+ public function frontend_rtl( $form ) {
160
 
161
+ if ( ! apply_filters( 'gform_iran_cities_fronend_rtl', is_rtl() && ! is_admin() ) ) {
 
 
 
162
  return;
163
  }
164
  ?>
165
  <style type="text/css">
166
+ <?php
167
+ foreach ( $form['fields'] as &$field ) {
168
+ if ( $this->is_iran_cities( $field ) ) {
169
+ $id = $form['id'] . '_' . $field['id'];
170
+ echo '
171
+ html[dir="rtl"] #input_' . $id . '_4_container{
172
+ float: right !important;
173
+ padding-right: 0 !important;
174
+ padding-left: 16px !important;
175
+ }
176
+ html[dir="rtl"] #input_' . $id . '_3_container{
177
+ float: left !important;
178
+ padding-right: 0 !important;
179
+ padding-left: 0 !important;
180
+ }';
181
+ }
182
+ }
183
+ ?>
184
  </style>
185
  <?php
186
  }
191
 
192
  if ( $this->is_iran_cities( $field ) ) {
193
 
194
+ $id = $form['id'] . '_' . $field['id'];
 
 
195
 
196
  $script = 'jQuery().ready(function($){' .
197
  '$(".has_city #input_' . $id . '_3").html(gform_iranCities(""+$(".has_city #input_' . $id . '_4").val()));' .
198
  'if ($(".has_city #input_' . $id . '_3").attr("data-selected")) {' .
199
+ '$(".has_city #input_' . $id . '_3").val($(".has_city #input_' . $id . '_3").attr("data-selected"));' .
200
+ '}' .
201
  '$(document.body).on("change", ".has_city #input_' . $id . '_4" ,function(){' .
202
  '$(".has_city #input_' . $id . '_3").html(gform_iranCities(""+$(".has_city #input_' . $id . '_4").val()));' .
203
  '}).on("change", ".has_city #input_' . $id . '_3" ,function(){' .
210
  }
211
 
212
  private function is_iran_cities( $field ) {
213
+ return $field['type'] == 'address' && $field['addressType'] == 'iran' && rgar( $field, 'iran_cities' ) && ! is_admin();
214
  }
215
 
216
  }
217
 
218
+ new GFPersian_Adress();
includes/class-admin.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+
5
+ class GFPersian_Admin extends GFPersian_Core {
6
+
7
+ public function __construct() {
8
+ add_filter( 'gform_print_styles', array( $this, 'print_styles' ), 10, 1 );
9
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_styles' ), 999 );
10
+ add_filter( 'gform_noconflict_styles', array( $this, 'noconflict_styles' ) );
11
+ add_filter( 'gform_noconflict_scripts', array( $this, 'noconflict_scripts' ) );
12
+ add_action( 'wp_dashboard_setup', array( $this, 'dashboard_rss_widget' ) );
13
+ add_action( 'admin_footer', array( $this, 'hide_license' ), 9999 );
14
+ }
15
+
16
+ public function admin_styles() {
17
+
18
+ if ( $this->is_gravity_page() ) {
19
+
20
+ if ( is_rtl() && $this->option( 'rtl_admin', '1' ) == '1' ) {
21
+ wp_register_style( 'gform_admin_rtl_style', GF_PERSIAN_URL . 'assets/css/rtl-admin.css' );
22
+ wp_enqueue_style( 'gform_admin_rtl_style' );
23
+ }
24
+
25
+ $this->font_styles();
26
+ }
27
+ }
28
+
29
+ public function print_styles( $styles ) {
30
+
31
+ $styles = (array) $styles;
32
+
33
+ if ( is_rtl() && $this->option( 'rtl_admin', '1' ) == '1' ) {
34
+ $styles[] = $style = 'gform_print_rtl_style';
35
+ wp_register_style( $style, GF_PERSIAN_URL . 'assets/css/rtl-print.css' );
36
+ }
37
+
38
+ return array_merge( $styles, $this->font_styles() );
39
+ }
40
+
41
+ private function font_styles( $only_face = false ) {
42
+
43
+ $styles = array();
44
+
45
+ if ( ( $font = $this->option( 'font_admin', 'vazir' ) ) != '0' ) {
46
+
47
+ $styles[] = $style = 'gform_admin_font_face';
48
+ wp_register_style( $style, GF_PERSIAN_URL . "assets/css/font-face-{$font}.css" );
49
+ wp_enqueue_style( $style );
50
+
51
+ if ( ! $only_face ) {
52
+ $styles[] = $style = 'gform_print_font_style';
53
+ wp_register_style( $style, GF_PERSIAN_URL . "assets/css/font-admin.css" );
54
+ wp_enqueue_style( $style );
55
+ }
56
+ }
57
+
58
+ return $styles;
59
+ }
60
+
61
+
62
+ public function noconflict_scripts( $scripts ) {
63
+ //$scripts[] = '';//ممکنه احتیاج بشه
64
+ return $scripts;
65
+ }
66
+
67
+ public function noconflict_styles( $styles ) {
68
+ $styles[] = 'gform_print_rtl_style';
69
+ $styles[] = 'gform_admin_rtl_style';
70
+ $styles[] = 'gform_admin_font_face';
71
+ $styles[] = 'gform_print_font_style';
72
+
73
+ return $styles;
74
+ }
75
+
76
+ public function dashboard_rss_widget() {
77
+
78
+ if ( current_user_can( 'manage_options' ) && $this->option( 'rss_widget', '1' ) == '1' ) {
79
+
80
+ /*wp_add_dashboard_widget( 'GFPersian_RSS', 'آخرین مطالب گرویتی فرم پارسی',
81
+ array( $this, 'callback_rss_widget' ) );*/
82
+
83
+ add_meta_box( 'GFPersian_RSS', 'آخرین مطالب گرویتی فرم پارسی', array( $this, 'callback_rss_widget' ),
84
+ 'dashboard', 'side', 'low' );
85
+ }
86
+ }
87
+
88
+ public function callback_rss_widget() {
89
+
90
+ $font = $this->font_styles( true );
91
+ $style = ! empty( $font ) ? 'style="font-family: GFPersian;"' : ''; ?>
92
+
93
+ <div class="rss-widget" <?php echo $style; ?>>
94
+ <?php wp_widget_rss_output( array(
95
+ 'url' => 'http://gravityforms.ir/feed/',
96
+ 'items' => 2,
97
+ 'show_summary' => 1,
98
+ 'show_author' => 1,
99
+ 'show_date' => 1
100
+ ) ); ?>
101
+ <div style="border-top: 1px solid #e7e7e7; padding-top: 12px !important; font-size: 13px; height: 20px;">
102
+
103
+ <img src="<?php echo GF_PERSIAN_URL ?>assets/images/logo.png" width="30" height="auto"
104
+ style="float: right; margin: -10px 1px 0 10px"/>
105
+
106
+ <a href="http://gravityforms.ir" target="_blank" title="گرویتی فرم پارسی">
107
+ مشاهده وب سایت گرویتی فرم پارسی
108
+ </a>
109
+ </div>
110
+ </div>
111
+ <?php
112
+ }
113
+
114
+
115
+ public function hide_license() {
116
+ if ( $this->is_gravity_page() && $this->option( 'hide_lic', '0' ) == '1' ) { ?>
117
+ <script type="text/javascript">
118
+ jQuery(document).ready(function ($) {
119
+ $('img').each(function () {
120
+ if (this.title.indexOf("licensed") !== -1 || this.alt.indexOf("licensed") !== -1)
121
+ $(this).hide().parent("a").hide().parent("div").hide();
122
+ });
123
+ });
124
+ </script>
125
+ <?php
126
+ }
127
+ }
128
+
129
+ }
130
+
131
+ new GFPersian_Admin;
includes/class-core.php ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+
5
+ class GFPersian_Core {
6
+
7
+ private static $settings;
8
+
9
+ public function __construct() {
10
+
11
+ if ( ! class_exists( 'GFCommon' ) ) {
12
+ add_action( 'admin_notices', array( $this, 'gform_notice' ) );
13
+
14
+ return;
15
+ }
16
+
17
+ add_action( 'admin_notices', array( $this, 'plugin_update' ), 9999 );
18
+ add_filter( 'load_textdomain_mofile', array( $this, 'load_translate' ), 10, 2 );
19
+ add_action( 'gform_loaded', array( $this, 'load_settings' ), 5 );
20
+ add_filter( 'gform_tooltips', array( $this, 'tooltips' ) );
21
+ add_filter( 'gform_add_field_buttons', array( $this, 'fields_group' ) );
22
+
23
+ $this->include_files();
24
+ }
25
+
26
+ public function gform_notice() {
27
+ $message = sprintf( 'شما فقط بسته گرویتی فرم پارسی را نصب کرده اید. در حالیکه نصب هسته اصلی گرویتی فرم هم نیاز است. %sسوالات متداول%s', '<a href="http://gravityforms.ir/faq/" target="_blank">', '</a>' );
28
+ printf( '<div class="notice notice-error"><p>%s</p></div>', $message );
29
+ }
30
+
31
+ public function plugin_update() {
32
+
33
+ if ( get_option( 'gform_pending_installation' ) ) {
34
+ update_option( 'gform_pending_installation', false );
35
+ $current_version = get_option( 'rg_form_version' );
36
+ if ( $current_version === false ) {
37
+ if ( class_exists( 'GFCommon' ) ) {
38
+ update_option( 'rg_form_version', GFCommon::$version );
39
+ } else {
40
+ update_option( 'rg_form_version', '2.0.0' );
41
+ }
42
+ }
43
+ }
44
+
45
+ if ( ! get_option( 'gf_persian_updated' ) ) {
46
+
47
+ for ( $i = 1; $i <= 5; $i ++ ) {
48
+ delete_option( 'persian_gf_notice_v' . $i );
49
+ }
50
+
51
+ //update national id
52
+ global $wpdb;
53
+ $table = RGFormsModel::get_meta_table_name();
54
+ $update = $wpdb->query( "UPDATE $table SET display_meta = REPLACE(display_meta, 'mellicart', 'ir_national_id')" );
55
+ if ( $update !== false ) {
56
+ $wpdb->query( "UPDATE $table SET display_meta = REPLACE(display_meta, '\"field_ir_national_id\"', '\"showLocation\"')" );
57
+ $wpdb->query( "UPDATE $table SET display_meta = REPLACE(display_meta, '\"field_ir_national_id_sp\"', '\"showSeperator\"')" );
58
+ $wpdb->query( "UPDATE $table SET display_meta = REPLACE(display_meta, '\"field_ir_national_id_sp1\"', '\"notDigitError\"')" );
59
+ $wpdb->query( "UPDATE $table SET display_meta = REPLACE(display_meta, '\"field_ir_national_id_sp2\"', '\"qtyDigitError\"')" );
60
+ $wpdb->query( "UPDATE $table SET display_meta = REPLACE(display_meta, '\"field_ir_national_id_sp3\"', '\"duplicateError\"')" );
61
+ $wpdb->query( "UPDATE $table SET display_meta = REPLACE(display_meta, '\"field_ir_national_id_sp4\"', '\"isInvalidError\"')" );
62
+ update_option( 'gf_persian_updated', GF_PERSIAN_VERSION );
63
+ }
64
+
65
+ echo '<div class="notice notice-success is-dismissible"><p>' . sprintf( 'گرویتی فرم پارسی با موفقیت بروز شد. %sرفتن به صفحه تنظیمات%s', '<a href="' . admin_url( 'admin.php?page=gf_settings&subview=persian' ) . '">', '</a>' ) . '</p></div>';
66
+ }
67
+ }
68
+
69
+ public function tooltips( $tooltips ) {
70
+
71
+ $tooltips['form_gf_persian_fields'] = '<h6>گرویتی فرم پارسی</h6>فیلدهای برنامه نویسی شده توسط گرویتی فرم پارسی به مرور اینجا اضافه خواهند شد.';
72
+
73
+ return $tooltips;
74
+ }
75
+
76
+
77
+ public function fields_group( $field_groups ) {
78
+
79
+ $group = 'gf_persian_fields';
80
+
81
+ if ( ! function_exists( 'wp_list_pluck' ) || ! in_array( $group, wp_list_pluck( $field_groups, 'name' ) ) ) {
82
+ array_push( $field_groups, array(
83
+ 'name' => $group,
84
+ 'label' => 'فیلدهای گرویتی فرم پارسی',
85
+ 'fields' => array()
86
+ ) );
87
+ }
88
+
89
+ return $field_groups;
90
+ }
91
+
92
+ public function load_settings() {
93
+
94
+ if ( method_exists( 'GFForms', 'include_addon_framework' ) ) {
95
+
96
+ GFForms::include_addon_framework();
97
+ GFAddOn::register( 'GFPersian_Settings' );
98
+
99
+ require_once( 'class-settings.php' );
100
+ }
101
+ }
102
+
103
+ public function load_translate( $mo_file, $domain ) {
104
+
105
+ if ( $this->option( 'translate', '1' ) == '1' && get_locale() == 'fa_IR' ) {
106
+
107
+ $translates = array(
108
+ 'gravityforms',
109
+ 'gravityformscoupons',
110
+ 'gravityformsmailchimp',
111
+ 'gravityformspolls',
112
+ 'gravityformsquiz',
113
+ 'gravityformssignature',
114
+ 'gravityformssurvey',
115
+ 'gravityformsuserregistration',
116
+ 'gravityformsauthorizenet',
117
+ 'gravityformsaweber',
118
+ 'gravityformscampaignmonitor',
119
+ 'gravityformspaypalpaymentspro',
120
+ 'gravityformsfreshbooks',
121
+ 'gravityformspaypal',
122
+ 'gravityformspaypalpro',
123
+ 'gravityformstwilio',
124
+ 'gravityformsstripe',
125
+ 'gravityformszapier',
126
+ 'sticky-list',
127
+ 'gf-limit'
128
+ );
129
+
130
+ if ( in_array( $domain, $translates ) ) {
131
+ $mo_file = dirname( plugin_dir_path( __FILE__ ) ) . "/languages/$domain/$domain-fa_IR.mo";
132
+ }
133
+ }
134
+
135
+ return $mo_file;
136
+ }
137
+
138
+ private function include_files() {
139
+ include 'class-admin.php';
140
+ include 'class-address.php';
141
+ include 'class-payments.php';
142
+ include 'class-snippets.php';
143
+ include 'class-merge-tag.php';
144
+ include 'class-currencies.php';
145
+ include 'class-jalali-date.php';
146
+ include 'class-live-preview.php';
147
+ include 'class-transaction-id.php';
148
+ include 'class-multi-page-navi.php';
149
+
150
+ include 'class-deprecated.php';
151
+ if ( get_option( 'gf_persian_updated' ) ) {
152
+ include 'class-national-id.php';
153
+ } else {
154
+ //the class is existed in class-deprecated.php
155
+ new GFParsi_MelliCode();
156
+ }
157
+ }
158
+
159
+ public static function _option( $setting_name = '', $default = null ) {
160
+
161
+ if ( empty( self::$settings ) ) {
162
+ if ( class_exists( 'GFPersian_Settings' ) ) {
163
+ if ( method_exists( 'GFPersian_Settings', 'get_plugin_settings' ) ) {
164
+ self::$settings = GFPersian_Settings::get_instance()->get_plugin_settings();
165
+ }
166
+ }
167
+ if ( empty( self::$settings ) && defined( 'GF_PERSIAN_SLUG' ) ) {
168
+ self::$settings = get_option( 'gravityformsaddon_' . GF_PERSIAN_SLUG . '_settings' );
169
+ }
170
+ }
171
+
172
+ $settings = self::$settings;
173
+
174
+ if ( ! empty( $setting_name ) ) {
175
+ $settings = isset( $settings[ $setting_name ] ) ? $settings[ $setting_name ] : '';
176
+ }
177
+
178
+ return ! empty( $settings ) || strval( $settings ) == '0' ? $settings : $default;
179
+ }
180
+
181
+ public function option( $setting_name = '', $default = null ) {
182
+ return self::_option( $setting_name, $default );
183
+ }
184
+
185
+ public function is_gravity_page() {
186
+
187
+ $is_gform = class_exists( 'RGForms' ) ? RGForms::is_gravity_page() : false;
188
+ $current_page = trim( strtolower( rgget( 'page' ) ) );
189
+
190
+ return $is_gform || substr( $current_page, 0, 2 ) == 'gf' || stripos( $current_page, 'gravity' ) !== false;
191
+ }
192
+
193
+ public static function get_base_url() {
194
+ return plugins_url( '', dirname(__FILE__) );
195
+ }
196
+ }
197
+
198
+ new GFPersian_Core;
includes/class-currencies.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+
5
+ class GFPersian_Currencies extends GFPersian_Core {
6
+
7
+ public function __construct() {
8
+
9
+ if ( $this->option( 'currencies', '1' ) != '1' ) {
10
+ return;
11
+ }
12
+
13
+ add_filter( 'gform_currencies', array( $this, 'iran_currencies' ) );
14
+ }
15
+
16
+ public function iran_currencies( $currencies ) {
17
+
18
+ unset( $currencies['IRR'], $currencies['irr'], $currencies['IRT'], $currencies['irt'] );
19
+
20
+ $is_rtl = true; /*may be need use is_rtl() later but not now*/
21
+ $is_fa = apply_filters( 'gform_iran_currencies_is_fa', get_locale() == 'fa_IR', $currencies );
22
+
23
+ $ir_currencies = array(
24
+
25
+ 'IRR' => array(
26
+ 'name' => 'ریال ایران',
27
+ 'symbol_left' => ( ! $is_rtl ? ( $is_fa ? 'ریال' : 'Rial' ) : '' ),
28
+ 'symbol_right' => ( $is_rtl ? ( $is_fa ? 'ریال' : 'Rial' ) : '' ),
29
+ 'symbol_padding' => ' ',
30
+ 'thousand_separator' => ',',
31
+ 'decimal_separator' => '.',
32
+ 'decimals' => 0
33
+ ),
34
+
35
+ 'IRHR' => array(
36
+ 'name' => 'هزار ریال ایران',
37
+ 'symbol_left' => ( ! $is_rtl ? ( $is_fa ? 'هزار ریال' : 'Thousand Rial' ) : '' ),
38
+ 'symbol_right' => ( $is_rtl ? ( $is_fa ? 'هزار ریال' : 'Thousand Rial' ) : '' ),
39
+ 'symbol_padding' => ' ',
40
+ 'thousand_separator' => ',',
41
+ 'decimal_separator' => '.',
42
+ 'decimals' => 0
43
+ ),
44
+
45
+ 'IRT' => array(
46
+ 'name' => 'تومان ایران',
47
+ 'symbol_left' => ( ! $is_rtl ? ( $is_fa ? 'تومان' : 'Toman' ) : '' ),
48
+ 'symbol_right' => ( $is_rtl ? ( $is_fa ? 'تومان' : 'Toman' ) : '' ),
49
+ 'symbol_padding' => ' ',
50
+ 'thousand_separator' => ',',
51
+ 'decimal_separator' => '.',
52
+ 'decimals' => 0
53
+ ),
54
+
55
+ 'IRHT' => array(
56
+ 'name' => 'هزار تومان ایران',
57
+ 'symbol_left' => ( ! $is_rtl ? ( $is_fa ? 'هزار تومان' : 'Thousand Toman' ) : '' ),
58
+ 'symbol_right' => ( $is_rtl ? ( $is_fa ? 'هزار تومان' : 'Thousand Toman' ) : '' ),
59
+ 'symbol_padding' => ' ',
60
+ 'thousand_separator' => ',',
61
+ 'decimal_separator' => '.',
62
+ 'decimals' => 0
63
+ ),
64
+
65
+ );
66
+
67
+ return array_merge( $ir_currencies, $currencies );
68
+ }
69
+ }
70
+
71
+ new GFPersian_Currencies();
includes/class-deprecated.php ADDED
@@ -0,0 +1,657 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+ /*
5
+ * @deprecated
6
+ * this methods are used in Gateway->charts
7
+ * will be deleted completely in some next updates
8
+ * */
9
+ if ( ! class_exists( 'GFParsi' ) ) :
10
+
11
+ class GFParsi {
12
+
13
+ public static function better_noDuplicate_hook( $version ) {
14
+ if ( version_compare( $version, '1.9.19', '>' ) ) {
15
+ add_filter( 'gform_is_duplicate', array( __CLASS__, 'better_noDuplicate_1_9_19' ), 10, 4 );
16
+ } else {
17
+ add_filter( 'gform_is_duplicate', array( __CLASS__, 'better_noDuplicate_old' ), 10, 4 );
18
+ }
19
+ }
20
+
21
+ public static function better_noDuplicate_1_9_19( $count, $form_id, $field, $value ) {
22
+ global $wpdb;
23
+
24
+ $lead_detail_table_name = GFFormsModel::get_lead_details_table_name();
25
+ $lead_table_name = GFFormsModel::get_lead_table_name();
26
+ $sql_comparison = 'ld.value = %s';
27
+
28
+ switch ( GFFormsModel::get_input_type( $field ) ) {
29
+ case 'time':
30
+ $value = sprintf( "%02d:%02d %s", $value[0], $value[1], $value[2] );
31
+ break;
32
+ case 'date':
33
+ $value = GFFormsModel::prepare_date( $field->dateFormat, $value );
34
+ break;
35
+ case 'number':
36
+ $value = GFCommon::clean_number( $value, $field->numberFormat );
37
+ break;
38
+ case 'phone':
39
+ $value = str_replace( array( ')', '(', '-', ' ' ), '', $value );
40
+ $sql_comparison = 'replace( replace( replace( replace( ld.value, ")", "" ), "(", "" ), "-", "" ), " ", "" ) = %s';
41
+ break;
42
+ case 'email':
43
+ $value = is_array( $value ) ? rgar( $value, 0 ) : $value;
44
+ break;
45
+ }
46
+
47
+ $inner_sql_template = "SELECT %s as input, ld.lead_id
48
+ FROM {$lead_detail_table_name} ld
49
+ INNER JOIN {$lead_table_name} l ON l.id = ld.lead_id\n";
50
+
51
+
52
+ $inner_sql_template .= "WHERE l.form_id=%d AND ld.form_id=%d
53
+ AND ld.field_number between %s AND %s
54
+ AND status='active'
55
+ AND (payment_status IS NULL OR LOWER(payment_status) IN ('', 'approved', 'approve', 'completed', 'complete', 'actived', 'active', 'paid'))
56
+ AND {$sql_comparison}";
57
+
58
+ $sql = "SELECT count(DISTINCT input) AS match_count FROM ( ";
59
+
60
+ $inner_sql = '';
61
+ $input_count = 1;
62
+ if ( is_array( $field->get_entry_inputs() ) ) {
63
+ $input_count = sizeof( $field->inputs );
64
+ foreach ( $field->inputs as $input ) {
65
+ $union = empty( $inner_sql ) ? '' : ' UNION ALL ';
66
+ $inner_sql .= $union . $wpdb->prepare( $inner_sql_template, $input['id'], $form_id, $form_id, $input['id'] - 0.0001, $input['id'] + 0.0001, $value[ $input['id'] ], $value[ $input['id'] ] );
67
+ }
68
+ } else {
69
+ $inner_sql = $wpdb->prepare( $inner_sql_template, $field->id, $form_id, $form_id, doubleval( $field->id ) - 0.0001, doubleval( $field->id ) + 0.0001, $value, $value );
70
+ }
71
+
72
+ $sql .= $inner_sql . "
73
+ ) as count
74
+ GROUP BY lead_id
75
+ ORDER BY match_count DESC";
76
+
77
+ $count = gf_apply_filters( array(
78
+ 'gform_is_duplicate_better',
79
+ $form_id
80
+ ), $wpdb->get_var( $sql ), $form_id, $field, $value );
81
+
82
+ return $count != null && $count >= $input_count;
83
+ }
84
+
85
+ public static function better_noDuplicate_old( $count, $form_id, $field, $value ) {
86
+
87
+ global $wpdb;
88
+
89
+ $lead_detail_table_name = GFFormsModel::get_lead_details_table_name();
90
+ $lead_table_name = GFFormsModel::get_lead_table_name();
91
+ $lead_detail_long = GFFormsModel::get_lead_details_long_table_name();
92
+ $is_long = ! is_array( $value ) && strlen( $value ) > GFORMS_MAX_FIELD_LENGTH - 10;
93
+
94
+ $sql_comparison = $is_long ? '( ld.value = %s OR ldl.value = %s )' : 'ld.value = %s';
95
+
96
+ switch ( GFFormsModel::get_input_type( $field ) ) {
97
+ case 'time':
98
+ $value = sprintf( "%02d:%02d %s", $value[0], $value[1], $value[2] );
99
+ break;
100
+ case 'date':
101
+ $value = GFFormsModel::prepare_date( $field->dateFormat, $value );
102
+ break;
103
+ case 'number':
104
+ $value = GFCommon::clean_number( $value, $field->numberFormat );
105
+ break;
106
+ case 'phone':
107
+ $value = str_replace( array( ')', '(', '-', ' ' ), '', $value );
108
+ $sql_comparison = 'replace( replace( replace( replace( ld.value, ")", "" ), "(", "" ), "-", "" ), " ", "" ) = %s';
109
+ break;
110
+ case 'email':
111
+ $value = is_array( $value ) ? rgar( $value, 0 ) : $value;
112
+ break;
113
+ }
114
+
115
+ $inner_sql_template = "SELECT %s as input, ld.lead_id
116
+ FROM {$lead_detail_table_name} ld
117
+ INNER JOIN {$lead_table_name} l ON l.id = ld.lead_id\n";
118
+
119
+ if ( $is_long ) {
120
+ $inner_sql_template .= "INNER JOIN {$lead_detail_long} ldl ON ldl.lead_detail_id = ld.id\n";
121
+ }
122
+
123
+ $inner_sql_template .= "WHERE l.form_id=%d AND ld.form_id=%d
124
+ AND ld.field_number between %s AND %s
125
+ AND status='active'
126
+ AND (payment_status IS NULL OR LOWER(payment_status) IN ('', 'approved', 'approve', 'completed', 'complete', 'actived', 'active', 'paid'))
127
+ AND {$sql_comparison}";
128
+
129
+ $sql = "SELECT count(DISTINCT input) AS match_count FROM ( ";
130
+
131
+ $inner_sql = '';
132
+ $input_count = 1;
133
+ if ( is_object( $field ) && is_array( $field->get_entry_inputs() ) ) {
134
+ $input_count = sizeof( $field->inputs );
135
+ foreach ( $field->inputs as $input ) {
136
+ $union = empty( $inner_sql ) ? '' : ' UNION ALL ';
137
+ $inner_sql .= $union . $wpdb->prepare( $inner_sql_template, $input['id'], $form_id, $form_id, $input['id'] - 0.0001, $input['id'] + 0.0001, $value[ $input['id'] ], $value[ $input['id'] ] );
138
+ }
139
+ } else {
140
+ $inner_sql = $wpdb->prepare( $inner_sql_template, $field->id, $form_id, $form_id, doubleval( $field->id ) - 0.0001, doubleval( $field->id ) + 0.0001, $value, $value );
141
+ }
142
+
143
+ $sql .= $inner_sql . "
144
+ ) as count
145
+ GROUP BY lead_id
146
+ ORDER BY match_count DESC";
147
+
148
+ $count = gf_apply_filters( 'gform_is_duplicate_better', $form_id, $wpdb->get_var( $sql ), $form_id, $field, $value );
149
+
150
+ return $count != null && $count >= $input_count;
151
+ }
152
+
153
+ public static function get_base_url() {
154
+ return plugins_url( '', dirname( __FILE__ ) );
155
+ }
156
+
157
+ public static function get_mysql_tz_offset() {
158
+
159
+ $time_zone_orig = $time_zone = get_option( 'gmt_offset' );
160
+
161
+ $prefix = intval( $time_zone ) > 0 ? '+' : '-';
162
+ $time_zone = abs( $time_zone ) * 3600;
163
+ $time_zone = gmdate( 'H:i', $time_zone );
164
+ $time_zone = $prefix . $time_zone;
165
+
166
+ $today = date( 'Y-m-d H:i:s' );
167
+ $date = new DateTime( $today );
168
+
169
+ $tzn = abs( $time_zone_orig ) * 3600;
170
+ $tzh = intval( gmdate( 'H', $tzn ) );
171
+ $tzm = intval( gmdate( 'i', $tzn ) );
172
+ try {
173
+ if ( intval( $time_zone_orig ) < 0 ) {
174
+ $date->sub( new DateInterval( 'P0DT' . $tzh . 'H' . $tzm . 'M' ) );
175
+ } else {
176
+ $date->add( new DateInterval( 'P0DT' . $tzh . 'H' . $tzm . 'M' ) );
177
+ }
178
+ } catch ( Exception $e ) {
179
+ return array( 'tz' => $time_zone, 'today' => time() );
180
+ }
181
+ $today = $date->format( 'Y-m-d H:i:s' );
182
+ $today = strtotime( $today );
183
+
184
+ return array( 'tz' => $time_zone, 'today' => $today );
185
+ }
186
+ }
187
+ endif;
188
+
189
+
190
+ if ( ! class_exists( 'GFParsi_MelliCode' ) ) :
191
+
192
+ class GFParsi_MelliCode {
193
+
194
+ private $field = array();
195
+
196
+ public function __construct() {
197
+
198
+ if ( GFPersian_Core::_option( 'national_id', '1' ) != '1' ) {
199
+ return;
200
+ }
201
+
202
+ if ( is_admin() ) {
203
+ add_filter( 'gform_add_field_buttons', array( $this, 'button' ) );
204
+ add_filter( 'gform_field_type_title', array( $this, 'title' ) );
205
+ add_filter( 'gform_editor_js_set_default_values', array( $this, 'label' ) );
206
+ add_action( 'gform_editor_js', array( $this, 'settings' ) );
207
+ add_action( 'gform_field_standard_settings', array( $this, 'standard_settings' ), 10, 2 );
208
+ add_filter( 'gform_tooltips', array( $this, 'tooltips' ) );
209
+ add_filter( 'gform_admin_pre_render', array( $this, 'admin_conditional_logic' ) );
210
+ }
211
+
212
+ add_action( 'gform_field_input', array( $this, 'input' ), 10, 5 );
213
+ add_action( 'gform_field_css_class', array( $this, 'classes' ), 10, 3 );
214
+ add_action( 'gform_pre_submission', array( $this, 'pre_submission' ) );
215
+ add_filter( 'gform_field_content', array( $this, 'city' ), 10, 5 );
216
+ add_filter( 'gform_field_validation', array( $this, 'validator' ), 10, 4 );
217
+ add_action( 'wp_footer', array( $this, 'js' ) );
218
+ add_action( 'gform_enqueue_scripts', array( $this, 'external_js' ), 10, 2 );
219
+ }
220
+
221
+ public function button( $field_groups ) {
222
+ foreach ( $field_groups as &$group ) {
223
+ if ( $group["name"] == "gf_persian_fields" ) {
224
+ $group["fields"][] = array(
225
+ "class" => "button",
226
+ "value" => 'کد ملی',
227
+ "onclick" => "StartAddField('mellicart');"
228
+ );
229
+
230
+ }
231
+ }
232
+
233
+ return $field_groups;
234
+ }
235
+
236
+ public function title( $type ) {
237
+ if ( $type == 'mellicart' ) {
238
+ return 'کد ملی';
239
+ }
240
+
241
+ return $type;
242
+ }
243
+
244
+ public function label() {
245
+ ?>
246
+ case "mellicart" :
247
+ field.label = 'کد ملی';
248
+ break;
249
+ <?php
250
+ }
251
+
252
+ public function classes( $classes, $field, $form ) {
253
+ if ( $field["type"] == "mellicart" ) {
254
+ $classes .= " gform_melli_code";
255
+ }
256
+
257
+ return $classes;
258
+ }
259
+
260
+ public function tooltips( $tooltips ) {
261
+ $tooltips['gform_melli_code_city'] = '<h6>نمایش لحظه ای شهر از روی کد ملی </h6>نمایش شهر و پیغام زیر فیلد کد ملی بعد از پر شدن فیلد . تذکر : در صورتی که این گزینه را فعال نمایید ،ممکن است فراخوانی شهر های ایران با توجه به زیاد بودن آنها سبب سنگین شدن صفحه گردد.';
262
+ $tooltips['gform_melli_code_seperate'] = '<h6>جدا سازی ارقام</h6>در صورتی که این گزینه را فعال نمایید ، پس از پر شدن فیلد کد ملی ، <strong>در صورتی که کد ملی وارد شده صحیح تشخصی داده شود</strong> ؛ کد ملی به صورت زیر در خواهد آمد و در غیر این صورت علی صحیح نبودن کد ملی زیر فیلد نمایش داده خواهد شد :<br>xxx-xxxxxx-x';
263
+ $tooltips['gform_melli_code_abnormal'] = 'با توجه به اینکه کد ملی فقط باید به صورت عدد باشد ، در صورتی که کاراکتری غیر از عدد وارد شده باشد پیغام خطا نمایش داده خواهد شد .<br/>پیغام پیشفرض : کد ملی فقط باید به صورت عدد وارد شود .';
264
+ $tooltips['gform_melli_code_len'] = 'با توجه به اینکه کد ملی می بایست 10 رقمی باشد اگر تعداد رقم وارد شده ، اشتباه باشد پیغام خطا نمایش داده خواهد شد .<br>پیغام پیشفرض : کد ملی می بایست 10 رقمی باشد . تنها در صورتی مجاز به استفاده از کد های 8 یا 9 رقمی هستید که ارقام سمت چپ 0 باشند .';
265
+ $tooltips['gform_melli_code_dup'] = 'در صورتی که از تب وِیژگی تیک گزینه بدون تکرار را زده باشید ؛ بعد از پر شدن فرم و زدن دکمه ارسال پیغامی مبتنی بر تکراری بودن کد ملی نمایش داده خواهد شد . <br/>پیغام پیشفرض : این کد ملی توسط فرد دیگری ثبت شده است .';
266
+ $tooltips['gform_melli_code_noStandard'] = 'در صورتی که کد ملی وارد شده مطابق با الگوریتم کشور نباشد پیغام خطا نمایش داده خواهد شد .<br/>پیغام پیشفرض : کد ملی وارد شده مطابق با استانداردهای کشور نمی باشد .';
267
+
268
+ return $tooltips;
269
+ }
270
+
271
+ public function input( $input, $field, $value, $lead_id, $form_id ) {
272
+
273
+ if ( $field["type"] == "mellicart" ) {
274
+
275
+ $is_admin = is_admin();
276
+ $is_frontend = ! $is_admin;
277
+ $is_form_editor = ( $is_admin && GFForms::get( 'view' ) != 'entry' );
278
+ $is_entry_page = ( $is_admin && GFForms::get( 'view' ) == 'entry' );
279
+
280
+ if ( ! $is_admin && ( RGFormsModel::get_input_type( $field ) == 'adminonly_hidden' ) ) {
281
+ return '';
282
+ }
283
+
284
+ $field_id = $field["id"];
285
+ $form_id = $is_admin && empty( $form_id ) ? rgget( "id" ) : $form_id;
286
+
287
+ $disabled_text = ( $is_admin && rgget( 'view' ) != 'entry' ) ? "disabled='disabled'" : '';
288
+
289
+ $size = rgar( $field, "size" );
290
+ $class_suffix = GFForms::get( 'view' ) == 'entry' ? '_admin' : '';
291
+ $class = $size . $class_suffix;
292
+
293
+ $html5_attributes = '';
294
+
295
+ $tabindex = GFCommon::get_tabindex();
296
+
297
+
298
+ //$this->get_conditional_logic_event( 'keyup' ) //text or radio
299
+ //$this->get_conditional_logic_event( 'change' ) //select
300
+ //$this->get_conditional_logic_event( 'click' ) // checkbox or radio
301
+ //note : radio has keyup and click
302
+ $logic_event = ! $is_form_editor && ! $is_entry_page ? $field->get_conditional_logic_event( 'keyup' ) : '';
303
+
304
+ $input = '<div class="ginput_container ginput_container_text ginput_container_melli_code">';
305
+ $input .= '<input onblur="melli_code_' . $field_id . '(this);" name="input_' . $field_id . '" id="input_' . $form_id . '_' . $field_id . '" type="text" value="' . esc_attr( $value ) . '" class="melli_code ' . esc_attr( $size ) . '" ' . $tabindex . ' ' . $logic_event . ' ' . $html5_attributes . ' ' . $disabled_text . '/>';
306
+ $input .= '</div>';
307
+
308
+ if ( $is_frontend ) {
309
+ $input .= '<span class="city melli_code" id="ir_national_id_location_' . $field_id . '"></span>';
310
+ }
311
+
312
+ }
313
+
314
+ return $input;
315
+ }
316
+
317
+ public function settings() { ?>
318
+ <script type='text/javascript'>
319
+ fieldSettings["mellicart"] = ".placeholder_setting, .input_mask_setting, .label_placement_setting, .prepopulate_field_setting, .conditional_logic_field_setting, .label_setting, .admin_label_setting, .size_setting, .rules_setting, .visibility_setting, .duplicate_setting, .default_value_setting, .description_setting, .css_class_setting, .mellicart_setting";
320
+ jQuery(document).bind("gform_load_field_settings", function (event, field, form) {
321
+ jQuery("#field_mellicart").attr("checked", field["field_mellicart"] == true);
322
+ jQuery("#field_mellicart_sp").attr("checked", field["field_mellicart_sp"] == true);
323
+ jQuery("#field_mellicart_sp1").val(field["field_mellicart_sp1"]);
324
+ jQuery("#field_mellicart_sp2").val(field["field_mellicart_sp2"]);
325
+ jQuery("#field_mellicart_sp3").val(field["field_mellicart_sp3"]);
326
+ jQuery("#field_mellicart_sp4").val(field["field_mellicart_sp4"]);
327
+ });
328
+ </script>
329
+ <?php
330
+ }
331
+
332
+
333
+ public function admin_conditional_logic( $form ) {
334
+
335
+ if ( GFCommon::is_entry_detail() ) {
336
+ return $form;
337
+ }
338
+
339
+ echo "<script type='text/javascript'>" .
340
+ " gform.addFilter('gform_is_conditional_logic_field', function (isConditionalLogicField, field) {" .
341
+ " return field.type == 'mellicart' ? true : isConditionalLogicField;" .
342
+ ' });' .
343
+ " gform.addFilter('gform_conditional_logic_operators', function (operators, objectType, fieldId) {" .
344
+ ' var targetField = GetFieldById(fieldId);' .
345
+ " if (targetField && targetField['type'] == 'mellicart') {" .
346
+ " operators = {'is':'is','isnot':'isNot', '>':'greaterThan', '<':'lessThan', 'contains':'contains', 'starts_with':'startsWith', 'ends_with':'endsWith'};" .
347
+ ' }' .
348
+ ' return operators;' .
349
+ ' });' .
350
+ '</script>';
351
+
352
+ return $form;
353
+ }
354
+
355
+ public function standard_settings( $position, $form_id ) {
356
+
357
+ if ( $position == 50 ) { ?>
358
+
359
+ <li class="mellicart_setting field_setting">
360
+
361
+ <input type="checkbox" id="field_mellicart"
362
+ onclick="SetFieldProperty('field_mellicart', this.checked);"/>
363
+ <label for="field_mellicart" class="inline">
364
+ نمایش شهر بر اساس کد ملی
365
+ <?php gform_tooltip( "gform_melli_code_city" ); ?>
366
+ </label>
367
+
368
+
369
+ <br/>
370
+ <input type="checkbox" id="field_mellicart_sp"
371
+ onclick="SetFieldProperty('field_mellicart_sp', this.checked);"/>
372
+ <label for="field_mellicart_sp" class="inline">
373
+ جداسازی خودکار ارقام توسط خط فاصله
374
+ <?php gform_tooltip( "gform_melli_code_seperate" ); ?>
375
+ </label>
376
+ <br/>
377
+
378
+
379
+ <br/>
380
+ <label for="field_mellicart_sp1">
381
+ پیغام زمانی که مقدار وارد شده شامل کاراکتر غیر عددی باشد
382
+ <?php gform_tooltip( "gform_melli_code_abnormal" ); ?>
383
+ </label>
384
+ <input type="text" class="fieldwidth-3" id="field_mellicart_sp1" size="35"
385
+ onkeyup="SetFieldProperty('field_mellicart_sp1', this.value);"/>
386
+ <br/>
387
+
388
+
389
+ <br/>
390
+ <label for="field_mellicart_sp2">
391
+ پیغام زمانیکه تعداد ارقام وارد شده استاندارد نباشد
392
+ <?php gform_tooltip( "gform_melli_code_len" ); ?>
393
+ </label>
394
+ <input type="text" class="fieldwidth-3" id="field_mellicart_sp2" size="35"
395
+ onkeyup="SetFieldProperty('field_mellicart_sp2', this.value);"/>
396
+ <br/>
397
+
398
+
399
+ <br/>
400
+ <label for="field_mellicart_sp3">
401
+ پیغام زمانیکه کد ملی وارد شده قبلا ثبت شده باشد
402
+ <?php gform_tooltip( "gform_melli_code_dup" ); ?>
403
+ </label>
404
+ <input type="text" class="fieldwidth-3" id="field_mellicart_sp3" size="35"
405
+ onkeyup="SetFieldProperty('field_mellicart_sp3', this.value);"/>
406
+ <br/>
407
+
408
+
409
+ <br/>
410
+ <label for="field_mellicart_sp4">
411
+ پیغام زمانیکه کد ملی وارد شده مطابق با الگوی ملی نباشد
412
+ <?php gform_tooltip( "gform_melli_code_noStandard" ); ?>
413
+ </label>
414
+ <input type="text" class="fieldwidth-3" id="field_mellicart_sp4" size="35"
415
+ onkeyup="SetFieldProperty('field_mellicart_sp4', this.value);"/>
416
+ <br/>
417
+
418
+
419
+ </li>
420
+ <?php
421
+ }
422
+ }
423
+
424
+
425
+ public function pre_submission( $form ) {
426
+
427
+ $mellicart_fields = GFCommon::get_fields_by_type( $form, array( 'mellicart' ) );
428
+
429
+ foreach ( (array) $mellicart_fields as $field ) {
430
+
431
+ $input_name = "input_{$field['id']}";
432
+ $input_value = ! rgempty( $input_name ) ? rgpost( $input_name ) : '';
433
+
434
+ if ( ! empty( $input_value ) ) {
435
+
436
+ if ( strlen( $input_value ) == 8 ) {
437
+ $_POST["input_{$field['id']}"] = '00' . $input_value;
438
+ } elseif ( strlen( $input_value ) == 9 ) {
439
+ $_POST["input_{$field['id']}"] = '0' . $input_value;
440
+ } else {
441
+ $_POST["input_{$field['id']}"] = $input_value;
442
+ }
443
+ }
444
+ }
445
+ }
446
+
447
+ public function city( $content, $field, $value, $lead_id, $form_id ) {
448
+
449
+ if ( $field['type'] == 'mellicart' ) {
450
+ if ( ! is_admin() ) {
451
+ $this->field[] = $field;
452
+ }
453
+ }
454
+
455
+ return $content;
456
+ }
457
+
458
+ public function external_js( $form, $ajax ) {
459
+
460
+ $melli_code = GFCommon::get_fields_by_type( $form, array( 'mellicart' ) );
461
+
462
+ foreach ( (array) $melli_code as $field ) {
463
+
464
+ $is_seperate = rgar( $field, 'field_mellicart_sp' );
465
+ $is_seperate = ! empty( $is_seperate ) ? $is_seperate : false;
466
+
467
+ $show_city = rgar( $field, 'field_mellicart' );
468
+ $show_city = ! empty( $show_city ) ? $show_city : false;
469
+
470
+ if ( $show_city || $is_seperate ) {
471
+ wp_register_script( 'gform_mellicode', GF_PERSIAN_URL . 'assets/js/national_id.min.js', array(), GF_PERSIAN_VERSION, false );
472
+ wp_enqueue_script( 'gform_mellicode' );
473
+ break;
474
+ }
475
+ }
476
+ }
477
+
478
+ public function js() {
479
+
480
+ $fields = $this->field;
481
+
482
+ if ( empty( $fields ) ) {
483
+ return;
484
+ }
485
+
486
+ foreach ( (array) $fields as $field ) {
487
+
488
+ $is_seperate = rgar( $field, 'field_mellicart_sp' );
489
+ $is_seperate = ! empty( $is_seperate ) && $is_seperate ? 1 : 0;
490
+
491
+ $show_city = rgar( $field, 'field_mellicart' );
492
+ $show_city = ! empty( $show_city ) && $show_city ? 1 : 0;
493
+
494
+ if ( ! $show_city && ! $is_seperate ) { ?>
495
+ <script type="text/javascript">
496
+ function melli_code_<?php echo $field['id']; ?> (melli_code) {
497
+ }
498
+ </script>
499
+ <?php
500
+ } else {
501
+
502
+ $message1 = rgar( $field, 'field_mellicart_sp1' );
503
+ $message1 = ! empty( $message1 ) ? $message1 : 'کد ملی فقط باید به صورت عدد وارد شود .';
504
+
505
+ $message2 = rgar( $field, 'field_mellicart_sp2' );
506
+ $message2 = ! empty( $message2 ) ? $message2 : 'کد ملی می بایست 10 رقمی باشد .';
507
+
508
+ $message3 = rgar( $field, 'field_mellicart_sp4' );
509
+ $message3 = ! empty( $message3 ) ? $message3 : 'کد ملی وارد شده مطابق با استانداردهای کشور نمی باشد .';
510
+ ?>
511
+
512
+ <script type="text/javascript">
513
+ function melli_code_<?php echo $field['id']; ?> (melli_code) {
514
+ var field_id = "<?php echo $field['id'] ?>";
515
+ var message1 = "<?php echo $message1 ?>";
516
+ var message2 = "<?php echo $message2 ?>";
517
+ var message3 = "<?php echo $message3 ?>";
518
+ var show_city = <?php echo $show_city ?>;
519
+ var is_seperate = <?php echo $is_seperate ?>;
520
+ GFPersian_National_ID_Handler(melli_code, field_id, message1, message2, message3, is_seperate, show_city);
521
+ jQuery(melli_code).trigger('change');
522
+ }
523
+ </script>
524
+
525
+ <?php
526
+ }
527
+ }
528
+ }
529
+
530
+ public function is_valid( $melli_code = '' ) {
531
+
532
+ if ( ! empty( $melli_code ) ) {
533
+
534
+ $_melli_code = $melli_code;
535
+
536
+ if ( strlen( $melli_code ) == 8 ) {
537
+ $_melli_code = '00' . $melli_code;
538
+ }
539
+
540
+ if ( strlen( $melli_code ) == 9 ) {
541
+ $_melli_code = '0' . $melli_code;
542
+ }
543
+
544
+ $pre_check = array(
545
+ '0000000000',
546
+ '1111111111',
547
+ '2222222222',
548
+ '3333333333',
549
+ '4444444444',
550
+ '5555555555',
551
+ '6666666666',
552
+ '7777777777',
553
+ '8888888888',
554
+ '9999999999',
555
+ '0123456789',
556
+ );
557
+
558
+ if ( in_array( $_melli_code, $pre_check ) ) {
559
+ return 2;
560
+ }
561
+
562
+ if ( ! is_numeric( $melli_code ) ) {
563
+ return 4;
564
+ }
565
+
566
+ $melli_code = (string) preg_replace( '/[^0-9]/', '', $melli_code );
567
+
568
+ if ( strlen( $melli_code ) > 10 || strlen( $melli_code ) < 8 ) {
569
+ return 3;
570
+ }
571
+
572
+ $melli_code = $_melli_code;
573
+
574
+ $list_code = str_split( $melli_code );
575
+ $last = (int) $list_code[9];
576
+ unset( $list_code[9] );
577
+
578
+ $i = 10;
579
+ $sum = 0;
580
+ foreach ( $list_code as $key => $val ) {
581
+ $sum += intval( $val ) * $i;
582
+ $i --;
583
+ }
584
+
585
+ $mod = (int) $sum % 11;
586
+
587
+ if ( $mod >= 2 ) {
588
+ $mod = 11 - $mod;
589
+ }
590
+ if ( $mod != $last ) {
591
+ return 2;
592
+ } else {
593
+ return 1;
594
+ }
595
+ }
596
+
597
+ return false;
598
+ }
599
+
600
+
601
+ public function validator( $result, $value, $form, $field ) {
602
+
603
+ if ( $field["type"] == 'mellicart' ) {
604
+
605
+ $melli_code = ! empty( $value ) ? str_replace( '-', '', $value ) : '';
606
+
607
+ $is_valid = $this->is_valid( $melli_code );
608
+
609
+ if ( $is_valid == 4 ) {
610
+ $message = rgar( $field, 'field_mellicart_sp1' );
611
+ $result['message'] = ! empty( $message ) ? $message : 'کد ملی فقط باید به صورت عدد وارد شود .';
612
+ $result['is_valid'] = false;
613
+
614
+ return $result;
615
+ }
616
+
617
+ if ( $is_valid == 3 ) {
618
+ $message = rgar( $field, 'field_mellicart_sp2' );
619
+ $result['message'] = ! empty( $message ) ? $message : 'کد ملی می بایست 10 رقمی باشد . تنها در صورتی مجاز به استفاده از کد های 8 یا 9 رقمی هستید که ارقام سمت چپ 0 باشند .';
620
+ $result['is_valid'] = false;
621
+
622
+ return $result;
623
+ }
624
+
625
+ if ( $is_valid == 2 ) {
626
+ $message = rgar( $field, 'field_mellicart_sp4' );
627
+ $result['message'] = ! empty( $message ) ? $message : 'کد ملی وارد شده مطابق با استانداردهای کشور نمی باشد .';
628
+ $result['is_valid'] = false;
629
+
630
+ return $result;
631
+ }
632
+
633
+ if ( $field['noDuplicates'] ) {
634
+
635
+ if ( strlen( $melli_code ) == 8 ) {
636
+ $melli_code = '00' . $melli_code;
637
+ }
638
+
639
+ if ( strlen( $melli_code ) == 9 ) {
640
+ $melli_code = '0' . $melli_code;
641
+ }
642
+
643
+ if ( RGFormsModel::is_duplicate( $form['id'], $field, $melli_code ) ) {
644
+ $message = rgar( $field, 'field_mellicart_sp3' );
645
+ $result['message'] = ! empty( $message ) ? $message : 'این کد ملی توسط فرد دیگری ثبت شده است .';
646
+ $result['is_valid'] = false;
647
+
648
+ return $result;
649
+ }
650
+ }
651
+ }
652
+
653
+ return $result;
654
+ }
655
+ }
656
+
657
+ endif;
includes/class-jalali-date.php CHANGED
@@ -1,281 +1,162 @@
1
- <?php if ( ! defined('ABSPATH') ) exit;
2
-
3
- class GFParsi_JalaliDate {
4
-
5
- public function __construct() {
6
-
7
- require_once( GF_PARSI_DIR . '/lib/jdf.php');
8
-
9
- add_action('gform_field_standard_settings' , array( $this, 'jalali_checkbox'), 10, 2);
10
- add_action('gform_editor_js' , array( $this, 'jalali_settings'));
11
- add_filter('gform_field_validation' , array( $this, 'jalali_validator'), 10, 4);
12
- add_filter('gform_tooltips' , array( $this, 'tooltips'));
13
- add_filter('gform_date_min_year' , array( $this, 'jalali_date_min' ), 10, 3);
14
- add_filter('gform_date_max_year' , array( $this, 'jalali_date_max' ), 10, 3);
15
- add_action('gform_enqueue_scripts' , array( $this, 'add_datepicker_jalali' ), 11, 1 );
16
-
17
- // add_action('admin_enqueue_scripts' , array( $this, 'admin_scripts' ));
18
- // add_action('admin_head' , array( $this, 'admin_head' ));
 
 
 
19
  }
20
-
21
  public function tooltips( $tooltips ) {
22
- $tooltips["gform_activate_jalali"] = __('<h6>فعالسازی تاریخ شمسی</h6>در صورتی که از چند فیلد تاریخ استفاده میکنید ، فعالسازی تاریخ شمسی یکی از فیلدها کفایت میکند .<br/>تذکر : با توجه به آزمایشی بودن این قسمت ممکن است تداخل توابع سبب ناسازگاری با برخی قالب ها شود.', 'GF_FA');
 
23
  return $tooltips;
24
  }
25
 
26
- public function jalali_settings(){ ?>
27
- <script type='text/javascript'>
28
- fieldSettings["date"] += ", .jalali_setting";
29
- jQuery(document).bind("gform_load_field_settings", function(event, field, form){
30
- jQuery("#check_jalali").attr("checked", field["check_jalali"] == true);
31
- });
32
- </script>
33
  <?php
34
  }
35
-
36
- public function jalali_checkbox( $position, $form_id ){
37
- if( $position == 25 ) { ?>
38
- <li class="jalali_setting field_setting">
39
- <input type="checkbox" id="check_jalali" onclick="SetFieldProperty('check_jalali', jQuery(this).is(':checked') ? 1 : 0);"/>
40
- <label class="inline gfield_value_label" for="check_jalali" class="inline">
41
- <?php _e( 'Activate Jalali date', 'GF_FA' ); ?>
42
- <?php gform_tooltip("gform_activate_jalali") ?>
43
- </label>
44
- </li>
45
- <?php
 
46
  }
47
  }
48
-
49
- public function add_datepicker_jalali( $form ) {
50
-
51
- if ( !is_admin() && ( wp_script_is( 'gform_datepicker_init' ) || wp_script_is( 'gform_datepicker_init', 'registered' ) ) ) {
52
-
53
- $is_jalali = false;
54
-
55
  foreach ( $form['fields'] as $field ) {
56
-
57
- if ( $field['type'] == 'date' && gfa_get( 'check_jalali', $field ) ) {
58
- $is_jalali = true;
 
 
 
 
 
 
 
 
 
 
59
  break;
60
  }
61
  }
62
-
63
- if ( $is_jalali ) {
64
-
65
- wp_dequeue_script('jquery-ui-datepicker');
66
- wp_deregister_script('jquery-ui-datepicker');
67
-
68
- wp_register_script('jquery-ui-datepicker', GF_PARSI_URL . 'assets/js/jalali.date.picker.js', array( 'jquery', 'jquery-migrate', 'jquery-ui-core', 'gform_gravityforms' ), GF_PARSI_VERSION, true );
69
- wp_enqueue_script( 'jquery-ui-datepicker' );
70
- }
71
-
72
- }
73
  }
74
 
75
- public function admin_head() {
76
- ?>
77
- <script type="text/javascript">
78
- jQuery(document).ready(function ($) {
79
-
80
- jQuery('.datepicker').datepicker({
81
- showOn: 'both',
82
- buttonImage: "<?php echo GFCommon::get_base_url() ?>/images/calendar.png",
83
- buttonImageOnly: true,
84
- changeMonth: true,
85
- changeYear: true,
86
- showButtonPanel: true,
87
- onSelect: function(dateStr, inst) {
88
- var selectedJalaliDate = new JalaliDate(inst.selectedYear, inst.selectedMonth, inst.selectedDay);
89
- var date = selectedJalaliDate.getGregorianDate();
90
- var month= date.getMonth()+1;
91
- var day = date.getDate() < 10 ? '0'+date.getDate() : date.getDate();
92
- var months = date.getMonth() < 9 ? '0'+month : month;
93
- $(this).val(months + '/' + day + '/' + date.getFullYear());
94
- }
95
- });
96
-
97
- jQuery('#export_date_start').datepicker({
98
- changeMonth: true,
99
- changeYear: true,
100
- showButtonPanel: true,
101
- onSelect: function(dateStr, inst) {
102
- var selectedJalaliDate = new JalaliDate(inst.selectedYear, inst.selectedMonth, inst.selectedDay);
103
- var date = selectedJalaliDate.getGregorianDate();
104
- var month= date.getMonth()+1;
105
- var day = date.getDate() < 10 ? '0'+date.getDate() : date.getDate();
106
- var months = date.getMonth() < 9 ? '0'+month : month;
107
- $(this).val(date.getFullYear() + '-' + months + '-' + day);
108
- }
109
- });
110
-
111
- jQuery('#export_date_end').datepicker({
112
- changeMonth: true,
113
- changeYear: true,
114
- showButtonPanel: true,
115
- onSelect: function(dateStr, inst) {
116
- var selectedJalaliDate = new JalaliDate(inst.selectedYear, inst.selectedMonth, inst.selectedDay);
117
- var date = selectedJalaliDate.getGregorianDate();
118
- var month= date.getMonth()+1;
119
- var day = date.getDate() < 10 ? '0'+date.getDate() : date.getDate();
120
- var months = date.getMonth() < 9 ? '0'+month : month;
121
- $(this).val(date.getFullYear() + '-' + months + '-' + day);
122
- }
123
- });
124
-
125
- });
126
-
127
- </script>
128
- <?php
129
- }
130
 
131
- public function admin_scripts() {
132
-
133
- if ( $this->is_gravity_page() && ( wp_script_is( 'jquery-ui-datepicker' ) || wp_script_is( 'jquery-ui-datepicker', 'registered' ) ) ) {
134
-
135
- wp_dequeue_script('jquery-ui-datepicker');
136
- wp_deregister_script('jquery-ui-datepicker');
137
-
138
- if ( ! wp_script_is( 'jquery-ui-core' ))
139
- wp_enqueue_script('jquery-ui-core');
140
-
141
- wp_register_script('gform_datepicker_jalali_admin', GF_PARSI_URL . 'assets/js/jalali.date.picker.js', array( 'jquery', 'jquery-ui-core' ), GF_PARSI_VERSION, true );
142
- wp_enqueue_script( 'gform_datepicker_jalali_admin' );
143
  }
 
 
144
  }
145
-
146
- public function jalali_date_min( $min_year, $form, $field ){
147
-
148
- if ( $field->type == 'date' && !empty($field->check_jalali) ) {
149
- $min_year = GF_gregorian_to_jalali($min_year,03,21);
150
- $min_year = $min_year[0]+1;
151
- }
152
-
153
- return apply_filters( 'jalali_date_min', $min_year, $form, $field );
154
- }
155
-
156
- public function jalali_date_max($max_year, $form, $field ){
157
-
158
- if ( $field->type == 'date' && !empty($field->check_jalali) ) {
159
- $max_year = GF_gregorian_to_jalali($max_year,03,21);
160
- $max_year = $max_year[0]+20;
161
  }
162
-
163
- return apply_filters( 'jalali_date_max', $max_year, $form, $field );
164
  }
165
-
166
- public function jalali_validator($result, $value, $form, $field){
167
-
168
- if ( $field["type"] == "date" ) {
169
-
170
- if ( gfa_get("check_jalali", $field) ) {
171
-
172
- if( is_array($value) && rgempty(0, $value) && rgempty(1, $value)&& rgempty(2, $value))
173
- $value = null;
174
-
175
- if( !empty($value) ) {
176
-
177
- $format = empty($field["dateFormat"]) ? "mdy" : $field["dateFormat"];
178
- $date = GFCommon::parse_date($value, $format);
179
-
180
- if (!empty($date) ){
181
-
182
- if ( intval($date["month"]) >= 1 && intval($date["month"]) <=12 ) {
183
-
184
- $min = 1;
185
- if ( intval($date["month"]) >= 1 && intval($date["month"]) <=6 )
186
- $max = 31;
187
-
188
- if ( intval($date["month"]) >= 7 && intval($date["month"]) <=12 )
189
- $max = 30;
190
-
191
- if ( intval($date["month"]) == 12 && intval($date["day"]) >= 1 && intval($date["day"]) <= 30 ) {
192
- $gregorian = GF_jalali_to_gregorian($date["year"],$date["month"],$date["day"]);
193
- $day = $gregorian[2];
194
- $month = $gregorian[1];
195
- $year = $gregorian[0];
196
- $target = new DateTime("$year-$month-$day 09:00:00");
197
- $target = $target->format('Y-m-d H:i:s');
198
- $target = strtotime ($target);
199
- $leap_year = GF_jdate('L',$target,'','','en');
200
- if ( $leap_year != 1 )
201
- $max = 29;
202
- }
203
-
204
- if ( intval($date["day"]) >= $min && intval($date["day"]) <= $max ) {
205
- $gregorian = GF_jalali_to_gregorian($date["year"],$date["month"],$date["day"]);
206
- $day = $gregorian[2];
207
- $month = $gregorian[1];
208
- $year = $gregorian[0];
209
- $result["is_valid"] = $this->jalali_checkdate($month, $day, $year);
210
- }
211
- else
212
- $result["is_valid"] = false;
213
-
214
- }
215
- else
216
- $result["is_valid"] = false;
217
- }
218
- else
219
- $result["is_valid"] = false;
220
-
221
- if( empty($date) || !$result["is_valid"] ) {
222
-
223
- $format_name = '';
224
- switch($format) {
225
-
226
- case "mdy" :
227
- $format_name = "mm/dd/yyyy";
228
- break;
229
-
230
- case "dmy" :
231
- $format_name = "dd/mm/yyyy";
232
- break;
233
- case "dmy_dash" :
234
- $format_name = "dd-mm-yyyy";
235
- break;
236
- case "dmy_dot" :
237
- $format_name = "dd.mm.yyyy";
238
- break;
239
-
240
- case "ymd_slash" :
241
- $format_name = "yyyy/mm/dd";
242
- break;
243
-
244
- case "ymd_dash" :
245
- $format_name = "yyyy-mm-dd";
246
- break;
247
- case "ymd_dot" :
248
- $format_name = "yyyy.mm.dd";
249
- break;
250
- }
251
-
252
- $result["is_valid"] = false;
253
- $message = $field["dateType"] == "datepicker" ? sprintf(__("Please enter a valid date in the format (%s).", "gravityforms"), $format_name) : __("Please enter a valid date.", "gravityforms");
254
- $result["message"] = empty($field["errorMessage"]) ? $message : $field["errorMessage"];
255
- }
256
- else
257
- $result["is_valid"] = true;
258
  }
259
  }
260
  }
261
-
262
  return $result;
263
  }
264
 
265
- public function jalali_checkdate($month, $day, $year){
266
- if( empty($month) || !is_numeric($month) || empty($day) || !is_numeric($day) || empty($year) || !is_numeric($year) || strlen($year) != 4 )
267
- return false;
268
- return checkdate($month, $day, $year);
269
- }
270
-
271
- public function is_gravity_page() {
272
-
273
- if ( !class_exists('RGForms') )
274
- return false;
275
-
276
- $current_page = trim(strtolower(RGForms::get("page")));
277
- return ( substr( $current_page , 0 , 2) == 'gf' || stripos( $current_page, 'gravity' ) !== false );
 
 
 
 
 
278
  }
 
279
  }
280
 
281
- new GFParsi_JalaliDate();
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+
5
+ class GFPersian_JalaliDate extends GFPersian_Core {
6
+
7
+ public function __construct() {
8
+
9
+ if ( $this->option( 'jalali', '1' ) != '1' ) {
10
+ return;
11
+ }
12
+
13
+ require_once( 'lib/jalali.php' );
14
+ add_filter( 'gform_tooltips', array( $this, 'tooltips' ) );
15
+ add_action( 'gform_editor_js', array( $this, 'jalali_settings' ) );
16
+ add_action( 'gform_field_standard_settings', array( $this, 'jalali_checkbox' ), 10, 2 );
17
+ add_action( 'gform_enqueue_scripts', array( $this, 'jalali_datepicker' ), 11, 1 );
18
+ add_filter( 'gform_date_min_year', array( $this, 'jalali_date_min' ), 10, 3 );
19
+ add_filter( 'gform_date_max_year', array( $this, 'jalali_date_max' ), 10, 3 );
20
+ add_filter( 'gform_field_validation', array( $this, 'jalali_validator' ), 999999, 4 );
21
+ add_filter( 'gform_predefined_choices', array( $this, 'jalali_predefined_choices' ), 1 );
22
  }
23
+
24
  public function tooltips( $tooltips ) {
25
+ $tooltips['gform_activate_jalali'] = '<h6>فعالسازی تاریخ شمسی</h6>در صورتی که از چند فیلد تاریخ استفاده میکنید، فعالسازی تاریخ شمسی یکی از فیلدها کفایت میکند.<br/>تذکر : با توجه به آزمایشی بودن این قسمت ممکن است تداخل توابع سبب ناسازگاری با برخی قالب ها شود.';
26
+
27
  return $tooltips;
28
  }
29
 
30
+ public function jalali_settings() { ?>
31
+ <script type='text/javascript'>
32
+ fieldSettings['date'] += ', .jalali_setting';
33
+ jQuery(document).bind('gform_load_field_settings', function (event, field, form) {
34
+ jQuery('#check_jalali').attr('checked', field['check_jalali'] == true);
35
+ });
36
+ </script>
37
  <?php
38
  }
39
+
40
+ public function jalali_checkbox( $position, $form_id ) {
41
+ if ( $position == 25 ) { ?>
42
+ <li class="jalali_setting field_setting">
43
+ <input type="checkbox" id="check_jalali"
44
+ onclick="SetFieldProperty('check_jalali', jQuery(this).is(':checked') ? 1 : 0);"/>
45
+ <label class="inline gfield_value_label" for="check_jalali" class="inline">
46
+ فعالسازی تاریخ شمسی
47
+ <?php gform_tooltip( "gform_activate_jalali" ) ?>
48
+ </label>
49
+ </li>
50
+ <?php
51
  }
52
  }
53
+
54
+ public function jalali_datepicker( $form ) {
55
+
56
+ if ( ! is_admin() && ( wp_script_is( 'gform_datepicker_init' ) || wp_script_is( 'gform_datepicker_init', 'registered' ) ) ) {
57
+
 
 
58
  foreach ( $form['fields'] as $field ) {
59
+
60
+ if ( $field['type'] == 'date' && rgar( $field, 'check_jalali' ) ) {
61
+
62
+ wp_dequeue_script( 'jquery-ui-datepicker' );
63
+ wp_deregister_script( 'jquery-ui-datepicker' );
64
+
65
+ wp_register_script( 'jquery-ui-datepicker', GF_PERSIAN_URL . 'assets/js/jalali-datepicker.js', array(
66
+ 'jquery',
67
+ 'jquery-migrate',
68
+ 'jquery-ui-core',
69
+ 'gform_gravityforms'
70
+ ), GF_PERSIAN_VERSION, true );
71
+ wp_enqueue_script( 'jquery-ui-datepicker' );
72
  break;
73
  }
74
  }
75
+ }
 
 
 
 
 
 
 
 
 
 
76
  }
77
 
78
+ public function jalali_date_min( $min_year, $form, $field ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
+ if ( rgar( $field, 'type' ) == 'date' && rgar( $field, 'check_jalali' ) ) {
81
+ $min_year = GF_gregorian_to_jalali( $min_year, 03, 21 );
82
+ $min_year = $min_year[0] + 1;
 
 
 
 
 
 
 
 
 
83
  }
84
+
85
+ return apply_filters( 'gform_jalali_date_min_year', $min_year, $form, $field );
86
  }
87
+
88
+ public function jalali_date_max( $max_year, $form, $field ) {
89
+
90
+ if ( rgar( $field, 'type' ) == 'date' && rgar( $field, 'check_jalali' ) ) {
91
+ $max_year = GF_gregorian_to_jalali( $max_year, 03, 21 );
92
+ $max_year = $max_year[0] + 20;
 
 
 
 
 
 
 
 
 
 
93
  }
94
+
95
+ return apply_filters( 'gform_jalali_date_max_year', $max_year, $form, $field );
96
  }
97
+
98
+ public function jalali_validator( $result, $value, $form, $field ) {
99
+
100
+ if ( rgar( $field, 'type' ) == 'date' && rgar( $field, 'check_jalali' ) ) {
101
+
102
+ $format = rgar( $field, 'dateFormat', 'mdy' );
103
+ $formats = array(
104
+ 'mdy' => 'mm/dd/yyyy',
105
+ 'dmy' => 'dd/mm/yyyy',
106
+ 'dmy_dash' => 'dd-mm-yyyy',
107
+ 'dmy_dot' => 'dd.mm.yyyy',
108
+ 'ymd_slash' => 'yyyy/mm/dd',
109
+ 'ymd_dash' => 'yyyy-mm-dd',
110
+ 'ymd_dot' => 'yyyy.mm.dd'
111
+ );
112
+ $format_name = ! empty( $formats[ $format ] ) ? $formats[ $format ] : '';
113
+ $message = $format_name && rgar( $field, 'dateType' ) == 'datepicker' ? sprintf( esc_html__( 'Please enter a valid date in the format (%s).', 'gravityforms' ), $format_name ) : esc_html__( 'Please enter a valid date.', 'gravityforms' );
114
+
115
+ /*این شرط مشخص میکنه فقط اگر خطایی وجود نداشت و یا اگر خطا مربوط به ولیدیت تاریخ بود وارد بررسی شود*/
116
+ if ( ! empty( $result['message'] ) && $message != $result['message'] ) {
117
+ return $result;
118
+ }
119
+
120
+ if ( is_array( $value ) && rgempty( 0, $value ) && rgempty( 1, $value ) && rgempty( 2, $value ) ) {
121
+ $value = null;
122
+ }
123
+
124
+ if ( ! empty( $value ) ) {
125
+ $date = GFCommon::parse_date( $value, $format );
126
+ $day = intval( rgar( $date, 'day' ) );
127
+ $month = intval( rgar( $date, 'month' ) );
128
+ $year = intval( rgar( $date, 'year' ) );
129
+
130
+ $result['is_valid'] = GF_jcheckdate( $month, $day, $year );
131
+ if ( ! $result['is_valid'] && empty( $result['message'] ) ) {
132
+ $result['message'] = $message;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  }
134
  }
135
  }
136
+
137
  return $result;
138
  }
139
 
140
+ public function jalali_predefined_choices( $choices ) {
141
+
142
+ $month['ماه های ایران'] = array(
143
+ 'فروردین',
144
+ 'اردیبهشت',
145
+ 'خرداد',
146
+ 'تیر',
147
+ 'مرداد',
148
+ 'شهریور',
149
+ 'مهر',
150
+ 'آبان',
151
+ 'آذر',
152
+ 'دی',
153
+ 'بهمن',
154
+ 'اسفند'
155
+ );
156
+
157
+ return array_merge( $month, $choices );
158
  }
159
+
160
  }
161
 
162
+ new GFPersian_JalaliDate();
includes/class-live-preview.php CHANGED
@@ -1,106 +1,112 @@
1
- <?php if ( ! defined('ABSPATH') ) exit;
2
-
3
- class GFParsi_LivePreview {
4
-
5
- var $post_type = 'gf_live_preview';
6
-
7
- public function __construct( $args = array() ) {
8
-
9
- if( ! property_exists( 'GFCommon', 'version' ) || ! version_compare( GFCommon::$version, '1.8', '>=' ) )
10
- return;
11
-
12
- $this->_args = wp_parse_args( $args, array(
13
- 'id' => 0,
14
- 'title' => true,
15
- 'description' => true,
16
- 'ajax' => true
17
- ) );
18
-
19
- add_action( 'init', array( $this, 'register_preview_post_type' ) );
20
- add_action( 'wp', array( $this, 'maybe_load_preview_functionality' ) );
21
- add_action( 'admin_footer', array( $this, 'display_preview_link' ) );
22
-
23
- add_action( 'admin_footer', array( $this, 'display_preview_link' ) );
 
 
 
 
 
 
24
  add_filter( 'gform_form_actions', array( $this, 'gform_form_actions' ), 10, 2 );
25
- }
26
-
27
- public function register_preview_post_type() {
28
-
29
  $args = array(
30
- 'label' => __( 'Form Preview', 'GF_FA' ),
31
- 'description' => __( 'A post type created for previewing Gravity Forms forms on the frontend.', 'GF_FA' ),
32
- 'public' => false,
33
  'publicly_queryable' => true,
34
- 'has_archive' => true,
35
- 'can_export' => false,
36
- 'supports' => false
37
  );
38
-
39
  register_post_type( $this->post_type, $args );
40
-
41
  // create preview post
42
  $preview_post = get_posts( array( 'post_type' => $this->post_type ) );
43
- if( empty( $preview_post ) ) {
44
- $post_id = wp_insert_post( array(
45
- 'post_type' => $this->post_type,
46
- 'post_title' => __( 'Form Preview', 'GF_FA' ),
47
  'post_status' => 'publish'
48
  ) );
49
  }
50
-
51
- }
52
-
53
- public function maybe_load_preview_functionality() {
54
- global $wp_query;
55
-
56
- if( ! $this->is_live_preview() )
 
57
  return;
58
-
59
- $this->live_preview_hooks();
60
-
 
 
61
  // quick hack for GF to ensure scripts/styles are loaded correctly
62
- foreach( $wp_query->posts as &$post ) {
63
  $post->post_content = $this->get_shortcode();
64
  }
65
-
66
- }
67
-
68
- public function live_preview_hooks() {
69
-
70
- add_filter( 'template_include', array( $this, 'load_preview_template' ) );
71
- add_filter( 'the_content', array( $this, 'modify_preview_post_content' ) );
72
-
73
- }
74
-
75
- public function gform_form_actions( $form_actions , $form_id ) {
76
-
77
-
78
- if ( !empty($_GET['trash']) && $_GET['trash'] == 1 )
79
  return $form_actions;
80
-
81
- $capabilities = array( 'gravityforms_view_entries', 'gravityforms_edit_entries', 'gravityforms_delete_entries' );
82
-
83
- $ajax_true_url = get_bloginfo("wpurl") . '/?post_type='.$this->post_type.'&id=' . $form_id;
84
- $ajax_false_url = get_bloginfo("wpurl") . '/?post_type='.$this->post_type.'&ajax=false&id=' . $form_id;
85
-
 
 
 
 
 
86
  $sub_menu_items = array();
87
-
88
  $sub_menu_items[] = array(
89
  'url' => $ajax_true_url,
90
- 'label' => __( 'Ajax option enabled' , 'GF_FA'),
91
  'capabilities' => $capabilities
92
  );
93
-
94
  $sub_menu_items[] = array(
95
  'url' => $ajax_false_url,
96
- 'label' => __( 'Ajax option disabled' , 'GF_FA'),
97
  'capabilities' => $capabilities
98
  );
99
-
100
  $form_actions['live_preview'] = array(
101
- 'label' => __( 'Live Preview', 'GF_FA' ),
102
  'icon' => '<i class="fa fa-cogs fa-lg"></i>',
103
- 'title' => __( 'Live Preview', 'GF_FA' ),
104
  'url' => '',
105
  'menu_class' => 'gf_form_toolbar_settings',
106
  'link_class' => 'gf_toolbar_active',
@@ -108,83 +114,83 @@ class GFParsi_LivePreview {
108
  'capabilities' => $capabilities,
109
  'priority' => 650,
110
  );
111
-
112
  return $form_actions;
113
  }
114
-
115
- public function display_preview_link() {
116
-
117
- if( ! $this->is_applicable_page() || apply_filters( 'gf_live_preview_page' , false) )
118
- return;
119
-
120
- $form_id = apply_filters( 'gf_live_preview_id' , rgget( 'id' ) );
121
- $ajax_true_url = get_bloginfo("wpurl") . '/?post_type='.$this->post_type.'&id=' . $form_id;
122
- $ajax_false_url = get_bloginfo("wpurl") . '/?post_type='.$this->post_type.'&ajax=false&id=' . $form_id;
123
- ?>
124
-
 
 
 
 
125
  <script type="text/javascript">
126
- (function($){
127
- $( '<li class="gf_form_toolbar_preview">'+
128
- '<a style="position:relative" id="gf-live-preview" target="_blank" href="<?php echo $ajax_true_url; ?>" class="" >' +
129
- '<i class="fa fa-eye" style="position: absolute; text-shadow: 0px 0px 5px rgb(255, 255, 255); z-index: 99; line-height: 7px; left: 0px font-size: 9px; top: 6px; background-color: rgb(243, 243, 243);"></i>' +
130
- '<i class="fa fa-file-o" style="margin-left: 5px; line-height: 12px; font-size: 18px; position: relative; top: 2px;"></i>' +
131
- '<?php _e( 'Live Preview', 'GF_FA' ); ?>' +
132
- '</a>'+
133
- '<div class="gf_submenu"><ul>'+
134
- '<li class=""><a target="_blank" href="<?php echo $ajax_true_url; ?>"><?php _e( 'Ajax option enabled' , 'GF_FA'); ?></a></li>'+
135
- '<li class=""><a target="_blank" href="<?php echo $ajax_false_url; ?>"><?php _e( 'Ajax option disabled', 'GF_FA' ); ?></a></li>'+
136
- '</ul></div>'+
137
- '</li>' )
138
- .insertAfter( 'li.gf_form_toolbar_preview' );
139
- })(jQuery);
140
  </script>
141
- <?php
142
- }
143
-
144
- public function is_applicable_page() {
145
- return in_array( rgget( 'page' ), array( 'gf_edit_forms', 'gf_entries' ) ) && rgget( 'id' );
146
- }
147
-
148
  public function load_preview_template( $template ) {
149
- return get_page_template();
150
  }
151
-
152
- public function modify_preview_post_content( $content ) {
153
  return $this->get_shortcode();
154
- }
155
-
156
- public function get_shortcode( $args = array() ) {
157
-
158
- if( ! is_user_logged_in() )
159
- return '<p>' . __( 'You need to log in to preview forms.', 'GF_FA') . '</p>' . wp_login_form( array( 'echo' => false ) );
160
-
161
- if( ! GFCommon::current_user_can_any( 'gravityforms_preview_forms' ) )
162
- return __( 'Oops! It doesn\'t look like you have the necessary permission to preview this form.', 'GF_FA' );
163
-
164
- if( empty( $args ) )
165
- $args = $this->get_shortcode_parameters_from_query_string();
166
-
167
- extract( wp_parse_args( $args, $this->_args ) );
168
-
169
- $title = $title === true ? 'true' : 'false';
170
- $description = $description === true ? 'true' : 'false';
171
- $ajax = $ajax === true ? 'true' : 'false';
172
-
 
 
 
 
173
  return "[gravityform id='$id' title='$title' description='$description' ajax='$ajax']";
174
- }
175
-
176
- public function get_shortcode_parameters_from_query_string() {
177
  return array_filter( array(
178
  'id' => rgget( 'id' ),
179
  'title' => rgget( 'title' ),
180
  'description' => rgget( 'description' ),
181
  'ajax' => rgget( 'ajax' )
182
  ) );
183
- }
184
-
185
- public function is_live_preview() {
186
- return is_post_type_archive( $this->post_type );
187
- }
188
-
189
  }
190
- new GFParsi_LivePreview();
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+
5
+ class GFPersian_LivePreview extends GFPersian_Core {
6
+
7
+ private $post_type = 'gf_live_preview';
8
+ private $_args;
9
+
10
+ public function __construct( $args = array() ) {
11
+
12
+ if ( $this->option( 'live_preview', '1' ) != '1' ) {
13
+ return;
14
+ }
15
+
16
+ if ( ! property_exists( 'GFCommon', 'version' ) || version_compare( GFCommon::$version, '1.8', '<' ) ) {
17
+ return;
18
+ }
19
+
20
+ $this->_args = wp_parse_args( $args, array(
21
+ 'id' => 0,
22
+ 'title' => true,
23
+ 'description' => true,
24
+ 'ajax' => true
25
+ ) );
26
+
27
+ add_action( 'init', array( $this, 'register_preview_post_type' ) );
28
+ add_action( 'wp', array( $this, 'maybe_load_preview_functionality' ) );
29
+ add_action( 'admin_footer', array( $this, 'display_preview_link' ) );
30
  add_filter( 'gform_form_actions', array( $this, 'gform_form_actions' ), 10, 2 );
31
+ }
32
+
33
+ public function register_preview_post_type() {
34
+
35
  $args = array(
36
+ 'label' => 'پیشنمایش زنده',
37
+ 'description' => 'پیشنمایش فرم در فرانت اند به صورت یک پست تایپ مجازی',
38
+ 'public' => false,
39
  'publicly_queryable' => true,
40
+ 'has_archive' => true,
41
+ 'can_export' => false,
42
+ 'supports' => false
43
  );
44
+
45
  register_post_type( $this->post_type, $args );
46
+
47
  // create preview post
48
  $preview_post = get_posts( array( 'post_type' => $this->post_type ) );
49
+ if ( empty( $preview_post ) ) {
50
+ wp_insert_post( array(
51
+ 'post_type' => $this->post_type,
52
+ 'post_title' => 'پیشنمایش زنده',
53
  'post_status' => 'publish'
54
  ) );
55
  }
56
+
57
+ }
58
+
59
+ public function maybe_load_preview_functionality() {
60
+
61
+ global $wp_query;
62
+
63
+ if ( ! is_post_type_archive( $this->post_type ) ) {
64
  return;
65
+ }
66
+
67
+ add_filter( 'template_include', array( $this, 'load_preview_template' ) );
68
+ add_filter( 'the_content', array( $this, 'modify_preview_post_content' ) );
69
+
70
  // quick hack for GF to ensure scripts/styles are loaded correctly
71
+ foreach ( $wp_query->posts as &$post ) {
72
  $post->post_content = $this->get_shortcode();
73
  }
74
+
75
+ }
76
+
77
+ public function gform_form_actions( $form_actions, $form_id ) {
78
+
79
+ if ( ! empty( $_GET['trash'] ) && $_GET['trash'] == 1 ) {
 
 
 
 
 
 
 
 
80
  return $form_actions;
81
+ }
82
+
83
+ $capabilities = array(
84
+ 'gravityforms_view_entries',
85
+ 'gravityforms_edit_entries',
86
+ 'gravityforms_delete_entries'
87
+ );
88
+
89
+ $ajax_true_url = get_bloginfo( "wpurl" ) . '/?post_type=' . $this->post_type . '&id=' . $form_id;
90
+ $ajax_false_url = get_bloginfo( "wpurl" ) . '/?post_type=' . $this->post_type . '&ajax=false&id=' . $form_id;
91
+
92
  $sub_menu_items = array();
93
+
94
  $sub_menu_items[] = array(
95
  'url' => $ajax_true_url,
96
+ 'label' => 'حالت آیجکس فعال',
97
  'capabilities' => $capabilities
98
  );
99
+
100
  $sub_menu_items[] = array(
101
  'url' => $ajax_false_url,
102
+ 'label' => 'حالت آیجکس غیرفعال',
103
  'capabilities' => $capabilities
104
  );
105
+
106
  $form_actions['live_preview'] = array(
107
+ 'label' => 'پیشنمایش زنده',
108
  'icon' => '<i class="fa fa-cogs fa-lg"></i>',
109
+ 'title' => 'پیشنمایش زنده',
110
  'url' => '',
111
  'menu_class' => 'gf_form_toolbar_settings',
112
  'link_class' => 'gf_toolbar_active',
114
  'capabilities' => $capabilities,
115
  'priority' => 650,
116
  );
117
+
118
  return $form_actions;
119
  }
120
+
121
+ public function display_preview_link() {
122
+
123
+ if ( ! in_array( rgget( 'page' ), array(
124
+ 'gf_edit_forms',
125
+ 'gf_entries'
126
+ ) ) || ! rgget( 'id' ) || apply_filters( 'gf_live_preview_page', false ) ) {
127
+ return;
128
+ }
129
+
130
+ $form_id = apply_filters( 'gf_live_preview_id', rgget( 'id' ) );
131
+ $ajax_true_url = get_bloginfo( "wpurl" ) . '/?post_type=' . $this->post_type . '&id=' . $form_id;
132
+ $ajax_false_url = get_bloginfo( "wpurl" ) . '/?post_type=' . $this->post_type . '&ajax=false&id=' . $form_id;
133
+ ?>
134
+
135
  <script type="text/javascript">
136
+ (function ($) {
137
+ $('<li class="gf_form_toolbar_preview">' +
138
+ '<a style="position:relative" id="gf-live-preview" target="_blank" href="<?php echo $ajax_true_url; ?>" class="" >' +
139
+ '<i class="fa fa-eye" style="position: absolute; text-shadow: 0px 0px 5px rgb(255, 255, 255); z-index: 99; line-height: 7px; left: 0px font-size: 9px; background-color: rgb(243, 243, 243);"></i>' +
140
+ '<i class="fa fa-file-o" style="margin-left: 5px; line-height: 12px; font-size: 18px; position: relative;"></i>' +
141
+ 'پیش نمایش زنده' +
142
+ '</a>' +
143
+ '<div class="gf_submenu"><ul>' +
144
+ '<li class=""><a target="_blank" href="<?php echo $ajax_true_url; ?>">حالت آیجکس فعال</a></li>' +
145
+ '<li class=""><a target="_blank" href="<?php echo $ajax_false_url; ?>">حالت آیجکس غیرفعال</a></li>' +
146
+ '</ul></div>' +
147
+ '</li>')
148
+ .insertAfter('li.gf_form_toolbar_preview');
149
+ })(jQuery);
150
  </script>
151
+ <?php
152
+ }
153
+
 
 
 
 
154
  public function load_preview_template( $template ) {
155
+ return get_page_template();
156
  }
157
+
158
+ public function modify_preview_post_content( $content ) {
159
  return $this->get_shortcode();
160
+ }
161
+
162
+ public function get_shortcode( $args = array() ) {
163
+
164
+ if ( ! is_user_logged_in() ) {
165
+ return '<p>برای دسترسی به این قسمت باید لاگین شوید.</p>' . wp_login_form( array( 'echo' => false ) );
166
+ }
167
+
168
+ if ( ! GFCommon::current_user_can_any( 'gravityforms_preview_forms' ) ) {
169
+ return 'شما مجوز دسترسی به این بخش را ندارید.';
170
+ }
171
+
172
+ if ( empty( $args ) ) {
173
+ $args = $this->get_shortcode_parameters_from_query_string();
174
+ }
175
+
176
+ extract( wp_parse_args( $args, $this->_args ) );
177
+
178
+ $title = ! empty( $title ) && $title === true ? 'true' : 'false';
179
+ $description = ! empty( $description ) && $description === true ? 'true' : 'false';
180
+ $ajax = ! empty( $ajax ) && $ajax === true ? 'true' : 'false';
181
+ $id = ! empty( $id ) && $id > 0 ? $id : 0;
182
+
183
  return "[gravityform id='$id' title='$title' description='$description' ajax='$ajax']";
184
+ }
185
+
186
+ public function get_shortcode_parameters_from_query_string() {
187
  return array_filter( array(
188
  'id' => rgget( 'id' ),
189
  'title' => rgget( 'title' ),
190
  'description' => rgget( 'description' ),
191
  'ajax' => rgget( 'ajax' )
192
  ) );
193
+ }
 
 
 
 
 
194
  }
195
+
196
+ new GFPersian_LivePreview();
includes/class-melli-code.php DELETED
@@ -1,434 +0,0 @@
1
- <?php if ( ! defined('ABSPATH') ) exit;
2
-
3
- class GFParsi_MelliCode {
4
-
5
- private $field = array();
6
-
7
- public function __construct() {
8
-
9
- if( is_admin() ) {
10
- add_filter('gform_add_field_buttons' , array( $this, 'button'));
11
- add_filter('gform_field_type_title' , array( $this, 'title'));
12
- add_filter('gform_editor_js_set_default_values' , array( $this, 'label'));
13
- add_action('gform_editor_js' , array( $this, 'settings'));
14
- add_action('gform_field_standard_settings' , array( $this, 'standard_settings'), 10, 2);
15
- add_filter('gform_tooltips' , array( $this, 'tooltips'));
16
- add_filter('gform_admin_pre_render' , array( $this ,'admin_conditional_logic' ) );
17
- }
18
-
19
- add_action('gform_field_input' , array( $this, 'input'), 10, 5);
20
- add_action('gform_field_css_class' , array( $this, 'classes'), 10, 3);
21
- add_action('gform_pre_submission' , array( $this, 'pre_submission' ) );
22
- add_filter('gform_field_content' , array( $this, 'city'), 10, 5);
23
- add_filter('gform_field_validation' , array( $this, 'validator'), 10, 4);
24
- add_action('wp_footer' , array( $this, 'js'));
25
- add_action('gform_enqueue_scripts' , array( $this, 'external_js') , 10 , 2 );
26
- }
27
-
28
- public function button( $field_groups ) {
29
- foreach( $field_groups as &$group ){
30
- if( $group["name"] == "advanced_fields" ){
31
- $group["fields"][] = array(
32
- "class"=>"button",
33
- "value" => __('National ID', 'GF_FA'),
34
- "onclick" => "StartAddField('mellicart');"
35
- );
36
-
37
- }
38
- }
39
- return $field_groups;
40
- }
41
-
42
- public function title($type) {
43
- if ($type == 'mellicart') {
44
- return __('National ID', 'GF_FA');
45
- }
46
- }
47
-
48
- public function label(){
49
- ?>
50
- case "mellicart" :
51
- field.label = '<?php _e('National ID', 'GF_FA') ?>';
52
- break;
53
- <?php
54
- }
55
-
56
- public function classes($classes, $field, $form){
57
- if( $field["type"] == "mellicart" ){
58
- $classes .= " gform_melli_code";
59
- }
60
- return $classes;
61
- }
62
-
63
- public function tooltips( $tooltips ) {
64
- $tooltips['gform_melli_code_city'] = __('<h6>نمایش لحظه ای شهر از روی کد ملی </h6>نمایش شهر و پیغام زیر فیلد کد ملی بعد از پر شدن فیلد . تذکر : در صورتی که این گزینه را فعال نمایید ،ممکن است فراخوانی شهر های ایران با توجه به زیاد بودن آنها سبب سنگین شدن صفحه گردد.' , 'GF_FA');
65
- $tooltips['gform_melli_code_seperate'] = __('<h6>جدا سازی ارقام</h6>در صورتی که این گزینه را فعال نمایید ، پس از پر شدن فیلد کد ملی ، <strong>در صورتی که کد ملی وارد شده صحیح تشخصی داده شود</strong> ؛ کد ملی به صورت زیر در خواهد آمد و در غیر این صورت علی صحیح نبودن کد ملی زیر فیلد نمایش داده خواهد شد :<br>xxx-xxxxxx-x' , 'GF_FA');
66
- $tooltips['gform_melli_code_abnormal'] = __('با توجه به اینکه کد ملی فقط باید به صورت عدد باشد ، در صورتی که کاراکتری غیر از عدد وارد شده باشد پیغام خطا نمایش داده خواهد شد .<br/>پیغام پیشفرض : کد ملی فقط باید به صورت عدد وارد شود .' , 'GF_FA');
67
- $tooltips['gform_melli_code_len'] = __('با توجه به اینکه کد ملی می بایست 10 رقمی باشد اگر تعداد رقم وارد شده ، اشتباه باشد پیغام خطا نمایش داده خواهد شد .<br>پیغام پیشفرض : کد ملی می بایست 10 رقمی باشد . تنها در صورتی مجاز به استفاده از کد های 8 یا 9 رقمی هستید که ارقام سمت چپ 0 باشند .' , 'GF_FA');
68
- $tooltips['gform_melli_code_dup'] = __('در صورتی که از تب وِیژگی تیک گزینه بدون تکرار را زده باشید ؛ بعد از پر شدن فرم و زدن دکمه ارسال پیغامی مبتنی بر تکراری بودن کد ملی نمایش داده خواهد شد . <br/>پیغام پیشفرض : این کد ملی توسط فرد دیگری ثبت شده است .' , 'GF_FA');
69
- $tooltips['gform_melli_code_noStandard'] = __('در صورتی که کد ملی وارد شده مطابق با الگوریتم کشور نباشد پیغام خطا نمایش داده خواهد شد .<br/>پیغام پیشفرض : کد ملی وارد شده مطابق با استانداردهای کشور نمی باشد .' , 'GF_FA');
70
- return $tooltips;
71
- }
72
-
73
- public function input($input, $field, $value, $lead_id, $form_id ){
74
-
75
- if ( $field["type"] == "mellicart" ) {
76
-
77
- $is_admin = is_admin();
78
- $is_frontend = ! $is_admin;
79
- $is_form_editor = ( $is_admin && GFForms::get( 'view' ) != 'entry' );
80
- $is_entry_page = ( $is_admin && GFForms::get( 'view' ) == 'entry' );
81
-
82
- if ( ! $is_admin && ( RGFormsModel::get_input_type( $field ) == 'adminonly_hidden') ) {
83
- return '';
84
- }
85
-
86
- $field_id = $field["id"];
87
- $form_id = $is_admin && empty($form_id) ? rgget("id") : $form_id;
88
-
89
- $disabled_text = ( $is_admin && GFForms::get( 'view' ) != 'entry' ) ? "disabled='disabled'" : '';
90
-
91
- $size = rgar($field, "size");
92
- $class_suffix = GFForms::get( 'view' ) == 'entry' ? '_admin' : '';
93
- $class = $size . $class_suffix;
94
-
95
- $html5_attributes = '';
96
-
97
- $tabindex = GFCommon::get_tabindex();
98
-
99
-
100
- //$this->get_conditional_logic_event( 'keyup' ) //text or radio
101
- //$this->get_conditional_logic_event( 'change' ) //select
102
- //$this->get_conditional_logic_event( 'click' ) // checkbox or radio
103
- //note : radio has keyup and click
104
- $logic_event = ! $is_form_editor && ! $is_entry_page ? $field->get_conditional_logic_event( 'keyup' ) : '';
105
-
106
- $input = '<div class="ginput_container ginput_container_text ginput_container_melli_code">';
107
- $input .= '<input onblur="melli_code_'.$field_id.'(this);" name="input_'.$field_id.'" id="input_'.$form_id.'_'.$field_id.'" type="text" value="'.esc_attr($value).'" class="melli_code '.esc_attr($size).'" '.$tabindex.' '.$logic_event.' '.$html5_attributes.' '.$disabled_text.'/>';
108
- $input .= '</div>';
109
-
110
- if ( $is_frontend ) {
111
- $input .= '<span class="city melli_code" id="city_'.$field_id.'"></span>';
112
- }
113
-
114
- }
115
-
116
- return $input;
117
- }
118
-
119
- public function settings(){ ?>
120
- <script type='text/javascript'>
121
- fieldSettings["mellicart"] = ".placeholder_setting, .input_mask_setting, .label_placement_setting, .prepopulate_field_setting, .conditional_logic_field_setting, .label_setting, .admin_label_setting, .size_setting, .rules_setting, .visibility_setting, .duplicate_setting, .default_value_setting, .description_setting, .css_class_setting, .mellicart_setting";
122
- jQuery(document).bind("gform_load_field_settings", function(event, field, form){
123
- jQuery("#field_mellicart").attr("checked", field["field_mellicart"] == true);
124
- jQuery("#field_mellicart_sp").attr("checked", field["field_mellicart_sp"] == true);
125
- jQuery("#field_mellicart_sp1").val(field["field_mellicart_sp1"]);
126
- jQuery("#field_mellicart_sp2").val(field["field_mellicart_sp2"]);
127
- jQuery("#field_mellicart_sp3").val(field["field_mellicart_sp3"]);
128
- jQuery("#field_mellicart_sp4").val(field["field_mellicart_sp4"]);
129
- });
130
- </script>
131
- <?php
132
- }
133
-
134
-
135
- public function admin_conditional_logic( $form ) {
136
-
137
- if ( GFCommon::is_entry_detail() ) {
138
- return $form;
139
- }
140
-
141
- echo "<script type='text/javascript'>" .
142
- " gform.addFilter('gform_is_conditional_logic_field', function (isConditionalLogicField, field) {" .
143
- " return field.type == 'mellicart' ? true : isConditionalLogicField;" .
144
- ' });' .
145
- " gform.addFilter('gform_conditional_logic_operators', function (operators, objectType, fieldId) {" .
146
- ' var targetField = GetFieldById(fieldId);' .
147
- " if (targetField && targetField['type'] == 'mellicart') {" .
148
- " operators = {'is':'is','isnot':'isNot', '>':'greaterThan', '<':'lessThan', 'contains':'contains', 'starts_with':'startsWith', 'ends_with':'endsWith'};" .
149
- ' }' .
150
- ' return operators;' .
151
- ' });' .
152
- '</script>';
153
-
154
- return $form;
155
- }
156
-
157
- public function standard_settings( $position, $form_id ){
158
-
159
- if( $position == 50 ){ ?>
160
-
161
- <li class="mellicart_setting field_setting">
162
-
163
- <input type="checkbox" id="field_mellicart" onclick="SetFieldProperty('field_mellicart', this.checked);" />
164
- <label for="field_mellicart" class="inline">
165
- <?php _e("نمایش شهر بر اساس کد ملی", "GF_FA"); ?>
166
- <?php gform_tooltip("gform_melli_code_city"); ?>
167
- </label>
168
-
169
-
170
- <br/>
171
- <input type="checkbox" id="field_mellicart_sp" onclick="SetFieldProperty('field_mellicart_sp', this.checked);" />
172
- <label for="field_mellicart_sp" class="inline">
173
- <?php _e("جدا سازی خودکار ارقام توسط خط فاصله", "GF_FA"); ?>
174
- <?php gform_tooltip("gform_melli_code_seperate"); ?>
175
- </label>
176
- <br/>
177
-
178
-
179
- <br/>
180
- <label for="field_mellicart_sp1" >
181
- <?php _e("پیغام زمانی که مقدار وارد شده شامل کاراکتر غیر عددی باشد", "GF_FA"); ?>
182
- <?php gform_tooltip("gform_melli_code_abnormal"); ?>
183
- </label>
184
- <input type="text" class="fieldwidth-3" id="field_mellicart_sp1" size="35" onkeyup="SetFieldProperty('field_mellicart_sp1', this.value);" />
185
- <br/>
186
-
187
-
188
- <br/>
189
- <label for="field_mellicart_sp2" >
190
- <?php _e("پیغام زمانیکه تعداد ارقام وارد شده استاندارد نباشد", "GF_FA"); ?>
191
- <?php gform_tooltip("gform_melli_code_len"); ?>
192
- </label>
193
- <input type="text" class="fieldwidth-3" id="field_mellicart_sp2" size="35" onkeyup="SetFieldProperty('field_mellicart_sp2', this.value);" />
194
- <br/>
195
-
196
-
197
- <br/>
198
- <label for="field_mellicart_sp3" >
199
- <?php _e("پیغام زمانیکه کد ملی وارد شده قبلا ثبت شده باشد", "GF_FA"); ?>
200
- <?php gform_tooltip("gform_melli_code_dup"); ?>
201
- </label>
202
- <input type="text" class="fieldwidth-3" id="field_mellicart_sp3" size="35" onkeyup="SetFieldProperty('field_mellicart_sp3', this.value);" />
203
- <br/>
204
-
205
-
206
- <br/>
207
- <label for="field_mellicart_sp4" >
208
- <?php _e("پیغام زمانیکه کد ملی وارد شده مطابق با الگوی ملی نباشد", "GF_FA"); ?>
209
- <?php gform_tooltip("gform_melli_code_noStandard"); ?>
210
- </label>
211
- <input type="text" class="fieldwidth-3" id="field_mellicart_sp4" size="35" onkeyup="SetFieldProperty('field_mellicart_sp4', this.value);" />
212
- <br/>
213
-
214
-
215
- </li>
216
- <?php
217
- }
218
- }
219
-
220
-
221
- public function pre_submission( $form ) {
222
-
223
- $mellicart_fields = GFCommon::get_fields_by_type( $form, array( 'mellicart' ) );
224
-
225
- foreach ( (array) $mellicart_fields as $field ) {
226
-
227
- $input_name = "input_{$field['id']}";
228
- $input_value = ! rgempty( $input_name ) ? rgpost( $input_name ) : '';
229
-
230
- if ( !empty( $input_value ) ) {
231
-
232
- if ( strlen($input_value) == 8 ) {
233
- $_POST["input_{$field['id']}"] = '00'.$input_value;
234
- }
235
- elseif ( strlen($input_value) == 9 ) {
236
- $_POST["input_{$field['id']}"] = '0'.$input_value;
237
- }
238
- else {
239
- $_POST["input_{$field['id']}"] = $input_value;
240
- }
241
- }
242
- }
243
- }
244
-
245
- public function city( $content, $field, $value, $lead_id, $form_id ){
246
-
247
- if ( $field['type'] == 'mellicart' ) {
248
- if ( ! is_admin() ) {
249
- $this->field[] = $field;
250
- }
251
- }
252
- return $content;
253
- }
254
-
255
- public function external_js( $form , $ajax ) {
256
-
257
- $melli_code = GFCommon::get_fields_by_type( $form, array( 'mellicart' ) );
258
-
259
- foreach ( (array) $melli_code as $field ) {
260
-
261
- $is_seperate = gfa_get('field_mellicart_sp', $field);
262
- $is_seperate = !empty($is_seperate) ? $is_seperate : false;
263
-
264
- $show_city = gfa_get('field_mellicart', $field);
265
- $show_city = !empty($show_city) ? $show_city : false;
266
-
267
- if ( $show_city || $is_seperate) {
268
- wp_register_script( 'gform_mellicode', GF_PARSI_URL . 'assets/js/melli-code.min.js', array() , GF_PARSI_VERSION, false );
269
- wp_enqueue_script( 'gform_mellicode' );
270
- break;
271
- }
272
- }
273
- }
274
-
275
- public function js() {
276
-
277
- $fields = $this->field;
278
-
279
- if ( empty($fields) )
280
- return;
281
-
282
- foreach( (array) $fields as $field ) {
283
-
284
- $is_seperate = gfa_get('field_mellicart_sp', $field);
285
- $is_seperate = !empty($is_seperate) && $is_seperate ? 1 : 0;
286
-
287
- $show_city = gfa_get('field_mellicart', $field);
288
- $show_city = !empty($show_city) && $show_city ? 1 : 0;
289
-
290
- if ( !$show_city && !$is_seperate )
291
- return;
292
-
293
- $message1 = gfa_get('field_mellicart_sp1', $field);
294
- $message1 = !empty($message1) ? $message1 : __('کد ملی فقط باید به صورت عدد وارد شود .', 'GF_FA');
295
-
296
- $message2 = gfa_get('field_mellicart_sp2', $field);
297
- $message2 = !empty($message2) ? $message2 : __('کد ملی می بایست 10 رقمی باشد .', 'GF_FA');
298
-
299
- $message3 = gfa_get('field_mellicart_sp4', $field);
300
- $message3 = !empty($message3) ? $message3 : __('کد ملی وارد شده مطابق با استانداردهای کشور نمی باشد .', 'GF_FA');
301
- ?>
302
-
303
- <script type="text/javascript">
304
- function melli_code_<?php echo $field['id']; ?> (melli_code) {
305
- var field_id = "<?php echo $field['id'] ?>";
306
- var message1 = "<?php echo $message1 ?>";
307
- var message2 = "<?php echo $message2 ?>";
308
- var message3 = "<?php echo $message3 ?>";
309
- var show_city = <?php echo $show_city ?>;
310
- var is_seperate = <?php echo $is_seperate ?>;
311
- melli_code_function( melli_code, field_id , message1 , message2 , message3 , is_seperate , show_city);
312
- }
313
- </script>
314
-
315
- <?php
316
- }
317
- }
318
-
319
- public function is_valid( $melli_code = '' ){
320
-
321
- if ( !empty($melli_code) ) {
322
-
323
- $_melli_code = $melli_code;
324
-
325
- if( strlen($melli_code) == 8 )
326
- $_melli_code = '00' . $melli_code;
327
-
328
- if( strlen($melli_code) == 9 )
329
- $_melli_code = '0' . $melli_code;
330
-
331
- $pre_check = array(
332
- '0000000000',
333
- '1111111111',
334
- '2222222222',
335
- '3333333333',
336
- '4444444444',
337
- '5555555555',
338
- '6666666666',
339
- '7777777777',
340
- '8888888888',
341
- '9999999999',
342
- );
343
-
344
- if( in_array( $_melli_code , $pre_check ) )
345
- return 2;
346
-
347
- if( ! is_numeric($melli_code) )
348
- return 4;
349
-
350
- $melli_code = (string) preg_replace('/[^0-9]/','',$melli_code);
351
-
352
- if( strlen($melli_code) > 10 || strlen($melli_code) <8 )
353
- return 3;
354
-
355
- $melli_code = $_melli_code;
356
-
357
- $list_code = str_split($melli_code);
358
- $last = (int) $list_code[9];
359
- unset($list_code[9]);
360
-
361
- $i = 10;
362
- $sum = 0;
363
- foreach( $list_code as $key => $val ) {
364
- $sum += intval($val) * $i;
365
- $i--;
366
- }
367
-
368
- $mod =(int) $sum % 11;
369
-
370
- if($mod >= 2)
371
- $mod = 11 - $mod;
372
- if ($mod != $last)
373
- return 2;
374
- else
375
- return 1;
376
- }
377
-
378
- return false;
379
- }
380
-
381
-
382
- public function validator($result, $value, $form, $field){
383
-
384
- if ( $field["type"] == 'mellicart' ) {
385
-
386
- $melli_code = !empty($value) ? str_replace( '-', '', $value) : '';
387
-
388
- $is_valid = $this->is_valid($melli_code);
389
-
390
- if ( $is_valid == 4 ) {
391
- $message = gfa_get('field_mellicart_sp1', $field);
392
- $result['message'] = !empty($message) ? $message : __('کد ملی فقط باید به صورت عدد وارد شود .' , 'GF_FA');
393
- $result['is_valid'] = false;
394
- return $result;
395
- }
396
-
397
- if ( $is_valid == 3 ){
398
- $message = gfa_get('field_mellicart_sp2', $field);
399
- $result['message'] = !empty($message) ? $message : __('کد ملی می بایست 10 رقمی باشد . تنها در صورتی مجاز به استفاده از کد های 8 یا 9 رقمی هستید که ارقام سمت چپ 0 باشند .' , 'GF_FA');
400
- $result['is_valid'] = false;
401
- return $result;
402
- }
403
-
404
- if ( $is_valid == 2 ) {
405
- $message = gfa_get('field_mellicart_sp4', $field);
406
- $result['message'] = !empty($message) ? $message : __('کد ملی وارد شده مطابق با استانداردهای کشور نمی باشد .' , 'GF_FA');
407
- $result['is_valid'] = false;
408
- return $result;
409
- }
410
-
411
- if ( $field['noDuplicates'] ) {
412
-
413
- if( strlen($melli_code) == 8 )
414
- $melli_code = '00' . $melli_code;
415
-
416
- if( strlen($melli_code) == 9 )
417
- $melli_code = '0' . $melli_code;
418
-
419
- if ( RGFormsModel::is_duplicate($form['id'], $field, $melli_code) ) {
420
- $message = gfa_get('field_mellicart_sp3', $field);
421
- $result['message'] = !empty($message) ? $message : __('این کد ملی توسط فرد دیگری ثبت شده است .' , 'GF_FA');
422
- $result['is_valid'] = false;
423
- return $result;
424
- }
425
- }
426
- }
427
-
428
- return $result;
429
- }
430
-
431
-
432
- }
433
-
434
- new GFParsi_MelliCode();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-merge-tag.php ADDED
@@ -0,0 +1,672 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+
5
+ class GFPersian_Merge_Tags extends GFPersian_Core {
6
+
7
+ public static $_entry = null;
8
+ private $entry_time = 0;
9
+
10
+ public function __construct() {
11
+
12
+ if ( $this->option( 'add_merge_tags', '1' ) == '1' ) {
13
+
14
+ add_filter( 'gform_admin_pre_render', array( $this, 'merge_tags_keys' ) );
15
+ add_filter( 'gform_replace_merge_tags', array( $this, 'merge_tags_values' ), 999, 7 );
16
+ /*------------------------------------------------------------*/
17
+ //todo:enable for next updates if was needed
18
+ if ( apply_filters( 'enable_subtotal_merge_tag', false ) ) {
19
+ add_filter( 'gform_pre_render', array( $this, 'maybe_replace_subtotal_merge_tag' ) );
20
+ add_filter( 'gform_pre_validation', array( $this, 'maybe_replace_subtotal_merge_tag' ), 10, 1 );
21
+ }
22
+ }
23
+
24
+ if ( $this->option( 'post_content_merge_tags', '1' ) == '1' ) {
25
+
26
+ $entry_time = $this->option( 'entry_time', '0' );
27
+ if ( intval( $entry_time ) > 0 ) {
28
+ $this->entry_time = intval( $entry_time ) * 60;
29
+ }
30
+
31
+ add_filter( 'the_content', array( $this, 'merge_tags_values_post_content' ), 1 );
32
+ add_filter( 'gform_confirmation', array( $this, 'confirmation_append_entry' ), 20, 3 );
33
+ }
34
+
35
+ if ( $this->option( 'pre_submission_merge_tags', '1' ) == '1' ) {
36
+ add_filter( 'gform_pre_render', array( $this, 'merge_tags_pre_submission' ) );
37
+ }
38
+ }
39
+
40
+ /*-------------------------------------------------------------*/
41
+ /*--------Start of Persian Gravity Merge Tags------------------*/
42
+ /*-------------------------------------------------------------*/
43
+ public static function get_merge_tags( $form ) {
44
+ $merge_tags = array(
45
+ '{rtl_start}' => 'ابتدای راستچین سازی',
46
+ '{rtl_end}' => 'انتهای راستچین سازی',
47
+ '{transaction_id}' => __( 'Transaction Id', 'gravityforms' ),
48
+ '{transaction_id_table}' => sprintf( 'جدول %s', __( 'Transaction Id', 'gravityforms' ) ),
49
+ '{payment_gateway}' => 'عنوان درگاه پرداخت',
50
+ '{payment_gateway_table}' => 'جدول درگاه پرداخت',
51
+ '{payment_status}' => 'عنوان وضعیت پرداخت',
52
+ '{payment_status_table}' => 'جدول وضعیت پرداخت',
53
+ '{payment_table}' => sprintf( 'جدول پرداخت (وضعیت - نام درگاه - %s)', __( 'Transaction Id', 'gravityforms' ) ),
54
+ );
55
+
56
+ if ( GFCommon::has_post_field( rgar( $form, 'fields' ) ) ) {
57
+ $merge_tags['{post_permalink}'] = 'لینک پست';
58
+ }
59
+
60
+ return $merge_tags;
61
+ }
62
+
63
+ public function merge_tags_keys( $form ) { ?>
64
+
65
+ <script type="text/javascript">
66
+ gform.addFilter('gform_merge_tags', function (mergeTags, elementId, hideAllFields, excludeFieldTypes, isPrepop, option) {
67
+ mergeTags['gf_persian'] = {
68
+ label: 'گرویتی فرم پارسی',
69
+ tags: []
70
+ };
71
+ <?php foreach ( self::get_merge_tags( $form ) as $key => $val ) { ?>
72
+ mergeTags['gf_persian'].tags.push({tag: '<?php echo $key ?>', label: '<?php echo $val ?>'});
73
+ <?php } ?>
74
+ return mergeTags;
75
+ });
76
+
77
+ <?php
78
+ /*todo:enable for next updates if was needed*/
79
+ if ( apply_filters( 'enable_subtotal_merge_tag', false ) ) :?>
80
+ jQuery(document).ready(function ($) {
81
+ $('#field_calculation_formula_variable_select').find('optgroup').eq(0).append('<option value="{subtotal}">مجموع قیمت ها</option>');
82
+ });
83
+ <?php endif; ?>
84
+ </script>
85
+ <?php
86
+ return $form;
87
+ }
88
+
89
+ public function merge_tags_values( $text, $form, $entry, $url_encode, $esc_html, $nl2br, $format ) {
90
+
91
+ //supprots deprecated merge tags
92
+ $deprecated_tags = array(
93
+ '{payment_pack}' => '{payment_table}',
94
+ '{payment_status_css}' => '{payment_status_table}',
95
+ '{transaction_id_css}' => '{transaction_id_table}',
96
+ '{payment_gateway_css}' => '{payment_gateway_table}',
97
+ );
98
+
99
+ $text = str_ireplace( array_keys( $deprecated_tags ), array_values( $deprecated_tags ), $text );
100
+
101
+ $entry = GFAPI::get_entry( rgar( $entry, 'id' ) );
102
+ $transaction_id = rgar( $entry, 'transaction_id' );
103
+ $payment_status = GFPersian_Payments::_payment_status( $entry );
104
+ $payment_gateway = gform_get_meta( rgar( $entry, 'id' ), 'payment_gateway' );
105
+
106
+ $merge_tags = array(
107
+ '{transaction_id}' => $transaction_id,
108
+ '{payment_gateway}' => $payment_gateway,
109
+ '{payment_status}' => strip_tags( $payment_status ),
110
+ );
111
+
112
+ $tabled_tags = array(
113
+ '{payment_status_table}' => array( 'وضعیت پرداخت', $payment_status ),
114
+ '{payment_gateway_table}' => array( 'درگاه پرداخت', $payment_gateway ),
115
+ '{transaction_id_table}' => array( __( 'Transaction Id', 'gravityforms' ), $transaction_id ),
116
+ );
117
+
118
+ foreach ( $tabled_tags as $tag => $value ) {
119
+
120
+ if ( empty( $value[1] ) ) {
121
+ $merge_tags[ $tag ] = '';
122
+ continue;
123
+ }
124
+ ob_start(); ?>
125
+ <tr bgcolor="<?php echo esc_attr( apply_filters( 'gform_email_background_color_label', '#EAF2FA', $tag, $entry ) ); ?>">
126
+ <td colspan="2" style="padding:5px !important">
127
+ <font style="font-family: sans-serif; font-size:12px;"><strong><?php echo $value[0]; ?></strong></font>
128
+ </td>
129
+ </tr>
130
+ <tr bgcolor="#FFFFFF">
131
+ <td width="20">&nbsp;</td>
132
+ <td style="padding:5px !important">
133
+ <font style="font-family:sans-serif;font-size:12px"><?php echo $value[1]; ?></font>
134
+ </td>
135
+ </tr>
136
+ <?php
137
+ $merge_tags[ $tag ] = ob_get_clean();
138
+ }
139
+ $merge_tags['{payment_table}'] = $merge_tags['{payment_status_table}'] . $merge_tags['{payment_gateway_table}'] . $merge_tags['{transaction_id_table}'];
140
+
141
+ foreach ( $merge_tags as $key => $value ) {
142
+ if ( ! empty( $value ) && stripos( $key, '_table}' ) !== false ) {
143
+ $merge_tags[ $key ] = '
144
+ <table width="99%" border="0" cellpadding="1" cellspacing="0" bgcolor="#EAEAEA">
145
+ <tr>
146
+ <td>
147
+ <table width="100%" border="0" cellpadding="5" cellspacing="0" bgcolor="#FFFFFF">' . $merge_tags[ $key ] . '</table>
148
+ </td>
149
+ </tr>
150
+ </table>';
151
+ }
152
+ }
153
+
154
+ $merge_tags = array_merge( $merge_tags, array(
155
+ '{rtl_start}' => '<div style="text-align: right !important; direction: rtl !important;">',
156
+ '{rtl_end}' => '</div>',
157
+ '{post_permalink}' => rgar( $entry, 'post_id' ) ? get_permalink( rgar( $entry, 'post_id' ) ) : '',
158
+ ) );
159
+
160
+ return str_replace( array_keys( $merge_tags ), array_values( $merge_tags ), $text );
161
+ }
162
+ /*-------------------------------------------------------------*/
163
+ /*--------End of Persian Gravity Merge Tags--------------------*/
164
+ /*-------------------------------------------------------------*/
165
+
166
+
167
+ /*-------------------------------------------------------------*/
168
+ /*--------Start of Subtotal Merge Tags-------------------------*/
169
+ /*-------------------------------------------------------------*/
170
+ public function maybe_replace_subtotal_merge_tag( $form, $filter_tags = true ) {
171
+
172
+ foreach ( $form['fields'] as &$field ) {
173
+
174
+ if ( current_filter() == 'gform_pre_render' ) {
175
+ $filter_tags = false;
176
+ if ( rgar( $field, 'origCalculationFormula' ) ) {
177
+ $field['calculationFormula'] = $field['origCalculationFormula'];
178
+ }
179
+ }
180
+
181
+ if ( ! $this->has_subtotal_merge_tag( $field ) ) {
182
+ continue;
183
+ }
184
+
185
+ $subtotal_merge_tags = $this->get_subtotal_merge_tag_string( $form, $field, $filter_tags );
186
+ $field['origCalculationFormula'] = $field['calculationFormula'];
187
+ $field['calculationFormula'] = str_replace( '{subtotal}', $subtotal_merge_tags, $field['calculationFormula'] );
188
+ }
189
+
190
+ return $form;
191
+ }
192
+
193
+ public function get_subtotal_merge_tag_string( $form, $current_field, $filter_tags = false ) {
194
+
195
+ $product_fields = array();
196
+
197
+ foreach ( $form["fields"] as $field ) {
198
+
199
+ if ( ! in_array( $field["type"], array( 'product', 'shopping_cart' ) ) ) {
200
+ continue;
201
+ }
202
+
203
+ switch ( $field["type"] ) {
204
+ case 'product':
205
+ $option_fields = GFCommon::get_product_fields_by_type( $form, array( "option" ), $field['id'] );
206
+ // can only have 1 quantity field
207
+ $quantity_field = GFCommon::get_product_fields_by_type( $form, array( "quantity" ), $field['id'] );
208
+ $quantity_field = rgar( $quantity_field, 0 );
209
+ $product_fields[] = array(
210
+ 'product' => $field,
211
+ 'options' => $option_fields,
212
+ 'quantity' => $quantity_field
213
+ );
214
+ break;
215
+
216
+ case 'shopping_cart':
217
+ //todo : for next update
218
+ break;
219
+ }
220
+ }
221
+ $shipping_field = GFCommon::get_fields_by_type( $form, array( "shipping" ) );
222
+ $pricing_fields = array( "products" => $product_fields, "shipping" => $shipping_field );
223
+
224
+ $product_tag_groups = array();
225
+ foreach ( $pricing_fields['products'] as $product ) {
226
+
227
+ $product_field = rgar( $product, 'product' );
228
+ $option_fields = rgar( $product, 'options' );
229
+ $quantity_field = rgar( $product, 'quantity' );
230
+
231
+ // do not include current field in subtotal
232
+ if ( $product_field['id'] == $current_field['id'] ) {
233
+ continue;
234
+ }
235
+
236
+ $product_tags = GFCommon::get_field_merge_tags( $product_field );
237
+ $quantity_tag = 1;
238
+
239
+ // if a single product type, only get the "price" merge tag
240
+ if ( in_array( GFFormsModel::get_input_type( $product_field ), array(
241
+ 'singleproduct',
242
+ 'calculation',
243
+ 'hiddenproduct'
244
+ ) ) ) {
245
+
246
+ // single products provide quantity merge tag
247
+ if ( empty( $quantity_field ) && ! rgar( $product_field, 'disableQuantity' ) ) {
248
+ $quantity_tag = $product_tags[2]['tag'];
249
+ }
250
+
251
+ $product_tags = array( $product_tags[1] );
252
+ }
253
+
254
+ // if quantity field is provided for product, get merge tag
255
+ if ( ! empty( $quantity_field ) ) {
256
+ $quantity_tag = GFCommon::get_field_merge_tags( $quantity_field );
257
+ $quantity_tag = $quantity_tag[0]['tag'];
258
+ }
259
+
260
+
261
+ if ( is_numeric( $quantity_tag ) ) {
262
+ $qty_value = $quantity_tag;
263
+ } else {
264
+ // extract qty input ID from the merge tag
265
+ preg_match_all( '/{[^{]*?:(\d+(\.\d+)?)(:(.*?))?}/mi', $quantity_tag, $matches, PREG_SET_ORDER );
266
+ $qty_input_id = rgars( $matches, '0/1' );
267
+ $qty_value = rgpost( 'input_' . str_replace( '.', '_', $qty_input_id ) );
268
+ }
269
+
270
+ if ( $filter_tags && floatval( $qty_value ) <= 0 ) {
271
+ continue;
272
+ }
273
+
274
+ $product_tags = wp_list_pluck( $product_tags, 'tag' );
275
+ $option_tags = array();
276
+
277
+ foreach ( $option_fields as $option_field ) {
278
+
279
+ if ( is_array( $option_field['inputs'] ) ) {
280
+
281
+ $choice_number = 1;
282
+
283
+ foreach ( $option_field['inputs'] as &$input ) {
284
+
285
+ //hack to skip numbers ending in 0. so that 5.1 doesn't conflict with 5.10
286
+ if ( $choice_number % 10 == 0 ) {
287
+ $choice_number ++;
288
+ }
289
+
290
+ $input['id'] = $option_field['id'] . '.' . $choice_number ++;
291
+
292
+ }
293
+ }
294
+
295
+ $new_options_tags = GFCommon::get_field_merge_tags( $option_field );
296
+ if ( ! is_array( $new_options_tags ) ) {
297
+ continue;
298
+ }
299
+
300
+ if ( GFFormsModel::get_input_type( $option_field ) == 'checkbox' ) {
301
+ array_shift( $new_options_tags );
302
+ }
303
+
304
+ $option_tags = array_merge( $option_tags, $new_options_tags );
305
+ }
306
+
307
+ $option_tags = wp_list_pluck( $option_tags, 'tag' );
308
+
309
+ $product_tag_groups[] = '( ( ' . implode( ' + ', array_merge( $product_tags, $option_tags ) ) . ' ) * ' . $quantity_tag . ' )';
310
+
311
+ }
312
+
313
+ $shipping_tag = 0;
314
+ //Shipping should not be included in subtotal, correct?
315
+ if ( rgar( $pricing_fields, 'shipping' ) ) {
316
+ $shipping_tag = GFCommon::get_field_merge_tags( rgars( $pricing_fields, 'shipping/0' ) );
317
+ $shipping_tag = $shipping_tag[0]['tag'];
318
+ }
319
+
320
+ $subtotal_merge_tags = '( ( ' . implode( ' + ', $product_tag_groups ) . ' ) + ' . $shipping_tag . ' )';
321
+
322
+ return $subtotal_merge_tags;
323
+ }
324
+
325
+ public function has_subtotal_merge_tag( $field ) {
326
+
327
+ // check if form is passed
328
+ if ( isset( $field['fields'] ) ) {
329
+
330
+ $form = $field;
331
+ foreach ( $form['fields'] as $field ) {
332
+ if ( $this->has_subtotal_merge_tag( $field ) ) {
333
+ return true;
334
+ }
335
+ }
336
+
337
+ } else {
338
+
339
+ if ( isset( $field['calculationFormula'] ) && strpos( $field['calculationFormula'], '{subtotal}' ) !== false ) {
340
+ return true;
341
+ }
342
+
343
+ }
344
+
345
+ return false;
346
+ }
347
+ /*-------------------------------------------------------------*/
348
+ /*--------End of Subtotal Merge Tags---------------------------*/
349
+ /*-------------------------------------------------------------*/
350
+
351
+
352
+ /*-------------------------------------------------------------*/
353
+ /*--------Start of Post Content Merge Tags---------------------*/
354
+ /*-------------------------------------------------------------*/
355
+ public function merge_tags_values_post_content( $post_content ) {
356
+
357
+ $entry_time = $this->entry_time;
358
+
359
+ if ( ! self::$_entry ) {
360
+
361
+ $entry_id = rgget( 'entry' );
362
+
363
+ if ( $entry_id ) {
364
+ if ( ! $entry_time || ! is_numeric( $entry_id ) || intval( $entry_id ) <= 0 ) {
365
+
366
+ if ( method_exists( 'GFCommon', 'openssl_decrypt' ) ) {
367
+ $entry_id = GFCommon::openssl_decrypt( $entry_id );
368
+ } elseif ( method_exists( 'GFCommon', 'decrypt' ) ) {
369
+ $entry_id = GFCommon::decrypt( $entry_id );
370
+ }
371
+ $entry_id = intval( $entry_id );
372
+ }
373
+ } else {
374
+ $post = get_post();
375
+ if ( $post ) {
376
+ $entry_id = get_post_meta( $post->ID, '_gform-entry-id', true );
377
+ }
378
+ }
379
+
380
+ if ( $entry_id ) {
381
+ $entry = GFAPI::get_entry( $entry_id );
382
+ }
383
+
384
+ self::$_entry = ! empty( $entry ) && $entry ? $entry : false;
385
+ }
386
+ $entry = self::$_entry;
387
+
388
+ if ( ! $entry ) {
389
+ $post_content = $this->replace_field_label_merge_tags( $post_content, '' );
390
+ } else {
391
+
392
+ if ( $entry_time ) {
393
+ $confirm_time = gform_get_meta( rgar( $entry, 'id' ), 'gform_page_confirm_time' );
394
+ if ( empty( $confirm_time ) ) {
395
+ gform_update_meta( $entry['id'], 'gform_page_confirm_time', time() );
396
+ } elseif ( $confirm_time + $entry_time < time() ) {
397
+ return $this->replace_field_label_merge_tags( $post_content, '' );
398
+ }
399
+ }
400
+
401
+ $form = GFFormsModel::get_form_meta( $entry['form_id'] );
402
+ $post_content = $this->replace_field_label_merge_tags( $post_content, $form );
403
+ $post_content = GFCommon::replace_variables( $post_content, $form, $entry, false, false, false );
404
+ }
405
+
406
+ return $post_content;
407
+ }
408
+
409
+ public function replace_field_label_merge_tags( $text, $form ) {
410
+
411
+ if ( ! empty( $form ) ) {
412
+
413
+ preg_match_all( '/{([^:]+?)}/', $text, $matches, PREG_SET_ORDER );
414
+ if ( empty( $matches ) ) {
415
+ return $text;
416
+ }
417
+
418
+ foreach ( $matches as $match ) {
419
+
420
+ list( $search, $field_label ) = $match;
421
+
422
+ foreach ( $form['fields'] as $field ) {
423
+
424
+ $matches_admin_label = rgar( $field, 'adminLabel' ) == $field_label;
425
+ $matches_field_label = false;
426
+
427
+ if ( is_array( $field['inputs'] ) ) {
428
+ foreach ( $field['inputs'] as $input ) {
429
+ if ( GFFormsModel::get_label( $field, $input['id'] ) == $field_label ) {
430
+ $matches_field_label = true;
431
+ $input_id = $input['id'];
432
+ break;
433
+ }
434
+ }
435
+ } else {
436
+ $matches_field_label = GFFormsModel::get_label( $field ) == $field_label;
437
+ $input_id = $field['id'];
438
+ }
439
+
440
+ if ( ! $matches_admin_label && ! $matches_field_label ) {
441
+ continue;
442
+ }
443
+
444
+ $replace = sprintf( '{%s:%s}', $field_label, (string) $input_id );
445
+ $text = str_replace( $search, $replace, $text );
446
+
447
+ break;
448
+ }
449
+ }
450
+ } else {
451
+
452
+ /*
453
+ preg_match_all( '/{[^{]*?:(\d+(\.\d+)?)(:(.*?))?}/mi', $text, $matches, PREG_SET_ORDER );
454
+ if( !empty( $matches ) ) {
455
+ foreach( $matches as $match ) {
456
+ if ( isset($match[0]))
457
+ $text = str_replace( $match[0], '' , $text );
458
+ }
459
+ }
460
+
461
+ unset($matches);
462
+
463
+ preg_match_all( '/{([^:]+?)}/', $text, $matches, PREG_SET_ORDER );
464
+ if( !empty( $matches ) ) {
465
+ foreach( $matches as $match ) {
466
+ if ( isset($match[0]))
467
+ $text = str_replace( $match[0], '' , $text );
468
+ }
469
+ }
470
+ */
471
+
472
+ }
473
+
474
+ return $text;
475
+ }
476
+
477
+ public function confirmation_append_entry( $confirmation, $form, $entry ) {
478
+
479
+ $is_ajax_redirect = is_string( $confirmation ) && strpos( $confirmation, 'gformRedirect' );
480
+ $is_redirect = is_array( $confirmation ) && isset( $confirmation['redirect'] );
481
+
482
+ if ( ! $is_ajax_redirect && ! $is_redirect ) {
483
+ return $confirmation;
484
+ }
485
+
486
+ $entry_id = $entry['id'];
487
+
488
+ if ( ! $this->entry_time ) {
489
+ if ( method_exists( 'GFCommon', 'openssl_encrypt' ) ) {
490
+ $entry_id = rawurlencode( GFCommon::openssl_encrypt( $entry_id ) );
491
+ } elseif ( method_exists( 'GFCommon', 'encrypt' ) ) {
492
+ $entry_id = rawurlencode( GFCommon::encrypt( $entry_id ) );
493
+ }
494
+ }
495
+
496
+ if ( $is_ajax_redirect ) {
497
+ preg_match_all( '/gformRedirect.+?(http.+?)(?=\'|")/', $confirmation, $matches, PREG_SET_ORDER );
498
+ list( $full_match, $url ) = $matches[0];
499
+ $redirect_url = add_query_arg( array( 'entry' => $entry_id ), $url );
500
+ $confirmation = str_replace( $url, $redirect_url, $confirmation );
501
+ } else {
502
+ $redirect_url = add_query_arg( array( 'entry' => $entry_id ), $confirmation['redirect'] );
503
+ $confirmation['redirect'] = $redirect_url;
504
+ }
505
+
506
+ return $confirmation;
507
+ }
508
+ /*-------------------------------------------------------------*/
509
+ /*--------End of Post Content Merge Tags-----------------------*/
510
+ /*-------------------------------------------------------------*/
511
+
512
+
513
+ /*-------------------------------------------------------------*/
514
+ /*--------Start of Pre Submission Merge Tags-------------------*/
515
+ /*-------------------------------------------------------------*/
516
+ public function merge_tags_pre_submission( $form ) {
517
+
518
+ if ( function_exists( 'is_checkout' ) && is_checkout() ) {
519
+ return $form;
520
+ }
521
+
522
+ $current_page = isset( GFFormDisplay::$submission[ $form['id'] ] ) && isset( GFFormDisplay::$submission[ $form['id'] ]['page_number'] ) ? GFFormDisplay::$submission[ $form['id'] ]['page_number'] : 1;
523
+ //$fields = array();
524
+
525
+ if ( empty( $form['fields'] ) || ! is_array( $form['fields'] ) ) {
526
+ return $form;
527
+ }
528
+
529
+ // get all HTML fields on the current page
530
+ foreach ( $form['fields'] as &$field ) {
531
+
532
+ // skip all fields on the first page
533
+ if ( rgar( $field, 'pageNumber' ) <= 1 ) {
534
+ continue;
535
+ }
536
+
537
+ $default_value = rgar( $field, 'defaultValue' );
538
+ preg_match_all( '/{.+}/', $default_value, $matches, PREG_SET_ORDER );
539
+ if ( ! empty( $matches ) ) {
540
+ // if default value needs to be replaced but is not on current page, wait until on the current page to replace it
541
+ if ( rgar( $field, 'pageNumber' ) != $current_page ) {
542
+ $field['defaultValue'] = '';
543
+ } else {
544
+ $field['defaultValue'] = $this->preview_replace_variables( $default_value, $form );
545
+ }
546
+ }
547
+
548
+ // only run 'content' filter for fields on the current page
549
+ if ( rgar( $field, 'pageNumber' ) != $current_page ) {
550
+ continue;
551
+ }
552
+
553
+ $html_content = rgar( $field, 'content' );
554
+ preg_match_all( '/{.+}/', $html_content, $matches, PREG_SET_ORDER );
555
+ if ( ! empty( $matches ) ) {
556
+ $field['content'] = $this->preview_replace_variables( $html_content, $form );
557
+ }
558
+
559
+ }
560
+
561
+ return $form;
562
+ }
563
+
564
+ public function preview_special_merge_tags( $value, $input_id, $merge_tag, $field ) {
565
+
566
+ // added to prevent overriding :noadmin filter (and other filters that remove fields)
567
+ if ( ! $value ) {
568
+ return $value;
569
+ }
570
+
571
+ $input_type = RGFormsModel::get_input_type( $field );
572
+
573
+ $is_upload_field = in_array( $input_type, array( 'post_image', 'fileupload' ) );
574
+ $is_multi_input = is_array( rgar( $field, 'inputs' ) );
575
+ $is_input = intval( $input_id ) != $input_id;
576
+
577
+ if ( ! $is_upload_field && ! $is_multi_input ) {
578
+ return $value;
579
+ }
580
+
581
+ // if is individual input of multi-input field, return just that input value
582
+ if ( $is_input ) {
583
+ return $value;
584
+ }
585
+
586
+ $form = RGFormsModel::get_form_meta( $field['formId'] );
587
+ $entry = $this->create_entry( $form );
588
+ $currency = GFCommon::get_currency();
589
+
590
+ if ( is_array( rgar( $field, 'inputs' ) ) ) {
591
+ $value = RGFormsModel::get_lead_field_value( $entry, $field );
592
+
593
+ return GFCommon::get_lead_field_display( $field, $value, $currency );
594
+ }
595
+
596
+ $input_name = "input_{$field['id']}";
597
+
598
+ $file_info = RGFormsModel::get_temp_filename( $form['id'], $input_name );
599
+ $source = RGFormsModel::get_upload_url( $form['id'] ) . "/tmp/" . $file_info["temp_filename"];
600
+
601
+ $value = '';
602
+ if ( $file_info ) {
603
+ switch ( RGFormsModel::get_input_type( $field ) ) {
604
+ case "post_image":
605
+ list( , $image_title, $image_caption, $image_description ) = explode( "|:|", $entry[ $field['id'] ] );
606
+ $value = ! empty( $source ) ? $source . "|:|" . $image_title . "|:|" . $image_caption . "|:|" . $image_description : "";
607
+ break;
608
+
609
+ case "fileupload" :
610
+ $value = $source;
611
+ break;
612
+
613
+ }
614
+ }
615
+
616
+ switch ( $input_type ) {
617
+ case 'fileupload':
618
+
619
+ if ( ! empty( $value ) ) {
620
+ $input_name = "input_" . str_replace( '.', '_', $field['id'] );
621
+ $file_info = RGFormsModel::get_temp_filename( $form['id'], $input_name );
622
+ $value = esc_attr( str_replace( " ", "%20", $value ) );
623
+ $value = "<a href='$value' target='_blank' title='" . __( "Click to view", "gravityforms" ) . "'>" . $file_info['uploaded_filename'] . "</a>";
624
+ }
625
+ break;
626
+ default:
627
+ $value = GFCommon::get_lead_field_display( $field, $value, $currency );
628
+ break;
629
+ }
630
+
631
+ return $value;
632
+ }
633
+
634
+ public function preview_replace_variables( $content, $form ) {
635
+
636
+ $entry = $this->create_entry( $form );
637
+
638
+ // add filter that will handle getting temporary URLs for file uploads and post image fields (removed below)
639
+ // beware, the RGFormsModel::create_lead() function also triggers the gform_merge_tag_filter at some point and will
640
+ // result in an infinite loop if not called first above
641
+ add_filter( 'gform_merge_tag_filter', array( $this, 'preview_special_merge_tags' ), 10, 4 );
642
+
643
+ $content = GFCommon::replace_variables( $content, $form, $entry, false, false, false );
644
+
645
+ // remove filter so this function is not applied after preview functionality is complete
646
+ remove_filter( 'gform_merge_tag_filter', array( $this, 'preview_special_merge_tags' ) );
647
+
648
+ return $content;
649
+ }
650
+
651
+ public function create_entry( $form ) {
652
+
653
+ if ( empty( self::$_entry ) ) {
654
+ self::$_entry = GFFormsModel::create_lead( $form );
655
+ if ( class_exists( 'GFCache' ) ) {
656
+ foreach ( $form['fields'] as &$field ) {
657
+ if ( GFFormsModel::get_input_type( $field ) == 'total' ) {
658
+ GFCache::delete( 'GFFormsModel::get_lead_field_value__' . $field['id'] );
659
+ }
660
+ }
661
+ }
662
+ }
663
+
664
+ return self::$_entry;
665
+ }
666
+ /*-------------------------------------------------------------*/
667
+ /*--------End of Pre Submission Merge Tags---------------------*/
668
+ /*-------------------------------------------------------------*/
669
+
670
+ }
671
+
672
+ new GFPersian_Merge_Tags;
includes/class-multi-page-navi.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+
5
+ class GFPersian_Multipage_Navigation extends GFPersian_Core {
6
+
7
+ public $_args = array();
8
+
9
+ private static $script_displayed;
10
+
11
+ public function __construct() {
12
+
13
+ if ( is_admin() || $this->option( 'multipage_nav', '1' ) != '1' ) {
14
+ return;
15
+ }
16
+
17
+ $this->_args = array(
18
+ 'activate_on_last_page' => $this->option( 'multipage_nav_last', '1' )
19
+ );
20
+
21
+ add_filter( 'gform_pre_render', array( $this, 'output_navigation_script' ), 10, 2 );
22
+ }
23
+
24
+ public function output_navigation_script( $form, $is_ajax ) {
25
+
26
+ // only apply this to multi-page forms
27
+ if ( empty( $form['pagination']['pages'] ) || ! is_array( $form['pagination']['pages'] ) || count( $form['pagination']['pages'] ) <= 1 ) {
28
+ return $form;
29
+ }
30
+
31
+ $this->register_script( $form );
32
+
33
+ if ( ! $this->_args['activate_on_last_page'] || $this->is_last_page( $form ) || $this->is_last_page_reached() ) {
34
+ add_filter( "gform_form_tag_{$form['id']}", function ( $tag ) {
35
+ return $tag . '<input id="gform_multi_page_nav_last_page_reached" name="gform_multi_page_nav_last_page_reached" value="1" type="hidden" />';
36
+ } );
37
+ }
38
+
39
+ // only output the gform_multi_page_nav object once regardless of how many forms are being displayed
40
+ // also do not output again on ajax submissions
41
+ if ( self::$script_displayed || ( $is_ajax && rgpost( 'gform_submit' ) ) ) {
42
+ return $form;
43
+ }
44
+ ?>
45
+
46
+ <script type="text/javascript">
47
+
48
+ (function ($) {
49
+
50
+ window.gform_multi_page_navObj = function (args) {
51
+
52
+ this.formId = args.formId;
53
+ this.formElem = jQuery('form#gform_' + this.formId);
54
+ this.currentPage = args.currentPage;
55
+ this.lastPage = args.lastPage;
56
+ this.activateOnLastPage = args.activateOnLastPage;
57
+
58
+ this.init = function () {
59
+
60
+ // if this form is ajax-enabled, we'll need to get the current page via JS
61
+ if (this.isAjax())
62
+ this.currentPage = this.getCurrentPage();
63
+
64
+ if (!this.isLastPage() && !this.isLastPageReached())
65
+ return;
66
+
67
+ var gform_multi_page_nav = this;
68
+ var steps = $('form#gform_' + this.formId + ' .gf_step');
69
+
70
+ steps.each(function () {
71
+
72
+ var stepNumber = parseInt($(this).find('span.gf_step_number').text());
73
+
74
+ if (stepNumber != gform_multi_page_nav.currentPage) {
75
+ $(this).html(gform_multi_page_nav.createPageLink(stepNumber, $(this).html()))
76
+ .addClass('gform_multi_page_nav-step-linked');
77
+ } else {
78
+ $(this).addClass('gform_multi_page_nav-step-current');
79
+ }
80
+
81
+ });
82
+
83
+ $(document).on('click', '#gform_' + this.formId + ' a.gform_multi_page_nav-page-link', function (event) {
84
+ event.preventDefault();
85
+
86
+ var hrefArray = $(this).attr('href').split('#');
87
+ if (hrefArray.length >= 2) {
88
+ var pageNumber = hrefArray.pop();
89
+ gform_multi_page_nav.postToPage(pageNumber, !$(this).hasClass('gform_multi_page_navmp-default'));
90
+ }
91
+
92
+ });
93
+
94
+ };
95
+
96
+ this.createPageLink = function (stepNumber, HTML) {
97
+ return '<a href="#' + stepNumber + '" class="gform_multi_page_nav-page-link gform_multi_page_nav-default">' + HTML + '</a>';
98
+ };
99
+
100
+ this.postToPage = function (page) {
101
+ this.formElem.append('<input type="hidden" name="gform_multi_page_nav_page_change" value="1" />');
102
+ this.formElem.find('input[name="gform_target_page_number_' + this.formId + '"]').val(page);
103
+ this.formElem.submit();
104
+ };
105
+
106
+ this.getCurrentPage = function () {
107
+ return this.formElem.find('input#gform_source_page_number_' + this.formId).val();
108
+ };
109
+
110
+ this.isLastPage = function () {
111
+ return this.currentPage >= this.lastPage;
112
+ };
113
+
114
+ this.isLastPageReached = function () {
115
+ return this.formElem.find('input[name="gform_multi_page_nav_last_page_reached"]').val() == true;
116
+ };
117
+
118
+ this.isAjax = function () {
119
+ return this.formElem.attr('target') == 'gform_ajax_frame_' + this.formId;
120
+ };
121
+
122
+ this.init();
123
+
124
+ }
125
+
126
+ })(jQuery);
127
+
128
+ </script>
129
+
130
+ <?php
131
+ self::$script_displayed = true;
132
+
133
+ return $form;
134
+ }
135
+
136
+ public function register_script( $form ) {
137
+
138
+ $page_number = GFFormDisplay::get_current_page( $form['id'] );
139
+ $last_page = count( $form['pagination']['pages'] );
140
+
141
+ $args = array(
142
+ 'formId' => $form['id'],
143
+ 'currentPage' => $page_number,
144
+ 'lastPage' => $last_page,
145
+ 'activateOnLastPage' => $this->_args['activate_on_last_page'],
146
+ );
147
+
148
+ $script = "window.gform_multi_page_nav = new gform_multi_page_navObj(" . json_encode( $args ) . ");";
149
+ GFFormDisplay::add_init_script( $form['id'], 'gform_multi_page_nav', GFFormDisplay::ON_PAGE_RENDER, $script );
150
+
151
+ }
152
+
153
+ public function is_last_page( $form ) {
154
+
155
+ $page_number = GFFormDisplay::get_current_page( $form['id'] );
156
+ $last_page = count( $form['pagination']['pages'] );
157
+
158
+ return $page_number >= $last_page;
159
+ }
160
+
161
+ public function is_last_page_reached() {
162
+ return rgpost( 'gform_multi_page_nav_last_page_reached' );
163
+ }
164
+
165
+ }
166
+
167
+ new GFPersian_Multipage_Navigation();
includes/class-multipage-navigation.php DELETED
@@ -1,160 +0,0 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) exit;
2
-
3
- class GFParsi_MultipageNavigation {
4
-
5
- public $_args = array();
6
-
7
- private static $script_displayed;
8
-
9
- function __construct() {
10
-
11
- if ( is_admin() )
12
- return;
13
-
14
- $this->_args = array(
15
- 'activate_on_last_page' => apply_filters( 'gf_mn_activate_on_last_page' , true )
16
- );
17
-
18
- add_filter( 'gform_pre_render', array( $this, 'output_navigation_script' ), 10, 2 );
19
- }
20
-
21
- function output_navigation_script( $form, $is_ajax ) {
22
-
23
- // only apply this to multi-page forms
24
- if( count($form['pagination']['pages']) <= 1 )
25
- return $form;
26
-
27
- $this->register_script( $form );
28
-
29
- if( ! $this->_args['activate_on_last_page'] || $this->is_last_page( $form ) || $this->is_last_page_reached() ) {
30
- $input = '<input id="gfir_last_page_reached" name="gfir_last_page_reached" value="1" type="hidden" />';
31
- add_filter( "gform_form_tag_{$form['id']}", create_function('$a', 'return $a . \'' . $input . '\';' ) );
32
- }
33
-
34
- // only output the gfirmpn object once regardless of how many forms are being displayed
35
- // also do not output again on ajax submissions
36
- if( self::$script_displayed || ( $is_ajax && rgpost('gform_submit') ))
37
- return $form;
38
-
39
- ?>
40
-
41
- <script type="text/javascript">
42
-
43
- (function($){
44
-
45
- window.gfirmpnObj = function( args ) {
46
-
47
- this.formId = args.formId;
48
- this.formElem = jQuery('form#gform_' + this.formId);
49
- this.currentPage = args.currentPage;
50
- this.lastPage = args.lastPage;
51
- this.activateOnLastPage = args.activateOnLastPage;
52
-
53
- this.init = function() {
54
-
55
- // if this form is ajax-enabled, we'll need to get the current page via JS
56
- if( this.isAjax() )
57
- this.currentPage = this.getCurrentPage();
58
-
59
- if( !this.isLastPage() && !this.isLastPageReached() )
60
- return;
61
-
62
- var gfirmpn = this;
63
- var steps = $('form#gform_' + this.formId + ' .gf_step');
64
-
65
- steps.each(function(){
66
-
67
- var stepNumber = parseInt( $(this).find('span.gf_step_number').text() );
68
-
69
- if( stepNumber != gfirmpn.currentPage ) {
70
- $(this).html( gfirmpn.createPageLink( stepNumber, $(this).html() ) )
71
- .addClass('gfir-step-linked');
72
- } else {
73
- $(this).addClass('gfir-step-current');
74
- }
75
-
76
- });
77
-
78
- $(document).on('click', '#gform_' + this.formId + ' a.gfirmpn-page-link', function(event){
79
- event.preventDefault();
80
-
81
- var hrefArray = $(this).attr('href').split('#');
82
- if( hrefArray.length >= 2 ) {
83
- var pageNumber = hrefArray.pop();
84
- gfirmpn.postToPage( pageNumber, ! $( this ).hasClass( 'gfirmp-default' ) );
85
- }
86
-
87
- });
88
-
89
- }
90
-
91
- this.createPageLink = function( stepNumber, HTML ) {
92
- return '<a href="#' + stepNumber + '" class="gfirmpn-page-link gfirmpn-default">' + HTML + '</a>';
93
- }
94
-
95
- this.postToPage = function( page ) {
96
- this.formElem.append('<input type="hidden" name="gfir_page_change" value="1" />');
97
- this.formElem.find( 'input[name="gform_target_page_number_' + this.formId + '"]' ).val( page );
98
- this.formElem.submit();
99
- }
100
-
101
- this.getCurrentPage = function() {
102
- return this.formElem.find( 'input#gform_source_page_number_' + this.formId ).val();
103
- }
104
-
105
- this.isLastPage = function() {
106
- return this.currentPage >= this.lastPage;
107
- }
108
-
109
- this.isLastPageReached = function() {
110
- return this.formElem.find('input[name="gfir_last_page_reached"]').val() == true;
111
- }
112
-
113
- this.isAjax = function() {
114
- return this.formElem.attr('target') == 'gform_ajax_frame_' + this.formId;
115
- }
116
-
117
- this.init();
118
-
119
- }
120
-
121
- })(jQuery);
122
-
123
- </script>
124
-
125
- <?php
126
- self::$script_displayed = true;
127
- return $form;
128
- }
129
-
130
- function register_script( $form ) {
131
-
132
- $page_number = GFFormDisplay::get_current_page($form['id']);
133
- $last_page = count($form['pagination']['pages']);
134
-
135
- $args = array(
136
- 'formId' => $form['id'],
137
- 'currentPage' => $page_number,
138
- 'lastPage' => $last_page,
139
- 'activateOnLastPage' => $this->_args['activate_on_last_page'],
140
- );
141
-
142
- $script = "window.gfirmpn = new gfirmpnObj(" . json_encode( $args ) . ");";
143
- GFFormDisplay::add_init_script( $form['id'], 'gfirmpn', GFFormDisplay::ON_PAGE_RENDER, $script );
144
-
145
- }
146
-
147
- function is_last_page( $form ) {
148
-
149
- $page_number = GFFormDisplay::get_current_page($form['id']);
150
- $last_page = count($form['pagination']['pages']);
151
-
152
- return $page_number >= $last_page;
153
- }
154
-
155
- function is_last_page_reached() {
156
- return rgpost('gfir_last_page_reached');
157
- }
158
-
159
- }
160
- $gfir_multipage_navigation = new GFParsi_MultipageNavigation( array() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-national-id.php ADDED
@@ -0,0 +1,434 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+
5
+ class GFPersian_National_ID extends GFPersian_Core {
6
+
7
+ public function __construct() {
8
+
9
+ if ( $this->option( 'national_id', '1' ) != '1' ) {
10
+ return;
11
+ }
12
+
13
+ if ( is_admin() ) {
14
+ add_filter( 'gform_add_field_buttons', array( $this, 'button' ) );
15
+ add_filter( 'gform_field_type_title', array( $this, 'title' ) );
16
+ add_filter( 'gform_editor_js_set_default_values', array( $this, 'label' ) );
17
+ add_action( 'gform_editor_js', array( $this, 'settings' ) );
18
+ add_action( 'gform_field_standard_settings', array( $this, 'standard_settings' ), 10, 2 );
19
+ add_filter( 'gform_tooltips', array( $this, 'tooltips' ) );
20
+ add_filter( 'gform_admin_pre_render', array( $this, 'admin_conditional_logic' ) );
21
+ }
22
+
23
+ add_action( 'gform_field_input', array( $this, 'input' ), 10, 5 );
24
+ add_action( 'gform_field_css_class', array( $this, 'classes' ), 10, 3 );
25
+ add_action( 'gform_pre_submission', array( $this, 'pre_submission' ) );
26
+ add_filter( 'gform_field_validation', array( $this, 'validator' ), 10, 4 );
27
+ add_action( 'gform_enqueue_scripts', array( $this, 'frontend_script' ), 10, 2 );
28
+ }
29
+
30
+ public function button( $field_groups ) {
31
+
32
+ foreach ( $field_groups as &$group ) {
33
+ if ( $group['name'] == 'gf_persian_fields' ) {
34
+ $group['fields'][] = array(
35
+ 'class' => 'button',
36
+ 'value' => 'کد ملی',
37
+ 'data-type' => 'ir_national_id',
38
+ //'onclick' => "StartAddField('ir_national_id');"//deprecated
39
+ );
40
+ }
41
+ }
42
+
43
+ return $field_groups;
44
+ }
45
+
46
+ public function title( $type ) {
47
+ if ( $type == 'ir_national_id' ) {
48
+ return 'کد ملی';
49
+ }
50
+
51
+ return $type;
52
+ }
53
+
54
+ public function label() { ?>
55
+ case 'ir_national_id':
56
+ field.label = 'کد ملی';
57
+ break;
58
+ <?php
59
+ }
60
+
61
+ public function classes( $classes, $field, $form ) {
62
+ if ( $field['type'] == 'ir_national_id' ) {
63
+ $classes .= ' gform_ir_national_id';
64
+ }
65
+
66
+ return $classes;
67
+ }
68
+
69
+ public function tooltips( $tooltips ) {
70
+ $tooltips['tooltip_showLocation'] = '<h6>نمایش لحظه ای شهر از روی کد ملی </h6>نمایش شهر و پیغام زیر فیلد کد ملی بعد از پر شدن فیلد. تذکر : در صورتی که این گزینه را فعال نمایید ،ممکن است فراخوانی شهر های ایران با توجه به زیاد بودن آنها سبب سنگین شدن صفحه گردد.';
71
+ $tooltips['tooltip_showSeperator'] = '<h6>جدا سازی ارقام</h6>در صورتی که این گزینه را فعال نمایید ، پس از پر شدن فیلد کد ملی ، <strong>در صورتی که کد ملی وارد شده صحیح تشخصی داده شود</strong> ؛ کد ملی به صورت زیر در خواهد آمد و در غیر این صورت علی صحیح نبودن کد ملی زیر فیلد نمایش داده خواهد شد :<br>xxx-xxxxxx-x';
72
+ $tooltips['tooltip_forceEnglish'] = '<h6>تبدیل اعداد فارسی و عربی به انگلیسی</h6>در صورتی که کاربر کد ملی خود را به صورت انگلیسی وارد نکند با خطا مواجه خواهد شد. پس با فعالسازی این گزینه اعداد وارد شده برای کد ملی را به صورت خودکار به انگلیسی تبدیل کنید.';
73
+ $tooltips['tooltip_notDigitError'] = 'با توجه به اینکه کد ملی فقط باید به صورت عدد باشد ، در صورتی که کاراکتری غیر از عدد وارد شده باشد پیغام خطا نمایش داده خواهد شد.<br/>پیغام پیشفرض : کد ملی فقط باید به صورت عدد وارد شود.';
74
+ $tooltips['tooltip_qtyDigitError'] = 'با توجه به اینکه کد ملی می بایست 10 رقمی باشد اگر تعداد رقم وارد شده ، اشتباه باشد پیغام خطا نمایش داده خواهد شد.<br>پیغام پیشفرض : کد ملی می بایست 10 رقمی باشد. تنها در صورتی مجاز به استفاده از کد های 8 یا 9 رقمی هستید که ارقام سمت چپ 0 باشند.';
75
+ $tooltips['tooltip_duplicateError'] = 'در صورتی که از تب وِیژگی تیک گزینه بدون تکرار را زده باشید ؛ بعد از پر شدن فرم و زدن دکمه ارسال پیغامی مبتنی بر تکراری بودن کد ملی نمایش داده خواهد شد. <br/>پیغام پیشفرض : این کد ملی توسط فرد دیگری ثبت شده است.';
76
+ $tooltips['tooltip_isInvalidError'] = 'در صورتی که کد ملی وارد شده مطابق با الگوریتم کشور نباشد پیغام خطا نمایش داده خواهد شد.<br/>پیغام پیشفرض : کد ملی وارد شده مطابق با استانداردهای کشور نمی باشد.';
77
+
78
+ return $tooltips;
79
+ }
80
+
81
+ public function input( $input, $field, $value, $entry_id, $form_id ) {
82
+
83
+ if ( $field['type'] == 'ir_national_id' ) {
84
+
85
+ $field_id = $field['id'];
86
+ $form_id = ! empty( $form_id ) ? $form_id : rgget( 'id' );
87
+ $is_admin = is_admin();
88
+ $is_frontend = ! $is_admin;
89
+ $is_entry_detail = GFCommon::is_entry_detail();
90
+ $is_form_editor = GFCommon::is_form_editor();
91
+
92
+ if ( $is_frontend && RGFormsModel::get_input_type( $field ) == 'adminonly_hidden' ) {
93
+ return '';
94
+ }
95
+
96
+ $size = rgar( $field, 'size' );
97
+ $class_suffix = $is_entry_detail ? '_admin' : '';
98
+ $class = $size . $class_suffix;
99
+
100
+ $input_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$field_id" : 'input_' . $form_id . "_$field_id";
101
+
102
+ $tabindex = GFCommon::get_tabindex();
103
+ $disabled_text = $is_form_editor ? "disabled='disabled'" : '';
104
+
105
+ $max_length = rgar( $field, 'showSeperator' ) ? 12 : 10;
106
+ $max_length = "maxlength='{$max_length}'";
107
+ /*
108
+ $this->get_conditional_logic_event( 'keyup' ) //text or radio
109
+ $this->get_conditional_logic_event( 'change' ) //select
110
+ $this->get_conditional_logic_event( 'click' ) // checkbox or radio
111
+ //note : radio has keyup and click
112
+ */
113
+
114
+ $logic_event = ! $is_form_editor && ! $is_entry_detail ? $field->get_conditional_logic_event( 'keyup' ) : '';
115
+
116
+ $placeholder_attribute = $field->get_field_placeholder_attribute();
117
+ $required_attribute = $field->isRequired ? 'aria-required="true"' : '';
118
+ $invalid_attribute = $field->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
119
+ $html5_attributes = " {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$max_length} ";
120
+
121
+ $input = '<div class="ginput_container ginput_container_text ginput_container_ir_national_id">';
122
+ $input .= '<input onblur="ir_national_id_' . $field_id . '(this);" name="input_' . $field_id . '" id="' . $input_id . '" type="text" value="' . esc_attr( $value ) . '" class="ir_national_id ' . esc_attr( $class ) . '" ' . $tabindex . ' ' . $logic_event . ' ' . $html5_attributes . ' ' . $disabled_text . '/>';
123
+ $input .= '</div>';
124
+
125
+ if ( $is_frontend ) {
126
+ $input .= '<span class="ir_national_id_location" id="ir_national_id_location_' . $field_id . '"></span>';
127
+ }
128
+ }
129
+
130
+ return $input;
131
+ }
132
+
133
+ public function settings() { ?>
134
+ <script type='text/javascript'>
135
+ fieldSettings["ir_national_id"] = ".placeholder_setting, .input_mask_setting, .label_placement_setting, .prepopulate_field_setting, .conditional_logic_field_setting, .label_setting, .admin_label_setting, .size_setting, .rules_setting, .visibility_setting, .duplicate_setting, .default_value_setting, .description_setting, .css_class_setting, .ir_national_id_setting";
136
+ jQuery(document).bind('gform_load_field_settings', function (event, field, form) {
137
+ jQuery("#showLocation").attr("checked", field["showLocation"] == true);
138
+ jQuery("#showSeperator").attr("checked", field["showSeperator"] == true);
139
+ jQuery("#forceEnglish").attr("checked", field["forceEnglish"] == true);
140
+ jQuery("#notDigitError").val(field["notDigitError"]);
141
+ jQuery("#qtyDigitError").val(field["qtyDigitError"]);
142
+ jQuery("#duplicateError").val(field["duplicateError"]);
143
+ jQuery("#isInvalidError").val(field["isInvalidError"]);
144
+ });
145
+ </script>
146
+ <?php
147
+ }
148
+
149
+
150
+ public function admin_conditional_logic( $form ) {
151
+
152
+ if ( GFCommon::is_entry_detail() ) {
153
+ return $form;
154
+ }
155
+
156
+ echo "<script type='text/javascript'>" .
157
+ " gform.addFilter('gform_is_conditional_logic_field', function (isConditionalLogicField, field) {" .
158
+ " return field.type == 'ir_national_id' ? true : isConditionalLogicField;" .
159
+ ' });' .
160
+ " gform.addFilter('gform_conditional_logic_operators', function (operators, objectType, fieldId) {" .
161
+ ' var targetField = GetFieldById(fieldId);' .
162
+ " if (targetField && targetField['type'] == 'ir_national_id') {" .
163
+ " operators = {'is':'is','isnot':'isNot', '>':'greaterThan', '<':'lessThan', 'contains':'contains', 'starts_with':'startsWith', 'ends_with':'endsWith'};" .
164
+ ' }' .
165
+ ' return operators;' .
166
+ ' });' .
167
+ '</script>';
168
+
169
+ return $form;
170
+ }
171
+
172
+ public function standard_settings( $position, $form_id ) {
173
+
174
+ if ( $position == 50 ) { ?>
175
+
176
+ <li class="ir_national_id_setting field_setting">
177
+
178
+ <input type="checkbox" id="showLocation"
179
+ onclick="SetFieldProperty('showLocation', this.checked);"/>
180
+ <label for="showLocation" class="inline">
181
+ نمایش شهر بر اساس کد ملی
182
+ <?php gform_tooltip( "tooltip_showLocation" ); ?>
183
+ </label>
184
+
185
+ <br/>
186
+ <input type="checkbox" id="showSeperator"
187
+ onclick="SetFieldProperty('showSeperator', this.checked);"/>
188
+ <label for="showSeperator" class="inline">
189
+ جداسازی خودکار ارقام توسط خط فاصله
190
+ <?php gform_tooltip( "tooltip_showSeperator" ); ?>
191
+ </label>
192
+
193
+ <br/>
194
+ <input type="checkbox" id="forceEnglish"
195
+ onclick="SetFieldProperty('forceEnglish', this.checked);"/>
196
+ <label for="forceEnglish" class="inline">
197
+ تبدیل خودکار اعداد فارسی و عربی به انگلیسی
198
+ <?php gform_tooltip( "tooltip_forceEnglish" ); ?>
199
+ </label>
200
+ <br/>
201
+
202
+ <br/>
203
+ <label for="notDigitError">
204
+ پیغام زمانی که مقدار وارد شده شامل کاراکتر غیر عددی باشد
205
+ <?php gform_tooltip( "tooltip_notDigitError" ); ?>
206
+ </label>
207
+ <input type="text" class="fieldwidth-3" id="notDigitError" size="35"
208
+ onkeyup="SetFieldProperty('notDigitError', this.value);"/>
209
+ <br/>
210
+
211
+ <br/>
212
+ <label for="qtyDigitError">
213
+ پیغام زمانیکه تعداد ارقام وارد شده استاندارد نباشد
214
+ <?php gform_tooltip( "tooltip_qtyDigitError" ); ?>
215
+ </label>
216
+ <input type="text" class="fieldwidth-3" id="qtyDigitError" size="35"
217
+ onkeyup="SetFieldProperty('qtyDigitError', this.value);"/>
218
+ <br/>
219
+
220
+ <br/>
221
+ <label for="isInvalidError">
222
+ پیغام زمانیکه کد ملی وارد شده مطابق با الگوی ملی نباشد
223
+ <?php gform_tooltip( "tooltip_isInvalidError" ); ?>
224
+ </label>
225
+ <input type="text" class="fieldwidth-3" id="isInvalidError" size="35"
226
+ onkeyup="SetFieldProperty('isInvalidError', this.value);"/>
227
+ <br/>
228
+
229
+ <br/>
230
+ <label for="duplicateError">
231
+ پیغام زمانیکه کد ملی وارد شده قبلا ثبت شده باشد
232
+ <?php gform_tooltip( "tooltip_duplicateError" ); ?>
233
+ </label>
234
+ <input type="text" class="fieldwidth-3" id="duplicateError" size="35"
235
+ onkeyup="SetFieldProperty('duplicateError', this.value);"/>
236
+ <br/>
237
+ </li>
238
+ <?php
239
+ }
240
+ }
241
+
242
+ public function frontend_script( $form, $ajax ) {
243
+
244
+ $flag_js = $flag_fn = false;
245
+ $fields = GFCommon::get_fields_by_type( $form, array( 'ir_national_id' ) );
246
+
247
+ foreach ( (array) $fields as $field ) {
248
+
249
+ $location = rgar( $field, 'showLocation', 0 ) ? 1 : 0;
250
+ $seperator = rgar( $field, 'showSeperator', 0 ) ? 1 : 0;
251
+ $forceEnglish = rgar( $field, 'forceEnglish', 0 ) ? 1 : 0;
252
+
253
+ if ( ! $flag_js && ( $location + $seperator ) ) {
254
+
255
+ $flag_js = true;
256
+
257
+ wp_dequeue_script( 'gform_ir_national_id' );
258
+ wp_deregister_script( 'gform_ir_national_id' );
259
+
260
+ wp_register_script( 'gform_ir_national_id', GF_PERSIAN_URL . 'assets/js/national_id.min.js', array(), GF_PERSIAN_VERSION, false );
261
+ wp_enqueue_script( 'gform_ir_national_id' );
262
+ }
263
+ ?>
264
+ <script type="text/javascript">
265
+ <?php if ( ! $flag_fn && $forceEnglish) : ?>
266
+ function ir_national_id_to_english(number) {
267
+ return number.replace(/[۰|٠]/g, '0').replace(/[۱|١]/g, '1')
268
+ .replace(/[۲|٢]/g, '2').replace(/[۳|٣]/g, '3')
269
+ .replace(/[۴|٤]/g, '4').replace(/[۵|٥]/g, '5').replace(/[۶|٦]/g, '6')
270
+ .replace(/[۷|٧]/g, '7').replace(/[۸|٨]/g, '8').replace(/[۹|٩]/g, '9')
271
+ }
272
+ <?php $flag_fn = true; endif;?>
273
+ function ir_national_id_<?php echo $field['id']; ?>(_this) {
274
+ <?php if ( $forceEnglish ) : ?>
275
+ _this.value = ir_national_id_to_english(_this.value);
276
+ <?php endif;
277
+ if ( $location + $seperator ) : ?>
278
+ var field_id = "<?php echo $field['id'] ?>";
279
+ var message1 = "<?php echo rgar( $field, 'notDigitError', 'کد ملی فقط باید به صورت عدد وارد شود.' ); ?>";
280
+ var message2 = "<?php echo rgar( $field, 'qtyDigitError', 'کد ملی می بایست 10 رقمی باشد.' ); ?>";
281
+ var message3 = "<?php echo rgar( $field, 'isInvalidError', 'کد ملی وارد شده مطابق با استانداردهای کشور نمی باشد.' ); ?>";
282
+ GFPersian_National_ID_Handler(_this, field_id, message1, message2, message3, <?php echo $seperator ?>, <?php echo $location ?>);
283
+ jQuery(_this).trigger('change');
284
+ <?php endif;?>
285
+ }
286
+ </script>
287
+ <?php
288
+ }
289
+ }
290
+
291
+ public function is_valid( $value = '' ) {
292
+
293
+ if ( ! empty( $value ) ) {
294
+
295
+ $_value = $value;
296
+
297
+ if ( strlen( $value ) == 8 ) {
298
+ $_value = '00' . $value;
299
+ }
300
+
301
+ if ( strlen( $value ) == 9 ) {
302
+ $_value = '0' . $value;
303
+ }
304
+
305
+ $pre_check = array(
306
+ '0000000000',
307
+ '1111111111',
308
+ '2222222222',
309
+ '3333333333',
310
+ '4444444444',
311
+ '5555555555',
312
+ '6666666666',
313
+ '7777777777',
314
+ '8888888888',
315
+ '9999999999',
316
+ '0123456789',
317
+ );
318
+
319
+ if ( in_array( $_value, $pre_check ) ) {
320
+ return 2;
321
+ }
322
+
323
+ if ( ! is_numeric( $value ) ) {
324
+ return 4;
325
+ }
326
+
327
+ $value = (string) preg_replace( '/[^0-9]/', '', $value );
328
+
329
+ if ( strlen( $value ) > 10 || strlen( $value ) < 8 ) {
330
+ return 3;
331
+ }
332
+
333
+ $value = $_value;
334
+
335
+ $list_code = str_split( $value );
336
+ $last = (int) $list_code[9];
337
+ unset( $list_code[9] );
338
+
339
+ $i = 10;
340
+ $sum = 0;
341
+ foreach ( $list_code as $key => $val ) {
342
+ $sum += intval( $val ) * $i;
343
+ $i --;
344
+ }
345
+
346
+ $mod = (int) $sum % 11;
347
+
348
+ if ( $mod >= 2 ) {
349
+ $mod = 11 - $mod;
350
+ }
351
+ if ( $mod != $last ) {
352
+ return 2;
353
+ } else {
354
+ return 1;
355
+ }
356
+ }
357
+
358
+ return false;
359
+ }
360
+
361
+ public function validator( $result, $value, $form, $field ) {
362
+
363
+ if ( $field['type'] == 'ir_national_id' ) {
364
+
365
+ $value = ! empty( $value ) ? str_replace( '-', '', $value ) : '';
366
+ $is_valid = $this->is_valid( $value );
367
+
368
+ if ( $is_valid == 4 ) {
369
+ $result['is_valid'] = false;
370
+ $result['message'] = rgar( $field, 'notDigitError', 'کد ملی فقط باید به صورت عدد وارد شود.' );
371
+
372
+ return $result;
373
+ }
374
+
375
+ if ( $is_valid == 3 ) {
376
+ $result['is_valid'] = false;
377
+ $result['message'] = rgar( $field, 'qtyDigitError', 'کد ملی می بایست 10 رقمی باشد. تنها در صورتی مجاز به استفاده از کد های 8 یا 9 رقمی هستید که ارقام سمت چپ 0 باشند.' );
378
+
379
+ return $result;
380
+ }
381
+
382
+ if ( $is_valid == 2 ) {
383
+ $result['is_valid'] = false;
384
+ $result['message'] = rgar( $field, 'isInvalidError', 'کد ملی وارد شده مطابق با استانداردهای کشور نمی باشد.' );
385
+
386
+ return $result;
387
+ }
388
+
389
+ if ( $field['noDuplicates'] ) {
390
+
391
+ if ( strlen( $value ) == 8 ) {
392
+ $value = '00' . $value;
393
+ }
394
+
395
+ if ( strlen( $value ) == 9 ) {
396
+ $value = '0' . $value;
397
+ }
398
+
399
+ if ( RGFormsModel::is_duplicate( $form['id'], $field, $value ) ) {
400
+ $result['is_valid'] = false;
401
+ $result['message'] = rgar( $field, 'duplicateError', 'این کد ملی توسط فرد دیگری ثبت شده است.' );
402
+
403
+ return $result;
404
+ }
405
+ }
406
+ }
407
+
408
+ return $result;
409
+ }
410
+
411
+ public function pre_submission( $form ) {
412
+
413
+ $ir_national_id_fields = GFCommon::get_fields_by_type( $form, array( 'ir_national_id' ) );
414
+
415
+ foreach ( (array) $ir_national_id_fields as $field ) {
416
+
417
+ $input_name = "input_{$field['id']}";
418
+ $input_value = rgpost( $input_name );
419
+
420
+ if ( ! empty( $input_value ) ) {
421
+
422
+ if ( strlen( $input_value ) == 8 ) {
423
+ $_POST["input_{$field['id']}"] = '00' . $input_value;
424
+ } elseif ( strlen( $input_value ) == 9 ) {
425
+ $_POST["input_{$field['id']}"] = '0' . $input_value;
426
+ } else {
427
+ $_POST["input_{$field['id']}"] = $input_value;
428
+ }
429
+ }
430
+ }
431
+ }
432
+ }
433
+
434
+ new GFPersian_National_ID();
includes/class-news-letter.php DELETED
@@ -1,50 +0,0 @@
1
- <?php if ( ! defined('ABSPATH') ) exit;
2
-
3
- class GFParsi_Newsletter {
4
-
5
- private static $instance = null;
6
-
7
- public static function get_instance() {
8
- if( null == self::$instance )
9
- self::$instance = new self;
10
- return self::$instance;
11
- }
12
-
13
- private function __construct() {
14
- add_filter( 'gform_notification_events', array( $this, 'add_manual_notification_event' ) );
15
- add_filter( 'gform_before_resend_notifications', array( $this, 'add_notification_filter' ) );
16
- }
17
-
18
- public function add_notification_filter( $form ) {
19
- add_filter( 'gform_notification', array( $this, 'evaluate_notification_conditional_logic' ), 10, 3 );
20
- return $form;
21
- }
22
-
23
- public function add_manual_notification_event( $events ) {
24
- $events['manual'] = __( 'Newsletter', 'GF_FA' );
25
- return $events;
26
- }
27
-
28
- public function evaluate_notification_conditional_logic( $notification, $form, $entry ) {
29
-
30
- // if it fails conditional logic, suppress it
31
- if( $notification['event'] == 'manual' && ! GFCommon::evaluate_conditional_logic( rgar( $notification, 'conditionalLogic' ), $form, $entry ) ) {
32
- add_filter( 'gform_pre_send_email', array( $this, 'abort_next_notification' ) );
33
- }
34
-
35
- return $notification;
36
- }
37
-
38
- public function abort_next_notification( $args ) {
39
- remove_filter( 'gform_pre_send_email', array( $this, 'abort_next_notification' ) );
40
- $args['abort_email'] = true;
41
- return $args;
42
- }
43
-
44
- }
45
-
46
- function GFParsi_Newsletter() {
47
- return GFParsi_Newsletter::get_instance();
48
- }
49
-
50
- GFParsi_Newsletter();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-payments.php ADDED
@@ -0,0 +1,499 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+
5
+ class GFPersian_Payments extends GFPersian_Core {
6
+
7
+ public function __construct() {
8
+
9
+ if ( $this->option( 'payments', '1' ) != '1' ) {
10
+ return;
11
+ }
12
+
13
+ $version = self::get_gform_version();
14
+ if ( version_compare( $version, '2.3-dev-1', '>=' ) ) {
15
+ add_filter( 'gform_is_duplicate', array( $this, 'better_noDuplicate_2_3_dev_1' ), 10, 4 );
16
+ } elseif ( class_exists( 'GFParsi' ) ) {
17
+ GFParsi::better_noDuplicate_hook( $version );
18
+ }
19
+
20
+ add_filter( 'gform_payment_status', array( $this, 'payment_status_entry' ) );
21
+ add_action( 'gform_entries_first_column', array( $this, 'payment_detail_entries' ), 10, 5 );
22
+ add_filter( 'admin_print_footer_scripts', array( $this, 'payment_status_conditional_logic' ) );
23
+
24
+ add_action( 'gform_notification_ui_settings', array( $this, 'payment_status_hint' ), 10, 3 );
25
+ add_action( 'gform_confirmation_ui_settings', array( $this, 'payment_status_hint' ), 10, 3 );
26
+
27
+ add_filter( 'gform_entry_meta', array( $this, 'gform_entry_meta' ) );
28
+ add_filter( 'gform_is_value_match', array( $this, 'is_value_match' ), 10, 6 );
29
+ }
30
+
31
+ public static function _payment_status( $entry, $only_name = false, $status = '' ) {
32
+
33
+ $status = ! empty( $status ) ? $status : rgar( $entry, 'payment_status' );
34
+
35
+ $status = ucfirst( $status );
36
+
37
+ if ( in_array( $status, array( 'Completed', 'Paid', 'Active', 'Approved' ) ) ) {
38
+ $status = array( '#3d804c', 'موفق' );
39
+
40
+ } elseif ( $status == 'Failed' ) {
41
+ $status = array( '#ff4b44', 'ناموفق' );
42
+
43
+ } elseif ( $status == 'Cancelled' ) {
44
+ $status = array( '#FFA500', 'منصرف شده' );
45
+
46
+ } elseif ( ! empty( $status ) ) {
47
+ $status = array( '#3399FF', 'در انتظار پرداخت' );
48
+
49
+ } else {
50
+ $status = array();
51
+ }
52
+
53
+ if ( empty( $status[0] ) || empty( $status[1] ) ) {
54
+ return '';
55
+ }
56
+
57
+ if ( $only_name ) {
58
+ return $status[1];
59
+ }
60
+
61
+ return "<span style='color: {$status[0]}'>{$status[1]}</span>";
62
+ }
63
+
64
+ public function payment_status_entry( $status ) {
65
+
66
+ if ( GFCommon::is_entry_detail() ) {
67
+ $status = self::_payment_status( '', false, $status );
68
+ }
69
+
70
+ return $status;
71
+ }
72
+
73
+ public function payment_detail_entries( $form_id, $field_id, $value, $entry, $query_string ) {
74
+
75
+ $url = remove_query_arg( array( 's', 'field_id', 'operator' ) );
76
+ $urls = array();
77
+
78
+ $status = self::_payment_status( $entry );
79
+ if ( ! empty( $status ) ) {
80
+
81
+ $url = add_query_arg( array(
82
+ 's' => ucfirst( rgar( $entry, 'payment_status' ) ),
83
+ 'field_id' => 'payment_status',
84
+ 'operator' => 'is'
85
+ ), $url );
86
+
87
+ $urls[] = '<a href="' . $url . '"> ' . $status . ' </a>';
88
+ }
89
+
90
+ $gateway = gform_get_meta( rgar( $entry, 'id' ), 'payment_gateway' );
91
+ if ( ! empty( $gateway ) ) {
92
+ $url = add_query_arg( array(
93
+ 's' => $gateway,
94
+ 'field_id' => 'payment_gateway',
95
+ 'operator' => 'is'
96
+ ), $url );
97
+ $urls[] = '<a href="' . $url . '" style="color:black"> ' . $gateway . ' </a>';
98
+ }
99
+
100
+ if ( ! empty( $urls ) ) {
101
+ echo implode( ' - ', $urls );
102
+ }
103
+ }
104
+
105
+ public function better_noDuplicate_2_3_dev_1( $count, $form_id, $field, $value ) {
106
+
107
+ global $wpdb;
108
+
109
+ $entry_meta_table_name = GFFormsModel::get_entry_meta_table_name();
110
+ $entry_table_name = GFFormsModel::get_entry_table_name();
111
+
112
+ switch ( GFFormsModel::get_input_type( $field ) ) {
113
+ case 'time':
114
+ $value = sprintf( "%02d:%02d %s", $value[0], $value[1], $value[2] );
115
+ break;
116
+ case 'date':
117
+ $value = GFFormsModel::prepare_date( $field->dateFormat, $value );
118
+ break;
119
+ case 'number':
120
+ $value = GFCommon::clean_number( $value, $field->numberFormat );
121
+ break;
122
+ case 'phone':
123
+ $value = str_replace( array( ')', '(', '-', ' ' ), '', $value );
124
+ $sql_comparison = 'replace( replace( replace( replace( ld.value, ")", "" ), "(", "" ), "-", "" ), " ", "" ) = %s';
125
+ break;
126
+ case 'email':
127
+ $value = is_array( $value ) ? rgar( $value, 0 ) : $value;
128
+ break;
129
+ }
130
+
131
+ $inner_sql_template = "SELECT %s as input, ld.entry_id
132
+ FROM {$entry_meta_table_name} ld
133
+ INNER JOIN {$entry_table_name} l ON l.id = ld.entry_id\n";
134
+
135
+
136
+ $inner_sql_template .= "WHERE l.form_id=%d AND ld.form_id=%d
137
+ AND ld.meta_key = %s
138
+ AND (payment_status IS NULL OR LOWER(payment_status) IN ('', 'approved', 'approve', 'completed', 'complete', 'actived', 'active', 'paid'))
139
+ AND status='active' AND ld.meta_value = %s";
140
+
141
+ $sql = "SELECT count(distinct input) as match_count FROM ( ";
142
+
143
+ $input_count = 1;
144
+ if ( is_array( $field->get_entry_inputs() ) ) {
145
+ $input_count = sizeof( $field->inputs );
146
+ $inner_sql = '';
147
+ foreach ( $field->inputs as $input ) {
148
+ $union = empty( $inner_sql ) ? '' : ' UNION ALL ';
149
+ $inner_sql .= $union . $wpdb->prepare( $inner_sql_template, $input['id'], $form_id, $form_id, $input['id'], $value[ $input['id'] ] );
150
+ }
151
+ } else {
152
+ $inner_sql = $wpdb->prepare( $inner_sql_template, $field->id, $form_id, $form_id, $field->id, $value );
153
+ }
154
+
155
+ $sql .= $inner_sql . "
156
+ ) as count
157
+ GROUP BY entry_id
158
+ ORDER BY match_count DESC";
159
+
160
+ $count = gf_apply_filters( array(
161
+ 'gform_is_duplicate_better',
162
+ $form_id
163
+ ), $wpdb->get_var( $sql ), $form_id, $field, $value );
164
+
165
+ return $count != null && $count >= $input_count;
166
+ }
167
+
168
+ /*-----------------------------------------------------------------------------------*/
169
+ /*-----------------------------------------------------------------------------------*/
170
+ /*-----------------------------------------------------------------------------------*/
171
+ /*-----------------------------------------------------------------------------------*/
172
+
173
+ public function payment_status_hint( $ui_settings, $notif_confirm, $form ) {
174
+
175
+ if ( ! empty( rgar( $notif_confirm, 'isDefault' ) ) ) {
176
+ return $ui_settings;
177
+ }
178
+
179
+ $current_action = current_action();
180
+ if ( stripos( $current_action, 'confirmation' ) !== false ) {
181
+ $current_action = 'تاییدیه';
182
+ } else {
183
+ $current_action = 'اعلان';
184
+ }
185
+
186
+ $ui_settings['payment_status_hint'] = '
187
+ <tr>
188
+ <th><label for="stickylist_confirmation_type">وضعیت پرداخت</label></th>
189
+ <td>' . sprintf( 'برای محدود کردن این %s به وضعیت پرداخت های مورد نظر، از طریق منطق شرطی بالا وضعیت پرداخت مورد نظر را ست نمایید. توجه نمایید که همه درگاه های پرداخت از وضعیت "انصرافی" پشتیبانی نمیکنند. ضمن اینکه نسخه درگاه پرداخت ایرانی شما باید حداقل 2.3 باشد.', $current_action ) . '</td>
190
+ </tr>';
191
+
192
+ return $ui_settings;
193
+ }
194
+
195
+ public function payment_status_conditional_logic() {
196
+
197
+ if ( ! $this->is_gravity_page() || ! in_array( rgget( 'subview' ), array( 'confirmation', 'notification' ) ) ) {
198
+ return;
199
+ }
200
+ ?>
201
+
202
+ <script type="text/javascript">
203
+ if (window.gform) {
204
+ gform.addFilter('gform_conditional_logic_fields', function (options, form, selectedFieldId) {
205
+ options.push({
206
+ label: 'وضعیت پرداخت',
207
+ value: 'payment_status'
208
+ });
209
+ return options;
210
+ });
211
+ jQuery(document).ready(function ($) {
212
+ var $InputsRefreshTimeout = false;
213
+ var baseSelector = '.gf_conditional_logic_rules_container';
214
+ $(document).bind('gform_load_field_settings', function (event, field) {
215
+ $(document).find(baseSelector + ' select[id*="_rule_field_"]').each(function () {
216
+ ConditionalLogicPaymentStatus($(this));
217
+ });
218
+ });
219
+ $(document).on('change', baseSelector + ' select[id*="_rule_field_"]', function () {
220
+ ConditionalLogicPaymentStatus($(this));
221
+ });
222
+ $(document).on('change', baseSelector + ' select[id*="_rule_operator_"]', function () {
223
+ ConditionalLogicPaymentStatus($(this).prev('select'));
224
+ });
225
+ $(document).on('change', baseSelector + ' .add_field_choice', function () {
226
+ delayedRefreshPaymentStatusInputs();
227
+ });
228
+ gform.addFilter('gform_conditional_logic_values_input', function (fields) {
229
+ delayedRefreshPaymentStatusInputs();
230
+ return fields;
231
+ });
232
+
233
+ function delayedRefreshPaymentStatusInputs() {
234
+ $InputsRefreshTimeout = setTimeout(function () {
235
+ $(document).find(baseSelector + ' select[id*="_rule_field_"]').each(function () {
236
+ ConditionalLogicPaymentStatus($(this));
237
+ });
238
+ }, 10);
239
+ }
240
+
241
+ function ConditionalLogicPaymentStatus($select) {
242
+ var value = $select.val();
243
+ if (value == 'payment_status') {
244
+ var $_input,
245
+ bits = $select.attr('id').split('_'),
246
+ index = bits[bits.length - 1],
247
+ prep = bits.indexOf('rule'),
248
+ prefix = bits.slice(0, prep).join('_'),
249
+ $input = $('#{0}_rule_value_{1}'.format(prefix, index)),
250
+ $operator = $('#{0}_rule_operator_{1}'.format(prefix, index));
251
+ $operator.find(":not(option[value^='is'])").each(function () {
252
+ $(this).remove();
253
+ });
254
+ var input_value, input_name, input_id;
255
+ input_value = 'completed';
256
+ if (typeof $input.val() != 'undefined' && $input.val().length)
257
+ input_value = $input.val();
258
+ if (typeof $input.attr('id') != 'undefined')
259
+ input_id = $input.attr('id');
260
+ else
261
+ input_id = $operator.attr('id').replace('operator', 'value');
262
+ if (typeof $input.attr('name') != 'undefined')
263
+ input_name = $input.attr('name');
264
+ else
265
+ input_name = input_id;
266
+ var options = '<option value="completed">موفق</option>';
267
+ options += '<option value="failed">ناموفق</option>';
268
+ options += '<option value="cancelled">انصرافی</option>';
269
+ options = options.replace(/ selected="selected"/g, '');
270
+ options = options.replace("value=\"" + input_value + "\"", "value=\"" + input_value + "\" selected=\"selected\"");
271
+ if (typeof $input[0] == 'undefined') {
272
+ $operator.after('<input id="paymetn_statuses_temp"/>');
273
+ $_input = $('#paymetn_statuses_temp')[0];
274
+ } else {
275
+ $_input = $input[0];
276
+ }
277
+ $_input.outerHTML = "<select value='" + input_value + "' id='" + input_id + "' name='" + input_name + "' class='gfield_rule_select gfield_rule_value_dropdown'>" + options + "</select>";
278
+ }
279
+ }
280
+
281
+ delayedRefreshPaymentStatusInputs();
282
+ });
283
+ }
284
+ </script>
285
+ <?php
286
+ }
287
+
288
+ public function gform_entry_meta( $metas ) {
289
+ $metas['payment_status'] = 'payment_status';
290
+
291
+ return $metas;
292
+ }
293
+
294
+ public function is_value_match( $is_match, $field_value/*entry['payment_status']*/, $rule_value, $rule_operator, $source_field = null, $rule ) {
295
+
296
+ if ( $rule['fieldId'] == 'payment_status' ) {
297
+
298
+ $field_value = strtolower( $field_value );
299
+
300
+ if ( in_array( $field_value, array( 'completed', 'paid', 'active', 'approved' ) ) ) {
301
+ $field_value = 'completed';
302
+ }
303
+
304
+ $rule_value = ! empty( $rule_value ) ? $rule_value : 'completed';
305
+
306
+ remove_filter( 'gform_is_value_match', array( $this, __FUNCTION__ ) );
307
+ $is_match = GFFormsModel::is_value_match( $field_value, $rule_value, $rule_operator );
308
+ add_filter( 'gform_is_value_match', array( $this, __FUNCTION__ ), 10, 6 );
309
+ }
310
+
311
+ return $is_match;
312
+ }
313
+ /*-----------------------------------------------------------------------------------*/
314
+ /*-----------------------------------------------------------------------------------*/
315
+ /*-----------------------------------------------------------------------------------*/
316
+ /*-----------------------------------------------------------------------------------*/
317
+ public static function notification( $form, $entry ) {
318
+ $entry = GFAPI::get_entry( rgar( $entry, 'id' ) );
319
+ $notifications = GFCommon::get_notifications_to_send( 'form_submission', $form, $entry );
320
+ $_notifications = array();
321
+ foreach ( (array) $notifications as $notification ) {
322
+ $logic = rgar( $notification, 'conditionalLogic' );
323
+ $rules = rgar( $logic, 'rules' );
324
+ if ( empty( $rules ) ) {
325
+ continue;
326
+ }
327
+ $fieldIds = wp_list_pluck( $rules, 'fieldId' );
328
+ if ( in_array( 'payment_status', $fieldIds ) ) {
329
+ $_notifications[] = $notification;
330
+ }
331
+ }
332
+ if ( ! empty( $_notifications ) ) {
333
+ $_notifications = wp_list_pluck( $_notifications, 'id' );
334
+ GFCommon::send_notifications( $_notifications, $form, $entry );
335
+ }
336
+ }
337
+
338
+ public static function confirmation( $form, $entry, $fault ) {
339
+
340
+ if ( ! class_exists( "GFFormDisplay" ) ) {
341
+ require_once( GFCommon::get_base_path() . "/form_display.php" );
342
+ }
343
+
344
+ $entry = GFAPI::get_entry( rgar( $entry, 'id' ) );
345
+ $confirmation = GFFormDisplay::handle_confirmation( $form, $entry );
346
+ if ( is_array( $confirmation ) && isset( $confirmation["redirect"] ) ) {
347
+ header( "Location: {$confirmation["redirect"]}" );
348
+ exit;
349
+ }
350
+ $fault = ! empty( $fault ) ? $fault : '';
351
+ $confirmation = str_ireplace( '{fault}', $fault, $confirmation );
352
+ GFFormDisplay::$submission[ $form['id'] ] = array(
353
+ "is_confirmation" => true,
354
+ "confirmation_message" => $confirmation,
355
+ "form" => $form,
356
+ "entry" => $entry,
357
+ "lead" => $entry
358
+ );
359
+ }
360
+
361
+ public static function currency( $entry = '', $form = '' ) {
362
+
363
+ if ( is_numeric( $entry ) ) {
364
+ $entry = GFAPI::get_entry( $entry );
365
+ }
366
+
367
+ if ( rgar( $entry, 'currency' ) ) {
368
+ return rgar( $entry, 'currency' );
369
+ }
370
+
371
+ if ( is_numeric( $form ) ) {
372
+ $form = GFAPI::get_form( $form );
373
+ }
374
+
375
+ if ( rgar( $form, 'currency' ) ) {
376
+ return rgar( $form, 'currency' );
377
+ }
378
+
379
+ return GFCommon::get_currency();
380
+ }
381
+
382
+ public static function amount( $amount, $to_currency = 'IRR', $entry = '', $form = '' ) {
383
+
384
+ $currency = self::currency( $entry, $form );
385
+
386
+ if ( in_array( $currency, array( 'IRHR', 'IRHT' ) ) ) {
387
+ $currency = str_ireplace( 'H', '', $currency );
388
+ $amount *= 1000;
389
+ }
390
+
391
+ if ( $currency == 'IRR' && $to_currency == 'IRT' ) {
392
+ $amount /= 10;
393
+ }
394
+
395
+ if ( $currency == 'IRT' && $to_currency == 'IRR' ) {
396
+ $amount *= 10;
397
+ }
398
+
399
+ return $amount;
400
+ }
401
+
402
+ public static function check_verification( $entry, $gateway, $params ) {
403
+
404
+ if ( empty( $params ) || trim( $params ) == '' ) {
405
+ return false;
406
+ }
407
+
408
+ $params = self::params_verification( $gateway, $params );
409
+
410
+ $table_name = '';
411
+ if ( method_exists( 'GFFormsModel', 'get_lead_meta_table_name' ) ) {
412
+ $table_name = GFFormsModel::get_lead_meta_table_name();
413
+ }
414
+ if ( version_compare( self::get_gform_version(), '2.3-dev-1', '>=' ) ) {
415
+ if ( method_exists( 'GFFormsModel', 'get_entry_meta_table_name' ) ) {
416
+ $table_name = GFFormsModel::get_entry_meta_table_name();
417
+ }
418
+ }
419
+
420
+ if ( ! empty( $table_name ) ) {
421
+
422
+ global $wpdb;
423
+ $check = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE meta_key='_verification_params' AND meta_value='%s'", $params ) );
424
+
425
+ if ( ! empty( $check ) ) {
426
+
427
+ if ( is_numeric( $entry ) ) {
428
+ $entry = GFAPI::get_entry( $entry );
429
+ }
430
+
431
+ $entry["payment_date"] = gmdate( "Y-m-d H:i:s" );
432
+ $entry["payment_status"] = "Failed";
433
+ $entry["payment_amount"] = 0;
434
+ $entry["is_fulfilled"] = 0;
435
+ GFAPI::update_entry( $entry );
436
+
437
+ global $current_user;
438
+ $user_id = 0;
439
+ $user_name = 'مهمان';
440
+ if ( $current_user && $user_data = get_userdata( $current_user->ID ) ) {
441
+ $user_id = $current_user->ID;
442
+ $user_name = $user_data->display_name;
443
+ }
444
+
445
+ $Message = 'تراکنش ناموفق ::: نتیجه تراکنش قبلا مشخص شده بود و تراکنش دوباره تکرار شد.';
446
+
447
+ RGFormsModel::add_note( $entry["id"], $user_id, $user_name, $Message );
448
+
449
+ $form = GFAPI::get_form( rgar( $entry, 'form_id' ) );
450
+
451
+ self::notification( $form, $entry );
452
+ self::confirmation( $form, $entry, $Message );
453
+
454
+ return true;
455
+ }
456
+ }
457
+
458
+ return false;
459
+ }
460
+
461
+ public static function set_verification( $entry, $gateway, $params ) {
462
+
463
+ if ( empty( $params ) || trim( $params ) == '' ) {
464
+ return false;
465
+ }
466
+
467
+ if ( ! is_numeric( $entry ) ) {
468
+ $entry = rgar( $entry, 'id' );
469
+ }
470
+
471
+ $params = self::params_verification( $gateway, $params );
472
+
473
+ gform_update_meta( $entry, '_verification_params', $params );
474
+ }
475
+
476
+ private static function params_verification( $gateway, $params ) {
477
+ if ( is_array( $params ) || is_object( $params ) ) {
478
+ $params = implode( '_', (array) $params );
479
+ }
480
+
481
+ return trim( $gateway . '_' . $params );
482
+ }
483
+
484
+ private static function get_gform_version() {
485
+ $version = GFCommon::$version;
486
+ if ( method_exists( 'GFFormsModel', 'get_database_version' ) ) {
487
+ $version = GFFormsModel::get_database_version();
488
+ }
489
+
490
+ return $version;
491
+ }
492
+
493
+ public static function nusoap() {
494
+ require_once 'lib/nusoap.php';
495
+ }
496
+
497
+ }
498
+
499
+ new GFPersian_Payments;
includes/class-post-content-merge-tags.php DELETED
@@ -1,249 +0,0 @@
1
- <?php if ( ! defined('ABSPATH') ) exit;
2
-
3
- class GFParsi_Post_Content_Merge_Tags {
4
-
5
- public static $_entry = null;
6
-
7
- private static $instance = null;
8
-
9
- public static function get_instance( $args = array() ) {
10
-
11
- if( self::$instance == null )
12
- self::$instance = new self( $args );
13
-
14
- return self::$instance;
15
- }
16
-
17
- function __construct( $args ) {
18
-
19
- if( ! class_exists( 'GFForms' ) )
20
- return;
21
-
22
- $this->_args = wp_parse_args( $args, array(
23
- 'auto_append_lead' => true, // true, false or array of form IDs
24
- 'encrypt_lead' => false,
25
- ) );
26
-
27
- add_filter( 'the_content', array( $this, 'replace_merge_tags' ), 1 );
28
- add_filter( 'gform_replace_merge_tags', array( $this, 'replace_encrypt_entry_id_merge_tag' ), 10, 3 );
29
-
30
- if( ! empty( $this->_args['auto_append_lead'] ) ) {
31
- add_filter( 'gform_confirmation', array( $this, 'append_lead_parameter' ), 20, 3 );
32
- }
33
-
34
- }
35
-
36
- function replace_merge_tags( $post_content ) {
37
-
38
- $entry = $this->get_entry();
39
- if( ! $entry )
40
- return $this->replace_field_label_merge_tags( $post_content, '' );
41
-
42
-
43
- $confirm_time = gform_get_meta( rgar($entry,'id') , 'gform_page_confirm_time');
44
-
45
- if ( !empty($confirm_time) && $confirm_time + 90 < time() )
46
- return $this->replace_field_label_merge_tags( $post_content, '' );
47
-
48
- if (empty($confirm_time))
49
- gform_update_meta($entry['id'], 'gform_page_confirm_time', time() );
50
-
51
- $form = GFFormsModel::get_form_meta( $entry['form_id'] );
52
-
53
- $post_content = $this->replace_field_label_merge_tags( $post_content, $form );
54
- $post_content = GFCommon::replace_variables( $post_content, $form, $entry, false, false, false );
55
-
56
- return $post_content;
57
- }
58
-
59
- function replace_field_label_merge_tags( $text, $form ) {
60
-
61
- if ( !empty($form) ) {
62
-
63
- preg_match_all( '/{([^:]+?)}/', $text, $matches, PREG_SET_ORDER );
64
- if( empty( $matches ) )
65
- return $text;
66
-
67
- foreach( $matches as $match ) {
68
-
69
- list( $search, $field_label ) = $match;
70
-
71
- foreach( $form['fields'] as $field ) {
72
-
73
- $full_input_id = false;
74
- $matches_admin_label = rgar( $field, 'adminLabel' ) == $field_label;
75
- $matches_field_label = false;
76
-
77
- if( is_array( $field['inputs'] ) ) {
78
- foreach( $field['inputs'] as $input ) {
79
- if( GFFormsModel::get_label( $field, $input['id'] ) == $field_label ) {
80
- $matches_field_label = true;
81
- $input_id = $input['id'];
82
- break;
83
- }
84
- }
85
- } else {
86
- $matches_field_label = GFFormsModel::get_label( $field ) == $field_label;
87
- $input_id = $field['id'];
88
- }
89
-
90
- if( ! $matches_admin_label && ! $matches_field_label )
91
- continue;
92
-
93
- $replace = sprintf( '{%s:%s}', $field_label, (string) $input_id );
94
- $text = str_replace( $search, $replace, $text );
95
-
96
- break;
97
- }
98
- }
99
- }
100
- else {
101
-
102
- /*
103
- preg_match_all( '/{[^{]*?:(\d+(\.\d+)?)(:(.*?))?}/mi', $text, $matches, PREG_SET_ORDER );
104
- if( !empty( $matches ) ) {
105
- foreach( $matches as $match ) {
106
- if ( isset($match[0]))
107
- $text = str_replace( $match[0], '' , $text );
108
- }
109
- }
110
-
111
- unset($matches);
112
-
113
- preg_match_all( '/{([^:]+?)}/', $text, $matches, PREG_SET_ORDER );
114
- if( !empty( $matches ) ) {
115
- foreach( $matches as $match ) {
116
- if ( isset($match[0]))
117
- $text = str_replace( $match[0], '' , $text );
118
- }
119
- }
120
- */
121
-
122
- }
123
-
124
- return $text;
125
- }
126
-
127
- function replace_encrypt_entry_id_merge_tag( $text, $form, $entry ) {
128
-
129
- if( strpos( $text, '{encrypted_entry_id}' ) === false ) {
130
- return $text;
131
- }
132
-
133
- // $entry is not always a "full" entry
134
- $entry_id = rgar( $entry, 'id' );
135
- if( $entry_id ) {
136
- $entry_id = $this->prepare_lead( $entry['id'], true );
137
- }
138
-
139
- return str_replace( '{encrypted_entry_id}', $entry_id, $text );
140
- }
141
-
142
- function append_lead_parameter( $confirmation, $form, $entry ) {
143
-
144
- $is_ajax_redirect = is_string( $confirmation ) && strpos( $confirmation, 'gformRedirect' );
145
- $is_redirect = is_array( $confirmation ) && isset( $confirmation['redirect'] );
146
-
147
- if( ! $this->is_auto_lead_enabled( $form ) || ! ( $is_ajax_redirect || $is_redirect ) ) {
148
- return $confirmation;
149
- }
150
-
151
- $lead = $this->prepare_lead( $entry['id'] );
152
-
153
- if( $is_ajax_redirect ) {
154
- preg_match_all( '/gformRedirect.+?(http.+?)(?=\'|")/', $confirmation, $matches, PREG_SET_ORDER );
155
- list( $full_match, $url ) = $matches[0];
156
- $redirect_url = add_query_arg( array( 'lead' => $lead ), $url );
157
- $confirmation = str_replace( $url, $redirect_url, $confirmation );
158
- } else {
159
- $redirect_url = add_query_arg( array( 'lead' => $lead ), $confirmation['redirect'] );
160
- $confirmation['redirect'] = $redirect_url;
161
- }
162
-
163
- return $confirmation;
164
- }
165
-
166
- function prepare_lead( $entry_id, $force_encrypt = false ) {
167
-
168
- $lead = $entry_id;
169
- $do_encrypt = $force_encrypt || $this->_args['encrypt_lead'];
170
-
171
- if( $do_encrypt && is_callable( array( 'GFCommon', 'encrypt' ) ) ) {
172
- $lead = rawurlencode( GFCommon::encrypt( $lead ) );
173
- }
174
-
175
- return $lead;
176
- }
177
-
178
- function get_entry() {
179
-
180
- if( ! self::$_entry ) {
181
-
182
- $entry_id = $this->get_entry_id();
183
- if( ! $entry_id )
184
- return false;
185
-
186
- $entry = GFFormsModel::get_lead( $entry_id );
187
- if( empty( $entry ) )
188
- return false;
189
-
190
- self::$_entry = $entry;
191
-
192
- }
193
-
194
- return self::$_entry;
195
- }
196
-
197
- function get_entry_id() {
198
-
199
- $entry_id = rgget( 'lead' );
200
- if( $entry_id ) {
201
- return $this->maybe_decrypt_entry_id( $entry_id );
202
- }
203
-
204
- $post = get_post();
205
- if( $post ) {
206
- $entry_id = get_post_meta( $post->ID, '_gform-entry-id', true );
207
- }
208
-
209
- return $entry_id ? $entry_id : false;
210
- }
211
-
212
- function maybe_decrypt_entry_id( $entry_id ) {
213
-
214
- // if encryption is enabled, 'lead' parameter MUST be encrypted
215
- $do_encrypt = $this->_args['encrypt_lead'];
216
-
217
- if( ! $entry_id ) {
218
- return null;
219
- } else if( ! $do_encrypt && is_numeric( $entry_id ) && intval( $entry_id ) > 0 ) {
220
- return $entry_id;
221
- } else {
222
- // gEYs6Cqzh1akKc7Y4RGkV8HtcJqQZRmNH+ONxuFEvXM
223
- // 0FSCGpzzmt+4Y05fFsJ4ipRZfqD/zdi2ecEeMMRKCjc=
224
- $entry_id = is_callable( array( 'GFCommon', 'decrypt' ) ) ? GFCommon::decrypt( $entry_id ) : $entry_id;
225
- return intval( $entry_id );
226
- }
227
-
228
- }
229
-
230
- function is_auto_lead_enabled( $form ) {
231
-
232
- $auto_append_lead = $this->_args['auto_append_lead'];
233
-
234
- if( is_bool( $auto_append_lead ) && $auto_append_lead === true )
235
- return true;
236
-
237
- if( is_array( $auto_append_lead ) && in_array( $form['id'], $auto_append_lead ) )
238
- return true;
239
-
240
- return false;
241
- }
242
-
243
- }
244
-
245
- function GFParsi_Post_Content_Merge_Tags( $args = array() ) {
246
- return GFParsi_Post_Content_Merge_Tags::get_instance( $args );
247
- }
248
-
249
- GFParsi_Post_Content_Merge_Tags();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-pre-submission.php DELETED
@@ -1,194 +0,0 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) {
2
- exit;
3
- }
4
-
5
- class GFParsi_PreSubmission {
6
-
7
- private static $lead;
8
-
9
- public static function init() {
10
- add_filter( 'gform_pre_render', array( __class__, 'replace_merge_tags' ) );
11
- }
12
-
13
- public static function replace_merge_tags( $form ) {
14
-
15
- if ( function_exists( 'is_checkout' ) && is_checkout() ) {
16
- return $form;
17
- }
18
-
19
- $current_page = isset( GFFormDisplay::$submission[ $form['id'] ] ) && isset( GFFormDisplay::$submission[ $form['id'] ]['page_number'] ) ? GFFormDisplay::$submission[ $form['id'] ]['page_number'] : 1;
20
- $fields = array();
21
-
22
- // get all HTML fields on the current page
23
- foreach ( $form['fields'] as &$field ) {
24
-
25
- // skip all fields on the first page
26
- if ( rgar( $field, 'pageNumber' ) <= 1 ) {
27
- continue;
28
- }
29
-
30
- $default_value = rgar( $field, 'defaultValue' );
31
- preg_match_all( '/{.+}/', $default_value, $matches, PREG_SET_ORDER );
32
- if ( ! empty( $matches ) ) {
33
- // if default value needs to be replaced but is not on current page, wait until on the current page to replace it
34
- if ( rgar( $field, 'pageNumber' ) != $current_page ) {
35
- $field['defaultValue'] = '';
36
- } else {
37
- $field['defaultValue'] = self::preview_replace_variables( $default_value, $form );
38
- }
39
- }
40
-
41
- // only run 'content' filter for fields on the current page
42
- if ( rgar( $field, 'pageNumber' ) != $current_page ) {
43
- continue;
44
- }
45
-
46
- $html_content = rgar( $field, 'content' );
47
- preg_match_all( '/{.+}/', $html_content, $matches, PREG_SET_ORDER );
48
- if ( ! empty( $matches ) ) {
49
- $field['content'] = self::preview_replace_variables( $html_content, $form );
50
- }
51
-
52
- }
53
-
54
- return $form;
55
- }
56
-
57
- /**
58
- * Adds special support for file upload, post image and multi input merge tags.
59
- */
60
- public static function preview_special_merge_tags( $value, $input_id, $merge_tag, $field ) {
61
-
62
- // added to prevent overriding :noadmin filter (and other filters that remove fields)
63
- if ( ! $value ) {
64
- return $value;
65
- }
66
-
67
- $input_type = RGFormsModel::get_input_type( $field );
68
-
69
- $is_upload_field = in_array( $input_type, array( 'post_image', 'fileupload' ) );
70
- $is_multi_input = is_array( rgar( $field, 'inputs' ) );
71
- $is_input = intval( $input_id ) != $input_id;
72
-
73
- if ( ! $is_upload_field && ! $is_multi_input ) {
74
- return $value;
75
- }
76
-
77
- // if is individual input of multi-input field, return just that input value
78
- if ( $is_input ) {
79
- return $value;
80
- }
81
-
82
- $form = RGFormsModel::get_form_meta( $field['formId'] );
83
- $lead = self::create_lead( $form );
84
- $currency = GFCommon::get_currency();
85
-
86
- if ( is_array( rgar( $field, 'inputs' ) ) ) {
87
- $value = RGFormsModel::get_lead_field_value( $lead, $field );
88
-
89
- return GFCommon::get_lead_field_display( $field, $value, $currency );
90
- }
91
-
92
- switch ( $input_type ) {
93
- case 'fileupload':
94
- $value = self::preview_image_value( "input_{$field['id']}", $field, $form, $lead );
95
- $value = self::preview_image_display( $field, $form, $value );
96
- break;
97
- default:
98
- $value = self::preview_image_value( "input_{$field['id']}", $field, $form, $lead );
99
- $value = GFCommon::get_lead_field_display( $field, $value, $currency );
100
- break;
101
- }
102
-
103
- return $value;
104
- }
105
-
106
- public static function preview_image_value( $input_name, $field, $form, $lead ) {
107
-
108
- $field_id = $field['id'];
109
- $file_info = RGFormsModel::get_temp_filename( $form['id'], $input_name );
110
- $source = RGFormsModel::get_upload_url( $form['id'] ) . "/tmp/" . $file_info["temp_filename"];
111
-
112
- if ( ! $file_info ) {
113
- return '';
114
- }
115
-
116
- switch ( RGFormsModel::get_input_type( $field ) ) {
117
-
118
- case "post_image":
119
- list( , $image_title, $image_caption, $image_description ) = explode( "|:|", $lead[ $field['id'] ] );
120
- $value = ! empty( $source ) ? $source . "|:|" . $image_title . "|:|" . $image_caption . "|:|" . $image_description : "";
121
- break;
122
-
123
- case "fileupload" :
124
- $value = $source;
125
- break;
126
-
127
- }
128
-
129
- return $value;
130
- }
131
-
132
- public static function preview_image_display( $field, $form, $value ) {
133
-
134
- // need to get the tmp $file_info to retrieve real uploaded filename, otherwise will display ugly tmp name
135
- $input_name = "input_" . str_replace( '.', '_', $field['id'] );
136
- $file_info = RGFormsModel::get_temp_filename( $form['id'], $input_name );
137
-
138
- $file_path = $value;
139
- if ( ! empty( $file_path ) ) {
140
- $file_path = esc_attr( str_replace( " ", "%20", $file_path ) );
141
- $value = "<a href='$file_path' target='_blank' title='" . __( "Click to view", "gravityforms" ) . "'>" . $file_info['uploaded_filename'] . "</a>";
142
- }
143
-
144
- return $value;
145
-
146
- }
147
-
148
- /**
149
- * Retrieves $lead object from class if it has already been created; otherwise creates a new $lead object.
150
- */
151
- public static function create_lead( $form ) {
152
-
153
- if ( empty( self::$lead ) ) {
154
- self::$lead = GFFormsModel::create_lead( $form );
155
- self::clear_field_value_cache( $form );
156
- }
157
-
158
- return self::$lead;
159
- }
160
-
161
- public static function preview_replace_variables( $content, $form ) {
162
-
163
- $lead = self::create_lead( $form );
164
-
165
- // add filter that will handle getting temporary URLs for file uploads and post image fields (removed below)
166
- // beware, the RGFormsModel::create_lead() function also triggers the gform_merge_tag_filter at some point and will
167
- // result in an infinite loop if not called first above
168
- add_filter( 'gform_merge_tag_filter', array( 'GFParsi_PreSubmission', 'preview_special_merge_tags' ), 10, 4 );
169
-
170
- $content = GFCommon::replace_variables( $content, $form, $lead, false, false, false );
171
-
172
- // remove filter so this function is not applied after preview functionality is complete
173
- remove_filter( 'gform_merge_tag_filter', array( 'GFParsi_PreSubmission', 'preview_special_merge_tags' ) );
174
-
175
- return $content;
176
- }
177
-
178
- public static function clear_field_value_cache( $form ) {
179
-
180
- if ( ! class_exists( 'GFCache' ) ) {
181
- return;
182
- }
183
-
184
- foreach ( $form['fields'] as &$field ) {
185
- if ( GFFormsModel::get_input_type( $field ) == 'total' ) {
186
- GFCache::delete( 'GFFormsModel::get_lead_field_value__' . $field['id'] );
187
- }
188
- }
189
-
190
- }
191
-
192
- }
193
-
194
- GFParsi_PreSubmission::init();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-settings.php ADDED
@@ -0,0 +1,418 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+
5
+ class GFPersian_Settings extends GFAddOn {
6
+
7
+ protected $_version = GF_PERSIAN_VERSION;
8
+ protected $_min_gravityforms_version = '1.9';
9
+ protected $_path = GF_PERSIAN_DIR . 'index.php';
10
+ protected $_full_path = __FILE__;
11
+ protected $_slug = GF_PERSIAN_SLUG;
12
+ protected $_short_title = 'گرویتی فرم پارسی';
13
+ protected $_title = 'بسته گرویتی فرم پارسی';
14
+
15
+ private static $_instance = null;
16
+
17
+ public static function get_instance() {
18
+
19
+ if ( self::$_instance == null ) {
20
+ self::$_instance = new self();
21
+ }
22
+
23
+ return self::$_instance;
24
+ }
25
+
26
+ public function init() {
27
+ parent::init();
28
+ }
29
+
30
+ public function plugin_settings_fields() {
31
+ return array(
32
+ array(
33
+ 'title' => 'تنظیمات گرویتی فرم پارسی',
34
+ 'fields' => array(
35
+ array(
36
+ 'name' => 'translate',
37
+ 'label' => 'ترجمه گرویتی فرم',
38
+ 'tooltip' => 'با فعالسازی این گزینه در صورتی که زبان سایت به صورت فارسی باشد گرویتی فرم به پارسی ترجمه خواهد شد.',
39
+ 'type' => 'radio',
40
+ 'horizontal' => true,
41
+ 'default_value' => '1',
42
+ 'choices' => array(
43
+ array( 'label' => 'بله', 'value' => '1' ),
44
+ array( 'label' => 'خیر', 'value' => '0' ),
45
+ ),
46
+ ),
47
+ array(
48
+ 'name' => 'address',
49
+ 'label' => 'آدرس های ایران',
50
+ 'tooltip' => 'با فعالسازی این گزینه استان ها و شهرهای ایران به فیلد "آدرس" اضافه خواهد شد. باید از تب "عمومی" فیلد آدرس گزینه "نوع آدرس" را بر روی "ایران" قرار دهید و سپس تیک "فعالسازی شهرهای ایران" را انتخاب کنید.',
51
+ 'type' => 'radio',
52
+ 'horizontal' => true,
53
+ 'default_value' => '1',
54
+ 'choices' => array(
55
+ array( 'label' => 'بله', 'value' => '1' ),
56
+ array( 'label' => 'خیر', 'value' => '0' ),
57
+ ),
58
+ ),
59
+ array(
60
+ 'name' => 'national_id',
61
+ 'label' => 'فیلد کد ملی',
62
+ 'tooltip' => 'با فعالسازی این فیلد "کد ملی" به فیلدهای پیشرفته گرویتی فرم اضافه خواهد شد. این فیلد قابلیت اعتبار سنجی کد ملی و همچنین نمایش شهر صادر کننده کد ملی را هم دارد.',
63
+ 'type' => 'radio',
64
+ 'horizontal' => true,
65
+ 'default_value' => '1',
66
+ 'choices' => array(
67
+ array( 'label' => 'بله', 'value' => '1' ),
68
+ array( 'label' => 'خیر', 'value' => '0' ),
69
+ ),
70
+ ),
71
+ array(
72
+ 'name' => 'jalali',
73
+ 'label' => 'شمسی ساز فیلد تاریخ',
74
+ 'tooltip' => 'با فعالسازی این فیلد گزینه تاریخ جلالی به قابلیت های فیلد تاریخ گرویتی فرم اضافه خواهد شد.',
75
+ 'type' => 'radio',
76
+ 'horizontal' => true,
77
+ 'default_value' => '1',
78
+ 'choices' => array(
79
+ array( 'label' => 'بله', 'value' => '1' ),
80
+ array( 'label' => 'خیر', 'value' => '0' ),
81
+ ),
82
+ ),
83
+ array(
84
+ 'name' => 'currencies',
85
+ 'label' => 'واحدهای پول ایران',
86
+ 'tooltip' => 'با فعالسازی این فیلد گزینه واحدهای پول ایران (ریال - تومان - هزار ریال - هزار تومان) به واحدهای پول گرویتی فرم اضافه خواهد شد.<br><br>واحد های "هزار ریال - هزار تومان" با نسخه 2.3 درگاه های پرداخت به بالا سازگارند و برای نسخه های پایین تر درگاه های پرداخت قابل استفاده نیستند.',
87
+ 'type' => 'radio',
88
+ 'horizontal' => true,
89
+ 'default_value' => '1',
90
+ 'choices' => array(
91
+ array( 'label' => 'بله', 'value' => '1' ),
92
+ array( 'label' => 'خیر', 'value' => '0' ),
93
+ ),
94
+ ),
95
+ array(
96
+ 'name' => 'rtl_admin',
97
+ 'label' => 'راستچین سازی مدیریت',
98
+ 'tooltip' => 'با فعالسازی این فیلد گزینه بخش هایی از محیط کار با گرویتی فرم در مدیریت که نیاز به راستچین سازی داشته باشند، راستچین خواهند شد.',
99
+ 'type' => 'radio',
100
+ 'horizontal' => true,
101
+ 'default_value' => '1',
102
+ 'choices' => array(
103
+ array( 'label' => 'بله', 'value' => '1' ),
104
+ array( 'label' => 'خیر', 'value' => '0' ),
105
+ ),
106
+ ),
107
+ array(
108
+ 'name' => 'font_admin',
109
+ 'label' => 'فونت مدیریت',
110
+ 'tooltip' => 'با توجه به جذاب بودن محیط کار با گرویتی فرم در بخش مدیریت سایت، با اضافه کردن فرم پارسی آن را جذاب تر نمایید.',
111
+ 'type' => 'radio',
112
+ 'horizontal' => true,
113
+ 'default_value' => 'vazir',
114
+ 'choices' => array(
115
+ array( 'label' => 'بدون فونت', 'value' => '0' ),
116
+ array( 'label' => 'یکان', 'value' => 'yekan' ),
117
+ array( 'label' => 'وزیر', 'value' => 'vazir' ),
118
+ array( 'label' => 'شبنم', 'value' => 'shabnam' ),
119
+ ),
120
+ ),
121
+ array(
122
+ 'name' => 'payments',
123
+ 'label' => 'سازگاری با درگاه های پرداخت',
124
+ 'tooltip' => 'در صورتی که از درگاه های پرداخت استفاده میکنید حتما باید این گزینه را فعال نمایید تا یک سری امکانات مربوط به درگاه پرداخت ایرانی به گرویتی فرم اضافه شود. (در حال حاضر با توجه به آزمایشی بودن این قسمت، باید فقط فعال باشد.)',
125
+ 'type' => 'radio',
126
+ 'horizontal' => true,
127
+ 'default_value' => '1',
128
+ 'disabled' => 'disabled',
129
+ 'choices' => array(
130
+ array( 'label' => 'بله', 'value' => '1' ),
131
+ array( 'label' => 'خیر', 'value' => '0' ),
132
+ ),
133
+ ),
134
+ array(
135
+ 'name' => 'rss_widget',
136
+ 'label' => 'خبرخوان گرویتی فرم پارسی',
137
+ 'tooltip' => 'با فعالسازی این فیلد گزینه ابزارک خبرخوان گرویتی فرم پارسی به داشبورد مدیریت وردپرس اضافه خواهد شد تا آخرین پست های گرویتی فرم پارسی را مشاهده کنید.',
138
+ 'type' => 'radio',
139
+ 'horizontal' => true,
140
+ 'default_value' => '1',
141
+ 'choices' => array(
142
+ array( 'label' => 'بله', 'value' => '1' ),
143
+ array( 'label' => 'خیر', 'value' => '0' ),
144
+ ),
145
+ ),
146
+
147
+ array(
148
+ 'name' => 'br',
149
+ 'label' => '',
150
+ 'type' => 'br',
151
+ ),
152
+ array(
153
+ 'name' => 'other_tools',
154
+ 'label' => '<strong>سایر تنظیمات اضافه شده</strong>',
155
+ 'tooltip' => 'سایر تنظیمات مربوط به امکانات اضافه شده توسط گرویتی فرم پارسی',
156
+ 'type' => 'hr',
157
+ 'text' => 'گزینه های زیر ارتباطی به بومی سازی برای ایران ندارند و به درخواست کاربران اضافه شده اند.',
158
+ ),
159
+ array(
160
+ 'name' => 'enable_transaction_id',
161
+ 'label' => 'فعالسازی کد رهگیری',
162
+ 'tooltip' => 'به صورت پیشفرض در گرویتی فرم فقط زمانیکه یک پرداخت انجام شود یک شماره تراکنش ثبت میشود<br> با فعالسازی این گزینه میتوانید حتی برای فرم هایی که به درگاه پرداخت متصل نیستند نیز کد رهگیری اختصاص دهید.',
163
+ 'type' => 'radio',
164
+ 'horizontal' => true,
165
+ 'default_value' => '1',
166
+ 'choices' => array(
167
+ array( 'label' => 'بله', 'value' => '1' ),
168
+ array( 'label' => 'خیر', 'value' => '0' ),
169
+ ),
170
+ ),
171
+ array(
172
+ 'name' => 'transaction_id_title',
173
+ 'label' => 'عنوان کد رهگیری',
174
+ 'tooltip' => 'در صورتیکه گزینه بالا را فعال کرده اید، عنوانی که میخواهید برای کد رهگیری نمایش داده شود را وارد کنید.',
175
+ 'type' => 'text',
176
+ 'default_value' => __( 'Transaction Id', 'gravityforms' ),
177
+ ),
178
+ array(
179
+ 'name' => 'transaction_id_mask',
180
+ 'label' => 'الگوی کد رهگیری (قاب)',
181
+ 'tooltip' => 'با توجه به آشنایی با مفهوم قاب (الگو) در گرویتی فرم، الگوی دلخواه خود برای تولید کد رهگیری را وارد کنید.',
182
+ 'type' => 'text',
183
+ 'default_value' => '9999999999',
184
+ 'style' => 'text-align:left; direction:ltr;',
185
+ 'after_input' => $this->mask_instructions(),
186
+ ),
187
+ array(
188
+ 'name' => '_',
189
+ 'label' => 'برچسب های ادغام (شورتکد)',
190
+ 'type' => 'hr',
191
+ 'tooltip' => 'برچسب های ادغام (Merge Tags) در واقع همان شورتکد های گرویتی فرم هستند',
192
+ ),
193
+ array(
194
+ 'name' => 'add_merge_tags',
195
+ 'label' => 'برچسب های ادغام جدید',
196
+ 'tooltip' => 'با فعالسازی این گزینه، شورتکدهای جدیدی به لیست آنها اضافه خواهد شد. شورتکدهایی نظیر اطلاعات پرداخت - وضعیت پرداخت - کد رهگیری و ...',
197
+ 'type' => 'radio',
198
+ 'horizontal' => true,
199
+ 'default_value' => '1',
200
+ 'choices' => array(
201
+ array( 'label' => 'بله', 'value' => '1' ),
202
+ array( 'label' => 'خیر', 'value' => '0' ),
203
+ ),
204
+ ),
205
+ array(
206
+ 'name' => 'post_content_merge_tags',
207
+ 'label' => 'برچسب ها در برگه ها',
208
+ 'tooltip' => 'به صورت پیشفرض وقتی نوع تاییدیه ها را روی "برگه" ست میکنید امکان استفاده از "برچسب ها (شورتکد های گرویتی فرم)" در آن برگه ها وجود نخواهد داشت. با فعالسازی این گزینه این امکان فراهم خواهد شد.',
209
+ 'type' => 'radio',
210
+ 'horizontal' => true,
211
+ 'default_value' => '1',
212
+ 'choices' => array(
213
+ array( 'label' => 'بله', 'value' => '1' ),
214
+ array( 'label' => 'خیر', 'value' => '0' ),
215
+ ),
216
+ ),
217
+ array(
218
+ 'name' => 'entry_time',
219
+ 'label' => 'ماندگاری برچسب ها در برگه',
220
+ 'tooltip' => 'با فعالسازی گزینه بالا، زمانیکه کاربر به برگه تاییدیه هدایت میشود، آیدی پیام ورودی اش نیز در آدرس بار پاس داده میشود و این سبب میشود که افراد دیگر با دانستن شماره پیام (و یا آزمون و خطا) به اطلاعات آن تاییدیه دسترسی داشته پیدا کنند. برای جلوگیری از این قضیه یک مدت زمان بر حسب دقیقه وارد کنید تا پس از گذشت آن زمان دسترسی به تاییدیه منقضی شود.',
221
+ 'type' => 'text',
222
+ 'class' => 'small',
223
+ 'input_type' => 'number',
224
+ 'default_value' => '0',
225
+ 'style' => 'width:70px;',
226
+ 'after_input' => ' (دقیقه) - در صورتی که این فیلد را خالی و یا برابر 0 قرار دهید، شماره پیام ورودی به صورت "انکریپت شده" پاس داده خواهد شد.',
227
+ ),
228
+ array(
229
+ 'name' => 'pre_submission_merge_tags',
230
+ 'label' => 'برچسب ها در فیلد HTML',
231
+ 'tooltip' => 'توسط این امکان میتوانید برای فرم های خود یک "پیشفاکتور" بسازید.<br>' . '<a target="_blank" href="http://gravityforms.ir/5690">برای مشاهده راهنما کلیک کنید.</a>',
232
+ 'type' => 'radio',
233
+ 'horizontal' => true,
234
+ 'default_value' => '1',
235
+ 'choices' => array(
236
+ array( 'label' => 'بله', 'value' => '1' ),
237
+ array( 'label' => 'خیر', 'value' => '0' ),
238
+ ),
239
+ ),
240
+ array(
241
+ 'name' => '__',
242
+ 'label' => 'تنظیمات سایر ویژگی ها',
243
+ 'type' => 'hr',
244
+ 'tooltip' => 'تنظیمات سایر ویژگی ها',
245
+ ),
246
+ array(
247
+ 'name' => 'hide_lic',
248
+ 'label' => 'حذف بنر فعال نبودن لایسنس',
249
+ 'tooltip' => 'در برخی نسخه های گرویتی فرم، در صورتی که لایسنس گرویتی فرم شما فعال نباشد یک بنر بالای صفحات گرویتی فرم مبنی بر عدم فعال بودن لایسنس شما ظاهر میشود که با فعالسازی این گزینه میتوانید آن را مخفی نمایید.',
250
+ 'type' => 'radio',
251
+ 'horizontal' => true,
252
+ 'default_value' => '0',
253
+ 'choices' => array(
254
+ array( 'label' => 'بله', 'value' => '1' ),
255
+ array( 'label' => 'خیر', 'value' => '0' ),
256
+ ),
257
+ ),
258
+ array(
259
+ 'name' => 'live_preview',
260
+ 'label' => 'پیشنمایش زنده',
261
+ 'tooltip' => 'با فعالسازی این گزینه، منوی پیشنمایش زنده در ویرایشگر فرم اضافه میشود تا فرم را داخل فرانت اند سایت مشاهده نمایید. البته این گزینه ممکن است با برخی قالب ها سازگاری نداشته باشد. چون یک پست تایپ مجازی ایجاد میکند.',
262
+ 'type' => 'radio',
263
+ 'horizontal' => true,
264
+ 'default_value' => '1',
265
+ 'choices' => array(
266
+ array( 'label' => 'بله', 'value' => '1' ),
267
+ array( 'label' => 'خیر', 'value' => '0' ),
268
+ ),
269
+ ),
270
+ array(
271
+ 'name' => 'label_visibility',
272
+ 'label' => 'مدیریت لیبل فیلدها',
273
+ 'tooltip' => 'با فعالسازی این گزینه، یک آپشن جدید در تب "نمایش" فیلدها زیر "نگه دارنده متن (Placeholder)" تحت عنوان "نمایش برچسب فیلد" اضافه خواهد شد تا بتوانید "لیبل (Lable)" فیلد ها را مخفی کنید.این گزینه برای زمانی که از "نگه دارنده متن (Placeholder)" استفاده میکنید مفید است.',
274
+ 'type' => 'radio',
275
+ 'horizontal' => true,
276
+ 'default_value' => '1',
277
+ 'choices' => array(
278
+ array( 'label' => 'بله', 'value' => '1' ),
279
+ array( 'label' => 'خیر', 'value' => '0' ),
280
+ ),
281
+ ),
282
+ array(
283
+ 'name' => 'newsletter',
284
+ 'label' => 'رویداد خبرنامه در اعلان ها',
285
+ 'tooltip' => 'توسط این امکان میتوانید گرویتی فرم خود را به یک پلاگین خبرنامه تبدیل کنید.<br>' . '<a target="_blank" href="http://gravityforms.ir/3940">برای مشاهده توضیحات کلیک کنید.</a>',
286
+ 'type' => 'radio',
287
+ 'horizontal' => true,
288
+ 'default_value' => '1',
289
+ 'choices' => array(
290
+ array( 'label' => 'بله', 'value' => '1' ),
291
+ array( 'label' => 'خیر', 'value' => '0' ),
292
+ ),
293
+ ),
294
+ array(
295
+ 'name' => 'private_post',
296
+ 'label' => 'وضعیت پست خصوصی',
297
+ 'tooltip' => 'به صورت پیشفرض وقتی از "فیلدهای ارسال نوشته" استفاده کنید وضعیت پست "خصوصی" در لیست وضیعت های پست وجود ندارد که با فعالسازی این گزینه اضافه خواهد شد.',
298
+ 'type' => 'radio',
299
+ 'horizontal' => true,
300
+ 'default_value' => '1',
301
+ 'choices' => array(
302
+ array( 'label' => 'بله', 'value' => '1' ),
303
+ array( 'label' => 'خیر', 'value' => '0' ),
304
+ ),
305
+ ),
306
+ array(
307
+ 'name' => 'multipage_nav',
308
+ 'label' => 'پیمایش فرم های مرحله ای',
309
+ 'tooltip' => 'با فعالسازی این گزینه در فرم های چند مرحله ای (چند برگه ای) در صورتی که از تب "عمومی" برگه "نشانگر پیشرفت" را روی حالت "مرحله ها" قرار دهید،‌ کاربران بدون استفاده از دکمه های "قبلی" و "بعدی" میتوانند از طریق خود "نشانگر پیشرفت" بین صفحات (مرحله ها) جابجا شوند.',
310
+ 'type' => 'radio',
311
+ 'horizontal' => true,
312
+ 'default_value' => '1',
313
+ 'choices' => array(
314
+ array( 'label' => 'بله', 'value' => '1' ),
315
+ array( 'label' => 'خیر', 'value' => '0' ),
316
+ ),
317
+ ),
318
+ array(
319
+ 'name' => 'multipage_nav_last',
320
+ 'label' => 'شرط پیمایش فرم های مرحله ای',
321
+ 'tooltip' => 'در صورتی که گزینه بالا را فعال کرده اید، میتوانید مشخص کنید که پیمایش بین مرحله ها همواره از ابتدا فعال باشد یا فقط زمانیکه که کاربر مرحله ها را پشت سر گذاشت و به مرحله آخر رسید فعال شود.',
322
+ 'type' => 'radio',
323
+ 'horizontal' => true,
324
+ 'default_value' => '1',
325
+ 'choices' => array(
326
+ array( 'label' => 'همواره فعال باشد', 'value' => '0' ),
327
+ array( 'label' => 'فقط زمانیکه تمام مراحل طی شدند و به مرحله آخر رسید فعال شود', 'value' => '1' ),
328
+ ),
329
+ ),
330
+ )
331
+ )
332
+ );
333
+ }
334
+
335
+
336
+ public function settings_br( $field, $echo = true ) {
337
+
338
+ $output = '<br>';
339
+
340
+ if ( $echo ) {
341
+ echo $output;
342
+ } else {
343
+ return $output;
344
+ }
345
+ }
346
+
347
+ public function settings_hr( $field, $echo = true ) {
348
+
349
+ $output = '';
350
+
351
+ if ( ! empty( $field['text'] ) ) {
352
+ $output .= $field['text'];
353
+ }
354
+
355
+ $output .= '<hr>';
356
+
357
+ if ( $echo ) {
358
+ echo $output;
359
+ } else {
360
+ return $output;
361
+ }
362
+ }
363
+
364
+ private function mask_instructions() {
365
+
366
+ ob_start(); ?>
367
+
368
+ <div id="custom_mask_instructions" style="display:none;">
369
+ <div class="custom_mask_instructions">
370
+ <h4><?php esc_html_e( 'Usage', 'gravityforms' ) ?></h4>
371
+ <ul class="description-list">
372
+ <li><?php esc_html_e( "Use a '9' to indicate a numerical character.", 'gravityforms' ) ?></li>
373
+ <li><?php esc_html_e( "Use a lower case 'a' to indicate an alphabetical character.", 'gravityforms' ) ?></li>
374
+ <li><?php esc_html_e( "Use an asterisk '*' to indicate any alphanumeric character.", 'gravityforms' ) ?></li>
375
+ <li><?php esc_html_e( 'All other characters are literal values and will be displayed automatically.', 'gravityforms' ) ?></li>
376
+ </ul>
377
+
378
+ <h4><?php esc_html_e( 'Examples', 'gravityforms' ) ?></h4>
379
+ <ul class="examples-list">
380
+
381
+ <li>
382
+ <h5><?php esc_html_e( 'Social Security Number', 'gravityforms' ) ?></h5>
383
+ <span class="label"><?php esc_html_e( 'Mask', 'gravityforms' ) ?></span>
384
+ <code>999-99-9999</code><br/>
385
+ <span
386
+ class="label">نمونه خروجی</span>
387
+ <code>987-65-4329</code>
388
+ </li>
389
+ <li>
390
+ <h5><?php esc_html_e( 'Course Code', 'gravityforms' ) ?></h5>
391
+ <span class="label"><?php esc_html_e( 'Mask', 'gravityforms' ) ?></span>
392
+ <code>aaa 999</code><br/>
393
+ <span
394
+ class="label">نمونه خروجی</span>
395
+ <code>BIO 101</code>
396
+ </li>
397
+ <li>
398
+ <h5><?php esc_html_e( 'License Key', 'gravityforms' ) ?></h5>
399
+ <span class="label"><?php esc_html_e( 'Mask', 'gravityforms' ) ?></span>
400
+ <code>***-***-***</code><br/>
401
+ <span
402
+ class="label">نمونه خروجی</span>
403
+ <code>a9a-f0c-28Q</code>
404
+ </li>
405
+ </ul>
406
+
407
+ </div>
408
+ </div>
409
+ (<a href="javascript:void(0);" style="text-decoration: none !important;"
410
+ onclick="tb_show('<?php echo esc_js( __( 'Custom Mask Instructions', 'gravityforms' ) ); ?>', '#TB_inline?width=350&amp;inlineId=custom_mask_instructions', '');"
411
+ onkeypress="tb_show('<?php echo esc_js( __( 'Custom Mask Instructions', 'gravityforms' ) ); ?>', '#TB_inline?width=350&amp;inlineId=custom_mask_instructions', '');">
412
+ راهنمای ایجاد الگو
413
+ </a>)
414
+ <?php
415
+ return ob_get_clean();
416
+ }
417
+
418
+ }
includes/class-snippets.php CHANGED
@@ -1,78 +1,67 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) exit;
2
-
3
- class GFParsi_PostPermalink {
4
-
5
- function __construct() {
6
- add_filter('gform_custom_merge_tags', array($this, 'add_custom_merge_tag'), 10, 4);
7
- add_filter('gform_replace_merge_tags', array($this, 'replace_merge_tag'), 10, 3);
8
- }
9
-
10
- function add_custom_merge_tag($merge_tags, $form_id, $fields, $element_id) {
11
- if(!GFCommon::has_post_field($fields))
12
- return $merge_tags;
13
- $merge_tags[] = array('label' => __('Post Permalink', 'GF_FA') , 'tag' => '{post_permalink}');
14
- return $merge_tags;
15
- }
16
-
17
- function replace_merge_tag($text, $form, $entry) {
18
-
19
- $custom_merge_tag = '{post_permalink}';
20
- if(strpos($text, $custom_merge_tag) === false || !rgar($entry, 'post_id'))
21
- return $text;
22
-
23
- $post_permalink = get_permalink(rgar($entry, 'post_id'));
24
- $text = str_replace($custom_merge_tag, $post_permalink, $text);
25
-
26
- return $text;
27
- }
28
-
29
- }
30
- new GFParsi_PostPermalink();
31
-
32
-
33
- add_filter('gform_pre_render', 'gfir_prepopluate_merge_tags');
34
- function gfir_prepopluate_merge_tags($form) {
35
-
36
- $filter_names = array();
37
-
38
- foreach($form['fields'] as &$field) {
39
-
40
- if(!rgar($field, 'allowsPrepopulate'))
41
- continue;
42
-
43
- // complex fields store inputName in the "name" property of the inputs array
44
- if(is_array(rgar($field, 'inputs')) && $field['type'] != 'checkbox') {
45
- foreach($field['inputs'] as $input) {
46
- if(rgar($input, 'name'))
47
- $filter_names[] = array('type' => $field['type'], 'name' => rgar($input, 'name'));
48
- }
49
- } else {
50
- $filter_names[] = array('type' => $field['type'], 'name' => rgar($field, 'inputName'));
51
- }
52
-
53
- }
54
-
55
- foreach($filter_names as $filter_name) {
56
-
57
- $filtered_name = GFCommon::replace_variables_prepopulate($filter_name['name']);
58
-
59
- if($filter_name['name'] == $filtered_name)
60
- continue;
61
-
62
- add_filter("gform_field_value_{$filter_name['name']}", create_function("", "return '$filtered_name';"));
63
- }
64
-
65
- return $form;
66
  }
67
 
 
68
 
69
- add_filter( 'gform_tabindex', 'gfir_gform_tabindexer', 10, 2 );
70
- function gfir_gform_tabindexer( $tab_index, $form = false ) {
71
- $starting_index = 1000; // if you need a higher tabindex, update this number
72
- if( $form )
73
- add_filter( 'gform_tabindex_' . $form['id'], 'gfir_gform_tabindexer' );
74
- return GFCommon::$tab_index >= $starting_index ? GFCommon::$tab_index : $starting_index;
75
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
- add_filter( 'gform_confirmation_anchor', '__return_false' );
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  }
4
 
5
+ class GFPersian_Snippets extends GFPersian_Core {
6
 
7
+ public function __construct() {
8
+
9
+ if ( $this->option( 'label_visibility', '1' ) == '1' ) {
10
+ add_filter( 'gform_enable_field_label_visibility_settings', '__return_true' );
11
+ }
12
+
13
+ if ( $this->option( 'private_post', '1' ) == '1' ) {
14
+ add_action( 'gform_post_status_options', array( $this, 'add_private_post_status' ) );
15
+ }
16
+
17
+ if ( $this->option( 'newsletter', '1' ) == '1' ) {
18
+ add_filter( 'gform_notification_events', array( $this, 'add_newsletter_notification_event' ) );
19
+ add_filter( 'gform_before_resend_notifications', array( $this, 'add_notification_filter' ) );
20
+ }
21
+ }
22
+
23
+ public function add_private_post_status( $post_statuses ) {
24
+ $post_statuses['private'] = 'خصوصی';
25
+
26
+ return $post_statuses;
27
+ }
28
+
29
+ /*---------------------------------------------------------------------------------------------*/
30
+ /*----------Start of NewsLetter----------------------------------------------------------------*/
31
+ /*---------------------------------------------------------------------------------------------*/
32
+ public function add_newsletter_notification_event( $events ) {
33
+ $events['newsletter'] = 'خبرنامه';
34
+
35
+ return $events;
36
+ }
37
+
38
+ public function add_notification_filter( $form ) {
39
+ add_filter( 'gform_notification', array( $this, 'evaluate_notification_conditional_logic' ), 10, 3 );
40
 
41
+ return $form;
42
+ }
43
+
44
+ public function evaluate_notification_conditional_logic( $notification, $form, $entry ) {
45
+
46
+ // if it fails conditional logic, suppress it
47
+ if ( $notification['event'] == 'newsletter' && ! GFCommon::evaluate_conditional_logic( rgar( $notification, 'conditionalLogic' ), $form, $entry ) ) {
48
+ add_filter( 'gform_pre_send_email', array( $this, 'abort_next_notification' ) );
49
+ }
50
+
51
+ return $notification;
52
+ }
53
+
54
+ public function abort_next_notification( $args ) {
55
+ remove_filter( 'gform_pre_send_email', array( $this, 'abort_next_notification' ) );
56
+ $args['abort_email'] = true;
57
+
58
+ return $args;
59
+ }
60
+ /*---------------------------------------------------------------------------------------------*/
61
+ /*----------End of NewsLetter------------------------------------------------------------------*/
62
+ /*---------------------------------------------------------------------------------------------*/
63
+
64
+
65
+ }
66
 
67
+ new GFPersian_Snippets;
includes/class-subtotal-calc.php DELETED
@@ -1,245 +0,0 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) exit;
2
-
3
- class GFParsi_CalcSubtotal {
4
-
5
- public static $merge_tag = '{subtotal}';
6
-
7
- function __construct() {
8
-
9
- // front-end
10
- add_filter( 'gform_pre_render', array( $this, 'maybe_replace_subtotal_merge_tag' ) );
11
- add_filter( 'gform_pre_validation', array( $this, 'maybe_replace_subtotal_merge_tag_submission' ) );
12
-
13
- // back-end
14
- add_filter( 'gform_admin_pre_render', array( $this, 'add_merge_tags' ) );
15
-
16
- }
17
-
18
- /**
19
- * Look for {subtotal} merge tag in form fields 'calculationFormula' property. If found, replace with the
20
- * aggregated subtotal merge tag string.
21
- *
22
- * @param mixed $form
23
- */
24
- function maybe_replace_subtotal_merge_tag( $form, $filter_tags = false ) {
25
-
26
- foreach( $form['fields'] as &$field ) {
27
-
28
- if( current_filter() == 'gform_pre_render' && rgar( $field, 'origCalculationFormula' ) )
29
- $field['calculationFormula'] = $field['origCalculationFormula'];
30
-
31
- if( ! self::has_subtotal_merge_tag( $field ) )
32
- continue;
33
-
34
- $subtotal_merge_tags = self::get_subtotal_merge_tag_string( $form, $field, $filter_tags );
35
- $field['origCalculationFormula'] = $field['calculationFormula'];
36
- $field['calculationFormula'] = str_replace( self::$merge_tag, $subtotal_merge_tags, $field['calculationFormula'] );
37
-
38
- }
39
-
40
- return $form;
41
- }
42
-
43
- function maybe_replace_subtotal_merge_tag_submission( $form ) {
44
- return $this->maybe_replace_subtotal_merge_tag( $form, true );
45
- }
46
-
47
- /**
48
- * Get all the pricing fields on the form, get their corresponding merge tags and aggregate them into a formula that
49
- * will yeild the form's subtotal.
50
- *
51
- * @param mixed $form
52
- */
53
- static function get_subtotal_merge_tag_string( $form, $current_field, $filter_tags = false ) {
54
-
55
- $pricing_fields = self::get_pricing_fields( $form );
56
- $product_tag_groups = array();
57
-
58
- foreach( $pricing_fields['products'] as $product ) {
59
-
60
- $product_field = rgar( $product, 'product' );
61
- $option_fields = rgar( $product, 'options' );
62
- $quantity_field = rgar( $product, 'quantity' );
63
-
64
- // do not include current field in subtotal
65
- if( $product_field['id'] == $current_field['id'] )
66
- continue;
67
-
68
- $product_tags = GFCommon::get_field_merge_tags( $product_field );
69
- $quantity_tag = 1;
70
-
71
- // if a single product type, only get the "price" merge tag
72
- if( in_array( GFFormsModel::get_input_type( $product_field ), array( 'singleproduct', 'calculation', 'hiddenproduct' ) ) ) {
73
-
74
- // single products provide quantity merge tag
75
- if( empty( $quantity_field ) && ! rgar( $product_field, 'disableQuantity' ) )
76
- $quantity_tag = $product_tags[2]['tag'];
77
-
78
- $product_tags = array( $product_tags[1] );
79
- }
80
-
81
- // if quantity field is provided for product, get merge tag
82
- if( ! empty( $quantity_field ) ) {
83
- $quantity_tag = GFCommon::get_field_merge_tags( $quantity_field );
84
- $quantity_tag = $quantity_tag[0]['tag'];
85
- }
86
-
87
- if( $filter_tags && ! self::has_valid_quantity( $quantity_tag ) )
88
- continue;
89
-
90
- $product_tags = wp_list_pluck( $product_tags, 'tag' );
91
- $option_tags = array();
92
-
93
- foreach( $option_fields as $option_field ) {
94
-
95
- if( is_array( $option_field['inputs'] ) ) {
96
-
97
- $choice_number = 1;
98
-
99
- $inputs = $option_field['inputs'];
100
-
101
- foreach( $inputs as &$input ) {
102
-
103
- //hack to skip numbers ending in 0. so that 5.1 doesn't conflict with 5.10
104
- if( $choice_number % 10 == 0 )
105
- $choice_number++;
106
-
107
- $input['id'] = $option_field['id'] . '.' . $choice_number++;
108
-
109
- }
110
- }
111
-
112
- $new_options_tags = GFCommon::get_field_merge_tags( $option_field );
113
- if( ! is_array( $new_options_tags ) )
114
- continue;
115
-
116
- if( GFFormsModel::get_input_type( $option_field ) == 'checkbox' )
117
- array_shift( $new_options_tags );
118
-
119
- $option_tags = array_merge( $option_tags, $new_options_tags );
120
- }
121
-
122
- $option_tags = wp_list_pluck( $option_tags, 'tag' );
123
-
124
- $product_tag_groups[] = '( ( ' . implode( ' + ', array_merge( $product_tags, $option_tags ) ) . ' ) * ' . $quantity_tag . ' )';
125
-
126
- }
127
-
128
- $shipping_tag = 0;
129
- /* Shipping should not be included in subtotal, correct?
130
- if( rgar( $pricing_fields, 'shipping' ) ) {
131
- $shipping_tag = GFCommon::get_field_merge_tags( rgars( $pricing_fields, 'shipping/0' ) );
132
- $shipping_tag = $shipping_tag[0]['tag'];
133
- }*/
134
-
135
- $pricing_tag_string = '( ( ' . implode( ' + ', $product_tag_groups ) . ' ) + ' . $shipping_tag . ' )';
136
-
137
- return $pricing_tag_string;
138
- }
139
-
140
- /**
141
- * Get all pricing fields from a given form object grouped by product and shipping with options nested under their
142
- * respective products.
143
- *
144
- * @param mixed $form
145
- */
146
- static function get_pricing_fields( $form ) {
147
-
148
- $product_fields = array();
149
-
150
- foreach( $form["fields"] as $field ) {
151
-
152
- if( $field["type"] != 'product' )
153
- continue;
154
-
155
- $option_fields = GFCommon::get_product_fields_by_type($form, array("option"), $field['id'] );
156
-
157
- // can only have 1 quantity field
158
- $quantity_field = GFCommon::get_product_fields_by_type( $form, array("quantity"), $field['id'] );
159
- $quantity_field = rgar( $quantity_field, 0 );
160
-
161
- $product_fields[] = array(
162
- 'product' => $field,
163
- 'options' => $option_fields,
164
- 'quantity' => $quantity_field
165
- );
166
-
167
- }
168
-
169
- $shipping_field = GFCommon::get_fields_by_type($form, array("shipping"));
170
-
171
- return array( "products" => $product_fields, "shipping" => $shipping_field );
172
- }
173
-
174
- static function has_valid_quantity( $quantity_tag ) {
175
-
176
- if( is_numeric( $quantity_tag ) ) {
177
-
178
- $qty_value = $quantity_tag;
179
-
180
- } else {
181
-
182
- // extract qty input ID from the merge tag
183
- preg_match_all( '/{[^{]*?:(\d+(\.\d+)?)(:(.*?))?}/mi', $quantity_tag, $matches, PREG_SET_ORDER );
184
- $qty_input_id = rgars( $matches, '0/1' );
185
- $qty_value = rgpost( 'input_' . str_replace( '.', '_', $qty_input_id ) );
186
-
187
- }
188
-
189
- return floatval( $qty_value ) > 0;
190
- }
191
-
192
- function add_merge_tags( $form ) {
193
-
194
- $label = __('Subtotal', 'GF_FA');
195
-
196
- ?>
197
-
198
- <script type="text/javascript">
199
-
200
- // for the future (not yet supported for calc field)
201
- gform.addFilter("gform_merge_tags", "gfircs_add_merge_tags");
202
- function gfircs_add_merge_tags( mergeTags, elementId, hideAllFields, excludeFieldTypes, isPrepop, option ) {
203
- mergeTags["pricing"].tags.push({ tag: '<?php echo self::$merge_tag; ?>', label: '<?php echo $label; ?>' });
204
- return mergeTags;
205
- }
206
-
207
- // hacky, but only temporary
208
- jQuery(document).ready(function($){
209
-
210
- var calcMergeTagSelect = $('#field_calculation_formula_variable_select');
211
- calcMergeTagSelect.find('optgroup').eq(0).append( '<option value="<?php echo self::$merge_tag; ?>"><?php echo $label; ?></option>' );
212
-
213
- });
214
-
215
- </script>
216
-
217
- <?php
218
- //return the form object from the php hook
219
- return $form;
220
- }
221
-
222
- static function has_subtotal_merge_tag( $field ) {
223
-
224
- // check if form is passed
225
- if( isset( $field['fields'] ) ) {
226
-
227
- $form = $field;
228
- foreach( $form['fields'] as $field ) {
229
- if( self::has_subtotal_merge_tag( $field ) )
230
- return true;
231
- }
232
-
233
- } else {
234
-
235
- if( isset( $field['calculationFormula'] ) && strpos( $field['calculationFormula'], self::$merge_tag ) !== false )
236
- return true;
237
-
238
- }
239
-
240
- return false;
241
- }
242
-
243
- }
244
-
245
- new GFParsi_CalcSubtotal();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class-transaction-id.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ }
4
+
5
+ class GFPersian_Transaction_ID extends GFPersian_Core {
6
+
7
+ private $transaction_id_title;
8
+
9
+ public function __construct() {
10
+
11
+ if ( $this->option( 'enable_transaction_id', '1' ) != '1' ) {
12
+ return;
13
+ }
14
+
15
+ $this->transaction_id_title = $this->option( 'transaction_id_title', __( 'Transaction Id', 'gravityforms' ) );
16
+
17
+ add_filter( 'gettext', array( $this, 'change_transaction_id_title' ), 999, 3 );
18
+ add_filter( 'ngettext', array( $this, 'change_transaction_id_title' ), 999, 3 );
19
+ add_action( 'gform_entry_created', array( $this, 'create_transaction_id' ), 10, 2 );
20
+ }
21
+
22
+ public function create_transaction_id( $entry, $form ) {
23
+
24
+ $default_mask = '9999999999';
25
+ $masked_input = $this->option( 'transaction_id_mask', $default_mask );
26
+ $masked_input = apply_filters( 'gform_transaction_id', $masked_input, $entry, $form );
27
+ $masked_input = ! empty( $masked_input ) ? $masked_input : $default_mask;
28
+
29
+ $transaction_id = '';
30
+ foreach ( str_split( $masked_input ) as $string ) {
31
+ if ( in_array( $string, array( '*', 'a' ) ) ) {
32
+ $rand = $string == '*' ? array_map( 'strval', range( 0, 9 ) ) : array();
33
+ $rand = array_merge( $rand, range( 'A', 'Z' ), range( 'a', 'z' ) );
34
+ shuffle( $rand );
35
+ $transaction_id .= $rand[ rand( 0, count( $rand ) - 1 ) ];
36
+ } elseif ( $string == '9' ) {
37
+ $transaction_id .= rand( 0, 9 );
38
+ } else {
39
+ $transaction_id .= $string;
40
+ }
41
+ }
42
+
43
+ GFAPI::update_entry_property( $entry['id'], 'transaction_id', $transaction_id );
44
+ }
45
+
46
+
47
+ public function change_transaction_id_title( $translated_text, $untranslated_text, $domain ) {
48
+ if ( $domain == 'gravityforms' && strtolower( $untranslated_text ) == 'transaction id' ) {
49
+
50
+ return $this->transaction_id_title;
51
+ }
52
+
53
+ return $translated_text;
54
+ }
55
+
56
+ }
57
+
58
+ new GFPersian_Transaction_ID;
includes/class-wpp-gravity-forms.php DELETED
@@ -1,116 +0,0 @@
1
- <?php
2
- /**
3
- * Makes GravityForms compatible with wp-parsidate plugin
4
- *
5
- * @package Persian-Gravity-Forms
6
- * @author HANNANStd
7
- */
8
- class WPP_GravityForms {
9
-
10
- public static $instance = null;
11
-
12
- public $font = 'yekan';
13
-
14
- /**
15
- * Returns an instance of class
16
- *
17
- * @return WPP_GravityForms
18
- */
19
- public static function getInstance() {
20
- if ( self::$instance == null )
21
- self::$instance = new WPP_GravityForms();
22
-
23
- return self::$instance;
24
- }
25
-
26
- /**
27
- * Hooks required tags
28
- */
29
- public function __construct() {
30
-
31
- if ( ! class_exists('GFCommon') ) {
32
- return;
33
- }
34
-
35
- global $wpp_settings;
36
-
37
- if ( !empty($wpp_settings) && $wpp_settings ) {
38
-
39
- if ( ! isset( $wpp_settings[ 'droidsans_admin' ] ) || $wpp_settings[ 'droidsans_admin' ] != 'disable' ) {
40
-
41
- add_filter( 'wpp_plugins_compability_settings', array( $this, 'add_settings' ) );
42
-
43
- if ( ! isset( $wpp_settings['gravityforms_droidsans_admin'] ) || $wpp_settings['gravityforms_droidsans_admin'] != 'disable' ) {
44
- $this->font = 'droidsans';
45
- }
46
- }
47
-
48
-
49
- }
50
-
51
- add_action('admin_enqueue_scripts', array( $this, 'admin_script' ));
52
- }
53
-
54
- /**
55
- * Adds desired fonts
56
- */
57
- public function admin_script() {
58
-
59
- if ( is_rtl() && $this->is_gravity_page() ) {
60
- wp_register_style( 'gravity-forms-admin-' . $this->font , GF_PARSI_URL . 'assets/css/font.' . $this->font . '.css' );
61
- wp_enqueue_style( 'gravity-forms-admin-' . $this->font );
62
- }
63
- }
64
-
65
-
66
- /**
67
- * Checks is gravityforms page
68
- *
69
- */
70
- public function is_gravity_page() {
71
-
72
- if ( !class_exists('RGForms') )
73
- return false;
74
-
75
- $current_page = trim(strtolower(RGForms::get("page")));
76
- return ( substr( $current_page , 0 , 2) == 'gf' || stripos( $current_page, 'gravity' ) !== false );
77
- }
78
-
79
-
80
- /**
81
- * Adds settings for toggle fixing
82
- *
83
- * @param array $old_settings Old settings
84
- * @return array New settings
85
- */
86
- public function add_settings( $old_settings ) {
87
-
88
- $options = array(
89
- 'enable' => __( 'Enable', 'wp-parsidate' ),
90
- 'disable' => __( 'Disable', 'wp-parsidate' )
91
- );
92
-
93
- $settings = array(
94
- 'gravityforms' => array(
95
- 'id' => 'gravityforms',
96
- 'name' => __( 'GravityForms', 'GF_FA' ),
97
- 'type' => 'header'
98
- ),
99
- 'gravityforms_droidsans_admin' => array(
100
- 'id' => 'gravityforms_droidsans_admin',
101
- 'name' => __( 'Use Droid Sans font for GravityForms Admin', 'GF_FA' ),
102
- 'type' => 'radio',
103
- 'options' => $options,
104
- 'std' => 'enable',
105
- 'desc' => __( 'By GravityForms.ir', 'GF_FA' )
106
- ),
107
- );
108
-
109
- return array_merge( $old_settings, $settings );
110
- }
111
- }
112
-
113
- add_action('plugins_loaded', 'wpp_gravity_forms', 0);
114
- function wpp_gravity_forms() {
115
- WPP_GravityForms::getInstance();
116
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/lib/jalali.php ADDED
@@ -0,0 +1,755 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* In The Name Of Allah */
3
+ /** Software Hijri_Shamsi , Solar(Jalali) Date and Time
4
+ * Copyright(C)2011, Reza Gholampanahi , http://jdf.scr.ir
5
+ * version 2.55 :: 1391/08/24 = 1433/12/18 = 2012/11/15
6
+ /* [ jdf.php ] version 2.55 ?> Download new version from [ http://jdf.scr.ir ] */
7
+ /*--- EDITED BY HANNANStd ---*/
8
+
9
+ /**/
10
+ /* F */
11
+ function GF_jdate( $format, $timestamp = '', $none = '', $time_zone = 'Asia/Tehran', $tr_num = 'fa' ) {
12
+
13
+ $T_sec = 0;/* <= رفع خطاي زمان سرور ، با اعداد '+' و '-' بر حسب ثانيه */
14
+
15
+ if ( $time_zone != 'local' ) {
16
+ date_default_timezone_set( ( $time_zone == '' ) ? 'Asia/Tehran' : $time_zone );
17
+ }
18
+
19
+ $ts = $T_sec + ( ( $timestamp == '' or $timestamp == 'now' ) ? time() : GF_tr_num( $timestamp ) );
20
+ $date = explode( '_', date( 'H_i_j_n_O_P_s_w_Y', $ts ) );
21
+ list( $j_y, $j_m, $j_d ) = GF_gregorian_to_jalali( $date[8], $date[3], $date[2] );
22
+ $doy = ( $j_m < 7 ) ? ( ( $j_m - 1 ) * 31 ) + $j_d - 1 : ( ( $j_m - 7 ) * 30 ) + $j_d + 185;
23
+ $kab = ( $j_y % 33 % 4 - 1 == (int) ( $j_y % 33 * .05 ) ) ? 1 : 0;
24
+ $sl = strlen( $format );
25
+ $out = '';
26
+
27
+ for ( $i = 0; $i < $sl; $i ++ ) {
28
+ $sub = substr( $format, $i, 1 );
29
+ if ( $sub == '\\' ) {
30
+ $out .= substr( $format, ++ $i, 1 );
31
+ continue;
32
+ }
33
+
34
+ switch ( $sub ) {
35
+ case'E':
36
+ case'R':
37
+ case'x':
38
+ case'X':
39
+ $out .= 'http://jdf.scr.ir';
40
+ break;
41
+
42
+ case'B':
43
+ case'e':
44
+ case'g':
45
+ case'G':
46
+ case'h':
47
+ case'I':
48
+ case'T':
49
+ case'u':
50
+ case'Z':
51
+ $out .= date( $sub, $ts );
52
+ break;
53
+
54
+ case'a':
55
+ $out .= ( $date[0] < 12 ) ? 'ق.ظ' : 'ب.ظ';
56
+ break;
57
+
58
+ case'A':
59
+ $out .= ( $date[0] < 12 ) ? 'قبل از ظهر' : 'بعد از ظهر';
60
+ break;
61
+
62
+ case'b':
63
+ $out .= (int) ( $j_m / 3.1 ) + 1;
64
+ break;
65
+
66
+ case'c':
67
+ $out .= $j_y . '/' . $j_m . '/' . $j_d . ' ،' . $date[0] . ':' . $date[1] . ':' . $date[6] . ' ' . $date[5];
68
+ break;
69
+
70
+ case'C':
71
+ $out .= (int) ( ( $j_y + 99 ) / 100 );
72
+ break;
73
+
74
+ case'd':
75
+ $out .= ( $j_d < 10 ) ? '0' . $j_d : $j_d;
76
+ break;
77
+
78
+ case'D':
79
+ $out .= GF_jdate_words( array( 'kh' => $date[7] ), ' ' );
80
+ break;
81
+
82
+ case'f':
83
+ $out .= GF_jdate_words( array( 'ff' => $j_m ), ' ' );
84
+ break;
85
+
86
+ case'F':
87
+ $out .= GF_jdate_words( array( 'mm' => $j_m ), ' ' );
88
+ break;
89
+
90
+ case'H':
91
+ $out .= $date[0];
92
+ break;
93
+
94
+ case'i':
95
+ $out .= $date[1];
96
+ break;
97
+
98
+ case'j':
99
+ $out .= $j_d;
100
+ break;
101
+
102
+ case'J':
103
+ $out .= GF_jdate_words( array( 'rr' => $j_d ), ' ' );
104
+ break;
105
+
106
+ case'k';
107
+ $out .= GF_tr_num( 100 - (int) ( $doy / ( $kab + 365 ) * 1000 ) / 10, $tr_num );
108
+ break;
109
+
110
+ case'K':
111
+ $out .= GF_tr_num( (int) ( $doy / ( $kab + 365 ) * 1000 ) / 10, $tr_num );
112
+ break;
113
+
114
+ case'l':
115
+ $out .= GF_jdate_words( array( 'rh' => $date[7] ), ' ' );
116
+ break;
117
+
118
+ case'L':
119
+ $out .= $kab;
120
+ break;
121
+
122
+ case'm':
123
+ $out .= ( $j_m > 9 ) ? $j_m : '0' . $j_m;
124
+ break;
125
+
126
+ case'M':
127
+ $out .= GF_jdate_words( array( 'km' => $j_m ), ' ' );
128
+ break;
129
+
130
+ case'n':
131
+ $out .= $j_m;
132
+ break;
133
+
134
+ case'N':
135
+ $out .= $date[7] + 1;
136
+ break;
137
+
138
+ case'o':
139
+ $jdw = ( $date[7] == 6 ) ? 0 : $date[7] + 1;
140
+ $dny = 364 + $kab - $doy;
141
+ $out .= ( $jdw > ( $doy + 3 ) and $doy < 3 ) ? $j_y - 1 : ( ( ( 3 - $dny ) > $jdw and $dny < 3 ) ? $j_y + 1 : $j_y );
142
+ break;
143
+
144
+ case'O':
145
+ $out .= $date[4];
146
+ break;
147
+
148
+ case'p':
149
+ $out .= GF_jdate_words( array( 'mb' => $j_m ), ' ' );
150
+ break;
151
+
152
+ case'P':
153
+ $out .= $date[5];
154
+ break;
155
+
156
+ case'q':
157
+ $out .= GF_jdate_words( array( 'sh' => $j_y ), ' ' );
158
+ break;
159
+
160
+ case'Q':
161
+ $out .= $kab + 364 - $doy;
162
+ break;
163
+
164
+ case'r':
165
+ $key = GF_jdate_words( array( 'rh' => $date[7], 'mm' => $j_m ) );
166
+ $out .= $date[0] . ':' . $date[1] . ':' . $date[6] . ' ' . $date[4] . ' ' . $key['rh'] . '، ' . $j_d . ' ' . $key['mm'] . ' ' . $j_y;
167
+ break;
168
+
169
+ case's':
170
+ $out .= $date[6];
171
+ break;
172
+
173
+ case'S':
174
+ $out .= 'ام';
175
+ break;
176
+
177
+ case't':
178
+ $out .= ( $j_m != 12 ) ? ( 31 - (int) ( $j_m / 6.5 ) ) : ( $kab + 29 );
179
+ break;
180
+
181
+ case'U':
182
+ $out .= $ts;
183
+ break;
184
+
185
+ case'v':
186
+ $out .= GF_jdate_words( array( 'ss' => substr( $j_y, 2, 2 ) ), ' ' );
187
+ break;
188
+
189
+ case'V':
190
+ $out .= GF_jdate_words( array( 'ss' => $j_y ), ' ' );
191
+ break;
192
+
193
+ case'w':
194
+ $out .= ( $date[7] == 6 ) ? 0 : $date[7] + 1;
195
+ break;
196
+
197
+ case'W':
198
+ $avs = ( ( $date[7] == 6 ) ? 0 : $date[7] + 1 ) - ( $doy % 7 );
199
+ if ( $avs < 0 ) {
200
+ $avs += 7;
201
+ }
202
+ $num = (int) ( ( $doy + $avs ) / 7 );
203
+ if ( $avs < 4 ) {
204
+ $num ++;
205
+ } elseif ( $num < 1 ) {
206
+ $num = ( $avs == 4 or $avs == ( ( $j_y % 33 % 4 - 2 == (int) ( $j_y % 33 * .05 ) ) ? 5 : 4 ) ) ? 53 : 52;
207
+ }
208
+ $aks = $avs + $kab;
209
+ if ( $aks == 7 ) {
210
+ $aks = 0;
211
+ }
212
+ $out .= ( ( $kab + 363 - $doy ) < $aks and $aks < 3 ) ? '01' : ( ( $num < 10 ) ? '0' . $num : $num );
213
+ break;
214
+
215
+ case'y':
216
+ $out .= substr( $j_y, 2, 2 );
217
+ break;
218
+
219
+ case'Y':
220
+ $out .= $j_y;
221
+ break;
222
+
223
+ case'z':
224
+ $out .= $doy;
225
+ break;
226
+
227
+ default:
228
+ $out .= $sub;
229
+ }
230
+ }
231
+
232
+ return ( $tr_num != 'en' ) ? GF_tr_num( $out, 'fa', '.' ) : $out;
233
+ }
234
+
235
+ /* F */
236
+ function GF_jstrftime( $format, $timestamp = '', $none = '', $time_zone = 'Asia/Tehran', $tr_num = 'fa' ) {
237
+
238
+ $T_sec = 0;/* <= رفع خطاي زمان سرور ، با اعداد '+' و '-' بر حسب ثانيه */
239
+ if ( $time_zone != 'local' ) {
240
+ date_default_timezone_set( ( $time_zone == '' ) ? 'Asia/Tehran' : $time_zone );
241
+ }
242
+
243
+ $ts = $T_sec + ( ( $timestamp == '' or $timestamp == 'now' ) ? time() : GF_tr_num( $timestamp ) );
244
+ $date = explode( '_', date( 'h_H_i_j_n_s_w_Y', $ts ) );
245
+ list( $j_y, $j_m, $j_d ) = GF_gregorian_to_jalali( $date[7], $date[4], $date[3] );
246
+ $doy = ( $j_m < 7 ) ? ( ( $j_m - 1 ) * 31 ) + $j_d - 1 : ( ( $j_m - 7 ) * 30 ) + $j_d + 185;
247
+
248
+ $kab = ( $j_y % 33 % 4 - 1 == (int) ( $j_y % 33 * .05 ) ) ? 1 : 0;
249
+ $sl = strlen( $format );
250
+ $out = '';
251
+ for ( $i = 0; $i < $sl; $i ++ ) {
252
+
253
+ $sub = substr( $format, $i, 1 );
254
+
255
+ if ( $sub == '%' ) {
256
+ $sub = substr( $format, ++ $i, 1 );
257
+ } else {
258
+ $out .= $sub;
259
+ continue;
260
+ }
261
+
262
+ switch ( $sub ) {
263
+
264
+ /* Day */
265
+ case'a':
266
+ $out .= GF_jdate_words( array( 'kh' => $date[6] ), ' ' );
267
+ break;
268
+
269
+ case'A':
270
+ $out .= GF_jdate_words( array( 'rh' => $date[6] ), ' ' );
271
+ break;
272
+
273
+ case'd':
274
+ $out .= ( $j_d < 10 ) ? '0' . $j_d : $j_d;
275
+ break;
276
+
277
+ case'e':
278
+ $out .= ( $j_d < 10 ) ? ' ' . $j_d : $j_d;
279
+ break;
280
+
281
+ case'j':
282
+ $out .= str_pad( $doy + 1, 3, 0, STR_PAD_LEFT );
283
+ break;
284
+
285
+ case'u':
286
+ $out .= $date[6] + 1;
287
+ break;
288
+
289
+ case'w':
290
+ $out .= ( $date[6] == 6 ) ? 0 : $date[6] + 1;
291
+ break;
292
+
293
+ /* Week */
294
+ case'U':
295
+ $avs = ( ( $date[6] < 5 ) ? $date[6] + 2 : $date[6] - 5 ) - ( $doy % 7 );
296
+ if ( $avs < 0 ) {
297
+ $avs += 7;
298
+ }
299
+ $num = (int) ( ( $doy + $avs ) / 7 ) + 1;
300
+ if ( $avs > 3 or $avs == 1 ) {
301
+ $num --;
302
+ }
303
+ $out .= ( $num < 10 ) ? '0' . $num : $num;
304
+ break;
305
+
306
+ case'V':
307
+ $avs = ( ( $date[6] == 6 ) ? 0 : $date[6] + 1 ) - ( $doy % 7 );
308
+
309
+ if ( $avs < 0 ) {
310
+ $avs += 7;
311
+ }
312
+ $num = (int) ( ( $doy + $avs ) / 7 );
313
+
314
+ if ( $avs < 4 ) {
315
+ $num ++;
316
+ } elseif ( $num < 1 ) {
317
+ $num = ( $avs == 4 or $avs == ( ( $j_y % 33 % 4 - 2 == (int) ( $j_y % 33 * .05 ) ) ? 5 : 4 ) ) ? 53 : 52;
318
+ }
319
+
320
+ $aks = $avs + $kab;
321
+ if ( $aks == 7 ) {
322
+ $aks = 0;
323
+ }
324
+ $out .= ( ( $kab + 363 - $doy ) < $aks and $aks < 3 ) ? '01' : ( ( $num < 10 ) ? '0' . $num : $num );
325
+ break;
326
+
327
+ case'W':
328
+ $avs = ( ( $date[6] == 6 ) ? 0 : $date[6] + 1 ) - ( $doy % 7 );
329
+ if ( $avs < 0 ) {
330
+ $avs += 7;
331
+ }
332
+ $num = (int) ( ( $doy + $avs ) / 7 ) + 1;
333
+ if ( $avs > 3 ) {
334
+ $num --;
335
+ }
336
+ $out .= ( $num < 10 ) ? '0' . $num : $num;
337
+ break;
338
+
339
+ /* Month */
340
+ case'b':
341
+ case'h':
342
+ $out .= GF_jdate_words( array( 'km' => $j_m ), ' ' );
343
+ break;
344
+
345
+ case'B':
346
+ $out .= GF_jdate_words( array( 'mm' => $j_m ), ' ' );
347
+ break;
348
+
349
+ case'm':
350
+ $out .= ( $j_m > 9 ) ? $j_m : '0' . $j_m;
351
+ break;
352
+
353
+ /* Year */
354
+ case'C':
355
+ $out .= substr( $j_y, 0, 2 );
356
+ break;
357
+
358
+ case'g':
359
+ $jdw = ( $date[6] == 6 ) ? 0 : $date[6] + 1;
360
+ $dny = 364 + $kab - $doy;
361
+ $out .= substr( ( $jdw > ( $doy + 3 ) and $doy < 3 ) ? $j_y - 1 : ( ( ( 3 - $dny ) > $jdw and $dny < 3 ) ? $j_y + 1 : $j_y ), 2, 2 );
362
+ break;
363
+
364
+ case'G':
365
+ $jdw = ( $date[6] == 6 ) ? 0 : $date[6] + 1;
366
+ $dny = 364 + $kab - $doy;
367
+ $out .= ( $jdw > ( $doy + 3 ) and $doy < 3 ) ? $j_y - 1 : ( ( ( 3 - $dny ) > $jdw and $dny < 3 ) ? $j_y + 1 : $j_y );
368
+ break;
369
+
370
+ case'y':
371
+ $out .= substr( $j_y, 2, 2 );
372
+ break;
373
+
374
+ case'Y':
375
+ $out .= $j_y;
376
+ break;
377
+
378
+ /* Time */
379
+ case'H':
380
+ $out .= $date[1];
381
+ break;
382
+
383
+ case'I':
384
+ $out .= $date[0];
385
+ break;
386
+
387
+ case'l':
388
+ $out .= ( $date[0] > 9 ) ? $date[0] : ' ' . (int) $date[0];
389
+ break;
390
+
391
+ case'M':
392
+ $out .= $date[2];
393
+ break;
394
+
395
+ case'p':
396
+ $out .= ( $date[1] < 12 ) ? 'قبل از ظهر' : 'بعد از ظهر';
397
+ break;
398
+
399
+ case'P':
400
+ $out .= ( $date[1] < 12 ) ? 'ق.ظ' : 'ب.ظ';
401
+ break;
402
+
403
+ case'r':
404
+ $out .= $date[0] . ':' . $date[2] . ':' . $date[5] . ' ' . ( ( $date[1] < 12 ) ? 'قبل از ظهر' : 'بعد از ظهر' );
405
+ break;
406
+
407
+ case'R':
408
+ $out .= $date[1] . ':' . $date[2];
409
+ break;
410
+
411
+ case'S':
412
+ $out .= $date[5];
413
+ break;
414
+
415
+ case'T':
416
+ $out .= $date[1] . ':' . $date[2] . ':' . $date[5];
417
+ break;
418
+
419
+ case'X':
420
+ $out .= $date[0] . ':' . $date[2] . ':' . $date[5];
421
+ break;
422
+
423
+ case'z':
424
+ $out .= date( 'O', $ts );
425
+ break;
426
+
427
+ case'Z':
428
+ $out .= date( 'T', $ts );
429
+ break;
430
+
431
+ /* Time and Date Stamps */
432
+ case'c':
433
+ $key = GF_jdate_words( array( 'rh' => $date[6], 'mm' => $j_m ) );
434
+ $out .= $date[1] . ':' . $date[2] . ':' . $date[5] . ' ' . date( 'P', $ts ) . ' ' . $key['rh'] . '، ' . $j_d . ' ' . $key['mm'] . ' ' . $j_y;
435
+ break;
436
+
437
+ case'D':
438
+ $out .= substr( $j_y, 2, 2 ) . '/' . ( ( $j_m > 9 ) ? $j_m : '0' . $j_m ) . '/' . ( ( $j_d < 10 ) ? '0' . $j_d : $j_d );
439
+ break;
440
+
441
+ case'F':
442
+ $out .= $j_y . '-' . ( ( $j_m > 9 ) ? $j_m : '0' . $j_m ) . '-' . ( ( $j_d < 10 ) ? '0' . $j_d : $j_d );
443
+ break;
444
+
445
+ case's':
446
+ $out .= $ts;
447
+ break;
448
+
449
+ case'x':
450
+ $out .= substr( $j_y, 2, 2 ) . '/' . ( ( $j_m > 9 ) ? $j_m : '0' . $j_m ) . '/' . ( ( $j_d < 10 ) ? '0' . $j_d : $j_d );
451
+ break;
452
+
453
+ /* Miscellaneous */
454
+ case'n':
455
+ $out .= "\n";
456
+ break;
457
+
458
+ case't':
459
+ $out .= "\t";
460
+ break;
461
+
462
+ case'%':
463
+ $out .= '%';
464
+ break;
465
+
466
+ default:
467
+ $out .= $sub;
468
+ }
469
+ }
470
+
471
+ return ( $tr_num != 'en' ) ? GF_tr_num( $out, 'fa', '.' ) : $out;
472
+ }
473
+
474
+ /* F */
475
+ function GF_jmktime( $h = '', $m = '', $s = '', $jm = '', $jd = '', $jy = '', $is_dst = - 1 ) {
476
+ $h = GF_tr_num( $h );
477
+ $m = GF_tr_num( $m );
478
+ $s = GF_tr_num( $s );
479
+ $jm = GF_tr_num( $jm );
480
+ $jd = GF_tr_num( $jd );
481
+ $jy = GF_tr_num( $jy );
482
+ if ( $h == '' and $m == '' and $s == '' and $jm == '' and $jd == '' and $jy == '' ) {
483
+ return mktime();
484
+ } else {
485
+ list( $year, $month, $day ) = GF_jalali_to_gregorian( $jy, $jm, $jd );
486
+
487
+ return mktime( $h, $m, $s, $month, $day, $year, $is_dst );
488
+ }
489
+ }
490
+
491
+
492
+ /* F */
493
+ function GF_jgetdate( $timestamp = '', $none = '', $tz = 'Asia/Tehran', $tn = 'en' ) {
494
+ $ts = ( $timestamp == '' ) ? time() : GF_tr_num( $timestamp );
495
+ $jdate = explode( '_', GF_jdate( 'F_G_i_j_l_n_s_w_Y_z', $ts, '', $tz, $tn ) );
496
+
497
+ return array(
498
+ 'seconds' => GF_tr_num( (int) GF_tr_num( $jdate[6] ), $tn ),
499
+ 'minutes' => GF_tr_num( (int) GF_tr_num( $jdate[2] ), $tn ),
500
+ 'hours' => $jdate[1],
501
+ 'mday' => $jdate[3],
502
+ 'wday' => $jdate[7],
503
+ 'mon' => $jdate[5],
504
+ 'year' => $jdate[8],
505
+ 'yday' => $jdate[9],
506
+ 'weekday' => $jdate[4],
507
+ 'month' => $jdate[0],
508
+ 0 => GF_tr_num( $ts, $tn )
509
+ );
510
+ }
511
+
512
+ /* F */
513
+ function GF_jcheckdate( $jm, $jd, $jy ) {
514
+ $jm = GF_tr_num( $jm );
515
+ $jd = GF_tr_num( $jd );
516
+ $jy = GF_tr_num( $jy );
517
+ $l_d = ( $jm == 12 ) ? ( ( $jy % 33 % 4 - 1 == (int) ( $jy % 33 * .05 ) ) ? 30 : 29 ) : 31 - (int) ( $jm / 6.5 );
518
+
519
+ return ( $jm > 0 and $jd > 0 and $jy > 0 and $jm < 13 and $jd <= $l_d ) ? true : false;
520
+ }
521
+
522
+ /* F */
523
+ function GF_tr_num( $str, $mod = 'en', $mf = '٫' ) {
524
+ $num_a = array( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.' );
525
+ $key_a = array( '۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹', $mf );
526
+
527
+ return ( $mod == 'fa' ) ? str_replace( $num_a, $key_a, $str ) : str_replace( $key_a, $num_a, $str );
528
+ }
529
+
530
+ /* F */
531
+ function GF_jdate_words( $array, $mod = '' ) {
532
+ foreach ( $array as $type => $num ) {
533
+ $num = (int) GF_tr_num( $num );
534
+ switch ( $type ) {
535
+ case'ss':
536
+ $sl = strlen( $num );
537
+ $xy3 = substr( $num, 2 - $sl, 1 );
538
+ $h3 = $h34 = $h4 = '';
539
+ if ( $xy3 == 1 ) {
540
+ $p34 = '';
541
+ $k34 = array(
542
+ 'ده',
543
+ 'یازده',
544
+ 'دوازده',
545
+ 'سیزده',
546
+ 'چهارده',
547
+ 'پانزده',
548
+ 'شانزده',
549
+ 'هفده',
550
+ 'هجده',
551
+ 'نوزده'
552
+ );
553
+ $h34 = $k34[ substr( $num, 2 - $sl, 2 ) - 10 ];
554
+ } else {
555
+ $xy4 = substr( $num, 3 - $sl, 1 );
556
+ $p34 = ( $xy3 == 0 or $xy4 == 0 ) ? '' : ' و ';
557
+ $k3 = array( '', '', 'بیست', 'سی', 'چهل', 'پنجاه', 'شصت', 'هفتاد', 'هشتاد', 'نود' );
558
+ $h3 = $k3[ $xy3 ];
559
+ $k4 = array( '', 'یک', 'دو', 'سه', 'چهار', 'پنج', 'شش', 'هفت', 'هشت', 'نه' );
560
+ $h4 = $k4[ $xy4 ];
561
+ }
562
+ $array[ $type ] = ( ( $num > 99 ) ? str_ireplace( array( '12', '13', '14', '19', '20' ),
563
+ array( 'هزار و دویست', 'هزار و سیصد', 'هزار و چهارصد', 'هزار و نهصد', 'دوهزار' ),
564
+ substr( $num, 0, 2 ) ) . ( ( substr( $num, 2, 2 ) == '00' ) ? '' : ' و ' ) : '' ) . $h3 . $p34 . $h34 . $h4;
565
+ break;
566
+
567
+ case'mm':
568
+ $key = array(
569
+ 'فروردین',
570
+ 'اردیبهشت',
571
+ 'خرداد',
572
+ 'تیر',
573
+ 'مرداد',
574
+ 'شهریور',
575
+ 'مهر',
576
+ 'آبان',
577
+ 'آذر',
578
+ 'دی',
579
+ 'بهمن',
580
+ 'اسفند'
581
+ );
582
+ $array[ $type ] = $key[ $num - 1 ];
583
+ break;
584
+
585
+ case'rr':
586
+ $key = array(
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
+ $array[ $type ] = $key[ $num - 1 ];
620
+ break;
621
+
622
+ case'rh':
623
+ $key = array( 'یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه' );
624
+ $array[ $type ] = $key[ $num ];
625
+ break;
626
+
627
+ case'sh':
628
+ $key = array(
629
+ 'مار',
630
+ 'اسب',
631
+ 'گوسفند',
632
+ 'میمون',
633
+ 'مرغ',
634
+ 'سگ',
635
+ 'خوک',
636
+ 'موش',
637
+ 'گاو',
638
+ 'پلنگ',
639
+ 'خرگوش',
640
+ 'نهنگ'
641
+ );
642
+ $array[ $type ] = $key[ $num % 12 ];
643
+ break;
644
+
645
+ case'mb':
646
+ $key = array(
647
+ 'حمل',
648
+ 'ثور',
649
+ 'جوزا',
650
+ 'سرطان',
651
+ 'اسد',
652
+ 'سنبله',
653
+ 'میزان',
654
+ 'عقرب',
655
+ 'قوس',
656
+ 'جدی',
657
+ 'دلو',
658
+ 'حوت'
659
+ );
660
+ $array[ $type ] = $key[ $num - 1 ];
661
+ break;
662
+
663
+ case'ff':
664
+ $key = array( 'بهار', 'تابستان', 'پاییز', 'زمستان' );
665
+ $array[ $type ] = $key[ (int) ( $num / 3.1 ) ];
666
+ break;
667
+
668
+ case'km':
669
+ $key = array( 'فر', 'ار', 'خر', 'تی‍', 'مر', 'شه‍', 'مه‍', 'آب‍', 'آذ', 'دی', 'به‍', 'اس‍' );
670
+ $array[ $type ] = $key[ $num - 1 ];
671
+ break;
672
+
673
+ case'kh':
674
+ $key = array( 'ی', 'د', 'س', 'چ', 'پ', 'ج', 'ش' );
675
+ $array[ $type ] = $key[ $num ];
676
+ break;
677
+
678
+ default:
679
+ $array[ $type ] = $num;
680
+ }
681
+ }
682
+
683
+ return ( $mod == '' ) ? $array : implode( $mod, $array );
684
+ }
685
+
686
+ /** Convertor from and to Gregorian and Jalali (Hijri_Shamsi,Solar) Functions
687
+ * Copyright(C)2011, Reza Gholampanahi [ http://jdf.scr.ir/jdf ] version 2.50 */
688
+
689
+ /* F */
690
+ function GF_gregorian_to_jalali( $g_y, $g_m, $g_d, $mod = '' ) {
691
+ $g_y = GF_tr_num( $g_y );
692
+ $g_m = GF_tr_num( $g_m );
693
+ $g_d = GF_tr_num( $g_d );/* <= :اين سطر ، جزء تابع اصلي نيست */
694
+ $d_4 = $g_y % 4;
695
+ $g_a = array( 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 );
696
+ $doy_g = $g_a[ (int) $g_m ] + $g_d;
697
+ if ( $d_4 == 0 and $g_m > 2 ) {
698
+ $doy_g ++;
699
+ }
700
+ $d_33 = (int) ( ( ( $g_y - 16 ) % 132 ) * .0305 );
701
+ $a = ( $d_33 == 3 or $d_33 < ( $d_4 - 1 ) or $d_4 == 0 ) ? 286 : 287;
702
+ $b = ( ( $d_33 == 1 or $d_33 == 2 ) and ( $d_33 == $d_4 or $d_4 == 1 ) ) ? 78 : ( ( $d_33 == 3 and $d_4 == 0 ) ? 80 : 79 );
703
+ if ( (int) ( ( $g_y - 10 ) / 63 ) == 30 ) {
704
+ $a --;
705
+ $b ++;
706
+ }
707
+ if ( $doy_g > $b ) {
708
+ $jy = $g_y - 621;
709
+ $doy_j = $doy_g - $b;
710
+ } else {
711
+ $jy = $g_y - 622;
712
+ $doy_j = $doy_g + $a;
713
+ }
714
+ if ( $doy_j < 187 ) {
715
+ $jm = (int) ( ( $doy_j - 1 ) / 31 );
716
+ $jd = $doy_j - ( 31 * $jm ++ );
717
+ } else {
718
+ $jm = (int) ( ( $doy_j - 187 ) / 30 );
719
+ $jd = $doy_j - 186 - ( $jm * 30 );
720
+ $jm += 7;
721
+ }
722
+
723
+ return ( $mod == '' ) ? array( $jy, $jm, $jd ) : $jy . $mod . $jm . $mod . $jd;
724
+ }
725
+
726
+ /* F */
727
+ function GF_jalali_to_gregorian( $j_y, $j_m, $j_d, $mod = '' ) {
728
+ $j_y = GF_tr_num( $j_y );
729
+ $j_m = GF_tr_num( $j_m );
730
+ $j_d = GF_tr_num( $j_d );/* <= :اين سطر ، جزء تابع اصلي نيست */
731
+ $d_4 = ( $j_y + 1 ) % 4;
732
+ $doy_j = ( $j_m < 7 ) ? ( ( $j_m - 1 ) * 31 ) + $j_d : ( ( $j_m - 7 ) * 30 ) + $j_d + 186;
733
+ $d_33 = (int) ( ( ( $j_y - 55 ) % 132 ) * .0305 );
734
+ $a = ( $d_33 != 3 and $d_4 <= $d_33 ) ? 287 : 286;
735
+ $b = ( ( $d_33 == 1 or $d_33 == 2 ) and ( $d_33 == $d_4 or $d_4 == 1 ) ) ? 78 : ( ( $d_33 == 3 and $d_4 == 0 ) ? 80 : 79 );
736
+ if ( (int) ( ( $j_y - 19 ) / 63 ) == 20 ) {
737
+ $a --;
738
+ $b ++;
739
+ }
740
+ if ( $doy_j <= $a ) {
741
+ $gy = $j_y + 621;
742
+ $gd = $doy_j + $b;
743
+ } else {
744
+ $gy = $j_y + 622;
745
+ $gd = $doy_j - $a;
746
+ }
747
+ foreach ( array( 0, 31, ( $gy % 4 == 0 ) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ) as $gm => $v ) {
748
+ if ( $gd <= $v ) {
749
+ break;
750
+ }
751
+ $gd -= $v;
752
+ }
753
+
754
+ return ( $mod == '' ) ? array( $gy, $gm, $gd ) : $gy . $mod . $gm . $mod . $gd;
755
+ }
includes/lib/nusoap-php5.3.php ADDED
@@ -0,0 +1,8484 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
4
+
5
+ NuSOAP - Web Services Toolkit for PHP
6
+
7
+ Copyright (c) 2002 NuSphere Corporation
8
+
9
+ This library is free software; you can redistribute it and/or
10
+ modify it under the terms of the GNU Lesser General Public
11
+ License as published by the Free Software Foundation; either
12
+ version 2.1 of the License, or (at your option) any later version.
13
+
14
+ This library is distributed in the hope that it will be useful,
15
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
+ Lesser General Public License for more details.
18
+
19
+ You should have received a copy of the GNU Lesser General Public
20
+ License along with this library; if not, write to the Free Software
21
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
+
23
+ The NuSOAP project home is:
24
+ http://sourceforge.net/projects/nusoap/
25
+
26
+ The primary support for NuSOAP is the Help forum on the project home page.
27
+
28
+ If you have any questions or comments, please email:
29
+
30
+ Dietrich Ayala
31
+ dietrich@ganx4.com
32
+ http://dietrich.ganx4.com/nusoap
33
+
34
+ NuSphere Corporation
35
+ http://www.nusphere.com
36
+
37
+ */
38
+
39
+ /*
40
+ * Some of the standards implmented in whole or part by NuSOAP:
41
+ *
42
+ * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
43
+ * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
44
+ * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
45
+ * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
46
+ * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
47
+ * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
48
+ * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
49
+ * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
50
+ * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
51
+ */
52
+
53
+ /* load classes
54
+
55
+ // necessary classes
56
+ require_once('class.soapclient.php');
57
+ require_once('class.soap_val.php');
58
+ require_once('class.soap_parser.php');
59
+ require_once('class.soap_fault.php');
60
+
61
+ // transport classes
62
+ require_once('class.soap_transport_http.php');
63
+
64
+ // optional add-on classes
65
+ require_once('class.xmlschema.php');
66
+ require_once('class.wsdl.php');
67
+
68
+ // server class
69
+ require_once('class.soap_server.php');*/
70
+
71
+ // class variable emulation
72
+ // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
73
+ $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9;
74
+
75
+ /**
76
+ *
77
+ * nusoap_base
78
+ *
79
+ * @author Dietrich Ayala <dietrich@ganx4.com>
80
+ * @author Scott Nichol <snichol@users.sourceforge.net>
81
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
82
+ * @access public
83
+ */
84
+ //error_reporting( '0' );
85
+
86
+ class nusoap_base {
87
+ /**
88
+ * Identification for HTTP headers.
89
+ *
90
+ * @var string
91
+ * @access private
92
+ */
93
+ var $title = 'NuSOAP';
94
+ /**
95
+ * Version for HTTP headers.
96
+ *
97
+ * @var string
98
+ * @access private
99
+ */
100
+ var $version = '0.9.5';
101
+ /**
102
+ * CVS revision for HTTP headers.
103
+ *
104
+ * @var string
105
+ * @access private
106
+ */
107
+ var $revision = '$Revision: 1.123 $';
108
+ /**
109
+ * Current error string (manipulated by getError/setError)
110
+ *
111
+ * @var string
112
+ * @access private
113
+ */
114
+ var $error_str = '';
115
+ /**
116
+ * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
117
+ *
118
+ * @var string
119
+ * @access private
120
+ */
121
+ var $debug_str = '';
122
+ /**
123
+ * toggles automatic encoding of special characters as entities
124
+ * (should always be true, I think)
125
+ *
126
+ * @var boolean
127
+ * @access private
128
+ */
129
+ var $charencoding = true;
130
+ /**
131
+ * the debug level for this instance
132
+ *
133
+ * @var integer
134
+ * @access private
135
+ */
136
+ var $debugLevel;
137
+
138
+ /**
139
+ * set schema version
140
+ *
141
+ * @var string
142
+ * @access public
143
+ */
144
+ var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
145
+
146
+ /**
147
+ * charset encoding for outgoing messages
148
+ *
149
+ * @var string
150
+ * @access public
151
+ */
152
+ var $soap_defencoding = 'ISO-8859-1';
153
+ //var $soap_defencoding = 'UTF-8';
154
+
155
+ /**
156
+ * namespaces in an array of prefix => uri
157
+ *
158
+ * this is "seeded" by a set of constants, but it may be altered by code
159
+ *
160
+ * @var array
161
+ * @access public
162
+ */
163
+ var $namespaces = array(
164
+ 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
165
+ 'xsd' => 'http://www.w3.org/2001/XMLSchema',
166
+ 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
167
+ 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
168
+ );
169
+
170
+ /**
171
+ * namespaces used in the current context, e.g. during serialization
172
+ *
173
+ * @var array
174
+ * @access private
175
+ */
176
+ var $usedNamespaces = array();
177
+
178
+ /**
179
+ * XML Schema types in an array of uri => (array of xml type => php type)
180
+ * is this legacy yet?
181
+ * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
182
+ * @var array
183
+ * @access public
184
+ */
185
+ var $typemap = array(
186
+ 'http://www.w3.org/2001/XMLSchema' => array(
187
+ 'string' => 'string',
188
+ 'boolean' => 'boolean',
189
+ 'float' => 'double',
190
+ 'double' => 'double',
191
+ 'decimal' => 'double',
192
+ 'duration' => '',
193
+ 'dateTime' => 'string',
194
+ 'time' => 'string',
195
+ 'date' => 'string',
196
+ 'gYearMonth' => '',
197
+ 'gYear' => '',
198
+ 'gMonthDay' => '',
199
+ 'gDay' => '',
200
+ 'gMonth' => '',
201
+ 'hexBinary' => 'string',
202
+ 'base64Binary' => 'string',
203
+ // abstract "any" types
204
+ 'anyType' => 'string',
205
+ 'anySimpleType' => 'string',
206
+ // derived datatypes
207
+ 'normalizedString' => 'string',
208
+ 'token' => 'string',
209
+ 'language' => '',
210
+ 'NMTOKEN' => '',
211
+ 'NMTOKENS' => '',
212
+ 'Name' => '',
213
+ 'NCName' => '',
214
+ 'ID' => '',
215
+ 'IDREF' => '',
216
+ 'IDREFS' => '',
217
+ 'ENTITY' => '',
218
+ 'ENTITIES' => '',
219
+ 'integer' => 'integer',
220
+ 'nonPositiveInteger' => 'integer',
221
+ 'negativeInteger' => 'integer',
222
+ 'long' => 'integer',
223
+ 'int' => 'integer',
224
+ 'short' => 'integer',
225
+ 'byte' => 'integer',
226
+ 'nonNegativeInteger' => 'integer',
227
+ 'unsignedLong' => '',
228
+ 'unsignedInt' => '',
229
+ 'unsignedShort' => '',
230
+ 'unsignedByte' => '',
231
+ 'positiveInteger' => ''
232
+ ),
233
+ 'http://www.w3.org/2000/10/XMLSchema' => array(
234
+ 'i4' => '',
235
+ 'int' => 'integer',
236
+ 'boolean' => 'boolean',
237
+ 'string' => 'string',
238
+ 'double' => 'double',
239
+ 'float' => 'double',
240
+ 'dateTime' => 'string',
241
+ 'timeInstant' => 'string',
242
+ 'base64Binary' => 'string',
243
+ 'base64' => 'string',
244
+ 'ur-type' => 'array'
245
+ ),
246
+ 'http://www.w3.org/1999/XMLSchema' => array(
247
+ 'i4' => '',
248
+ 'int' => 'integer',
249
+ 'boolean' => 'boolean',
250
+ 'string' => 'string',
251
+ 'double' => 'double',
252
+ 'float' => 'double',
253
+ 'dateTime' => 'string',
254
+ 'timeInstant' => 'string',
255
+ 'base64Binary' => 'string',
256
+ 'base64' => 'string',
257
+ 'ur-type' => 'array'
258
+ ),
259
+ 'http://soapinterop.org/xsd' => array( 'SOAPStruct' => 'struct' ),
260
+ 'http://schemas.xmlsoap.org/soap/encoding/' => array(
261
+ 'base64' => 'string',
262
+ 'array' => 'array',
263
+ 'Array' => 'array'
264
+ ),
265
+ 'http://xml.apache.org/xml-soap' => array( 'Map' )
266
+ );
267
+
268
+ /**
269
+ * XML entities to convert
270
+ *
271
+ * @var array
272
+ * @access public
273
+ * @deprecated
274
+ * @see expandEntities
275
+ */
276
+ var $xmlEntities = array(
277
+ 'quot' => '"',
278
+ 'amp' => '&',
279
+ 'lt' => '<',
280
+ 'gt' => '>',
281
+ 'apos' => "'"
282
+ );
283
+
284
+ /**
285
+ * constructor
286
+ *
287
+ * @access public
288
+ */
289
+ function nusoap_base() {
290
+ $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
291
+ }
292
+
293
+ /**
294
+ * gets the global debug level, which applies to future instances
295
+ *
296
+ * @return integer Debug level 0-9, where 0 turns off
297
+ * @access public
298
+ */
299
+ function getGlobalDebugLevel() {
300
+ return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
301
+ }
302
+
303
+ /**
304
+ * sets the global debug level, which applies to future instances
305
+ *
306
+ * @param int $level Debug level 0-9, where 0 turns off
307
+ *
308
+ * @access public
309
+ */
310
+ function setGlobalDebugLevel( $level ) {
311
+ $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
312
+ }
313
+
314
+ /**
315
+ * gets the debug level for this instance
316
+ *
317
+ * @return int Debug level 0-9, where 0 turns off
318
+ * @access public
319
+ */
320
+ function getDebugLevel() {
321
+ return $this->debugLevel;
322
+ }
323
+
324
+ /**
325
+ * sets the debug level for this instance
326
+ *
327
+ * @param int $level Debug level 0-9, where 0 turns off
328
+ *
329
+ * @access public
330
+ */
331
+ function setDebugLevel( $level ) {
332
+ $this->debugLevel = $level;
333
+ }
334
+
335
+ /**
336
+ * adds debug data to the instance debug string with formatting
337
+ *
338
+ * @param string $string debug data
339
+ *
340
+ * @access private
341
+ */
342
+ function debug( $string ) {
343
+ if ( $this->debugLevel > 0 ) {
344
+ $this->appendDebug( $this->getmicrotime() . ' ' . get_class( $this ) . ": $string\n" );
345
+ }
346
+ }
347
+
348
+ /**
349
+ * adds debug data to the instance debug string without formatting
350
+ *
351
+ * @param string $string debug data
352
+ *
353
+ * @access public
354
+ */
355
+ function appendDebug( $string ) {
356
+ if ( $this->debugLevel > 0 ) {
357
+ // it would be nice to use a memory stream here to use
358
+ // memory more efficiently
359
+ $this->debug_str .= $string;
360
+ }
361
+ }
362
+
363
+ /**
364
+ * clears the current debug data for this instance
365
+ *
366
+ * @access public
367
+ */
368
+ function clearDebug() {
369
+ // it would be nice to use a memory stream here to use
370
+ // memory more efficiently
371
+ $this->debug_str = '';
372
+ }
373
+
374
+ /**
375
+ * gets the current debug data for this instance
376
+ *
377
+ * @return debug data
378
+ * @access public
379
+ */
380
+ function &getDebug() {
381
+ // it would be nice to use a memory stream here to use
382
+ // memory more efficiently
383
+ return $this->debug_str;
384
+ }
385
+
386
+ /**
387
+ * gets the current debug data for this instance as an XML comment
388
+ * this may change the contents of the debug data
389
+ *
390
+ * @return debug data as an XML comment
391
+ * @access public
392
+ */
393
+ function &getDebugAsXMLComment() {
394
+ // it would be nice to use a memory stream here to use
395
+ // memory more efficiently
396
+ while ( strpos( $this->debug_str, '--' ) ) {
397
+ $this->debug_str = str_replace( '--', '- -', $this->debug_str );
398
+ }
399
+ $ret = "<!--\n" . $this->debug_str . "\n-->";
400
+
401
+ return $ret;
402
+ }
403
+
404
+ /**
405
+ * expands entities, e.g. changes '<' to '&lt;'.
406
+ *
407
+ * @param string $val The string in which to expand entities.
408
+ *
409
+ * @access private
410
+ */
411
+ function expandEntities( $val ) {
412
+ if ( $this->charencoding ) {
413
+ $val = str_replace( '&', '&amp;', $val );
414
+ $val = str_replace( "'", '&apos;', $val );
415
+ $val = str_replace( '"', '&quot;', $val );
416
+ $val = str_replace( '<', '&lt;', $val );
417
+ $val = str_replace( '>', '&gt;', $val );
418
+ }
419
+
420
+ return $val;
421
+ }
422
+
423
+ /**
424
+ * returns error string if present
425
+ *
426
+ * @return mixed error string or false
427
+ * @access public
428
+ */
429
+ function getError() {
430
+ if ( $this->error_str != '' ) {
431
+ return $this->error_str;
432
+ }
433
+
434
+ return false;
435
+ }
436
+
437
+ /**
438
+ * sets error string
439
+ *
440
+ * @return boolean $string error string
441
+ * @access private
442
+ */
443
+ function setError( $str ) {
444
+ $this->error_str = $str;
445
+ }
446
+
447
+ /**
448
+ * detect if array is a simple array or a struct (associative array)
449
+ *
450
+ * @param mixed $val The PHP array
451
+ *
452
+ * @return string (arraySimple|arrayStruct)
453
+ * @access private
454
+ */
455
+ function isArraySimpleOrStruct( $val ) {
456
+ $keyList = array_keys( $val );
457
+ foreach ( $keyList as $keyListValue ) {
458
+ if ( ! is_int( $keyListValue ) ) {
459
+ return 'arrayStruct';
460
+ }
461
+ }
462
+
463
+ return 'arraySimple';
464
+ }
465
+
466
+ /**
467
+ * serializes PHP values in accordance w/ section 5. Type information is
468
+ * not serialized if $use == 'literal'.
469
+ *
470
+ * @param mixed $val The value to serialize
471
+ * @param string $name The name (local part) of the XML element
472
+ * @param string $type The XML schema type (local part) for the element
473
+ * @param string $name_ns The namespace for the name of the XML element
474
+ * @param string $type_ns The namespace for the type of the element
475
+ * @param array $attributes The attributes to serialize as name=>value pairs
476
+ * @param string $use The WSDL "use" (encoded|literal)
477
+ * @param boolean $soapval Whether this is called from soapval.
478
+ *
479
+ * @return string The serialized element, possibly with child elements
480
+ * @access public
481
+ */
482
+ function serialize_val( $val, $name = false, $type = false, $name_ns = false, $type_ns = false, $attributes = false, $use = 'encoded', $soapval = false ) {
483
+ $this->debug( "in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval" );
484
+ $this->appendDebug( 'value=' . $this->varDump( $val ) );
485
+ $this->appendDebug( 'attributes=' . $this->varDump( $attributes ) );
486
+
487
+ if ( is_object( $val ) && get_class( $val ) == 'soapval' && ( ! $soapval ) ) {
488
+ $this->debug( "serialize_val: serialize soapval" );
489
+ $xml = $val->serialize( $use );
490
+ $this->appendDebug( $val->getDebug() );
491
+ $val->clearDebug();
492
+ $this->debug( "serialize_val of soapval returning $xml" );
493
+
494
+ return $xml;
495
+ }
496
+ // force valid name if necessary
497
+ if ( is_numeric( $name ) ) {
498
+ $name = '__numeric_' . $name;
499
+ } elseif ( ! $name ) {
500
+ $name = 'noname';
501
+ }
502
+ // if name has ns, add ns prefix to name
503
+ $xmlns = '';
504
+ if ( $name_ns ) {
505
+ $prefix = 'nu' . rand( 1000, 9999 );
506
+ $name = $prefix . ':' . $name;
507
+ $xmlns .= " xmlns:$prefix=\"$name_ns\"";
508
+ }
509
+ // if type is prefixed, create type prefix
510
+ if ( $type_ns != '' && $type_ns == $this->namespaces['xsd'] ) {
511
+ // need to fix this. shouldn't default to xsd if no ns specified
512
+ // w/o checking against typemap
513
+ $type_prefix = 'xsd';
514
+ } elseif ( $type_ns ) {
515
+ $type_prefix = 'ns' . rand( 1000, 9999 );
516
+ $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
517
+ }
518
+ // serialize attributes if present
519
+ $atts = '';
520
+ if ( $attributes ) {
521
+ foreach ( $attributes as $k => $v ) {
522
+ $atts .= " $k=\"" . $this->expandEntities( $v ) . '"';
523
+ }
524
+ }
525
+ // serialize null value
526
+ if ( is_null( $val ) ) {
527
+ $this->debug( "serialize_val: serialize null" );
528
+ if ( $use == 'literal' ) {
529
+ // TODO: depends on minOccurs
530
+ $xml = "<$name$xmlns$atts/>";
531
+ $this->debug( "serialize_val returning $xml" );
532
+
533
+ return $xml;
534
+ } else {
535
+ if ( isset( $type ) && isset( $type_prefix ) ) {
536
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
537
+ } else {
538
+ $type_str = '';
539
+ }
540
+ $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
541
+ $this->debug( "serialize_val returning $xml" );
542
+
543
+ return $xml;
544
+ }
545
+ }
546
+ // serialize if an xsd built-in primitive type
547
+ if ( $type != '' && isset( $this->typemap[ $this->XMLSchemaVersion ][ $type ] ) ) {
548
+ $this->debug( "serialize_val: serialize xsd built-in primitive type" );
549
+ if ( is_bool( $val ) ) {
550
+ if ( $type == 'boolean' ) {
551
+ $val = $val ? 'true' : 'false';
552
+ } elseif ( ! $val ) {
553
+ $val = 0;
554
+ }
555
+ } else if ( is_string( $val ) ) {
556
+ $val = $this->expandEntities( $val );
557
+ }
558
+ if ( $use == 'literal' ) {
559
+ $xml = "<$name$xmlns$atts>$val</$name>";
560
+ $this->debug( "serialize_val returning $xml" );
561
+
562
+ return $xml;
563
+ } else {
564
+ $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
565
+ $this->debug( "serialize_val returning $xml" );
566
+
567
+ return $xml;
568
+ }
569
+ }
570
+ // detect type and serialize
571
+ $xml = '';
572
+ switch ( true ) {
573
+ case ( is_bool( $val ) || $type == 'boolean' ):
574
+ $this->debug( "serialize_val: serialize boolean" );
575
+ if ( $type == 'boolean' ) {
576
+ $val = $val ? 'true' : 'false';
577
+ } elseif ( ! $val ) {
578
+ $val = 0;
579
+ }
580
+ if ( $use == 'literal' ) {
581
+ $xml .= "<$name$xmlns$atts>$val</$name>";
582
+ } else {
583
+ $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
584
+ }
585
+ break;
586
+ case ( is_int( $val ) || is_long( $val ) || $type == 'int' ):
587
+ $this->debug( "serialize_val: serialize int" );
588
+ if ( $use == 'literal' ) {
589
+ $xml .= "<$name$xmlns$atts>$val</$name>";
590
+ } else {
591
+ $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
592
+ }
593
+ break;
594
+ case ( is_float( $val ) || is_double( $val ) || $type == 'float' ):
595
+ $this->debug( "serialize_val: serialize float" );
596
+ if ( $use == 'literal' ) {
597
+ $xml .= "<$name$xmlns$atts>$val</$name>";
598
+ } else {
599
+ $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
600
+ }
601
+ break;
602
+ case ( is_string( $val ) || $type == 'string' ):
603
+ $this->debug( "serialize_val: serialize string" );
604
+ $val = $this->expandEntities( $val );
605
+ if ( $use == 'literal' ) {
606
+ $xml .= "<$name$xmlns$atts>$val</$name>";
607
+ } else {
608
+ $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
609
+ }
610
+ break;
611
+ case is_object( $val ):
612
+ $this->debug( "serialize_val: serialize object" );
613
+ if ( get_class( $val ) == 'soapval' ) {
614
+ $this->debug( "serialize_val: serialize soapval object" );
615
+ $pXml = $val->serialize( $use );
616
+ $this->appendDebug( $val->getDebug() );
617
+ $val->clearDebug();
618
+ } else {
619
+ if ( ! $name ) {
620
+ $name = get_class( $val );
621
+ $this->debug( "In serialize_val, used class name $name as element name" );
622
+ } else {
623
+ $this->debug( "In serialize_val, do not override name $name for element name for class " . get_class( $val ) );
624
+ }
625
+ foreach ( get_object_vars( $val ) as $k => $v ) {
626
+ $pXml = isset( $pXml ) ? $pXml . $this->serialize_val( $v, $k, false, false, false, false, $use ) : $this->serialize_val( $v, $k, false, false, false, false, $use );
627
+ }
628
+ }
629
+ if ( isset( $type ) && isset( $type_prefix ) ) {
630
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
631
+ } else {
632
+ $type_str = '';
633
+ }
634
+ if ( $use == 'literal' ) {
635
+ $xml .= "<$name$xmlns$atts>$pXml</$name>";
636
+ } else {
637
+ $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
638
+ }
639
+ break;
640
+ break;
641
+ case ( is_array( $val ) || $type ):
642
+ // detect if struct or array
643
+ $valueType = $this->isArraySimpleOrStruct( $val );
644
+ if ( $valueType == 'arraySimple' || preg_match( '/^ArrayOf/', $type ) ) {
645
+ $this->debug( "serialize_val: serialize array" );
646
+ $i = 0;
647
+ if ( is_array( $val ) && count( $val ) > 0 ) {
648
+ foreach ( $val as $v ) {
649
+ if ( is_object( $v ) && get_class( $v ) == 'soapval' ) {
650
+ $tt_ns = $v->type_ns;
651
+ $tt = $v->type;
652
+ } elseif ( is_array( $v ) ) {
653
+ $tt = $this->isArraySimpleOrStruct( $v );
654
+ } else {
655
+ $tt = gettype( $v );
656
+ }
657
+ $array_types[ $tt ] = 1;
658
+ // TODO: for literal, the name should be $name
659
+ $xml .= $this->serialize_val( $v, 'item', false, false, false, false, $use );
660
+ ++ $i;
661
+ }
662
+ if ( count( $array_types ) > 1 ) {
663
+ $array_typename = 'xsd:anyType';
664
+ } elseif ( isset( $tt ) && isset( $this->typemap[ $this->XMLSchemaVersion ][ $tt ] ) ) {
665
+ if ( $tt == 'integer' ) {
666
+ $tt = 'int';
667
+ }
668
+ $array_typename = 'xsd:' . $tt;
669
+ } elseif ( isset( $tt ) && $tt == 'arraySimple' ) {
670
+ $array_typename = 'SOAP-ENC:Array';
671
+ } elseif ( isset( $tt ) && $tt == 'arrayStruct' ) {
672
+ $array_typename = 'unnamed_struct_use_soapval';
673
+ } else {
674
+ // if type is prefixed, create type prefix
675
+ if ( $tt_ns != '' && $tt_ns == $this->namespaces['xsd'] ) {
676
+ $array_typename = 'xsd:' . $tt;
677
+ } elseif ( $tt_ns ) {
678
+ $tt_prefix = 'ns' . rand( 1000, 9999 );
679
+ $array_typename = "$tt_prefix:$tt";
680
+ $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
681
+ } else {
682
+ $array_typename = $tt;
683
+ }
684
+ }
685
+ $array_type = $i;
686
+ if ( $use == 'literal' ) {
687
+ $type_str = '';
688
+ } else if ( isset( $type ) && isset( $type_prefix ) ) {
689
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
690
+ } else {
691
+ $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"" . $array_typename . "[$array_type]\"";
692
+ }
693
+ // empty array
694
+ } else {
695
+ if ( $use == 'literal' ) {
696
+ $type_str = '';
697
+ } else if ( isset( $type ) && isset( $type_prefix ) ) {
698
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
699
+ } else {
700
+ $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
701
+ }
702
+ }
703
+ // TODO: for array in literal, there is no wrapper here
704
+ $xml = "<$name$xmlns$type_str$atts>" . $xml . "</$name>";
705
+ } else {
706
+ // got a struct
707
+ $this->debug( "serialize_val: serialize struct" );
708
+ if ( isset( $type ) && isset( $type_prefix ) ) {
709
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
710
+ } else {
711
+ $type_str = '';
712
+ }
713
+ if ( $use == 'literal' ) {
714
+ $xml .= "<$name$xmlns$atts>";
715
+ } else {
716
+ $xml .= "<$name$xmlns$type_str$atts>";
717
+ }
718
+ foreach ( $val as $k => $v ) {
719
+ // Apache Map
720
+ if ( $type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap' ) {
721
+ $xml .= '<item>';
722
+ $xml .= $this->serialize_val( $k, 'key', false, false, false, false, $use );
723
+ $xml .= $this->serialize_val( $v, 'value', false, false, false, false, $use );
724
+ $xml .= '</item>';
725
+ } else {
726
+ $xml .= $this->serialize_val( $v, $k, false, false, false, false, $use );
727
+ }
728
+ }
729
+ $xml .= "</$name>";
730
+ }
731
+ break;
732
+ default:
733
+ $this->debug( "serialize_val: serialize unknown" );
734
+ $xml .= 'not detected, got ' . gettype( $val ) . ' for ' . $val;
735
+ break;
736
+ }
737
+ $this->debug( "serialize_val returning $xml" );
738
+
739
+ return $xml;
740
+ }
741
+
742
+ /**
743
+ * serializes a message
744
+ *
745
+ * @param string $body the XML of the SOAP body
746
+ * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
747
+ * @param array $namespaces optional the namespaces used in generating the body and headers
748
+ * @param string $style optional (rpc|document)
749
+ * @param string $use optional (encoded|literal)
750
+ * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
751
+ *
752
+ * @return string the message
753
+ * @access public
754
+ */
755
+ function serializeEnvelope( $body, $headers = false, $namespaces = array(), $style = 'rpc', $use = 'encoded', $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/' ) {
756
+ // TODO: add an option to automatically run utf8_encode on $body and $headers
757
+ // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
758
+ // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
759
+
760
+ $this->debug( "In serializeEnvelope length=" . strlen( $body ) . " body (max 1000 characters)=" . substr( $body, 0, 1000 ) . " style=$style use=$use encodingStyle=$encodingStyle" );
761
+ $this->debug( "headers:" );
762
+ $this->appendDebug( $this->varDump( $headers ) );
763
+ $this->debug( "namespaces:" );
764
+ $this->appendDebug( $this->varDump( $namespaces ) );
765
+
766
+ // serialize namespaces
767
+ $ns_string = '';
768
+ foreach ( array_merge( $this->namespaces, $namespaces ) as $k => $v ) {
769
+ $ns_string .= " xmlns:$k=\"$v\"";
770
+ }
771
+ if ( $encodingStyle ) {
772
+ $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
773
+ }
774
+
775
+ // serialize headers
776
+ if ( $headers ) {
777
+ if ( is_array( $headers ) ) {
778
+ $xml = '';
779
+ foreach ( $headers as $k => $v ) {
780
+ if ( is_object( $v ) && get_class( $v ) == 'soapval' ) {
781
+ $xml .= $this->serialize_val( $v, false, false, false, false, false, $use );
782
+ } else {
783
+ $xml .= $this->serialize_val( $v, $k, false, false, false, false, $use );
784
+ }
785
+ }
786
+ $headers = $xml;
787
+ $this->debug( "In serializeEnvelope, serialized array of headers to $headers" );
788
+ }
789
+ $headers = "<SOAP-ENV:Header>" . $headers . "</SOAP-ENV:Header>";
790
+ }
791
+
792
+ // serialize envelope
793
+ return
794
+ '<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?' . ">" .
795
+ '<SOAP-ENV:Envelope' . $ns_string . ">" .
796
+ $headers .
797
+ "<SOAP-ENV:Body>" .
798
+ $body .
799
+ "</SOAP-ENV:Body>" .
800
+ "</SOAP-ENV:Envelope>";
801
+ }
802
+
803
+ /**
804
+ * formats a string to be inserted into an HTML stream
805
+ *
806
+ * @param string $str The string to format
807
+ *
808
+ * @return string The formatted string
809
+ * @access public
810
+ * @deprecated
811
+ */
812
+ function formatDump( $str ) {
813
+ $str = htmlspecialchars( $str );
814
+
815
+ return nl2br( $str );
816
+ }
817
+
818
+ /**
819
+ * contracts (changes namespace to prefix) a qualified name
820
+ *
821
+ * @param string $qname qname
822
+ *
823
+ * @return string contracted qname
824
+ * @access private
825
+ */
826
+ function contractQname( $qname ) {
827
+ // get element namespace
828
+ //$this->xdebug("Contract $qname");
829
+ if ( strrpos( $qname, ':' ) ) {
830
+ // get unqualified name
831
+ $name = substr( $qname, strrpos( $qname, ':' ) + 1 );
832
+ // get ns
833
+ $ns = substr( $qname, 0, strrpos( $qname, ':' ) );
834
+ $p = $this->getPrefixFromNamespace( $ns );
835
+ if ( $p ) {
836
+ return $p . ':' . $name;
837
+ }
838
+
839
+ return $qname;
840
+ } else {
841
+ return $qname;
842
+ }
843
+ }
844
+
845
+ /**
846
+ * expands (changes prefix to namespace) a qualified name
847
+ *
848
+ * @param string $qname qname
849
+ *
850
+ * @return string expanded qname
851
+ * @access private
852
+ */
853
+ function expandQname( $qname ) {
854
+ // get element prefix
855
+ if ( strpos( $qname, ':' ) && ! preg_match( '/^http:\/\//', $qname ) ) {
856
+ // get unqualified name
857
+ $name = substr( strstr( $qname, ':' ), 1 );
858
+ // get ns prefix
859
+ $prefix = substr( $qname, 0, strpos( $qname, ':' ) );
860
+ if ( isset( $this->namespaces[ $prefix ] ) ) {
861
+ return $this->namespaces[ $prefix ] . ':' . $name;
862
+ } else {
863
+ return $qname;
864
+ }
865
+ } else {
866
+ return $qname;
867
+ }
868
+ }
869
+
870
+ /**
871
+ * returns the local part of a prefixed string
872
+ * returns the original string, if not prefixed
873
+ *
874
+ * @param string $str The prefixed string
875
+ *
876
+ * @return string The local part
877
+ * @access public
878
+ */
879
+ function getLocalPart( $str ) {
880
+ if ( $sstr = strrchr( $str, ':' ) ) {
881
+ // get unqualified name
882
+ return substr( $sstr, 1 );
883
+ } else {
884
+ return $str;
885
+ }
886
+ }
887
+
888
+ /**
889
+ * returns the prefix part of a prefixed string
890
+ * returns false, if not prefixed
891
+ *
892
+ * @param string $str The prefixed string
893
+ *
894
+ * @return mixed The prefix or false if there is no prefix
895
+ * @access public
896
+ */
897
+ function getPrefix( $str ) {
898
+ if ( $pos = strrpos( $str, ':' ) ) {
899
+ // get prefix
900
+ return substr( $str, 0, $pos );
901
+ }
902
+
903
+ return false;
904
+ }
905
+
906
+ /**
907
+ * pass it a prefix, it returns a namespace
908
+ *
909
+ * @param string $prefix The prefix
910
+ *
911
+ * @return mixed The namespace, false if no namespace has the specified prefix
912
+ * @access public
913
+ */
914
+ function getNamespaceFromPrefix( $prefix ) {
915
+ if ( isset( $this->namespaces[ $prefix ] ) ) {
916
+ return $this->namespaces[ $prefix ];
917
+ }
918
+
919
+ //$this->setError("No namespace registered for prefix '$prefix'");
920
+ return false;
921
+ }
922
+
923
+ /**
924
+ * returns the prefix for a given namespace (or prefix)
925
+ * or false if no prefixes registered for the given namespace
926
+ *
927
+ * @param string $ns The namespace
928
+ *
929
+ * @return mixed The prefix, false if the namespace has no prefixes
930
+ * @access public
931
+ */
932
+ function getPrefixFromNamespace( $ns ) {
933
+ foreach ( $this->namespaces as $p => $n ) {
934
+ if ( $ns == $n || $ns == $p ) {
935
+ $this->usedNamespaces[ $p ] = $n;
936
+
937
+ return $p;
938
+ }
939
+ }
940
+
941
+ return false;
942
+ }
943
+
944
+ /**
945
+ * returns the time in ODBC canonical form with microseconds
946
+ *
947
+ * @return string The time in ODBC canonical form with microseconds
948
+ * @access public
949
+ */
950
+ function getmicrotime() {
951
+ if ( function_exists( 'gettimeofday' ) ) {
952
+ $tod = gettimeofday();
953
+ $sec = $tod['sec'];
954
+ $usec = $tod['usec'];
955
+ } else {
956
+ $sec = time();
957
+ $usec = 0;
958
+ }
959
+
960
+ return strftime( '%Y-%m-%d %H:%M:%S', $sec ) . '.' . sprintf( '%06d', $usec );
961
+ }
962
+
963
+ /**
964
+ * Returns a string with the output of var_dump
965
+ *
966
+ * @param mixed $data The variable to var_dump
967
+ *
968
+ * @return string The output of var_dump
969
+ * @access public
970
+ */
971
+ function varDump( $data ) {
972
+ ob_start();
973
+ var_dump( $data );
974
+ $ret_val = ob_get_contents();
975
+ ob_end_clean();
976
+
977
+ return $ret_val;
978
+ }
979
+
980
+ /**
981
+ * represents the object as a string
982
+ *
983
+ * @return string
984
+ * @access public
985
+ */
986
+ function __toString() {
987
+ return $this->varDump( $this );
988
+ }
989
+ }
990
+
991
+ // XML Schema Datatype Helper Functions
992
+
993
+ //xsd:dateTime helpers
994
+
995
+ /**
996
+ * convert unix timestamp to ISO 8601 compliant date string
997
+ *
998
+ * @param int $timestamp Unix time stamp
999
+ * @param boolean $utc Whether the time stamp is UTC or local
1000
+ *
1001
+ * @return mixed ISO 8601 date string or false
1002
+ * @access public
1003
+ */
1004
+ function timestamp_to_iso8601( $timestamp, $utc = true ) {
1005
+ $datestr = date( 'Y-m-d\TH:i:sO', $timestamp );
1006
+ $pos = strrpos( $datestr, "+" );
1007
+ if ( $pos === false ) {
1008
+ $pos = strrpos( $datestr, "-" );
1009
+ }
1010
+ if ( $pos !== false ) {
1011
+ if ( strlen( $datestr ) == $pos + 5 ) {
1012
+ $datestr = substr( $datestr, 0, $pos + 3 ) . ':' . substr( $datestr, - 2 );
1013
+ }
1014
+ }
1015
+ if ( $utc ) {
1016
+ $pattern = '/' .
1017
+ '([0-9]{4})-' . // centuries & years CCYY-
1018
+ '([0-9]{2})-' . // months MM-
1019
+ '([0-9]{2})' . // days DD
1020
+ 'T' . // separator T
1021
+ '([0-9]{2}):' . // hours hh:
1022
+ '([0-9]{2}):' . // minutes mm:
1023
+ '([0-9]{2})(\.[0-9]*)?' . // seconds ss.ss...
1024
+ '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
1025
+ '/';
1026
+
1027
+ if ( preg_match( $pattern, $datestr, $regs ) ) {
1028
+ return sprintf( '%04d-%02d-%02dT%02d:%02d:%02dZ', $regs[1], $regs[2], $regs[3], $regs[4], $regs[5], $regs[6] );
1029
+ }
1030
+
1031
+ return false;
1032
+ } else {
1033
+ return $datestr;
1034
+ }
1035
+ }
1036
+
1037
+ /**
1038
+ * convert ISO 8601 compliant date string to unix timestamp
1039
+ *
1040
+ * @param string $datestr ISO 8601 compliant date string
1041
+ *
1042
+ * @return mixed Unix timestamp (int) or false
1043
+ * @access public
1044
+ */
1045
+ function iso8601_to_timestamp( $datestr ) {
1046
+ $pattern = '/' .
1047
+ '([0-9]{4})-' . // centuries & years CCYY-
1048
+ '([0-9]{2})-' . // months MM-
1049
+ '([0-9]{2})' . // days DD
1050
+ 'T' . // separator T
1051
+ '([0-9]{2}):' . // hours hh:
1052
+ '([0-9]{2}):' . // minutes mm:
1053
+ '([0-9]{2})(\.[0-9]+)?' . // seconds ss.ss...
1054
+ '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
1055
+ '/';
1056
+ if ( preg_match( $pattern, $datestr, $regs ) ) {
1057
+ // not utc
1058
+ if ( $regs[8] != 'Z' ) {
1059
+ $op = substr( $regs[8], 0, 1 );
1060
+ $h = substr( $regs[8], 1, 2 );
1061
+ $m = substr( $regs[8], strlen( $regs[8] ) - 2, 2 );
1062
+ if ( $op == '-' ) {
1063
+ $regs[4] = $regs[4] + $h;
1064
+ $regs[5] = $regs[5] + $m;
1065
+ } elseif ( $op == '+' ) {
1066
+ $regs[4] = $regs[4] - $h;
1067
+ $regs[5] = $regs[5] - $m;
1068
+ }
1069
+ }
1070
+
1071
+ return gmmktime( $regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1] );
1072
+ // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
1073
+ } else {
1074
+ return false;
1075
+ }
1076
+ }
1077
+
1078
+ /**
1079
+ * sleeps some number of microseconds
1080
+ *
1081
+ * @param string $usec the number of microseconds to sleep
1082
+ *
1083
+ * @access public
1084
+ * @deprecated
1085
+ */
1086
+ function usleepWindows( $usec ) {
1087
+ $start = gettimeofday();
1088
+
1089
+ do {
1090
+ $stop = gettimeofday();
1091
+ $timePassed = 1000000 * ( $stop['sec'] - $start['sec'] )
1092
+ + $stop['usec'] - $start['usec'];
1093
+ } while ( $timePassed < $usec );
1094
+ }
1095
+
1096
+ ?><?php
1097
+
1098
+
1099
+ /**
1100
+ * Contains information for a SOAP fault.
1101
+ * Mainly used for returning faults from deployed functions
1102
+ * in a server instance.
1103
+ * @author Dietrich Ayala <dietrich@ganx4.com>
1104
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
1105
+ * @access public
1106
+ */
1107
+ class nusoap_fault extends nusoap_base {
1108
+ /**
1109
+ * The fault code (client|server)
1110
+ * @var string
1111
+ * @access private
1112
+ */
1113
+ var $faultcode;
1114
+ /**
1115
+ * The fault actor
1116
+ * @var string
1117
+ * @access private
1118
+ */
1119
+ var $faultactor;
1120
+ /**
1121
+ * The fault string, a description of the fault
1122
+ * @var string
1123
+ * @access private
1124
+ */
1125
+ var $faultstring;
1126
+ /**
1127
+ * The fault detail, typically a string or array of string
1128
+ * @var mixed
1129
+ * @access private
1130
+ */
1131
+ var $faultdetail;
1132
+
1133
+ /**
1134
+ * constructor
1135
+ *
1136
+ * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server)
1137
+ * @param string $faultactor only used when msg routed between multiple actors
1138
+ * @param string $faultstring human readable error message
1139
+ * @param mixed $faultdetail detail, typically a string or array of string
1140
+ */
1141
+ function nusoap_fault( $faultcode, $faultactor = '', $faultstring = '', $faultdetail = '' ) {
1142
+ parent::nusoap_base();
1143
+ $this->faultcode = $faultcode;
1144
+ $this->faultactor = $faultactor;
1145
+ $this->faultstring = $faultstring;
1146
+ $this->faultdetail = $faultdetail;
1147
+ }
1148
+
1149
+ /**
1150
+ * serialize a fault
1151
+ *
1152
+ * @return string The serialization of the fault instance.
1153
+ * @access public
1154
+ */
1155
+ function serialize() {
1156
+ $ns_string = '';
1157
+ foreach ( $this->namespaces as $k => $v ) {
1158
+ $ns_string .= "\n xmlns:$k=\"$v\"";
1159
+ }
1160
+ $return_msg =
1161
+ '<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?>' .
1162
+ '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string . ">\n" .
1163
+ '<SOAP-ENV:Body>' .
1164
+ '<SOAP-ENV:Fault>' .
1165
+ $this->serialize_val( $this->faultcode, 'faultcode' ) .
1166
+ $this->serialize_val( $this->faultactor, 'faultactor' ) .
1167
+ $this->serialize_val( $this->faultstring, 'faultstring' ) .
1168
+ $this->serialize_val( $this->faultdetail, 'detail' ) .
1169
+ '</SOAP-ENV:Fault>' .
1170
+ '</SOAP-ENV:Body>' .
1171
+ '</SOAP-ENV:Envelope>';
1172
+
1173
+ return $return_msg;
1174
+ }
1175
+ }
1176
+
1177
+ /**
1178
+ * Backward compatibility
1179
+ */
1180
+ class soap_fault extends nusoap_fault {
1181
+ }
1182
+
1183
+ ?><?php
1184
+
1185
+
1186
+ /**
1187
+ * parses an XML Schema, allows access to it's data, other utility methods.
1188
+ * imperfect, no validation... yet, but quite functional.
1189
+ *
1190
+ * @author Dietrich Ayala <dietrich@ganx4.com>
1191
+ * @author Scott Nichol <snichol@users.sourceforge.net>
1192
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
1193
+ * @access public
1194
+ */
1195
+ class nusoap_xmlschema extends nusoap_base {
1196
+
1197
+ // files
1198
+ var $schema = '';
1199
+ var $xml = '';
1200
+ // namespaces
1201
+ var $enclosingNamespaces;
1202
+ // schema info
1203
+ var $schemaInfo = array();
1204
+ var $schemaTargetNamespace = '';
1205
+ // types, elements, attributes defined by the schema
1206
+ var $attributes = array();
1207
+ var $complexTypes = array();
1208
+ var $complexTypeStack = array();
1209
+ var $currentComplexType = null;
1210
+ var $elements = array();
1211
+ var $elementStack = array();
1212
+ var $currentElement = null;
1213
+ var $simpleTypes = array();
1214
+ var $simpleTypeStack = array();
1215
+ var $currentSimpleType = null;
1216
+ // imports
1217
+ var $imports = array();
1218
+ // parser vars
1219
+ var $parser;
1220
+ var $position = 0;
1221
+ var $depth = 0;
1222
+ var $depth_array = array();
1223
+ var $message = array();
1224
+ var $defaultNamespace = array();
1225
+
1226
+ /**
1227
+ * constructor
1228
+ *
1229
+ * @param string $schema schema document URI
1230
+ * @param string $xml xml document URI
1231
+ * @param string $namespaces namespaces defined in enclosing XML
1232
+ *
1233
+ * @access public
1234
+ */
1235
+ function nusoap_xmlschema( $schema = '', $xml = '', $namespaces = array() ) {
1236
+ parent::nusoap_base();
1237
+ $this->debug( 'nusoap_xmlschema class instantiated, inside constructor' );
1238
+ // files
1239
+ $this->schema = $schema;
1240
+ $this->xml = $xml;
1241
+
1242
+ // namespaces
1243
+ $this->enclosingNamespaces = $namespaces;
1244
+ $this->namespaces = array_merge( $this->namespaces, $namespaces );
1245
+
1246
+ // parse schema file
1247
+ if ( $schema != '' ) {
1248
+ $this->debug( 'initial schema file: ' . $schema );
1249
+ $this->parseFile( $schema, 'schema' );
1250
+ }
1251
+
1252
+ // parse xml file
1253
+ if ( $xml != '' ) {
1254
+ $this->debug( 'initial xml file: ' . $xml );
1255
+ $this->parseFile( $xml, 'xml' );
1256
+ }
1257
+
1258
+ }
1259
+
1260
+ /**
1261
+ * parse an XML file
1262
+ *
1263
+ * @param string $xml path/URL to XML file
1264
+ * @param string $type (schema | xml)
1265
+ *
1266
+ * @return boolean
1267
+ * @access public
1268
+ */
1269
+ function parseFile( $xml, $type ) {
1270
+ // parse xml file
1271
+ if ( $xml != "" ) {
1272
+ $xmlStr = @join( "", @file( $xml ) );
1273
+ if ( $xmlStr == "" ) {
1274
+ $msg = 'Error reading XML from ' . $xml;
1275
+ $this->setError( $msg );
1276
+ $this->debug( $msg );
1277
+
1278
+ return false;
1279
+ } else {
1280
+ $this->debug( "parsing $xml" );
1281
+ $this->parseString( $xmlStr, $type );
1282
+ $this->debug( "done parsing $xml" );
1283
+
1284
+ return true;
1285
+ }
1286
+ }
1287
+
1288
+ return false;
1289
+ }
1290
+
1291
+ /**
1292
+ * parse an XML string
1293
+ *
1294
+ * @param string $xml path or URL
1295
+ * @param string $type (schema|xml)
1296
+ *
1297
+ * @access private
1298
+ */
1299
+ function parseString( $xml, $type ) {
1300
+ // parse xml string
1301
+ if ( $xml != "" ) {
1302
+
1303
+ // Create an XML parser.
1304
+ $this->parser = xml_parser_create();
1305
+ // Set the options for parsing the XML data.
1306
+ xml_parser_set_option( $this->parser, XML_OPTION_CASE_FOLDING, 0 );
1307
+
1308
+ // Set the object for the parser.
1309
+ xml_set_object( $this->parser, $this );
1310
+
1311
+ // Set the element handlers for the parser.
1312
+ if ( $type == "schema" ) {
1313
+ xml_set_element_handler( $this->parser, 'schemaStartElement', 'schemaEndElement' );
1314
+ xml_set_character_data_handler( $this->parser, 'schemaCharacterData' );
1315
+ } elseif ( $type == "xml" ) {
1316
+ xml_set_element_handler( $this->parser, 'xmlStartElement', 'xmlEndElement' );
1317
+ xml_set_character_data_handler( $this->parser, 'xmlCharacterData' );
1318
+ }
1319
+
1320
+ // Parse the XML file.
1321
+ if ( ! xml_parse( $this->parser, $xml, true ) ) {
1322
+ // Display an error message.
1323
+ $errstr = sprintf( 'XML error parsing XML schema on line %d: %s',
1324
+ xml_get_current_line_number( $this->parser ),
1325
+ xml_error_string( xml_get_error_code( $this->parser ) )
1326
+ );
1327
+ $this->debug( $errstr );
1328
+ $this->debug( "XML payload:\n" . $xml );
1329
+ $this->setError( $errstr );
1330
+ }
1331
+
1332
+ xml_parser_free( $this->parser );
1333
+ } else {
1334
+ $this->debug( 'no xml passed to parseString()!!' );
1335
+ $this->setError( 'no xml passed to parseString()!!' );
1336
+ }
1337
+ }
1338
+
1339
+ /**
1340
+ * gets a type name for an unnamed type
1341
+ *
1342
+ * @param string Element name
1343
+ *
1344
+ * @return string A type name for an unnamed type
1345
+ * @access private
1346
+ */
1347
+ function CreateTypeName( $ename ) {
1348
+ $scope = '';
1349
+ for ( $i = 0; $i < count( $this->complexTypeStack ); $i ++ ) {
1350
+ $scope .= $this->complexTypeStack[ $i ] . '_';
1351
+ }
1352
+
1353
+ return $scope . $ename . '_ContainedType';
1354
+ }
1355
+
1356
+ /**
1357
+ * start-element handler
1358
+ *
1359
+ * @param string $parser XML parser object
1360
+ * @param string $name element name
1361
+ * @param string $attrs associative array of attributes
1362
+ *
1363
+ * @access private
1364
+ */
1365
+ function schemaStartElement( $parser, $name, $attrs ) {
1366
+
1367
+ // position in the total number of elements, starting from 0
1368
+ $pos = $this->position ++;
1369
+ $depth = $this->depth ++;
1370
+ // set self as current value for this depth
1371
+ $this->depth_array[ $depth ] = $pos;
1372
+ $this->message[ $pos ] = array( 'cdata' => '' );
1373
+ if ( $depth > 0 ) {
1374
+ $this->defaultNamespace[ $pos ] = $this->defaultNamespace[ $this->depth_array[ $depth - 1 ] ];
1375
+ } else {
1376
+ $this->defaultNamespace[ $pos ] = false;
1377
+ }
1378
+
1379
+ // get element prefix
1380
+ if ( $prefix = $this->getPrefix( $name ) ) {
1381
+ // get unqualified name
1382
+ $name = $this->getLocalPart( $name );
1383
+ } else {
1384
+ $prefix = '';
1385
+ }
1386
+
1387
+ // loop thru attributes, expanding, and registering namespace declarations
1388
+ if ( count( $attrs ) > 0 ) {
1389
+ foreach ( $attrs as $k => $v ) {
1390
+ // if ns declarations, add to class level array of valid namespaces
1391
+ if ( preg_match( '/^xmlns/', $k ) ) {
1392
+ //$this->xdebug("$k: $v");
1393
+ //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1394
+ if ( $ns_prefix = substr( strrchr( $k, ':' ), 1 ) ) {
1395
+ //$this->xdebug("Add namespace[$ns_prefix] = $v");
1396
+ $this->namespaces[ $ns_prefix ] = $v;
1397
+ } else {
1398
+ $this->defaultNamespace[ $pos ] = $v;
1399
+ if ( ! $this->getPrefixFromNamespace( $v ) ) {
1400
+ $this->namespaces[ 'ns' . ( count( $this->namespaces ) + 1 ) ] = $v;
1401
+ }
1402
+ }
1403
+ if ( $v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema' ) {
1404
+ $this->XMLSchemaVersion = $v;
1405
+ $this->namespaces['xsi'] = $v . '-instance';
1406
+ }
1407
+ }
1408
+ }
1409
+ foreach ( $attrs as $k => $v ) {
1410
+ // expand each attribute
1411
+ $k = strpos( $k, ':' ) ? $this->expandQname( $k ) : $k;
1412
+ $v = strpos( $v, ':' ) ? $this->expandQname( $v ) : $v;
1413
+ $eAttrs[ $k ] = $v;
1414
+ }
1415
+ $attrs = $eAttrs;
1416
+ } else {
1417
+ $attrs = array();
1418
+ }
1419
+ // find status, register data
1420
+ switch ( $name ) {
1421
+ case 'all': // (optional) compositor content for a complexType
1422
+ case 'choice':
1423
+ case 'group':
1424
+ case 'sequence':
1425
+ //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1426
+ $this->complexTypes[ $this->currentComplexType ]['compositor'] = $name;
1427
+ //if($name == 'all' || $name == 'sequence'){
1428
+ // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1429
+ //}
1430
+ break;
1431
+ case 'attribute': // complexType attribute
1432
+ //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1433
+ $this->xdebug( "parsing attribute:" );
1434
+ $this->appendDebug( $this->varDump( $attrs ) );
1435
+ if ( ! isset( $attrs['form'] ) ) {
1436
+ // TODO: handle globals
1437
+ $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1438
+ }
1439
+ if ( isset( $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] ) ) {
1440
+ $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1441
+ if ( ! strpos( $v, ':' ) ) {
1442
+ // no namespace in arrayType attribute value...
1443
+ if ( $this->defaultNamespace[ $pos ] ) {
1444
+ // ...so use the default
1445
+ $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[ $pos ] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1446
+ }
1447
+ }
1448
+ }
1449
+ if ( isset( $attrs['name'] ) ) {
1450
+ $this->attributes[ $attrs['name'] ] = $attrs;
1451
+ $aname = $attrs['name'];
1452
+ } elseif ( isset( $attrs['ref'] ) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType' ) {
1453
+ if ( isset( $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] ) ) {
1454
+ $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1455
+ } else {
1456
+ $aname = '';
1457
+ }
1458
+ } elseif ( isset( $attrs['ref'] ) ) {
1459
+ $aname = $attrs['ref'];
1460
+ $this->attributes[ $attrs['ref'] ] = $attrs;
1461
+ }
1462
+
1463
+ if ( $this->currentComplexType ) { // This should *always* be
1464
+ $this->complexTypes[ $this->currentComplexType ]['attrs'][ $aname ] = $attrs;
1465
+ }
1466
+ // arrayType attribute
1467
+ if ( isset( $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] ) || $this->getLocalPart( $aname ) == 'arrayType' ) {
1468
+ $this->complexTypes[ $this->currentComplexType ]['phpType'] = 'array';
1469
+ $prefix = $this->getPrefix( $aname );
1470
+ if ( isset( $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] ) ) {
1471
+ $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1472
+ } else {
1473
+ $v = '';
1474
+ }
1475
+ if ( strpos( $v, '[,]' ) ) {
1476
+ $this->complexTypes[ $this->currentComplexType ]['multidimensional'] = true;
1477
+ }
1478
+ $v = substr( $v, 0, strpos( $v, '[' ) ); // clip the []
1479
+ if ( ! strpos( $v, ':' ) && isset( $this->typemap[ $this->XMLSchemaVersion ][ $v ] ) ) {
1480
+ $v = $this->XMLSchemaVersion . ':' . $v;
1481
+ }
1482
+ $this->complexTypes[ $this->currentComplexType ]['arrayType'] = $v;
1483
+ }
1484
+ break;
1485
+ case 'complexContent': // (optional) content for a complexType
1486
+ $this->xdebug( "do nothing for element $name" );
1487
+ break;
1488
+ case 'complexType':
1489
+ array_push( $this->complexTypeStack, $this->currentComplexType );
1490
+ if ( isset( $attrs['name'] ) ) {
1491
+ // TODO: what is the scope of named complexTypes that appear
1492
+ // nested within other c complexTypes?
1493
+ $this->xdebug( 'processing named complexType ' . $attrs['name'] );
1494
+ //$this->currentElement = false;
1495
+ $this->currentComplexType = $attrs['name'];
1496
+ $this->complexTypes[ $this->currentComplexType ] = $attrs;
1497
+ $this->complexTypes[ $this->currentComplexType ]['typeClass'] = 'complexType';
1498
+ // This is for constructs like
1499
+ // <complexType name="ListOfString" base="soap:Array">
1500
+ // <sequence>
1501
+ // <element name="string" type="xsd:string"
1502
+ // minOccurs="0" maxOccurs="unbounded" />
1503
+ // </sequence>
1504
+ // </complexType>
1505
+ if ( isset( $attrs['base'] ) && preg_match( '/:Array$/', $attrs['base'] ) ) {
1506
+ $this->xdebug( 'complexType is unusual array' );
1507
+ $this->complexTypes[ $this->currentComplexType ]['phpType'] = 'array';
1508
+ } else {
1509
+ $this->complexTypes[ $this->currentComplexType ]['phpType'] = 'struct';
1510
+ }
1511
+ } else {
1512
+ $name = $this->CreateTypeName( $this->currentElement );
1513
+ $this->xdebug( 'processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name );
1514
+ $this->currentComplexType = $name;
1515
+ //$this->currentElement = false;
1516
+ $this->complexTypes[ $this->currentComplexType ] = $attrs;
1517
+ $this->complexTypes[ $this->currentComplexType ]['typeClass'] = 'complexType';
1518
+ // This is for constructs like
1519
+ // <complexType name="ListOfString" base="soap:Array">
1520
+ // <sequence>
1521
+ // <element name="string" type="xsd:string"
1522
+ // minOccurs="0" maxOccurs="unbounded" />
1523
+ // </sequence>
1524
+ // </complexType>
1525
+ if ( isset( $attrs['base'] ) && preg_match( '/:Array$/', $attrs['base'] ) ) {
1526
+ $this->xdebug( 'complexType is unusual array' );
1527
+ $this->complexTypes[ $this->currentComplexType ]['phpType'] = 'array';
1528
+ } else {
1529
+ $this->complexTypes[ $this->currentComplexType ]['phpType'] = 'struct';
1530
+ }
1531
+ }
1532
+ $this->complexTypes[ $this->currentComplexType ]['simpleContent'] = 'false';
1533
+ break;
1534
+ case 'element':
1535
+ array_push( $this->elementStack, $this->currentElement );
1536
+ if ( ! isset( $attrs['form'] ) ) {
1537
+ if ( $this->currentComplexType ) {
1538
+ $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1539
+ } else {
1540
+ // global
1541
+ $attrs['form'] = 'qualified';
1542
+ }
1543
+ }
1544
+ if ( isset( $attrs['type'] ) ) {
1545
+ $this->xdebug( "processing typed element " . $attrs['name'] . " of type " . $attrs['type'] );
1546
+ if ( ! $this->getPrefix( $attrs['type'] ) ) {
1547
+ if ( $this->defaultNamespace[ $pos ] ) {
1548
+ $attrs['type'] = $this->defaultNamespace[ $pos ] . ':' . $attrs['type'];
1549
+ $this->xdebug( 'used default namespace to make type ' . $attrs['type'] );
1550
+ }
1551
+ }
1552
+ // This is for constructs like
1553
+ // <complexType name="ListOfString" base="soap:Array">
1554
+ // <sequence>
1555
+ // <element name="string" type="xsd:string"
1556
+ // minOccurs="0" maxOccurs="unbounded" />
1557
+ // </sequence>
1558
+ // </complexType>
1559
+ if ( $this->currentComplexType && $this->complexTypes[ $this->currentComplexType ]['phpType'] == 'array' ) {
1560
+ $this->xdebug( 'arrayType for unusual array is ' . $attrs['type'] );
1561
+ $this->complexTypes[ $this->currentComplexType ]['arrayType'] = $attrs['type'];
1562
+ }
1563
+ $this->currentElement = $attrs['name'];
1564
+ $ename = $attrs['name'];
1565
+ } elseif ( isset( $attrs['ref'] ) ) {
1566
+ $this->xdebug( "processing element as ref to " . $attrs['ref'] );
1567
+ $this->currentElement = "ref to " . $attrs['ref'];
1568
+ $ename = $this->getLocalPart( $attrs['ref'] );
1569
+ } else {
1570
+ $type = $this->CreateTypeName( $this->currentComplexType . '_' . $attrs['name'] );
1571
+ $this->xdebug( "processing untyped element " . $attrs['name'] . ' type ' . $type );
1572
+ $this->currentElement = $attrs['name'];
1573
+ $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
1574
+ $ename = $attrs['name'];
1575
+ }
1576
+ if ( isset( $ename ) && $this->currentComplexType ) {
1577
+ $this->xdebug( "add element $ename to complexType $this->currentComplexType" );
1578
+ $this->complexTypes[ $this->currentComplexType ]['elements'][ $ename ] = $attrs;
1579
+ } elseif ( ! isset( $attrs['ref'] ) ) {
1580
+ $this->xdebug( "add element $ename to elements array" );
1581
+ $this->elements[ $attrs['name'] ] = $attrs;
1582
+ $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1583
+ }
1584
+ break;
1585
+ case 'enumeration': // restriction value list member
1586
+ $this->xdebug( 'enumeration ' . $attrs['value'] );
1587
+ if ( $this->currentSimpleType ) {
1588
+ $this->simpleTypes[ $this->currentSimpleType ]['enumeration'][] = $attrs['value'];
1589
+ } elseif ( $this->currentComplexType ) {
1590
+ $this->complexTypes[ $this->currentComplexType ]['enumeration'][] = $attrs['value'];
1591
+ }
1592
+ break;
1593
+ case 'extension': // simpleContent or complexContent type extension
1594
+ $this->xdebug( 'extension ' . $attrs['base'] );
1595
+ if ( $this->currentComplexType ) {
1596
+ $ns = $this->getPrefix( $attrs['base'] );
1597
+ if ( $ns == '' ) {
1598
+ $this->complexTypes[ $this->currentComplexType ]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
1599
+ } else {
1600
+ $this->complexTypes[ $this->currentComplexType ]['extensionBase'] = $attrs['base'];
1601
+ }
1602
+ } else {
1603
+ $this->xdebug( 'no current complexType to set extensionBase' );
1604
+ }
1605
+ break;
1606
+ case 'import':
1607
+ if ( isset( $attrs['schemaLocation'] ) ) {
1608
+ $this->xdebug( 'import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation'] );
1609
+ $this->imports[ $attrs['namespace'] ][] = array(
1610
+ 'location' => $attrs['schemaLocation'],
1611
+ 'loaded' => false
1612
+ );
1613
+ } else {
1614
+ $this->xdebug( 'import namespace ' . $attrs['namespace'] );
1615
+ $this->imports[ $attrs['namespace'] ][] = array( 'location' => '', 'loaded' => true );
1616
+ if ( ! $this->getPrefixFromNamespace( $attrs['namespace'] ) ) {
1617
+ $this->namespaces[ 'ns' . ( count( $this->namespaces ) + 1 ) ] = $attrs['namespace'];
1618
+ }
1619
+ }
1620
+ break;
1621
+ case 'include':
1622
+ if ( isset( $attrs['schemaLocation'] ) ) {
1623
+ $this->xdebug( 'include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation'] );
1624
+ $this->imports[ $this->schemaTargetNamespace ][] = array(
1625
+ 'location' => $attrs['schemaLocation'],
1626
+ 'loaded' => false
1627
+ );
1628
+ } else {
1629
+ $this->xdebug( 'ignoring invalid XML Schema construct: include without schemaLocation attribute' );
1630
+ }
1631
+ break;
1632
+ case 'list': // simpleType value list
1633
+ $this->xdebug( "do nothing for element $name" );
1634
+ break;
1635
+ case 'restriction': // simpleType, simpleContent or complexContent value restriction
1636
+ $this->xdebug( 'restriction ' . $attrs['base'] );
1637
+ if ( $this->currentSimpleType ) {
1638
+ $this->simpleTypes[ $this->currentSimpleType ]['type'] = $attrs['base'];
1639
+ } elseif ( $this->currentComplexType ) {
1640
+ $this->complexTypes[ $this->currentComplexType ]['restrictionBase'] = $attrs['base'];
1641
+ if ( strstr( $attrs['base'], ':' ) == ':Array' ) {
1642
+ $this->complexTypes[ $this->currentComplexType ]['phpType'] = 'array';
1643
+ }
1644
+ }
1645
+ break;
1646
+ case 'schema':
1647
+ $this->schemaInfo = $attrs;
1648
+ $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix( $prefix );
1649
+ if ( isset( $attrs['targetNamespace'] ) ) {
1650
+ $this->schemaTargetNamespace = $attrs['targetNamespace'];
1651
+ }
1652
+ if ( ! isset( $attrs['elementFormDefault'] ) ) {
1653
+ $this->schemaInfo['elementFormDefault'] = 'unqualified';
1654
+ }
1655
+ if ( ! isset( $attrs['attributeFormDefault'] ) ) {
1656
+ $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1657
+ }
1658
+ break;
1659
+ case 'simpleContent': // (optional) content for a complexType
1660
+ if ( $this->currentComplexType ) { // This should *always* be
1661
+ $this->complexTypes[ $this->currentComplexType ]['simpleContent'] = 'true';
1662
+ } else {
1663
+ $this->xdebug( "do nothing for element $name because there is no current complexType" );
1664
+ }
1665
+ break;
1666
+ case 'simpleType':
1667
+ array_push( $this->simpleTypeStack, $this->currentSimpleType );
1668
+ if ( isset( $attrs['name'] ) ) {
1669
+ $this->xdebug( "processing simpleType for name " . $attrs['name'] );
1670
+ $this->currentSimpleType = $attrs['name'];
1671
+ $this->simpleTypes[ $attrs['name'] ] = $attrs;
1672
+ $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1673
+ $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1674
+ } else {
1675
+ $name = $this->CreateTypeName( $this->currentComplexType . '_' . $this->currentElement );
1676
+ $this->xdebug( 'processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name );
1677
+ $this->currentSimpleType = $name;
1678
+ //$this->currentElement = false;
1679
+ $this->simpleTypes[ $this->currentSimpleType ] = $attrs;
1680
+ $this->simpleTypes[ $this->currentSimpleType ]['phpType'] = 'scalar';
1681
+ }
1682
+ break;
1683
+ case 'union': // simpleType type list
1684
+ $this->xdebug( "do nothing for element $name" );
1685
+ break;
1686
+ default:
1687
+ $this->xdebug( "do not have any logic to process element $name" );
1688
+ }
1689
+ }
1690
+
1691
+ /**
1692
+ * end-element handler
1693
+ *
1694
+ * @param string $parser XML parser object
1695
+ * @param string $name element name
1696
+ *
1697
+ * @access private
1698
+ */
1699
+ function schemaEndElement( $parser, $name ) {
1700
+ // bring depth down a notch
1701
+ $this->depth --;
1702
+ // position of current element is equal to the last value left in depth_array for my depth
1703
+ if ( isset( $this->depth_array[ $this->depth ] ) ) {
1704
+ $pos = $this->depth_array[ $this->depth ];
1705
+ }
1706
+ // get element prefix
1707
+ if ( $prefix = $this->getPrefix( $name ) ) {
1708
+ // get unqualified name
1709
+ $name = $this->getLocalPart( $name );
1710
+ } else {
1711
+ $prefix = '';
1712
+ }
1713
+ // move on...
1714
+ if ( $name == 'complexType' ) {
1715
+ $this->xdebug( 'done processing complexType ' . ( $this->currentComplexType ? $this->currentComplexType : '(unknown)' ) );
1716
+ $this->xdebug( $this->varDump( $this->complexTypes[ $this->currentComplexType ] ) );
1717
+ $this->currentComplexType = array_pop( $this->complexTypeStack );
1718
+ //$this->currentElement = false;
1719
+ }
1720
+ if ( $name == 'element' ) {
1721
+ $this->xdebug( 'done processing element ' . ( $this->currentElement ? $this->currentElement : '(unknown)' ) );
1722
+ $this->currentElement = array_pop( $this->elementStack );
1723
+ }
1724
+ if ( $name == 'simpleType' ) {
1725
+ $this->xdebug( 'done processing simpleType ' . ( $this->currentSimpleType ? $this->currentSimpleType : '(unknown)' ) );
1726
+ $this->xdebug( $this->varDump( $this->simpleTypes[ $this->currentSimpleType ] ) );
1727
+ $this->currentSimpleType = array_pop( $this->simpleTypeStack );
1728
+ }
1729
+ }
1730
+
1731
+ /**
1732
+ * element content handler
1733
+ *
1734
+ * @param string $parser XML parser object
1735
+ * @param string $data element content
1736
+ *
1737
+ * @access private
1738
+ */
1739
+ function schemaCharacterData( $parser, $data ) {
1740
+ $pos = $this->depth_array[ $this->depth - 1 ];
1741
+ $this->message[ $pos ]['cdata'] .= $data;
1742
+ }
1743
+
1744
+ /**
1745
+ * serialize the schema
1746
+ *
1747
+ * @access public
1748
+ */
1749
+ function serializeSchema() {
1750
+
1751
+ $schemaPrefix = $this->getPrefixFromNamespace( $this->XMLSchemaVersion );
1752
+ $xml = '';
1753
+ // imports
1754
+ if ( sizeof( $this->imports ) > 0 ) {
1755
+ foreach ( $this->imports as $ns => $list ) {
1756
+ foreach ( $list as $ii ) {
1757
+ if ( $ii['location'] != '' ) {
1758
+ $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1759
+ } else {
1760
+ $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1761
+ }
1762
+ }
1763
+ }
1764
+ }
1765
+ // complex types
1766
+ foreach ( $this->complexTypes as $typeName => $attrs ) {
1767
+ $contentStr = '';
1768
+ // serialize child elements
1769
+ if ( isset( $attrs['elements'] ) && ( count( $attrs['elements'] ) > 0 ) ) {
1770
+ foreach ( $attrs['elements'] as $element => $eParts ) {
1771
+ if ( isset( $eParts['ref'] ) ) {
1772
+ $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
1773
+ } else {
1774
+ $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName( $eParts['type'] ) . "\"";
1775
+ foreach ( $eParts as $aName => $aValue ) {
1776
+ // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1777
+ if ( $aName != 'name' && $aName != 'type' ) {
1778
+ $contentStr .= " $aName=\"$aValue\"";
1779
+ }
1780
+ }
1781
+ $contentStr .= "/>\n";
1782
+ }
1783
+ }
1784
+ // compositor wraps elements
1785
+ if ( isset( $attrs['compositor'] ) && ( $attrs['compositor'] != '' ) ) {
1786
+ $contentStr = " <$schemaPrefix:$attrs[compositor]>\n" . $contentStr . " </$schemaPrefix:$attrs[compositor]>\n";
1787
+ }
1788
+ }
1789
+ // attributes
1790
+ if ( isset( $attrs['attrs'] ) && ( count( $attrs['attrs'] ) >= 1 ) ) {
1791
+ foreach ( $attrs['attrs'] as $attr => $aParts ) {
1792
+ $contentStr .= " <$schemaPrefix:attribute";
1793
+ foreach ( $aParts as $a => $v ) {
1794
+ if ( $a == 'ref' || $a == 'type' ) {
1795
+ $contentStr .= " $a=\"" . $this->contractQName( $v ) . '"';
1796
+ } elseif ( $a == 'http://schemas.xmlsoap.org/wsdl/:arrayType' ) {
1797
+ $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1798
+ $contentStr .= ' wsdl:arrayType="' . $this->contractQName( $v ) . '"';
1799
+ } else {
1800
+ $contentStr .= " $a=\"$v\"";
1801
+ }
1802
+ }
1803
+ $contentStr .= "/>\n";
1804
+ }
1805
+ }
1806
+ // if restriction
1807
+ if ( isset( $attrs['restrictionBase'] ) && $attrs['restrictionBase'] != '' ) {
1808
+ $contentStr = " <$schemaPrefix:restriction base=\"" . $this->contractQName( $attrs['restrictionBase'] ) . "\">\n" . $contentStr . " </$schemaPrefix:restriction>\n";
1809
+ // complex or simple content
1810
+ if ( ( isset( $attrs['elements'] ) && count( $attrs['elements'] ) > 0 ) || ( isset( $attrs['attrs'] ) && count( $attrs['attrs'] ) > 0 ) ) {
1811
+ $contentStr = " <$schemaPrefix:complexContent>\n" . $contentStr . " </$schemaPrefix:complexContent>\n";
1812
+ }
1813
+ }
1814
+ // finalize complex type
1815
+ if ( $contentStr != '' ) {
1816
+ $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n" . $contentStr . " </$schemaPrefix:complexType>\n";
1817
+ } else {
1818
+ $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1819
+ }
1820
+ $xml .= $contentStr;
1821
+ }
1822
+ // simple types
1823
+ if ( isset( $this->simpleTypes ) && count( $this->simpleTypes ) > 0 ) {
1824
+ foreach ( $this->simpleTypes as $typeName => $eParts ) {
1825
+ $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"" . $this->contractQName( $eParts['type'] ) . "\">\n";
1826
+ if ( isset( $eParts['enumeration'] ) ) {
1827
+ foreach ( $eParts['enumeration'] as $e ) {
1828
+ $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
1829
+ }
1830
+ }
1831
+ $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
1832
+ }
1833
+ }
1834
+ // elements
1835
+ if ( isset( $this->elements ) && count( $this->elements ) > 0 ) {
1836
+ foreach ( $this->elements as $element => $eParts ) {
1837
+ $xml .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName( $eParts['type'] ) . "\"/>\n";
1838
+ }
1839
+ }
1840
+ // attributes
1841
+ if ( isset( $this->attributes ) && count( $this->attributes ) > 0 ) {
1842
+ foreach ( $this->attributes as $attr => $aParts ) {
1843
+ $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"" . $this->contractQName( $aParts['type'] ) . "\"\n/>";
1844
+ }
1845
+ }
1846
+ // finish 'er up
1847
+ $attr = '';
1848
+ foreach ( $this->schemaInfo as $k => $v ) {
1849
+ if ( $k == 'elementFormDefault' || $k == 'attributeFormDefault' ) {
1850
+ $attr .= " $k=\"$v\"";
1851
+ }
1852
+ }
1853
+ $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
1854
+ foreach ( array_diff( $this->usedNamespaces, $this->enclosingNamespaces ) as $nsp => $ns ) {
1855
+ $el .= " xmlns:$nsp=\"$ns\"";
1856
+ }
1857
+ $xml = $el . ">\n" . $xml . "</$schemaPrefix:schema>\n";
1858
+
1859
+ return $xml;
1860
+ }
1861
+
1862
+ /**
1863
+ * adds debug data to the clas level debug string
1864
+ *
1865
+ * @param string $string debug data
1866
+ *
1867
+ * @access private
1868
+ */
1869
+ function xdebug( $string ) {
1870
+ $this->debug( '<' . $this->schemaTargetNamespace . '> ' . $string );
1871
+ }
1872
+
1873
+ /**
1874
+ * get the PHP type of a user defined type in the schema
1875
+ * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
1876
+ * returns false if no type exists, or not w/ the given namespace
1877
+ * else returns a string that is either a native php type, or 'struct'
1878
+ *
1879
+ * @param string $type name of defined type
1880
+ * @param string $ns namespace of type
1881
+ *
1882
+ * @return mixed
1883
+ * @access public
1884
+ * @deprecated
1885
+ */
1886
+ function getPHPType( $type, $ns ) {
1887
+ if ( isset( $this->typemap[ $ns ][ $type ] ) ) {
1888
+ //print "found type '$type' and ns $ns in typemap<br>";
1889
+ return $this->typemap[ $ns ][ $type ];
1890
+ } elseif ( isset( $this->complexTypes[ $type ] ) ) {
1891
+ //print "getting type '$type' and ns $ns from complexTypes array<br>";
1892
+ return $this->complexTypes[ $type ]['phpType'];
1893
+ }
1894
+
1895
+ return false;
1896
+ }
1897
+
1898
+ /**
1899
+ * returns an associative array of information about a given type
1900
+ * returns false if no type exists by the given name
1901
+ *
1902
+ * For a complexType typeDef = array(
1903
+ * 'restrictionBase' => '',
1904
+ * 'phpType' => '',
1905
+ * 'compositor' => '(sequence|all)',
1906
+ * 'elements' => array(), // refs to elements array
1907
+ * 'attrs' => array() // refs to attributes array
1908
+ * ... and so on (see addComplexType)
1909
+ * )
1910
+ *
1911
+ * For simpleType or element, the array has different keys.
1912
+ *
1913
+ * @param string $type
1914
+ *
1915
+ * @return mixed
1916
+ * @access public
1917
+ * @see addComplexType
1918
+ * @see addSimpleType
1919
+ * @see addElement
1920
+ */
1921
+ function getTypeDef( $type ) {
1922
+ //$this->debug("in getTypeDef for type $type");
1923
+ if ( substr( $type, - 1 ) == '^' ) {
1924
+ $is_element = 1;
1925
+ $type = substr( $type, 0, - 1 );
1926
+ } else {
1927
+ $is_element = 0;
1928
+ }
1929
+
1930
+ if ( ( ! $is_element ) && isset( $this->complexTypes[ $type ] ) ) {
1931
+ $this->xdebug( "in getTypeDef, found complexType $type" );
1932
+
1933
+ return $this->complexTypes[ $type ];
1934
+ } elseif ( ( ! $is_element ) && isset( $this->simpleTypes[ $type ] ) ) {
1935
+ $this->xdebug( "in getTypeDef, found simpleType $type" );
1936
+ if ( ! isset( $this->simpleTypes[ $type ]['phpType'] ) ) {
1937
+ // get info for type to tack onto the simple type
1938
+ // TODO: can this ever really apply (i.e. what is a simpleType really?)
1939
+ $uqType = substr( $this->simpleTypes[ $type ]['type'], strrpos( $this->simpleTypes[ $type ]['type'], ':' ) + 1 );
1940
+ $ns = substr( $this->simpleTypes[ $type ]['type'], 0, strrpos( $this->simpleTypes[ $type ]['type'], ':' ) );
1941
+ $etype = $this->getTypeDef( $uqType );
1942
+ if ( $etype ) {
1943
+ $this->xdebug( "in getTypeDef, found type for simpleType $type:" );
1944
+ $this->xdebug( $this->varDump( $etype ) );
1945
+ if ( isset( $etype['phpType'] ) ) {
1946
+ $this->simpleTypes[ $type ]['phpType'] = $etype['phpType'];
1947
+ }
1948
+ if ( isset( $etype['elements'] ) ) {
1949
+ $this->simpleTypes[ $type ]['elements'] = $etype['elements'];
1950
+ }
1951
+ }
1952
+ }
1953
+
1954
+ return $this->simpleTypes[ $type ];
1955
+ } elseif ( isset( $this->elements[ $type ] ) ) {
1956
+ $this->xdebug( "in getTypeDef, found element $type" );
1957
+ if ( ! isset( $this->elements[ $type ]['phpType'] ) ) {
1958
+ // get info for type to tack onto the element
1959
+ $uqType = substr( $this->elements[ $type ]['type'], strrpos( $this->elements[ $type ]['type'], ':' ) + 1 );
1960
+ $ns = substr( $this->elements[ $type ]['type'], 0, strrpos( $this->elements[ $type ]['type'], ':' ) );
1961
+ $etype = $this->getTypeDef( $uqType );
1962
+ if ( $etype ) {
1963
+ $this->xdebug( "in getTypeDef, found type for element $type:" );
1964
+ $this->xdebug( $this->varDump( $etype ) );
1965
+ if ( isset( $etype['phpType'] ) ) {
1966
+ $this->elements[ $type ]['phpType'] = $etype['phpType'];
1967
+ }
1968
+ if ( isset( $etype['elements'] ) ) {
1969
+ $this->elements[ $type ]['elements'] = $etype['elements'];
1970
+ }
1971
+ if ( isset( $etype['extensionBase'] ) ) {
1972
+ $this->elements[ $type ]['extensionBase'] = $etype['extensionBase'];
1973
+ }
1974
+ } elseif ( $ns == 'http://www.w3.org/2001/XMLSchema' ) {
1975
+ $this->xdebug( "in getTypeDef, element $type is an XSD type" );
1976
+ $this->elements[ $type ]['phpType'] = 'scalar';
1977
+ }
1978
+ }
1979
+
1980
+ return $this->elements[ $type ];
1981
+ } elseif ( isset( $this->attributes[ $type ] ) ) {
1982
+ $this->xdebug( "in getTypeDef, found attribute $type" );
1983
+
1984
+ return $this->attributes[ $type ];
1985
+ } elseif ( preg_match( '/_ContainedType$/', $type ) ) {
1986
+ $this->xdebug( "in getTypeDef, have an untyped element $type" );
1987
+ $typeDef['typeClass'] = 'simpleType';
1988
+ $typeDef['phpType'] = 'scalar';
1989
+ $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
1990
+
1991
+ return $typeDef;
1992
+ }
1993
+ $this->xdebug( "in getTypeDef, did not find $type" );
1994
+
1995
+ return false;
1996
+ }
1997
+
1998
+ /**
1999
+ * returns a sample serialization of a given type, or false if no type by the given name
2000
+ *
2001
+ * @param string $type name of type
2002
+ *
2003
+ * @return mixed
2004
+ * @access public
2005
+ * @deprecated
2006
+ */
2007
+ function serializeTypeDef( $type ) {
2008
+ //print "in sTD() for type $type<br>";
2009
+ if ( $typeDef = $this->getTypeDef( $type ) ) {
2010
+ $str .= '<' . $type;
2011
+ if ( is_array( $typeDef['attrs'] ) ) {
2012
+ foreach ( $typeDef['attrs'] as $attName => $data ) {
2013
+ $str .= " $attName=\"{type = " . $data['type'] . "}\"";
2014
+ }
2015
+ }
2016
+ $str .= " xmlns=\"" . $this->schema['targetNamespace'] . "\"";
2017
+ if ( count( $typeDef['elements'] ) > 0 ) {
2018
+ $str .= ">";
2019
+ foreach ( $typeDef['elements'] as $element => $eData ) {
2020
+ $str .= $this->serializeTypeDef( $element );
2021
+ }
2022
+ $str .= "</$type>";
2023
+ } elseif ( $typeDef['typeClass'] == 'element' ) {
2024
+ $str .= "></$type>";
2025
+ } else {
2026
+ $str .= "/>";
2027
+ }
2028
+
2029
+ return $str;
2030
+ }
2031
+
2032
+ return false;
2033
+ }
2034
+
2035
+ /**
2036
+ * returns HTML form elements that allow a user
2037
+ * to enter values for creating an instance of the given type.
2038
+ *
2039
+ * @param string $name name for type instance
2040
+ * @param string $type name of type
2041
+ *
2042
+ * @return string
2043
+ * @access public
2044
+ * @deprecated
2045
+ */
2046
+ function typeToForm( $name, $type ) {
2047
+ // get typedef
2048
+ if ( $typeDef = $this->getTypeDef( $type ) ) {
2049
+ // if struct
2050
+ if ( $typeDef['phpType'] == 'struct' ) {
2051
+ $buffer .= '<table>';
2052
+ foreach ( $typeDef['elements'] as $child => $childDef ) {
2053
+ $buffer .= "
2054
+ <tr><td align='right'>$childDef[name] (type: " . $this->getLocalPart( $childDef['type'] ) . "):</td>
2055
+ <td><input type='text' name='parameters[" . $name . "][$childDef[name]]'></td></tr>";
2056
+ }
2057
+ $buffer .= '</table>';
2058
+ // if array
2059
+ } elseif ( $typeDef['phpType'] == 'array' ) {
2060
+ $buffer .= '<table>';
2061
+ for ( $i = 0; $i < 3; $i ++ ) {
2062
+ $buffer .= "
2063
+ <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
2064
+ <td><input type='text' name='parameters[" . $name . "][]'></td></tr>";
2065
+ }
2066
+ $buffer .= '</table>';
2067
+ // if scalar
2068
+ } else {
2069
+ $buffer .= "<input type='text' name='parameters[$name]'>";
2070
+ }
2071
+ } else {
2072
+ $buffer .= "<input type='text' name='parameters[$name]'>";
2073
+ }
2074
+
2075
+ return $buffer;
2076
+ }
2077
+
2078
+ /**
2079
+ * adds a complex type to the schema
2080
+ *
2081
+ * example: array
2082
+ *
2083
+ * addType(
2084
+ * 'ArrayOfstring',
2085
+ * 'complexType',
2086
+ * 'array',
2087
+ * '',
2088
+ * 'SOAP-ENC:Array',
2089
+ * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
2090
+ * 'xsd:string'
2091
+ * );
2092
+ *
2093
+ * example: PHP associative array ( SOAP Struct )
2094
+ *
2095
+ * addType(
2096
+ * 'SOAPStruct',
2097
+ * 'complexType',
2098
+ * 'struct',
2099
+ * 'all',
2100
+ * array('myVar'=> array('name'=>'myVar','type'=>'string')
2101
+ * );
2102
+ *
2103
+ * @param name
2104
+ * @param typeClass (complexType|simpleType|attribute)
2105
+ * @param phpType : currently supported are array and struct (php assoc array)
2106
+ * @param compositor (all|sequence|choice)
2107
+ * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2108
+ * @param elements = array ( name = array(name=>'',type=>'') )
2109
+ * @param attrs = array(
2110
+ * array(
2111
+ * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
2112
+ * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
2113
+ * )
2114
+ * )
2115
+ * @param arrayType : namespace:name (http://www.w3.org/2001/XMLSchema:string)
2116
+ *
2117
+ * @access public
2118
+ * @see getTypeDef
2119
+ */
2120
+ function addComplexType( $name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '' ) {
2121
+ $this->complexTypes[ $name ] = array(
2122
+ 'name' => $name,
2123
+ 'typeClass' => $typeClass,
2124
+ 'phpType' => $phpType,
2125
+ 'compositor' => $compositor,
2126
+ 'restrictionBase' => $restrictionBase,
2127
+ 'elements' => $elements,
2128
+ 'attrs' => $attrs,
2129
+ 'arrayType' => $arrayType
2130
+ );
2131
+
2132
+ $this->xdebug( "addComplexType $name:" );
2133
+ $this->appendDebug( $this->varDump( $this->complexTypes[ $name ] ) );
2134
+ }
2135
+
2136
+ /**
2137
+ * adds a simple type to the schema
2138
+ *
2139
+ * @param string $name
2140
+ * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2141
+ * @param string $typeClass (should always be simpleType)
2142
+ * @param string $phpType (should always be scalar)
2143
+ * @param array $enumeration array of values
2144
+ *
2145
+ * @access public
2146
+ * @see nusoap_xmlschema
2147
+ * @see getTypeDef
2148
+ */
2149
+ function addSimpleType( $name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array() ) {
2150
+ $this->simpleTypes[ $name ] = array(
2151
+ 'name' => $name,
2152
+ 'typeClass' => $typeClass,
2153
+ 'phpType' => $phpType,
2154
+ 'type' => $restrictionBase,
2155
+ 'enumeration' => $enumeration
2156
+ );
2157
+
2158
+ $this->xdebug( "addSimpleType $name:" );
2159
+ $this->appendDebug( $this->varDump( $this->simpleTypes[ $name ] ) );
2160
+ }
2161
+
2162
+ /**
2163
+ * adds an element to the schema
2164
+ *
2165
+ * @param array $attrs attributes that must include name and type
2166
+ *
2167
+ * @see nusoap_xmlschema
2168
+ * @access public
2169
+ */
2170
+ function addElement( $attrs ) {
2171
+ if ( ! $this->getPrefix( $attrs['type'] ) ) {
2172
+ $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
2173
+ }
2174
+ $this->elements[ $attrs['name'] ] = $attrs;
2175
+ $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
2176
+
2177
+ $this->xdebug( "addElement " . $attrs['name'] );
2178
+ $this->appendDebug( $this->varDump( $this->elements[ $attrs['name'] ] ) );
2179
+ }
2180
+ }
2181
+
2182
+ /**
2183
+ * Backward compatibility
2184
+ */
2185
+ class XMLSchema extends nusoap_xmlschema {
2186
+ }
2187
+
2188
+ ?><?php
2189
+
2190
+
2191
+ /**
2192
+ * For creating serializable abstractions of native PHP types. This class
2193
+ * allows element name/namespace, XSD type, and XML attributes to be
2194
+ * associated with a value. This is extremely useful when WSDL is not
2195
+ * used, but is also useful when WSDL is used with polymorphic types, including
2196
+ * xsd:anyType and user-defined types.
2197
+ *
2198
+ * @author Dietrich Ayala <dietrich@ganx4.com>
2199
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
2200
+ * @access public
2201
+ */
2202
+ class soapval extends nusoap_base {
2203
+ /**
2204
+ * The XML element name
2205
+ *
2206
+ * @var string
2207
+ * @access private
2208
+ */
2209
+ var $name;
2210
+ /**
2211
+ * The XML type name (string or false)
2212
+ *
2213
+ * @var mixed
2214
+ * @access private
2215
+ */
2216
+ var $type;
2217
+ /**
2218
+ * The PHP value
2219
+ *
2220
+ * @var mixed
2221
+ * @access private
2222
+ */
2223
+ var $value;
2224
+ /**
2225
+ * The XML element namespace (string or false)
2226
+ *
2227
+ * @var mixed
2228
+ * @access private
2229
+ */
2230
+ var $element_ns;
2231
+ /**
2232
+ * The XML type namespace (string or false)
2233
+ *
2234
+ * @var mixed
2235
+ * @access private
2236
+ */
2237
+ var $type_ns;
2238
+ /**
2239
+ * The XML element attributes (array or false)
2240
+ *
2241
+ * @var mixed
2242
+ * @access private
2243
+ */
2244
+ var $attributes;
2245
+
2246
+ /**
2247
+ * constructor
2248
+ *
2249
+ * @param string $name optional name
2250
+ * @param mixed $type optional type name
2251
+ * @param mixed $value optional value
2252
+ * @param mixed $element_ns optional namespace of value
2253
+ * @param mixed $type_ns optional namespace of type
2254
+ * @param mixed $attributes associative array of attributes to add to element serialization
2255
+ *
2256
+ * @access public
2257
+ */
2258
+ function soapval( $name = 'soapval', $type = false, $value = - 1, $element_ns = false, $type_ns = false, $attributes = false ) {
2259
+ parent::nusoap_base();
2260
+ $this->name = $name;
2261
+ $this->type = $type;
2262
+ $this->value = $value;
2263
+ $this->element_ns = $element_ns;
2264
+ $this->type_ns = $type_ns;
2265
+ $this->attributes = $attributes;
2266
+ }
2267
+
2268
+ /**
2269
+ * return serialized value
2270
+ *
2271
+ * @param string $use The WSDL use value (encoded|literal)
2272
+ *
2273
+ * @return string XML data
2274
+ * @access public
2275
+ */
2276
+ function serialize( $use = 'encoded' ) {
2277
+ return $this->serialize_val( $this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true );
2278
+ }
2279
+
2280
+ /**
2281
+ * decodes a soapval object into a PHP native type
2282
+ *
2283
+ * @return mixed
2284
+ * @access public
2285
+ */
2286
+ function decode() {
2287
+ return $this->value;
2288
+ }
2289
+ }
2290
+
2291
+
2292
+ ?><?php
2293
+
2294
+
2295
+ /**
2296
+ * transport class for sending/receiving data via HTTP and HTTPS
2297
+ * NOTE: PHP must be compiled with the CURL extension for HTTPS support
2298
+ *
2299
+ * @author Dietrich Ayala <dietrich@ganx4.com>
2300
+ * @author Scott Nichol <snichol@users.sourceforge.net>
2301
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
2302
+ * @access public
2303
+ */
2304
+ class soap_transport_http extends nusoap_base {
2305
+
2306
+ var $url = '';
2307
+ var $uri = '';
2308
+ var $digest_uri = '';
2309
+ var $scheme = '';
2310
+ var $host = '';
2311
+ var $port = '';
2312
+ var $path = '';
2313
+ var $request_method = 'POST';
2314
+ var $protocol_version = '1.0';
2315
+ var $encoding = '';
2316
+ var $outgoing_headers = array();
2317
+ var $incoming_headers = array();
2318
+ var $incoming_cookies = array();
2319
+ var $outgoing_payload = '';
2320
+ var $incoming_payload = '';
2321
+ var $response_status_line; // HTTP response status line
2322
+ var $useSOAPAction = true;
2323
+ var $persistentConnection = false;
2324
+ var $ch = false; // cURL handle
2325
+ var $ch_options = array(); // cURL custom options
2326
+ var $use_curl = false; // force cURL use
2327
+ var $proxy = null; // proxy information (associative array)
2328
+ var $username = '';
2329
+ var $password = '';
2330
+ var $authtype = '';
2331
+ var $digestRequest = array();
2332
+ var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
2333
+ // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2334
+ // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2335
+ // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2336
+ // passphrase: SSL key password/passphrase
2337
+ // certpassword: SSL certificate password
2338
+ // verifypeer: default is 1
2339
+ // verifyhost: default is 1
2340
+
2341
+ /**
2342
+ * constructor
2343
+ *
2344
+ * @param string $url The URL to which to connect
2345
+ * @param array $curl_options User-specified cURL options
2346
+ * @param boolean $use_curl Whether to try to force cURL use
2347
+ *
2348
+ * @access public
2349
+ */
2350
+ function soap_transport_http( $url, $curl_options = null, $use_curl = false ) {
2351
+ parent::nusoap_base();
2352
+ $this->debug( "ctor url=$url use_curl=$use_curl curl_options:" );
2353
+ $this->appendDebug( $this->varDump( $curl_options ) );
2354
+ $this->setURL( $url );
2355
+ if ( is_array( $curl_options ) ) {
2356
+ $this->ch_options = $curl_options;
2357
+ }
2358
+ $this->use_curl = $use_curl;
2359
+ preg_match( '/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev );
2360
+ $this->setHeader( 'User-Agent', $this->title . '/' . $this->version . ' (' . $rev[1] . ')' );
2361
+ }
2362
+
2363
+ /**
2364
+ * sets a cURL option
2365
+ *
2366
+ * @param mixed $option The cURL option (always integer?)
2367
+ * @param mixed $value The cURL option value
2368
+ *
2369
+ * @access private
2370
+ */
2371
+ function setCurlOption( $option, $value ) {
2372
+ $this->debug( "setCurlOption option=$option, value=" );
2373
+ $this->appendDebug( $this->varDump( $value ) );
2374
+ curl_setopt( $this->ch, $option, $value );
2375
+ }
2376
+
2377
+ /**
2378
+ * sets an HTTP header
2379
+ *
2380
+ * @param string $name The name of the header
2381
+ * @param string $value The value of the header
2382
+ *
2383
+ * @access private
2384
+ */
2385
+ function setHeader( $name, $value ) {
2386
+ $this->outgoing_headers[ $name ] = $value;
2387
+ $this->debug( "set header $name: $value" );
2388
+ }
2389
+
2390
+ /**
2391
+ * unsets an HTTP header
2392
+ *
2393
+ * @param string $name The name of the header
2394
+ *
2395
+ * @access private
2396
+ */
2397
+ function unsetHeader( $name ) {
2398
+ if ( isset( $this->outgoing_headers[ $name ] ) ) {
2399
+ $this->debug( "unset header $name" );
2400
+ unset( $this->outgoing_headers[ $name ] );
2401
+ }
2402
+ }
2403
+
2404
+ /**
2405
+ * sets the URL to which to connect
2406
+ *
2407
+ * @param string $url The URL to which to connect
2408
+ *
2409
+ * @access private
2410
+ */
2411
+ function setURL( $url ) {
2412
+ $this->url = $url;
2413
+
2414
+ $u = parse_url( $url );
2415
+ foreach ( $u as $k => $v ) {
2416
+ $this->debug( "parsed URL $k = $v" );
2417
+ $this->$k = $v;
2418
+ }
2419
+
2420
+ // add any GET params to path
2421
+ if ( isset( $u['query'] ) && $u['query'] != '' ) {
2422
+ $this->path .= '?' . $u['query'];
2423
+ }
2424
+
2425
+ // set default port
2426
+ if ( ! isset( $u['port'] ) ) {
2427
+ if ( $u['scheme'] == 'https' ) {
2428
+ $this->port = 443;
2429
+ } else {
2430
+ $this->port = 80;
2431
+ }
2432
+ }
2433
+
2434
+ $this->uri = $this->path;
2435
+ $this->digest_uri = $this->uri;
2436
+
2437
+ // build headers
2438
+ if ( ! isset( $u['port'] ) ) {
2439
+ $this->setHeader( 'Host', $this->host );
2440
+ } else {
2441
+ $this->setHeader( 'Host', $this->host . ':' . $this->port );
2442
+ }
2443
+
2444
+ if ( isset( $u['user'] ) && $u['user'] != '' ) {
2445
+ $this->setCredentials( urldecode( $u['user'] ), isset( $u['pass'] ) ? urldecode( $u['pass'] ) : '' );
2446
+ }
2447
+ }
2448
+
2449
+ /**
2450
+ * gets the I/O method to use
2451
+ *
2452
+ * @return string I/O method to use (socket|curl|unknown)
2453
+ * @access private
2454
+ */
2455
+ function io_method() {
2456
+ if ( $this->use_curl || ( $this->scheme == 'https' ) || ( $this->scheme == 'http' && $this->authtype == 'ntlm' ) || ( $this->scheme == 'http' && is_array( $this->proxy ) && $this->proxy['authtype'] == 'ntlm' ) ) {
2457
+ return 'curl';
2458
+ }
2459
+ if ( ( $this->scheme == 'http' || $this->scheme == 'ssl' ) && $this->authtype != 'ntlm' && ( ! is_array( $this->proxy ) || $this->proxy['authtype'] != 'ntlm' ) ) {
2460
+ return 'socket';
2461
+ }
2462
+
2463
+ return 'unknown';
2464
+ }
2465
+
2466
+ /**
2467
+ * establish an HTTP connection
2468
+ *
2469
+ * @param integer $timeout set connection timeout in seconds
2470
+ * @param integer $response_timeout set response timeout in seconds
2471
+ *
2472
+ * @return boolean true if connected, false if not
2473
+ * @access private
2474
+ */
2475
+ function connect( $connection_timeout = 0, $response_timeout = 30 ) {
2476
+ // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2477
+ // "regular" socket.
2478
+ // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2479
+ // loaded), and until PHP5 stream_get_wrappers is not available.
2480
+ // if ($this->scheme == 'https') {
2481
+ // if (version_compare(phpversion(), '4.3.0') >= 0) {
2482
+ // if (extension_loaded('openssl')) {
2483
+ // $this->scheme = 'ssl';
2484
+ // $this->debug('Using SSL over OpenSSL');
2485
+ // }
2486
+ // }
2487
+ // }
2488
+ $this->debug( "connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port" );
2489
+ if ( $this->io_method() == 'socket' ) {
2490
+ if ( ! is_array( $this->proxy ) ) {
2491
+ $host = $this->host;
2492
+ $port = $this->port;
2493
+ } else {
2494
+ $host = $this->proxy['host'];
2495
+ $port = $this->proxy['port'];
2496
+ }
2497
+
2498
+ // use persistent connection
2499
+ if ( $this->persistentConnection && isset( $this->fp ) && is_resource( $this->fp ) ) {
2500
+ if ( ! feof( $this->fp ) ) {
2501
+ $this->debug( 'Re-use persistent connection' );
2502
+
2503
+ return true;
2504
+ }
2505
+ fclose( $this->fp );
2506
+ $this->debug( 'Closed persistent connection at EOF' );
2507
+ }
2508
+
2509
+ // munge host if using OpenSSL
2510
+ if ( $this->scheme == 'ssl' ) {
2511
+ $host = 'ssl://' . $host;
2512
+ }
2513
+ $this->debug( 'calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout );
2514
+
2515
+ // open socket
2516
+ if ( $connection_timeout > 0 ) {
2517
+ $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout );
2518
+ } else {
2519
+ $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str );
2520
+ }
2521
+
2522
+ // test pointer
2523
+ if ( ! $this->fp ) {
2524
+ $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2525
+ if ( $this->errno ) {
2526
+ $msg .= ', Error (' . $this->errno . '): ' . $this->error_str;
2527
+ } else {
2528
+ $msg .= ' prior to connect(). This is often a problem looking up the host name.';
2529
+ }
2530
+ $this->debug( $msg );
2531
+ $this->setError( $msg );
2532
+
2533
+ return false;
2534
+ }
2535
+
2536
+ // set response timeout
2537
+ $this->debug( 'set response timeout to ' . $response_timeout );
2538
+ socket_set_timeout( $this->fp, $response_timeout );
2539
+
2540
+ $this->debug( 'socket connected' );
2541
+
2542
+ return true;
2543
+ } else if ( $this->io_method() == 'curl' ) {
2544
+ if ( ! extension_loaded( 'curl' ) ) {
2545
+ // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
2546
+ $this->setError( 'The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.' );
2547
+
2548
+ return false;
2549
+ }
2550
+ // Avoid warnings when PHP does not have these options
2551
+ if ( defined( 'CURLOPT_CONNECTIONTIMEOUT' ) ) {
2552
+ $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
2553
+ } else {
2554
+ $CURLOPT_CONNECTIONTIMEOUT = 78;
2555
+ }
2556
+ if ( defined( 'CURLOPT_HTTPAUTH' ) ) {
2557
+ $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
2558
+ } else {
2559
+ $CURLOPT_HTTPAUTH = 107;
2560
+ }
2561
+ if ( defined( 'CURLOPT_PROXYAUTH' ) ) {
2562
+ $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
2563
+ } else {
2564
+ $CURLOPT_PROXYAUTH = 111;
2565
+ }
2566
+ if ( defined( 'CURLAUTH_BASIC' ) ) {
2567
+ $CURLAUTH_BASIC = CURLAUTH_BASIC;
2568
+ } else {
2569
+ $CURLAUTH_BASIC = 1;
2570
+ }
2571
+ if ( defined( 'CURLAUTH_DIGEST' ) ) {
2572
+ $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
2573
+ } else {
2574
+ $CURLAUTH_DIGEST = 2;
2575
+ }
2576
+ if ( defined( 'CURLAUTH_NTLM' ) ) {
2577
+ $CURLAUTH_NTLM = CURLAUTH_NTLM;
2578
+ } else {
2579
+ $CURLAUTH_NTLM = 8;
2580
+ }
2581
+
2582
+ $this->debug( 'connect using cURL' );
2583
+ // init CURL
2584
+ $this->ch = curl_init();
2585
+ // set url
2586
+ $hostURL = ( $this->port != '' ) ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
2587
+ // add path
2588
+ $hostURL .= $this->path;
2589
+ $this->setCurlOption( CURLOPT_URL, $hostURL );
2590
+ // follow location headers (re-directs)
2591
+ if ( ini_get( 'safe_mode' ) || ini_get( 'open_basedir' ) ) {
2592
+ $this->debug( 'safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION' );
2593
+ $this->debug( 'safe_mode = ' );
2594
+ $this->appendDebug( $this->varDump( ini_get( 'safe_mode' ) ) );
2595
+ $this->debug( 'open_basedir = ' );
2596
+ $this->appendDebug( $this->varDump( ini_get( 'open_basedir' ) ) );
2597
+ } else {
2598
+ $this->setCurlOption( CURLOPT_FOLLOWLOCATION, 1 );
2599
+ }
2600
+ // ask for headers in the response output
2601
+ $this->setCurlOption( CURLOPT_HEADER, 1 );
2602
+ // ask for the response output as the return value
2603
+ $this->setCurlOption( CURLOPT_RETURNTRANSFER, 1 );
2604
+ // encode
2605
+ // We manage this ourselves through headers and encoding
2606
+ // if(function_exists('gzuncompress')){
2607
+ // $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
2608
+ // }
2609
+ // persistent connection
2610
+ if ( $this->persistentConnection ) {
2611
+ // I believe the following comment is now bogus, having applied to
2612
+ // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
2613
+ // The way we send data, we cannot use persistent connections, since
2614
+ // there will be some "junk" at the end of our request.
2615
+ //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
2616
+ $this->persistentConnection = false;
2617
+ $this->setHeader( 'Connection', 'close' );
2618
+ }
2619
+ // set timeouts
2620
+ if ( $connection_timeout != 0 ) {
2621
+ $this->setCurlOption( $CURLOPT_CONNECTIONTIMEOUT, $connection_timeout );
2622
+ }
2623
+ if ( $response_timeout != 0 ) {
2624
+ $this->setCurlOption( CURLOPT_TIMEOUT, $response_timeout );
2625
+ }
2626
+
2627
+ if ( $this->scheme == 'https' ) {
2628
+ $this->debug( 'set cURL SSL verify options' );
2629
+ // recent versions of cURL turn on peer/host checking by default,
2630
+ // while PHP binaries are not compiled with a default location for the
2631
+ // CA cert bundle, so disable peer/host checking.
2632
+ //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
2633
+ $this->setCurlOption( CURLOPT_SSL_VERIFYPEER, 0 );
2634
+ $this->setCurlOption( CURLOPT_SSL_VERIFYHOST, 0 );
2635
+
2636
+ // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2637
+ if ( $this->authtype == 'certificate' ) {
2638
+ $this->debug( 'set cURL certificate options' );
2639
+ if ( isset( $this->certRequest['cainfofile'] ) ) {
2640
+ $this->setCurlOption( CURLOPT_CAINFO, $this->certRequest['cainfofile'] );
2641
+ }
2642
+ if ( isset( $this->certRequest['verifypeer'] ) ) {
2643
+ $this->setCurlOption( CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer'] );
2644
+ } else {
2645
+ $this->setCurlOption( CURLOPT_SSL_VERIFYPEER, 1 );
2646
+ }
2647
+ if ( isset( $this->certRequest['verifyhost'] ) ) {
2648
+ $this->setCurlOption( CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost'] );
2649
+ } else {
2650
+ $this->setCurlOption( CURLOPT_SSL_VERIFYHOST, 1 );
2651
+ }
2652
+ if ( isset( $this->certRequest['sslcertfile'] ) ) {
2653
+ $this->setCurlOption( CURLOPT_SSLCERT, $this->certRequest['sslcertfile'] );
2654
+ }
2655
+ if ( isset( $this->certRequest['sslkeyfile'] ) ) {
2656
+ $this->setCurlOption( CURLOPT_SSLKEY, $this->certRequest['sslkeyfile'] );
2657
+ }
2658
+ if ( isset( $this->certRequest['passphrase'] ) ) {
2659
+ $this->setCurlOption( CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase'] );
2660
+ }
2661
+ if ( isset( $this->certRequest['certpassword'] ) ) {
2662
+ $this->setCurlOption( CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword'] );
2663
+ }
2664
+ }
2665
+ }
2666
+ if ( $this->authtype && ( $this->authtype != 'certificate' ) ) {
2667
+ if ( $this->username ) {
2668
+ $this->debug( 'set cURL username/password' );
2669
+ $this->setCurlOption( CURLOPT_USERPWD, "$this->username:$this->password" );
2670
+ }
2671
+ if ( $this->authtype == 'basic' ) {
2672
+ $this->debug( 'set cURL for Basic authentication' );
2673
+ $this->setCurlOption( $CURLOPT_HTTPAUTH, $CURLAUTH_BASIC );
2674
+ }
2675
+ if ( $this->authtype == 'digest' ) {
2676
+ $this->debug( 'set cURL for digest authentication' );
2677
+ $this->setCurlOption( $CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST );
2678
+ }
2679
+ if ( $this->authtype == 'ntlm' ) {
2680
+ $this->debug( 'set cURL for NTLM authentication' );
2681
+ $this->setCurlOption( $CURLOPT_HTTPAUTH, $CURLAUTH_NTLM );
2682
+ }
2683
+ }
2684
+ if ( is_array( $this->proxy ) ) {
2685
+ $this->debug( 'set cURL proxy options' );
2686
+ if ( $this->proxy['port'] != '' ) {
2687
+ $this->setCurlOption( CURLOPT_PROXY, $this->proxy['host'] . ':' . $this->proxy['port'] );
2688
+ } else {
2689
+ $this->setCurlOption( CURLOPT_PROXY, $this->proxy['host'] );
2690
+ }
2691
+ if ( $this->proxy['username'] || $this->proxy['password'] ) {
2692
+ $this->debug( 'set cURL proxy authentication options' );
2693
+ $this->setCurlOption( CURLOPT_PROXYUSERPWD, $this->proxy['username'] . ':' . $this->proxy['password'] );
2694
+ if ( $this->proxy['authtype'] == 'basic' ) {
2695
+ $this->setCurlOption( $CURLOPT_PROXYAUTH, $CURLAUTH_BASIC );
2696
+ }
2697
+ if ( $this->proxy['authtype'] == 'ntlm' ) {
2698
+ $this->setCurlOption( $CURLOPT_PROXYAUTH, $CURLAUTH_NTLM );
2699
+ }
2700
+ }
2701
+ }
2702
+ $this->debug( 'cURL connection set up' );
2703
+
2704
+ return true;
2705
+ } else {
2706
+ $this->setError( 'Unknown scheme ' . $this->scheme );
2707
+ $this->debug( 'Unknown scheme ' . $this->scheme );
2708
+
2709
+ return false;
2710
+ }
2711
+ }
2712
+
2713
+ /**
2714
+ * sends the SOAP request and gets the SOAP response via HTTP[S]
2715
+ *
2716
+ * @param string $data message data
2717
+ * @param integer $timeout set connection timeout in seconds
2718
+ * @param integer $response_timeout set response timeout in seconds
2719
+ * @param array $cookies cookies to send
2720
+ *
2721
+ * @return string data
2722
+ * @access public
2723
+ */
2724
+ function send( $data, $timeout = 0, $response_timeout = 30, $cookies = null ) {
2725
+
2726
+ $this->debug( 'entered send() with data of length: ' . strlen( $data ) );
2727
+
2728
+ $this->tryagain = true;
2729
+ $tries = 0;
2730
+ while ( $this->tryagain ) {
2731
+ $this->tryagain = false;
2732
+ if ( $tries ++ < 2 ) {
2733
+ // make connnection
2734
+ if ( ! $this->connect( $timeout, $response_timeout ) ) {
2735
+ return false;
2736
+ }
2737
+
2738
+ // send request
2739
+ if ( ! $this->sendRequest( $data, $cookies ) ) {
2740
+ return false;
2741
+ }
2742
+
2743
+ // get response
2744
+ $respdata = $this->getResponse();
2745
+ } else {
2746
+ $this->setError( "Too many tries to get an OK response ($this->response_status_line)" );
2747
+ }
2748
+ }
2749
+ $this->debug( 'end of send()' );
2750
+
2751
+ return $respdata;
2752
+ }
2753
+
2754
+
2755
+ /**
2756
+ * sends the SOAP request and gets the SOAP response via HTTPS using CURL
2757
+ *
2758
+ * @param string $data message data
2759
+ * @param integer $timeout set connection timeout in seconds
2760
+ * @param integer $response_timeout set response timeout in seconds
2761
+ * @param array $cookies cookies to send
2762
+ *
2763
+ * @return string data
2764
+ * @access public
2765
+ * @deprecated
2766
+ */
2767
+ function sendHTTPS( $data, $timeout = 0, $response_timeout = 30, $cookies ) {
2768
+ return $this->send( $data, $timeout, $response_timeout, $cookies );
2769
+ }
2770
+
2771
+ /**
2772
+ * if authenticating, set user credentials here
2773
+ *
2774
+ * @param string $username
2775
+ * @param string $password
2776
+ * @param string $authtype (basic|digest|certificate|ntlm)
2777
+ * @param array $digestRequest (keys must be nonce, nc, realm, qop)
2778
+ * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
2779
+ *
2780
+ * @access public
2781
+ */
2782
+ function setCredentials( $username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array() ) {
2783
+ $this->debug( "setCredentials username=$username authtype=$authtype digestRequest=" );
2784
+ $this->appendDebug( $this->varDump( $digestRequest ) );
2785
+ $this->debug( "certRequest=" );
2786
+ $this->appendDebug( $this->varDump( $certRequest ) );
2787
+ // cf. RFC 2617
2788
+ if ( $authtype == 'basic' ) {
2789
+ $this->setHeader( 'Authorization', 'Basic ' . base64_encode( str_replace( ':', '', $username ) . ':' . $password ) );
2790
+ } elseif ( $authtype == 'digest' ) {
2791
+ if ( isset( $digestRequest['nonce'] ) ) {
2792
+ $digestRequest['nc'] = isset( $digestRequest['nc'] ) ? $digestRequest['nc'] ++ : 1;
2793
+
2794
+ // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2795
+
2796
+ // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2797
+ $A1 = $username . ':' . ( isset( $digestRequest['realm'] ) ? $digestRequest['realm'] : '' ) . ':' . $password;
2798
+
2799
+ // H(A1) = MD5(A1)
2800
+ $HA1 = md5( $A1 );
2801
+
2802
+ // A2 = Method ":" digest-uri-value
2803
+ $A2 = $this->request_method . ':' . $this->digest_uri;
2804
+
2805
+ // H(A2)
2806
+ $HA2 = md5( $A2 );
2807
+
2808
+ // KD(secret, data) = H(concat(secret, ":", data))
2809
+ // if qop == auth:
2810
+ // request-digest = <"> < KD ( H(A1), unq(nonce-value)
2811
+ // ":" nc-value
2812
+ // ":" unq(cnonce-value)
2813
+ // ":" unq(qop-value)
2814
+ // ":" H(A2)
2815
+ // ) <">
2816
+ // if qop is missing,
2817
+ // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2818
+
2819
+ $unhashedDigest = '';
2820
+ $nonce = isset( $digestRequest['nonce'] ) ? $digestRequest['nonce'] : '';
2821
+ $cnonce = $nonce;
2822
+ if ( $digestRequest['qop'] != '' ) {
2823
+ $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf( "%08d", $digestRequest['nc'] ) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2824
+ } else {
2825
+ $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2826
+ }
2827
+
2828
+ $hashedDigest = md5( $unhashedDigest );
2829
+
2830
+ $opaque = '';
2831
+ if ( isset( $digestRequest['opaque'] ) ) {
2832
+ $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
2833
+ }
2834
+
2835
+ $this->setHeader( 'Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf( "%08x", $digestRequest['nc'] ) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"' );
2836
+ }
2837
+ } elseif ( $authtype == 'certificate' ) {
2838
+ $this->certRequest = $certRequest;
2839
+ $this->debug( 'Authorization header not set for certificate' );
2840
+ } elseif ( $authtype == 'ntlm' ) {
2841
+ // do nothing
2842
+ $this->debug( 'Authorization header not set for ntlm' );
2843
+ }
2844
+ $this->username = $username;
2845
+ $this->password = $password;
2846
+ $this->authtype = $authtype;
2847
+ $this->digestRequest = $digestRequest;
2848
+ }
2849
+
2850
+ /**
2851
+ * set the soapaction value
2852
+ *
2853
+ * @param string $soapaction
2854
+ *
2855
+ * @access public
2856
+ */
2857
+ function setSOAPAction( $soapaction ) {
2858
+ $this->setHeader( 'SOAPAction', '"' . $soapaction . '"' );
2859
+ }
2860
+
2861
+ /**
2862
+ * use http encoding
2863
+ *
2864
+ * @param string $enc encoding style. supported values: gzip, deflate, or both
2865
+ *
2866
+ * @access public
2867
+ */
2868
+ function setEncoding( $enc = 'gzip, deflate' ) {
2869
+ if ( function_exists( 'gzdeflate' ) ) {
2870
+ $this->protocol_version = '1.1';
2871
+ $this->setHeader( 'Accept-Encoding', $enc );
2872
+ if ( ! isset( $this->outgoing_headers['Connection'] ) ) {
2873
+ $this->setHeader( 'Connection', 'close' );
2874
+ $this->persistentConnection = false;
2875
+ }
2876
+ // deprecated as of PHP 5.3.0
2877
+ //set_magic_quotes_runtime(0);
2878
+ $this->encoding = $enc;
2879
+ }
2880
+ }
2881
+
2882
+ /**
2883
+ * set proxy info here
2884
+ *
2885
+ * @param string $proxyhost use an empty string to remove proxy
2886
+ * @param string $proxyport
2887
+ * @param string $proxyusername
2888
+ * @param string $proxypassword
2889
+ * @param string $proxyauthtype (basic|ntlm)
2890
+ *
2891
+ * @access public
2892
+ */
2893
+ function setProxy( $proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic' ) {
2894
+ if ( $proxyhost ) {
2895
+ $this->proxy = array(
2896
+ 'host' => $proxyhost,
2897
+ 'port' => $proxyport,
2898
+ 'username' => $proxyusername,
2899
+ 'password' => $proxypassword,
2900
+ 'authtype' => $proxyauthtype
2901
+ );
2902
+ if ( $proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic' ) {
2903
+ $this->setHeader( 'Proxy-Authorization', ' Basic ' . base64_encode( $proxyusername . ':' . $proxypassword ) );
2904
+ }
2905
+ } else {
2906
+ $this->debug( 'remove proxy' );
2907
+ $proxy = null;
2908
+ unsetHeader( 'Proxy-Authorization' );
2909
+ }
2910
+ }
2911
+
2912
+
2913
+ /**
2914
+ * Test if the given string starts with a header that is to be skipped.
2915
+ * Skippable headers result from chunked transfer and proxy requests.
2916
+ *
2917
+ * @param string $data The string to check.
2918
+ *
2919
+ * @returns boolean Whether a skippable header was found.
2920
+ * @access private
2921
+ */
2922
+ function isSkippableCurlHeader( &$data ) {
2923
+ $skipHeaders = array(
2924
+ 'HTTP/1.1 100',
2925
+ 'HTTP/1.0 301',
2926
+ 'HTTP/1.1 301',
2927
+ 'HTTP/1.0 302',
2928
+ 'HTTP/1.1 302',
2929
+ 'HTTP/1.0 401',
2930
+ 'HTTP/1.1 401',
2931
+ 'HTTP/1.0 200 Connection established'
2932
+ );
2933
+ foreach ( $skipHeaders as $hd ) {
2934
+ $prefix = substr( $data, 0, strlen( $hd ) );
2935
+ if ( $prefix == $hd ) {
2936
+ return true;
2937
+ }
2938
+ }
2939
+
2940
+ return false;
2941
+ }
2942
+
2943
+ /**
2944
+ * decode a string that is encoded w/ "chunked' transfer encoding
2945
+ * as defined in RFC2068 19.4.6
2946
+ *
2947
+ * @param string $buffer
2948
+ * @param string $lb
2949
+ *
2950
+ * @returns string
2951
+ * @access public
2952
+ * @deprecated
2953
+ */
2954
+ function decodeChunked( $buffer, $lb ) {
2955
+ // length := 0
2956
+ $length = 0;
2957
+ $new = '';
2958
+
2959
+ // read chunk-size, chunk-extension (if any) and CRLF
2960
+ // get the position of the linebreak
2961
+ $chunkend = strpos( $buffer, $lb );
2962
+ if ( $chunkend == false ) {
2963
+ $this->debug( 'no linebreak found in decodeChunked' );
2964
+
2965
+ return $new;
2966
+ }
2967
+ $temp = substr( $buffer, 0, $chunkend );
2968
+ $chunk_size = hexdec( trim( $temp ) );
2969
+ $chunkstart = $chunkend + strlen( $lb );
2970
+ // while (chunk-size > 0) {
2971
+ while ( $chunk_size > 0 ) {
2972
+ $this->debug( "chunkstart: $chunkstart chunk_size: $chunk_size" );
2973
+ $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size );
2974
+
2975
+ // Just in case we got a broken connection
2976
+ if ( $chunkend == false ) {
2977
+ $chunk = substr( $buffer, $chunkstart );
2978
+ // append chunk-data to entity-body
2979
+ $new .= $chunk;
2980
+ $length += strlen( $chunk );
2981
+ break;
2982
+ }
2983
+
2984
+ // read chunk-data and CRLF
2985
+ $chunk = substr( $buffer, $chunkstart, $chunkend - $chunkstart );
2986
+ // append chunk-data to entity-body
2987
+ $new .= $chunk;
2988
+ // length := length + chunk-size
2989
+ $length += strlen( $chunk );
2990
+ // read chunk-size and CRLF
2991
+ $chunkstart = $chunkend + strlen( $lb );
2992
+
2993
+ $chunkend = strpos( $buffer, $lb, $chunkstart ) + strlen( $lb );
2994
+ if ( $chunkend == false ) {
2995
+ break; //Just in case we got a broken connection
2996
+ }
2997
+ $temp = substr( $buffer, $chunkstart, $chunkend - $chunkstart );
2998
+ $chunk_size = hexdec( trim( $temp ) );
2999
+ $chunkstart = $chunkend;
3000
+ }
3001
+
3002
+ return $new;
3003
+ }
3004
+
3005
+ /**
3006
+ * Writes the payload, including HTTP headers, to $this->outgoing_payload.
3007
+ *
3008
+ * @param string $data HTTP body
3009
+ * @param string $cookie_str data for HTTP Cookie header
3010
+ *
3011
+ * @return void
3012
+ * @access private
3013
+ */
3014
+ function buildPayload( $data, $cookie_str = '' ) {
3015
+ // Note: for cURL connections, $this->outgoing_payload is ignored,
3016
+ // as is the Content-Length header, but these are still created as
3017
+ // debugging guides.
3018
+
3019
+ // add content-length header
3020
+ if ( $this->request_method != 'GET' ) {
3021
+ $this->setHeader( 'Content-Length', strlen( $data ) );
3022
+ }
3023
+
3024
+ // start building outgoing payload:
3025
+ if ( $this->proxy ) {
3026
+ $uri = $this->url;
3027
+ } else {
3028
+ $uri = $this->uri;
3029
+ }
3030
+ $req = "$this->request_method $uri HTTP/$this->protocol_version";
3031
+ $this->debug( "HTTP request: $req" );
3032
+ $this->outgoing_payload = "$req\r\n";
3033
+
3034
+ // loop thru headers, serializing
3035
+ foreach ( $this->outgoing_headers as $k => $v ) {
3036
+ $hdr = $k . ': ' . $v;
3037
+ $this->debug( "HTTP header: $hdr" );
3038
+ $this->outgoing_payload .= "$hdr\r\n";
3039
+ }
3040
+
3041
+ // add any cookies
3042
+ if ( $cookie_str != '' ) {
3043
+ $hdr = 'Cookie: ' . $cookie_str;
3044
+ $this->debug( "HTTP header: $hdr" );
3045
+ $this->outgoing_payload .= "$hdr\r\n";
3046
+ }
3047
+
3048
+ // header/body separator
3049
+ $this->outgoing_payload .= "\r\n";
3050
+
3051
+ // add data
3052
+ $this->outgoing_payload .= $data;
3053
+ }
3054
+
3055
+ /**
3056
+ * sends the SOAP request via HTTP[S]
3057
+ *
3058
+ * @param string $data message data
3059
+ * @param array $cookies cookies to send
3060
+ *
3061
+ * @return boolean true if OK, false if problem
3062
+ * @access private
3063
+ */
3064
+ function sendRequest( $data, $cookies = null ) {
3065
+ // build cookie string
3066
+ $cookie_str = $this->getCookiesForRequest( $cookies, ( ( $this->scheme == 'ssl' ) || ( $this->scheme == 'https' ) ) );
3067
+
3068
+ // build payload
3069
+ $this->buildPayload( $data, $cookie_str );
3070
+
3071
+ if ( $this->io_method() == 'socket' ) {
3072
+ // send payload
3073
+ if ( ! fputs( $this->fp, $this->outgoing_payload, strlen( $this->outgoing_payload ) ) ) {
3074
+ $this->setError( 'couldn\'t write message data to socket' );
3075
+ $this->debug( 'couldn\'t write message data to socket' );
3076
+
3077
+ return false;
3078
+ }
3079
+ $this->debug( 'wrote data to socket, length = ' . strlen( $this->outgoing_payload ) );
3080
+
3081
+ return true;
3082
+ } else if ( $this->io_method() == 'curl' ) {
3083
+ // set payload
3084
+ // cURL does say this should only be the verb, and in fact it
3085
+ // turns out that the URI and HTTP version are appended to this, which
3086
+ // some servers refuse to work with (so we no longer use this method!)
3087
+ //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
3088
+ $curl_headers = array();
3089
+ foreach ( $this->outgoing_headers as $k => $v ) {
3090
+ if ( $k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization' ) {
3091
+ $this->debug( "Skip cURL header $k: $v" );
3092
+ } else {
3093
+ $curl_headers[] = "$k: $v";
3094
+ }
3095
+ }
3096
+ if ( $cookie_str != '' ) {
3097
+ $curl_headers[] = 'Cookie: ' . $cookie_str;
3098
+ }
3099
+ $this->setCurlOption( CURLOPT_HTTPHEADER, $curl_headers );
3100
+ $this->debug( 'set cURL HTTP headers' );
3101
+ if ( $this->request_method == "POST" ) {
3102
+ $this->setCurlOption( CURLOPT_POST, 1 );
3103
+ $this->setCurlOption( CURLOPT_POSTFIELDS, $data );
3104
+ $this->debug( 'set cURL POST data' );
3105
+ } else {
3106
+ }
3107
+ // insert custom user-set cURL options
3108
+ foreach ( $this->ch_options as $key => $val ) {
3109
+ $this->setCurlOption( $key, $val );
3110
+ }
3111
+
3112
+ $this->debug( 'set cURL payload' );
3113
+
3114
+ return true;
3115
+ }
3116
+ }
3117
+
3118
+ /**
3119
+ * gets the SOAP response via HTTP[S]
3120
+ *
3121
+ * @return string the response (also sets member variables like incoming_payload)
3122
+ * @access private
3123
+ */
3124
+ function getResponse() {
3125
+ $this->incoming_payload = '';
3126
+
3127
+ if ( $this->io_method() == 'socket' ) {
3128
+ // loop until headers have been retrieved
3129
+ $data = '';
3130
+ while ( ! isset( $lb ) ) {
3131
+
3132
+ // We might EOF during header read.
3133
+ if ( feof( $this->fp ) ) {
3134
+ $this->incoming_payload = $data;
3135
+ $this->debug( 'found no headers before EOF after length ' . strlen( $data ) );
3136
+ $this->debug( "received before EOF:\n" . $data );
3137
+ $this->setError( 'server failed to send headers' );
3138
+
3139
+ return false;
3140
+ }
3141
+
3142
+ $tmp = fgets( $this->fp, 256 );
3143
+ $tmplen = strlen( $tmp );
3144
+ $this->debug( "read line of $tmplen bytes: " . trim( $tmp ) );
3145
+
3146
+ if ( $tmplen == 0 ) {
3147
+ $this->incoming_payload = $data;
3148
+ $this->debug( 'socket read of headers timed out after length ' . strlen( $data ) );
3149
+ $this->debug( "read before timeout: " . $data );
3150
+ $this->setError( 'socket read of headers timed out' );
3151
+
3152
+ return false;
3153
+ }
3154
+
3155
+ $data .= $tmp;
3156
+ $pos = strpos( $data, "\r\n\r\n" );
3157
+ if ( $pos > 1 ) {
3158
+ $lb = "\r\n";
3159
+ } else {
3160
+ $pos = strpos( $data, "\n\n" );
3161
+ if ( $pos > 1 ) {
3162
+ $lb = "\n";
3163
+ }
3164
+ }
3165
+ // remove 100 headers
3166
+ if ( isset( $lb ) && preg_match( '/^HTTP\/1.1 100/', $data ) ) {
3167
+ unset( $lb );
3168
+ $data = '';
3169
+ }//
3170
+ }
3171
+ // store header data
3172
+ $this->incoming_payload .= $data;
3173
+ $this->debug( 'found end of headers after length ' . strlen( $data ) );
3174
+ // process headers
3175
+ $header_data = trim( substr( $data, 0, $pos ) );
3176
+ $header_array = explode( $lb, $header_data );
3177
+ $this->incoming_headers = array();
3178
+ $this->incoming_cookies = array();
3179
+ foreach ( $header_array as $header_line ) {
3180
+ $arr = explode( ':', $header_line, 2 );
3181
+ if ( count( $arr ) > 1 ) {
3182
+ $header_name = strtolower( trim( $arr[0] ) );
3183
+ $this->incoming_headers[ $header_name ] = trim( $arr[1] );
3184
+ if ( $header_name == 'set-cookie' ) {
3185
+ // TODO: allow multiple cookies from parseCookie
3186
+ $cookie = $this->parseCookie( trim( $arr[1] ) );
3187
+ if ( $cookie ) {
3188
+ $this->incoming_cookies[] = $cookie;
3189
+ $this->debug( 'found cookie: ' . $cookie['name'] . ' = ' . $cookie['value'] );
3190
+ } else {
3191
+ $this->debug( 'did not find cookie in ' . trim( $arr[1] ) );
3192
+ }
3193
+ }
3194
+ } else if ( isset( $header_name ) ) {
3195
+ // append continuation line to previous header
3196
+ $this->incoming_headers[ $header_name ] .= $lb . ' ' . $header_line;
3197
+ }
3198
+ }
3199
+
3200
+ // loop until msg has been received
3201
+ if ( isset( $this->incoming_headers['transfer-encoding'] ) && strtolower( $this->incoming_headers['transfer-encoding'] ) == 'chunked' ) {
3202
+ $content_length = 2147483647; // ignore any content-length header
3203
+ $chunked = true;
3204
+ $this->debug( "want to read chunked content" );
3205
+ } elseif ( isset( $this->incoming_headers['content-length'] ) ) {
3206
+ $content_length = $this->incoming_headers['content-length'];
3207
+ $chunked = false;
3208
+ $this->debug( "want to read content of length $content_length" );
3209
+ } else {
3210
+ $content_length = 2147483647;
3211
+ $chunked = false;
3212
+ $this->debug( "want to read content to EOF" );
3213
+ }
3214
+ $data = '';
3215
+ do {
3216
+ if ( $chunked ) {
3217
+ $tmp = fgets( $this->fp, 256 );
3218
+ $tmplen = strlen( $tmp );
3219
+ $this->debug( "read chunk line of $tmplen bytes" );
3220
+ if ( $tmplen == 0 ) {
3221
+ $this->incoming_payload = $data;
3222
+ $this->debug( 'socket read of chunk length timed out after length ' . strlen( $data ) );
3223
+ $this->debug( "read before timeout:\n" . $data );
3224
+ $this->setError( 'socket read of chunk length timed out' );
3225
+
3226
+ return false;
3227
+ }
3228
+ $content_length = hexdec( trim( $tmp ) );
3229
+ $this->debug( "chunk length $content_length" );
3230
+ }
3231
+ $strlen = 0;
3232
+ while ( ( $strlen < $content_length ) && ( ! feof( $this->fp ) ) ) {
3233
+ $readlen = min( 8192, $content_length - $strlen );
3234
+ $tmp = fread( $this->fp, $readlen );
3235
+ $tmplen = strlen( $tmp );
3236
+ $this->debug( "read buffer of $tmplen bytes" );
3237
+ if ( ( $tmplen == 0 ) && ( ! feof( $this->fp ) ) ) {
3238
+ $this->incoming_payload = $data;
3239
+ $this->debug( 'socket read of body timed out after length ' . strlen( $data ) );
3240
+ $this->debug( "read before timeout:\n" . $data );
3241
+ $this->setError( 'socket read of body timed out' );
3242
+
3243
+ return false;
3244
+ }
3245
+ $strlen += $tmplen;
3246
+ $data .= $tmp;
3247
+ }
3248
+ if ( $chunked && ( $content_length > 0 ) ) {
3249
+ $tmp = fgets( $this->fp, 256 );
3250
+ $tmplen = strlen( $tmp );
3251
+ $this->debug( "read chunk terminator of $tmplen bytes" );
3252
+ if ( $tmplen == 0 ) {
3253
+ $this->incoming_payload = $data;
3254
+ $this->debug( 'socket read of chunk terminator timed out after length ' . strlen( $data ) );
3255
+ $this->debug( "read before timeout:\n" . $data );
3256
+ $this->setError( 'socket read of chunk terminator timed out' );
3257
+
3258
+ return false;
3259
+ }
3260
+ }
3261
+ } while ( $chunked && ( $content_length > 0 ) && ( ! feof( $this->fp ) ) );
3262
+ if ( feof( $this->fp ) ) {
3263
+ $this->debug( 'read to EOF' );
3264
+ }
3265
+ $this->debug( 'read body of length ' . strlen( $data ) );
3266
+ $this->incoming_payload .= $data;
3267
+ $this->debug( 'received a total of ' . strlen( $this->incoming_payload ) . ' bytes of data from server' );
3268
+
3269
+ // close filepointer
3270
+ if (
3271
+ ( isset( $this->incoming_headers['connection'] ) && strtolower( $this->incoming_headers['connection'] ) == 'close' ) ||
3272
+ ( ! $this->persistentConnection ) || feof( $this->fp ) ) {
3273
+ fclose( $this->fp );
3274
+ $this->fp = false;
3275
+ $this->debug( 'closed socket' );
3276
+ }
3277
+
3278
+ // connection was closed unexpectedly
3279
+ if ( $this->incoming_payload == '' ) {
3280
+ $this->setError( 'no response from server' );
3281
+
3282
+ return false;
3283
+ }
3284
+
3285
+ // decode transfer-encoding
3286
+ // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
3287
+ // if(!$data = $this->decodeChunked($data, $lb)){
3288
+ // $this->setError('Decoding of chunked data failed');
3289
+ // return false;
3290
+ // }
3291
+ //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
3292
+ // set decoded payload
3293
+ // $this->incoming_payload = $header_data.$lb.$lb.$data;
3294
+ // }
3295
+
3296
+ } else if ( $this->io_method() == 'curl' ) {
3297
+ // send and receive
3298
+ $this->debug( 'send and receive with cURL' );
3299
+ $this->incoming_payload = curl_exec( $this->ch );
3300
+ $data = $this->incoming_payload;
3301
+
3302
+ $cErr = curl_error( $this->ch );
3303
+ if ( $cErr != '' ) {
3304
+ $err = 'cURL ERROR: ' . curl_errno( $this->ch ) . ': ' . $cErr . '<br>';
3305
+ // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
3306
+ foreach ( curl_getinfo( $this->ch ) as $k => $v ) {
3307
+ $err .= "$k: $v<br>";
3308
+ }
3309
+ $this->debug( $err );
3310
+ $this->setError( $err );
3311
+ curl_close( $this->ch );
3312
+
3313
+ return false;
3314
+ } else {
3315
+ //echo '<pre>';
3316
+ //var_dump(curl_getinfo($this->ch));
3317
+ //echo '</pre>';
3318
+ }
3319
+ // close curl
3320
+ $this->debug( 'No cURL error, closing cURL' );
3321
+ curl_close( $this->ch );
3322
+
3323
+ // try removing skippable headers
3324
+ $savedata = $data;
3325
+ while ( $this->isSkippableCurlHeader( $data ) ) {
3326
+ $this->debug( "Found HTTP header to skip" );
3327
+ if ( $pos = strpos( $data, "\r\n\r\n" ) ) {
3328
+ $data = ltrim( substr( $data, $pos ) );
3329
+ } elseif ( $pos = strpos( $data, "\n\n" ) ) {
3330
+ $data = ltrim( substr( $data, $pos ) );
3331
+ }
3332
+ }
3333
+
3334
+ if ( $data == '' ) {
3335
+ // have nothing left; just remove 100 header(s)
3336
+ $data = $savedata;
3337
+ while ( preg_match( '/^HTTP\/1.1 100/', $data ) ) {
3338
+ if ( $pos = strpos( $data, "\r\n\r\n" ) ) {
3339
+ $data = ltrim( substr( $data, $pos ) );
3340
+ } elseif ( $pos = strpos( $data, "\n\n" ) ) {
3341
+ $data = ltrim( substr( $data, $pos ) );
3342
+ }
3343
+ }
3344
+ }
3345
+
3346
+ // separate content from HTTP headers
3347
+ if ( $pos = strpos( $data, "\r\n\r\n" ) ) {
3348
+ $lb = "\r\n";
3349
+ } elseif ( $pos = strpos( $data, "\n\n" ) ) {
3350
+ $lb = "\n";
3351
+ } else {
3352
+ $this->debug( 'no proper separation of headers and document' );
3353
+ $this->setError( 'no proper separation of headers and document' );
3354
+
3355
+ return false;
3356
+ }
3357
+ $header_data = trim( substr( $data, 0, $pos ) );
3358
+ $header_array = explode( $lb, $header_data );
3359
+ $data = ltrim( substr( $data, $pos ) );
3360
+ $this->debug( 'found proper separation of headers and document' );
3361
+ $this->debug( 'cleaned data, stringlen: ' . strlen( $data ) );
3362
+ // clean headers
3363
+ foreach ( $header_array as $header_line ) {
3364
+ $arr = explode( ':', $header_line, 2 );
3365
+ if ( count( $arr ) > 1 ) {
3366
+ $header_name = strtolower( trim( $arr[0] ) );
3367
+ $this->incoming_headers[ $header_name ] = trim( $arr[1] );
3368
+ if ( $header_name == 'set-cookie' ) {
3369
+ // TODO: allow multiple cookies from parseCookie
3370
+ $cookie = $this->parseCookie( trim( $arr[1] ) );
3371
+ if ( $cookie ) {
3372
+ $this->incoming_cookies[] = $cookie;
3373
+ $this->debug( 'found cookie: ' . $cookie['name'] . ' = ' . $cookie['value'] );
3374
+ } else {
3375
+ $this->debug( 'did not find cookie in ' . trim( $arr[1] ) );
3376
+ }
3377
+ }
3378
+ } else if ( isset( $header_name ) ) {
3379
+ // append continuation line to previous header
3380
+ $this->incoming_headers[ $header_name ] .= $lb . ' ' . $header_line;
3381
+ }
3382
+ }
3383
+ }
3384
+
3385
+ $this->response_status_line = $header_array[0];
3386
+ $arr = explode( ' ', $this->response_status_line, 3 );
3387
+ $http_version = $arr[0];
3388
+ $http_status = intval( $arr[1] );
3389
+ $http_reason = count( $arr ) > 2 ? $arr[2] : '';
3390
+
3391
+ // see if we need to resend the request with http digest authentication
3392
+ if ( isset( $this->incoming_headers['location'] ) && ( $http_status == 301 || $http_status == 302 ) ) {
3393
+ $this->debug( "Got $http_status $http_reason with Location: " . $this->incoming_headers['location'] );
3394
+ $this->setURL( $this->incoming_headers['location'] );
3395
+ $this->tryagain = true;
3396
+
3397
+ return false;
3398
+ }
3399
+
3400
+ // see if we need to resend the request with http digest authentication
3401
+ if ( isset( $this->incoming_headers['www-authenticate'] ) && $http_status == 401 ) {
3402
+ $this->debug( "Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate'] );
3403
+ if ( strstr( $this->incoming_headers['www-authenticate'], "Digest " ) ) {
3404
+ $this->debug( 'Server wants digest authentication' );
3405
+ // remove "Digest " from our elements
3406
+ $digestString = str_replace( 'Digest ', '', $this->incoming_headers['www-authenticate'] );
3407
+
3408
+ // parse elements into array
3409
+ $digestElements = explode( ',', $digestString );
3410
+ foreach ( $digestElements as $val ) {
3411
+ $tempElement = explode( '=', trim( $val ), 2 );
3412
+ $digestRequest[ $tempElement[0] ] = str_replace( "\"", '', $tempElement[1] );
3413
+ }
3414
+
3415
+ // should have (at least) qop, realm, nonce
3416
+ if ( isset( $digestRequest['nonce'] ) ) {
3417
+ $this->setCredentials( $this->username, $this->password, 'digest', $digestRequest );
3418
+ $this->tryagain = true;
3419
+
3420
+ return false;
3421
+ }
3422
+ }
3423
+ $this->debug( 'HTTP authentication failed' );
3424
+ $this->setError( 'HTTP authentication failed' );
3425
+
3426
+ return false;
3427
+ }
3428
+
3429
+ if (
3430
+ ( $http_status >= 300 && $http_status <= 307 ) ||
3431
+ ( $http_status >= 400 && $http_status <= 417 ) ||
3432
+ ( $http_status >= 501 && $http_status <= 505 )
3433
+ ) {
3434
+ $this->setError( "Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)" );
3435
+
3436
+ return false;
3437
+ }
3438
+
3439
+ // decode content-encoding
3440
+ if ( isset( $this->incoming_headers['content-encoding'] ) && $this->incoming_headers['content-encoding'] != '' ) {
3441
+ if ( strtolower( $this->incoming_headers['content-encoding'] ) == 'deflate' || strtolower( $this->incoming_headers['content-encoding'] ) == 'gzip' ) {
3442
+ // if decoding works, use it. else assume data wasn't gzencoded
3443
+ if ( function_exists( 'gzinflate' ) ) {
3444
+ //$timer->setMarker('starting decoding of gzip/deflated content');
3445
+ // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
3446
+ // this means there are no Zlib headers, although there should be
3447
+ $this->debug( 'The gzinflate function exists' );
3448
+ $datalen = strlen( $data );
3449
+ if ( $this->incoming_headers['content-encoding'] == 'deflate' ) {
3450
+ if ( $degzdata = @gzinflate( $data ) ) {
3451
+ $data = $degzdata;
3452
+ $this->debug( 'The payload has been inflated to ' . strlen( $data ) . ' bytes' );
3453
+ if ( strlen( $data ) < $datalen ) {
3454
+ // test for the case that the payload has been compressed twice
3455
+ $this->debug( 'The inflated payload is smaller than the gzipped one; try again' );
3456
+ if ( $degzdata = @gzinflate( $data ) ) {
3457
+ $data = $degzdata;
3458
+ $this->debug( 'The payload has been inflated again to ' . strlen( $data ) . ' bytes' );
3459
+ }
3460
+ }
3461
+ } else {
3462
+ $this->debug( 'Error using gzinflate to inflate the payload' );
3463
+ $this->setError( 'Error using gzinflate to inflate the payload' );
3464
+ }
3465
+ } elseif ( $this->incoming_headers['content-encoding'] == 'gzip' ) {
3466
+ if ( $degzdata = @gzinflate( substr( $data, 10 ) ) ) { // do our best
3467
+ $data = $degzdata;
3468
+ $this->debug( 'The payload has been un-gzipped to ' . strlen( $data ) . ' bytes' );
3469
+ if ( strlen( $data ) < $datalen ) {
3470
+ // test for the case that the payload has been compressed twice
3471
+ $this->debug( 'The un-gzipped payload is smaller than the gzipped one; try again' );
3472
+ if ( $degzdata = @gzinflate( substr( $data, 10 ) ) ) {
3473
+ $data = $degzdata;
3474
+ $this->debug( 'The payload has been un-gzipped again to ' . strlen( $data ) . ' bytes' );
3475
+ }
3476
+ }
3477
+ } else {
3478
+ $this->debug( 'Error using gzinflate to un-gzip the payload' );
3479
+ $this->setError( 'Error using gzinflate to un-gzip the payload' );
3480
+ }
3481
+ }
3482
+ //$timer->setMarker('finished decoding of gzip/deflated content');
3483
+ //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
3484
+ // set decoded payload
3485
+ $this->incoming_payload = $header_data . $lb . $lb . $data;
3486
+ } else {
3487
+ $this->debug( 'The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.' );
3488
+ $this->setError( 'The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.' );
3489
+ }
3490
+ } else {
3491
+ $this->debug( 'Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding'] );
3492
+ $this->setError( 'Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding'] );
3493
+ }
3494
+ } else {
3495
+ $this->debug( 'No Content-Encoding header' );
3496
+ }
3497
+
3498
+ if ( strlen( $data ) == 0 ) {
3499
+ $this->debug( 'no data after headers!' );
3500
+ $this->setError( 'no data present after HTTP headers' );
3501
+
3502
+ return false;
3503
+ }
3504
+
3505
+ return $data;
3506
+ }
3507
+
3508
+ /**
3509
+ * sets the content-type for the SOAP message to be sent
3510
+ *
3511
+ * @param string $type the content type, MIME style
3512
+ * @param mixed $charset character set used for encoding (or false)
3513
+ *
3514
+ * @access public
3515
+ */
3516
+ function setContentType( $type, $charset = false ) {
3517
+ $this->setHeader( 'Content-Type', $type . ( $charset ? '; charset=' . $charset : '' ) );
3518
+ }
3519
+
3520
+ /**
3521
+ * specifies that an HTTP persistent connection should be used
3522
+ *
3523
+ * @return boolean whether the request was honored by this method.
3524
+ * @access public
3525
+ */
3526
+ function usePersistentConnection() {
3527
+ if ( isset( $this->outgoing_headers['Accept-Encoding'] ) ) {
3528
+ return false;
3529
+ }
3530
+ $this->protocol_version = '1.1';
3531
+ $this->persistentConnection = true;
3532
+ $this->setHeader( 'Connection', 'Keep-Alive' );
3533
+
3534
+ return true;
3535
+ }
3536
+
3537
+ /**
3538
+ * parse an incoming Cookie into it's parts
3539
+ *
3540
+ * @param string $cookie_str content of cookie
3541
+ *
3542
+ * @return array with data of that cookie
3543
+ * @access private
3544
+ */
3545
+ /*
3546
+ * TODO: allow a Set-Cookie string to be parsed into multiple cookies
3547
+ */
3548
+ function parseCookie( $cookie_str ) {
3549
+ $cookie_str = str_replace( '; ', ';', $cookie_str ) . ';';
3550
+ $data = preg_split( '/;/', $cookie_str );
3551
+ $value_str = $data[0];
3552
+
3553
+ $cookie_param = 'domain=';
3554
+ $start = strpos( $cookie_str, $cookie_param );
3555
+ if ( $start > 0 ) {
3556
+ $domain = substr( $cookie_str, $start + strlen( $cookie_param ) );
3557
+ $domain = substr( $domain, 0, strpos( $domain, ';' ) );
3558
+ } else {
3559
+ $domain = '';
3560
+ }
3561
+
3562
+ $cookie_param = 'expires=';
3563
+ $start = strpos( $cookie_str, $cookie_param );
3564
+ if ( $start > 0 ) {
3565
+ $expires = substr( $cookie_str, $start + strlen( $cookie_param ) );
3566
+ $expires = substr( $expires, 0, strpos( $expires, ';' ) );
3567
+ } else {
3568
+ $expires = '';
3569
+ }
3570
+
3571
+ $cookie_param = 'path=';
3572
+ $start = strpos( $cookie_str, $cookie_param );
3573
+ if ( $start > 0 ) {
3574
+ $path = substr( $cookie_str, $start + strlen( $cookie_param ) );
3575
+ $path = substr( $path, 0, strpos( $path, ';' ) );
3576
+ } else {
3577
+ $path = '/';
3578
+ }
3579
+
3580
+ $cookie_param = ';secure;';
3581
+ if ( strpos( $cookie_str, $cookie_param ) !== false ) {
3582
+ $secure = true;
3583
+ } else {
3584
+ $secure = false;
3585
+ }
3586
+
3587
+ $sep_pos = strpos( $value_str, '=' );
3588
+
3589
+ if ( $sep_pos ) {
3590
+ $name = substr( $value_str, 0, $sep_pos );
3591
+ $value = substr( $value_str, $sep_pos + 1 );
3592
+ $cookie = array(
3593
+ 'name' => $name,
3594
+ 'value' => $value,
3595
+ 'domain' => $domain,
3596
+ 'path' => $path,
3597
+ 'expires' => $expires,
3598
+ 'secure' => $secure
3599
+ );
3600
+
3601
+ return $cookie;
3602
+ }
3603
+
3604
+ return false;
3605
+ }
3606
+
3607
+ /**
3608
+ * sort out cookies for the current request
3609
+ *
3610
+ * @param array $cookies array with all cookies
3611
+ * @param boolean $secure is the send-content secure or not?
3612
+ *
3613
+ * @return string for Cookie-HTTP-Header
3614
+ * @access private
3615
+ */
3616
+ function getCookiesForRequest( $cookies, $secure = false ) {
3617
+ $cookie_str = '';
3618
+ if ( ( ! is_null( $cookies ) ) && ( is_array( $cookies ) ) ) {
3619
+ foreach ( $cookies as $cookie ) {
3620
+ if ( ! is_array( $cookie ) ) {
3621
+ continue;
3622
+ }
3623
+ $this->debug( "check cookie for validity: " . $cookie['name'] . '=' . $cookie['value'] );
3624
+ if ( ( isset( $cookie['expires'] ) ) && ( ! empty( $cookie['expires'] ) ) ) {
3625
+ if ( strtotime( $cookie['expires'] ) <= time() ) {
3626
+ $this->debug( 'cookie has expired' );
3627
+ continue;
3628
+ }
3629
+ }
3630
+ if ( ( isset( $cookie['domain'] ) ) && ( ! empty( $cookie['domain'] ) ) ) {
3631
+ $domain = preg_quote( $cookie['domain'] );
3632
+ if ( ! preg_match( "'.*$domain$'i", $this->host ) ) {
3633
+ $this->debug( 'cookie has different domain' );
3634
+ continue;
3635
+ }
3636
+ }
3637
+ if ( ( isset( $cookie['path'] ) ) && ( ! empty( $cookie['path'] ) ) ) {
3638
+ $path = preg_quote( $cookie['path'] );
3639
+ if ( ! preg_match( "'^$path.*'i", $this->path ) ) {
3640
+ $this->debug( 'cookie is for a different path' );
3641
+ continue;
3642
+ }
3643
+ }
3644
+ if ( ( ! $secure ) && ( isset( $cookie['secure'] ) ) && ( $cookie['secure'] ) ) {
3645
+ $this->debug( 'cookie is secure, transport is not' );
3646
+ continue;
3647
+ }
3648
+ $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3649
+ $this->debug( 'add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value'] );
3650
+ }
3651
+ }
3652
+
3653
+ return $cookie_str;
3654
+ }
3655
+ }
3656
+
3657
+ ?><?php
3658
+
3659
+
3660
+ /**
3661
+ *
3662
+ * nusoap_server allows the user to create a SOAP server
3663
+ * that is capable of receiving messages and returning responses
3664
+ *
3665
+ * @author Dietrich Ayala <dietrich@ganx4.com>
3666
+ * @author Scott Nichol <snichol@users.sourceforge.net>
3667
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
3668
+ * @access public
3669
+ */
3670
+ class nusoap_server extends nusoap_base {
3671
+ /**
3672
+ * HTTP headers of request
3673
+ * @var array
3674
+ * @access private
3675
+ */
3676
+ var $headers = array();
3677
+ /**
3678
+ * HTTP request
3679
+ * @var string
3680
+ * @access private
3681
+ */
3682
+ var $request = '';
3683
+ /**
3684
+ * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
3685
+ * @var string
3686
+ * @access public
3687
+ */
3688
+ var $requestHeaders = '';
3689
+ /**
3690
+ * SOAP Headers from request (parsed)
3691
+ * @var mixed
3692
+ * @access public
3693
+ */
3694
+ var $requestHeader = null;
3695
+ /**
3696
+ * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
3697
+ * @var string
3698
+ * @access public
3699
+ */
3700
+ var $document = '';
3701
+ /**
3702
+ * SOAP payload for request (text)
3703
+ * @var string
3704
+ * @access public
3705
+ */
3706
+ var $requestSOAP = '';
3707
+ /**
3708
+ * requested method namespace URI
3709
+ * @var string
3710
+ * @access private
3711
+ */
3712
+ var $methodURI = '';
3713
+ /**
3714
+ * name of method requested
3715
+ * @var string
3716
+ * @access private
3717
+ */
3718
+ var $methodname = '';
3719
+ /**
3720
+ * method parameters from request
3721
+ * @var array
3722
+ * @access private
3723
+ */
3724
+ var $methodparams = array();
3725
+ /**
3726
+ * SOAP Action from request
3727
+ * @var string
3728
+ * @access private
3729
+ */
3730
+ var $SOAPAction = '';
3731
+ /**
3732
+ * character set encoding of incoming (request) messages
3733
+ * @var string
3734
+ * @access public
3735
+ */
3736
+ var $xml_encoding = '';
3737
+ /**
3738
+ * toggles whether the parser decodes element content w/ utf8_decode()
3739
+ * @var boolean
3740
+ * @access public
3741
+ */
3742
+ var $decode_utf8 = true;
3743
+
3744
+ /**
3745
+ * HTTP headers of response
3746
+ * @var array
3747
+ * @access public
3748
+ */
3749
+ var $outgoing_headers = array();
3750
+ /**
3751
+ * HTTP response
3752
+ * @var string
3753
+ * @access private
3754
+ */
3755
+ var $response = '';
3756
+ /**
3757
+ * SOAP headers for response (text or array of soapval or associative array)
3758
+ * @var mixed
3759
+ * @access public
3760
+ */
3761
+ var $responseHeaders = '';
3762
+ /**
3763
+ * SOAP payload for response (text)
3764
+ * @var string
3765
+ * @access private
3766
+ */
3767
+ var $responseSOAP = '';
3768
+ /**
3769
+ * method return value to place in response
3770
+ * @var mixed
3771
+ * @access private
3772
+ */
3773
+ var $methodreturn = false;
3774
+ /**
3775
+ * whether $methodreturn is a string of literal XML
3776
+ * @var boolean
3777
+ * @access public
3778
+ */
3779
+ var $methodreturnisliteralxml = false;
3780
+ /**
3781
+ * SOAP fault for response (or false)
3782
+ * @var mixed
3783
+ * @access private
3784
+ */
3785
+ var $fault = false;
3786
+ /**
3787
+ * text indication of result (for debugging)
3788
+ * @var string
3789
+ * @access private
3790
+ */
3791
+ var $result = 'successful';
3792
+
3793
+ /**
3794
+ * assoc array of operations => opData; operations are added by the register()
3795
+ * method or by parsing an external WSDL definition
3796
+ * @var array
3797
+ * @access private
3798
+ */
3799
+ var $operations = array();
3800
+ /**
3801
+ * wsdl instance (if one)
3802
+ * @var mixed
3803
+ * @access private
3804
+ */
3805
+ var $wsdl = false;
3806
+ /**
3807
+ * URL for WSDL (if one)
3808
+ * @var mixed
3809
+ * @access private
3810
+ */
3811
+ var $externalWSDLURL = false;
3812
+ /**
3813
+ * whether to append debug to response as XML comment
3814
+ * @var boolean
3815
+ * @access public
3816
+ */
3817
+ var $debug_flag = false;
3818
+
3819
+
3820
+ /**
3821
+ * constructor
3822
+ * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
3823
+ *
3824
+ * @param mixed $wsdl file path or URL (string), or wsdl instance (object)
3825
+ *
3826
+ * @access public
3827
+ */
3828
+ function nusoap_server( $wsdl = false ) {
3829
+ parent::nusoap_base();
3830
+ // turn on debugging?
3831
+ global $debug;
3832
+ global $HTTP_SERVER_VARS;
3833
+
3834
+ if ( isset( $_SERVER ) ) {
3835
+ $this->debug( "_SERVER is defined:" );
3836
+ $this->appendDebug( $this->varDump( $_SERVER ) );
3837
+ } elseif ( isset( $HTTP_SERVER_VARS ) ) {
3838
+ $this->debug( "HTTP_SERVER_VARS is defined:" );
3839
+ $this->appendDebug( $this->varDump( $HTTP_SERVER_VARS ) );
3840
+ } else {
3841
+ $this->debug( "Neither _SERVER nor HTTP_SERVER_VARS is defined." );
3842
+ }
3843
+
3844
+ if ( isset( $debug ) ) {
3845
+ $this->debug( "In nusoap_server, set debug_flag=$debug based on global flag" );
3846
+ $this->debug_flag = $debug;
3847
+ } elseif ( isset( $_SERVER['QUERY_STRING'] ) ) {
3848
+ $qs = explode( '&', $_SERVER['QUERY_STRING'] );
3849
+ foreach ( $qs as $v ) {
3850
+ if ( substr( $v, 0, 6 ) == 'debug=' ) {
3851
+ $this->debug( "In nusoap_server, set debug_flag=" . substr( $v, 6 ) . " based on query string #1" );
3852
+ $this->debug_flag = substr( $v, 6 );
3853
+ }
3854
+ }
3855
+ } elseif ( isset( $HTTP_SERVER_VARS['QUERY_STRING'] ) ) {
3856
+ $qs = explode( '&', $HTTP_SERVER_VARS['QUERY_STRING'] );
3857
+ foreach ( $qs as $v ) {
3858
+ if ( substr( $v, 0, 6 ) == 'debug=' ) {
3859
+ $this->debug( "In nusoap_server, set debug_flag=" . substr( $v, 6 ) . " based on query string #2" );
3860
+ $this->debug_flag = substr( $v, 6 );
3861
+ }
3862
+ }
3863
+ }
3864
+
3865
+ // wsdl
3866
+ if ( $wsdl ) {
3867
+ $this->debug( "In nusoap_server, WSDL is specified" );
3868
+ if ( is_object( $wsdl ) && ( get_class( $wsdl ) == 'wsdl' ) ) {
3869
+ $this->wsdl = $wsdl;
3870
+ $this->externalWSDLURL = $this->wsdl->wsdl;
3871
+ $this->debug( 'Use existing wsdl instance from ' . $this->externalWSDLURL );
3872
+ } else {
3873
+ $this->debug( 'Create wsdl from ' . $wsdl );
3874
+ $this->wsdl = new wsdl( $wsdl );
3875
+ $this->externalWSDLURL = $wsdl;
3876
+ }
3877
+ $this->appendDebug( $this->wsdl->getDebug() );
3878
+ $this->wsdl->clearDebug();
3879
+ if ( $err = $this->wsdl->getError() ) {
3880
+ die( 'WSDL ERROR: ' . $err );
3881
+ }
3882
+ }
3883
+ }
3884
+
3885
+ /**
3886
+ * processes request and returns response
3887
+ *
3888
+ * @param string $data usually is the value of $HTTP_RAW_POST_DATA
3889
+ *
3890
+ * @access public
3891
+ */
3892
+ function service( $data ) {
3893
+ global $HTTP_SERVER_VARS;
3894
+
3895
+ if ( isset( $_SERVER['REQUEST_METHOD'] ) ) {
3896
+ $rm = $_SERVER['REQUEST_METHOD'];
3897
+ } elseif ( isset( $HTTP_SERVER_VARS['REQUEST_METHOD'] ) ) {
3898
+ $rm = $HTTP_SERVER_VARS['REQUEST_METHOD'];
3899
+ } else {
3900
+ $rm = '';
3901
+ }
3902
+
3903
+ if ( isset( $_SERVER['QUERY_STRING'] ) ) {
3904
+ $qs = $_SERVER['QUERY_STRING'];
3905
+ } elseif ( isset( $HTTP_SERVER_VARS['QUERY_STRING'] ) ) {
3906
+ $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3907
+ } else {
3908
+ $qs = '';
3909
+ }
3910
+ $this->debug( "In service, request method=$rm query string=$qs strlen(\$data)=" . strlen( $data ) );
3911
+
3912
+ if ( $rm == 'POST' ) {
3913
+ $this->debug( "In service, invoke the request" );
3914
+ $this->parse_request( $data );
3915
+ if ( ! $this->fault ) {
3916
+ $this->invoke_method();
3917
+ }
3918
+ if ( ! $this->fault ) {
3919
+ $this->serialize_return();
3920
+ }
3921
+ $this->send_response();
3922
+ } elseif ( preg_match( '/wsdl/', $qs ) ) {
3923
+ $this->debug( "In service, this is a request for WSDL" );
3924
+ if ( $this->externalWSDLURL ) {
3925
+ if ( strpos( $this->externalWSDLURL, "http://" ) !== false ) { // assume URL
3926
+ $this->debug( "In service, re-direct for WSDL" );
3927
+ header( 'Location: ' . $this->externalWSDLURL );
3928
+ } else { // assume file
3929
+ $this->debug( "In service, use file passthru for WSDL" );
3930
+ header( "Content-Type: text/xml\r\n" );
3931
+ $pos = strpos( $this->externalWSDLURL, "file://" );
3932
+ if ( $pos === false ) {
3933
+ $filename = $this->externalWSDLURL;
3934
+ } else {
3935
+ $filename = substr( $this->externalWSDLURL, $pos + 7 );
3936
+ }
3937
+ $fp = fopen( $this->externalWSDLURL, 'r' );
3938
+ fpassthru( $fp );
3939
+ }
3940
+ } elseif ( $this->wsdl ) {
3941
+ $this->debug( "In service, serialize WSDL" );
3942
+ header( "Content-Type: text/xml; charset=ISO-8859-1\r\n" );
3943
+ print $this->wsdl->serialize( $this->debug_flag );
3944
+ if ( $this->debug_flag ) {
3945
+ $this->debug( 'wsdl:' );
3946
+ $this->appendDebug( $this->varDump( $this->wsdl ) );
3947
+ print $this->getDebugAsXMLComment();
3948
+ }
3949
+ } else {
3950
+ $this->debug( "In service, there is no WSDL" );
3951
+ header( "Content-Type: text/html; charset=ISO-8859-1\r\n" );
3952
+ print "This service does not provide WSDL";
3953
+ }
3954
+ } elseif ( $this->wsdl ) {
3955
+ $this->debug( "In service, return Web description" );
3956
+ print $this->wsdl->webDescription();
3957
+ } else {
3958
+ $this->debug( "In service, no Web description" );
3959
+ header( "Content-Type: text/html; charset=ISO-8859-1\r\n" );
3960
+ print "This service does not provide a Web description";
3961
+ }
3962
+ }
3963
+
3964
+ /**
3965
+ * parses HTTP request headers.
3966
+ *
3967
+ * The following fields are set by this function (when successful)
3968
+ *
3969
+ * headers
3970
+ * request
3971
+ * xml_encoding
3972
+ * SOAPAction
3973
+ *
3974
+ * @access private
3975
+ */
3976
+ function parse_http_headers() {
3977
+ global $HTTP_SERVER_VARS;
3978
+
3979
+ $this->request = '';
3980
+ $this->SOAPAction = '';
3981
+ if ( function_exists( 'getallheaders' ) ) {
3982
+ $this->debug( "In parse_http_headers, use getallheaders" );
3983
+ $headers = getallheaders();
3984
+ foreach ( $headers as $k => $v ) {
3985
+ $k = strtolower( $k );
3986
+ $this->headers[ $k ] = $v;
3987
+ $this->request .= "$k: $v\r\n";
3988
+ $this->debug( "$k: $v" );
3989
+ }
3990
+ // get SOAPAction header
3991
+ if ( isset( $this->headers['soapaction'] ) ) {
3992
+ $this->SOAPAction = str_replace( '"', '', $this->headers['soapaction'] );
3993
+ }
3994
+ // get the character encoding of the incoming request
3995
+ if ( isset( $this->headers['content-type'] ) && strpos( $this->headers['content-type'], '=' ) ) {
3996
+ $enc = str_replace( '"', '', substr( strstr( $this->headers["content-type"], '=' ), 1 ) );
3997
+ if ( preg_match( '/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc ) ) {
3998
+ $this->xml_encoding = strtoupper( $enc );
3999
+ } else {
4000
+ $this->xml_encoding = 'US-ASCII';
4001
+ }
4002
+ } else {
4003
+ // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4004
+ $this->xml_encoding = 'ISO-8859-1';
4005
+ }
4006
+ } elseif ( isset( $_SERVER ) && is_array( $_SERVER ) ) {
4007
+ $this->debug( "In parse_http_headers, use _SERVER" );
4008
+ foreach ( $_SERVER as $k => $v ) {
4009
+ if ( substr( $k, 0, 5 ) == 'HTTP_' ) {
4010
+ $k = str_replace( ' ', '-', strtolower( str_replace( '_', ' ', substr( $k, 5 ) ) ) );
4011
+ } else {
4012
+ $k = str_replace( ' ', '-', strtolower( str_replace( '_', ' ', $k ) ) );
4013
+ }
4014
+ if ( $k == 'soapaction' ) {
4015
+ // get SOAPAction header
4016
+ $k = 'SOAPAction';
4017
+ $v = str_replace( '"', '', $v );
4018
+ $v = str_replace( '\\', '', $v );
4019
+ $this->SOAPAction = $v;
4020
+ } else if ( $k == 'content-type' ) {
4021
+ // get the character encoding of the incoming request
4022
+ if ( strpos( $v, '=' ) ) {
4023
+ $enc = substr( strstr( $v, '=' ), 1 );
4024
+ $enc = str_replace( '"', '', $enc );
4025
+ $enc = str_replace( '\\', '', $enc );
4026
+ if ( preg_match( '/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc ) ) {
4027
+ $this->xml_encoding = strtoupper( $enc );
4028
+ } else {
4029
+ $this->xml_encoding = 'US-ASCII';
4030
+ }
4031
+ } else {
4032
+ // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4033
+ $this->xml_encoding = 'ISO-8859-1';
4034
+ }
4035
+ }
4036
+ $this->headers[ $k ] = $v;
4037
+ $this->request .= "$k: $v\r\n";
4038
+ $this->debug( "$k: $v" );
4039
+ }
4040
+ } elseif ( is_array( $HTTP_SERVER_VARS ) ) {
4041
+ $this->debug( "In parse_http_headers, use HTTP_SERVER_VARS" );
4042
+ foreach ( $HTTP_SERVER_VARS as $k => $v ) {
4043
+ if ( substr( $k, 0, 5 ) == 'HTTP_' ) {
4044
+ $k = str_replace( ' ', '-', strtolower( str_replace( '_', ' ', substr( $k, 5 ) ) ) );
4045
+ $k = strtolower( substr( $k, 5 ) );
4046
+ } else {
4047
+ $k = str_replace( ' ', '-', strtolower( str_replace( '_', ' ', $k ) ) );
4048
+ $k = strtolower( $k );
4049
+ }
4050
+ if ( $k == 'soapaction' ) {
4051
+ // get SOAPAction header
4052
+ $k = 'SOAPAction';
4053
+ $v = str_replace( '"', '', $v );
4054
+ $v = str_replace( '\\', '', $v );
4055
+ $this->SOAPAction = $v;
4056
+ } else if ( $k == 'content-type' ) {
4057
+ // get the character encoding of the incoming request
4058
+ if ( strpos( $v, '=' ) ) {
4059
+ $enc = substr( strstr( $v, '=' ), 1 );
4060
+ $enc = str_replace( '"', '', $enc );
4061
+ $enc = str_replace( '\\', '', $enc );
4062
+ if ( preg_match( '/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc ) ) {
4063
+ $this->xml_encoding = strtoupper( $enc );
4064
+ } else {
4065
+ $this->xml_encoding = 'US-ASCII';
4066
+ }
4067
+ } else {
4068
+ // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4069
+ $this->xml_encoding = 'ISO-8859-1';
4070
+ }
4071
+ }
4072
+ $this->headers[ $k ] = $v;
4073
+ $this->request .= "$k: $v\r\n";
4074
+ $this->debug( "$k: $v" );
4075
+ }
4076
+ } else {
4077
+ $this->debug( "In parse_http_headers, HTTP headers not accessible" );
4078
+ $this->setError( "HTTP headers not accessible" );
4079
+ }
4080
+ }
4081
+
4082
+ /**
4083
+ * parses a request
4084
+ *
4085
+ * The following fields are set by this function (when successful)
4086
+ *
4087
+ * headers
4088
+ * request
4089
+ * xml_encoding
4090
+ * SOAPAction
4091
+ * request
4092
+ * requestSOAP
4093
+ * methodURI
4094
+ * methodname
4095
+ * methodparams
4096
+ * requestHeaders
4097
+ * document
4098
+ *
4099
+ * This sets the fault field on error
4100
+ *
4101
+ * @param string $data XML string
4102
+ *
4103
+ * @access private
4104
+ */
4105
+ function parse_request( $data = '' ) {
4106
+ $this->debug( 'entering parse_request()' );
4107
+ $this->parse_http_headers();
4108
+ $this->debug( 'got character encoding: ' . $this->xml_encoding );
4109
+ // uncompress if necessary
4110
+ if ( isset( $this->headers['content-encoding'] ) && $this->headers['content-encoding'] != '' ) {
4111
+ $this->debug( 'got content encoding: ' . $this->headers['content-encoding'] );
4112
+ if ( $this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip' ) {
4113
+ // if decoding works, use it. else assume data wasn't gzencoded
4114
+ if ( function_exists( 'gzuncompress' ) ) {
4115
+ if ( $this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress( $data ) ) {
4116
+ $data = $degzdata;
4117
+ } elseif ( $this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate( substr( $data, 10 ) ) ) {
4118
+ $data = $degzdata;
4119
+ } else {
4120
+ $this->fault( 'SOAP-ENV:Client', 'Errors occurred when trying to decode the data' );
4121
+
4122
+ return;
4123
+ }
4124
+ } else {
4125
+ $this->fault( 'SOAP-ENV:Client', 'This Server does not support compressed data' );
4126
+
4127
+ return;
4128
+ }
4129
+ }
4130
+ }
4131
+ $this->request .= "\r\n" . $data;
4132
+ $data = $this->parseRequest( $this->headers, $data );
4133
+ $this->requestSOAP = $data;
4134
+ $this->debug( 'leaving parse_request' );
4135
+ }
4136
+
4137
+ /**
4138
+ * invokes a PHP function for the requested SOAP method
4139
+ *
4140
+ * The following fields are set by this function (when successful)
4141
+ *
4142
+ * methodreturn
4143
+ *
4144
+ * Note that the PHP function that is called may also set the following
4145
+ * fields to affect the response sent to the client
4146
+ *
4147
+ * responseHeaders
4148
+ * outgoing_headers
4149
+ *
4150
+ * This sets the fault field on error
4151
+ *
4152
+ * @access private
4153
+ */
4154
+ function invoke_method() {
4155
+ $this->debug( 'in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction );
4156
+
4157
+ //
4158
+ // if you are debugging in this area of the code, your service uses a class to implement methods,
4159
+ // you use SOAP RPC, and the client is .NET, please be aware of the following...
4160
+ // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the
4161
+ // method name. that is fine for naming the .NET methods. it is not fine for properly constructing
4162
+ // the XML request and reading the XML response. you need to add the RequestElementName and
4163
+ // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe
4164
+ // generates for the method. these parameters are used to specify the correct XML element names
4165
+ // for .NET to use, i.e. the names with the '.' in them.
4166
+ //
4167
+ $orig_methodname = $this->methodname;
4168
+ if ( $this->wsdl ) {
4169
+ if ( $this->opData = $this->wsdl->getOperationData( $this->methodname ) ) {
4170
+ $this->debug( 'in invoke_method, found WSDL operation=' . $this->methodname );
4171
+ $this->appendDebug( 'opData=' . $this->varDump( $this->opData ) );
4172
+ } elseif ( $this->opData = $this->wsdl->getOperationDataForSoapAction( $this->SOAPAction ) ) {
4173
+ // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
4174
+ $this->debug( 'in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name'] );
4175
+ $this->appendDebug( 'opData=' . $this->varDump( $this->opData ) );
4176
+ $this->methodname = $this->opData['name'];
4177
+ } else {
4178
+ $this->debug( 'in invoke_method, no WSDL for operation=' . $this->methodname );
4179
+ $this->fault( 'SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service" );
4180
+
4181
+ return;
4182
+ }
4183
+ } else {
4184
+ $this->debug( 'in invoke_method, no WSDL to validate method' );
4185
+ }
4186
+
4187
+ // if a . is present in $this->methodname, we see if there is a class in scope,
4188
+ // which could be referred to. We will also distinguish between two deliminators,
4189
+ // to allow methods to be called a the class or an instance
4190
+ if ( strpos( $this->methodname, '..' ) > 0 ) {
4191
+ $delim = '..';
4192
+ } else if ( strpos( $this->methodname, '.' ) > 0 ) {
4193
+ $delim = '.';
4194
+ } else {
4195
+ $delim = '';
4196
+ }
4197
+ $this->debug( "in invoke_method, delim=$delim" );
4198
+
4199
+ $class = '';
4200
+ $method = '';
4201
+ if ( strlen( $delim ) > 0 && substr_count( $this->methodname, $delim ) == 1 ) {
4202
+ $try_class = substr( $this->methodname, 0, strpos( $this->methodname, $delim ) );
4203
+ if ( class_exists( $try_class ) ) {
4204
+ // get the class and method name
4205
+ $class = $try_class;
4206
+ $method = substr( $this->methodname, strpos( $this->methodname, $delim ) + strlen( $delim ) );
4207
+ $this->debug( "in invoke_method, class=$class method=$method delim=$delim" );
4208
+ } else {
4209
+ $this->debug( "in invoke_method, class=$try_class not found" );
4210
+ }
4211
+ } else {
4212
+ $try_class = '';
4213
+ $this->debug( "in invoke_method, no class to try" );
4214
+ }
4215
+
4216
+ // does method exist?
4217
+ if ( $class == '' ) {
4218
+ if ( ! function_exists( $this->methodname ) ) {
4219
+ $this->debug( "in invoke_method, function '$this->methodname' not found!" );
4220
+ $this->result = 'fault: method not found';
4221
+ $this->fault( 'SOAP-ENV:Client', "method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')" );
4222
+
4223
+ return;
4224
+ }
4225
+ } else {
4226
+ $method_to_compare = ( substr( phpversion(), 0, 2 ) == '4.' ) ? strtolower( $method ) : $method;
4227
+ if ( ! in_array( $method_to_compare, get_class_methods( $class ) ) ) {
4228
+ $this->debug( "in invoke_method, method '$this->methodname' not found in class '$class'!" );
4229
+ $this->result = 'fault: method not found';
4230
+ $this->fault( 'SOAP-ENV:Client', "method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')" );
4231
+
4232
+ return;
4233
+ }
4234
+ }
4235
+
4236
+ // evaluate message, getting back parameters
4237
+ // verify that request parameters match the method's signature
4238
+ if ( ! $this->verify_method( $this->methodname, $this->methodparams ) ) {
4239
+ // debug
4240
+ $this->debug( 'ERROR: request not verified against method signature' );
4241
+ $this->result = 'fault: request failed validation against method signature';
4242
+ // return fault
4243
+ $this->fault( 'SOAP-ENV:Client', "Operation '$this->methodname' not defined in service." );
4244
+
4245
+ return;
4246
+ }
4247
+
4248
+ // if there are parameters to pass
4249
+ $this->debug( 'in invoke_method, params:' );
4250
+ $this->appendDebug( $this->varDump( $this->methodparams ) );
4251
+ $this->debug( "in invoke_method, calling '$this->methodname'" );
4252
+ if ( ! function_exists( 'call_user_func_array' ) ) {
4253
+ if ( $class == '' ) {
4254
+ $this->debug( 'in invoke_method, calling function using eval()' );
4255
+ $funcCall = "\$this->methodreturn = $this->methodname(";
4256
+ } else {
4257
+ if ( $delim == '..' ) {
4258
+ $this->debug( 'in invoke_method, calling class method using eval()' );
4259
+ $funcCall = "\$this->methodreturn = " . $class . "::" . $method . "(";
4260
+ } else {
4261
+ $this->debug( 'in invoke_method, calling instance method using eval()' );
4262
+ // generate unique instance name
4263
+ $instname = "\$inst_" . time();
4264
+ $funcCall = $instname . " = new " . $class . "(); ";
4265
+ $funcCall .= "\$this->methodreturn = " . $instname . "->" . $method . "(";
4266
+ }
4267
+ }
4268
+ if ( $this->methodparams ) {
4269
+ foreach ( $this->methodparams as $param ) {
4270
+ if ( is_array( $param ) || is_object( $param ) ) {
4271
+ $this->fault( 'SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available' );
4272
+
4273
+ return;
4274
+ }
4275
+ $funcCall .= "\"$param\",";
4276
+ }
4277
+ $funcCall = substr( $funcCall, 0, - 1 );
4278
+ }
4279
+ $funcCall .= ');';
4280
+ $this->debug( 'in invoke_method, function call: ' . $funcCall );
4281
+ @eval( $funcCall );
4282
+ } else {
4283
+ if ( $class == '' ) {
4284
+ $this->debug( 'in invoke_method, calling function using call_user_func_array()' );
4285
+ $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array()
4286
+ } elseif ( $delim == '..' ) {
4287
+ $this->debug( 'in invoke_method, calling class method using call_user_func_array()' );
4288
+ $call_arg = array( $class, $method );
4289
+ } else {
4290
+ $this->debug( 'in invoke_method, calling instance method using call_user_func_array()' );
4291
+ $instance = new $class ();
4292
+ $call_arg = array( &$instance, $method );
4293
+ }
4294
+ if ( is_array( $this->methodparams ) ) {
4295
+ $this->methodreturn = call_user_func_array( $call_arg, array_values( $this->methodparams ) );
4296
+ } else {
4297
+ $this->methodreturn = call_user_func_array( $call_arg, array() );
4298
+ }
4299
+ }
4300
+ $this->debug( 'in invoke_method, methodreturn:' );
4301
+ $this->appendDebug( $this->varDump( $this->methodreturn ) );
4302
+ $this->debug( "in invoke_method, called method $this->methodname, received data of type " . gettype( $this->methodreturn ) );
4303
+ }
4304
+
4305
+ /**
4306
+ * serializes the return value from a PHP function into a full SOAP Envelope
4307
+ *
4308
+ * The following fields are set by this function (when successful)
4309
+ *
4310
+ * responseSOAP
4311
+ *
4312
+ * This sets the fault field on error
4313
+ *
4314
+ * @access private
4315
+ */
4316
+ function serialize_return() {
4317
+ $this->debug( 'Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI );
4318
+ // if fault
4319
+ if ( isset( $this->methodreturn ) && is_object( $this->methodreturn ) && ( ( get_class( $this->methodreturn ) == 'soap_fault' ) || ( get_class( $this->methodreturn ) == 'nusoap_fault' ) ) ) {
4320
+ $this->debug( 'got a fault object from method' );
4321
+ $this->fault = $this->methodreturn;
4322
+
4323
+ return;
4324
+ } elseif ( $this->methodreturnisliteralxml ) {
4325
+ $return_val = $this->methodreturn;
4326
+ // returned value(s)
4327
+ } else {
4328
+ $this->debug( 'got a(n) ' . gettype( $this->methodreturn ) . ' from method' );
4329
+ $this->debug( 'serializing return value' );
4330
+ if ( $this->wsdl ) {
4331
+ if ( sizeof( $this->opData['output']['parts'] ) > 1 ) {
4332
+ $this->debug( 'more than one output part, so use the method return unchanged' );
4333
+ $opParams = $this->methodreturn;
4334
+ } elseif ( sizeof( $this->opData['output']['parts'] ) == 1 ) {
4335
+ $this->debug( 'exactly one output part, so wrap the method return in a simple array' );
4336
+ // TODO: verify that it is not already wrapped!
4337
+ //foreach ($this->opData['output']['parts'] as $name => $type) {
4338
+ // $this->debug('wrap in element named ' . $name);
4339
+ //}
4340
+ $opParams = array( $this->methodreturn );
4341
+ }
4342
+ $return_val = $this->wsdl->serializeRPCParameters( $this->methodname, 'output', $opParams );
4343
+ $this->appendDebug( $this->wsdl->getDebug() );
4344
+ $this->wsdl->clearDebug();
4345
+ if ( $errstr = $this->wsdl->getError() ) {
4346
+ $this->debug( 'got wsdl error: ' . $errstr );
4347
+ $this->fault( 'SOAP-ENV:Server', 'unable to serialize result' );
4348
+
4349
+ return;
4350
+ }
4351
+ } else {
4352
+ if ( isset( $this->methodreturn ) ) {
4353
+ $return_val = $this->serialize_val( $this->methodreturn, 'return' );
4354
+ } else {
4355
+ $return_val = '';
4356
+ $this->debug( 'in absence of WSDL, assume void return for backward compatibility' );
4357
+ }
4358
+ }
4359
+ }
4360
+ $this->debug( 'return value:' );
4361
+ $this->appendDebug( $this->varDump( $return_val ) );
4362
+
4363
+ $this->debug( 'serializing response' );
4364
+ if ( $this->wsdl ) {
4365
+ $this->debug( 'have WSDL for serialization: style is ' . $this->opData['style'] );
4366
+ if ( $this->opData['style'] == 'rpc' ) {
4367
+ $this->debug( 'style is rpc for serialization: use is ' . $this->opData['output']['use'] );
4368
+ if ( $this->opData['output']['use'] == 'literal' ) {
4369
+ // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
4370
+ if ( $this->methodURI ) {
4371
+ $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4372
+ } else {
4373
+ $payload = '<' . $this->methodname . 'Response>' . $return_val . '</' . $this->methodname . 'Response>';
4374
+ }
4375
+ } else {
4376
+ if ( $this->methodURI ) {
4377
+ $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4378
+ } else {
4379
+ $payload = '<' . $this->methodname . 'Response>' . $return_val . '</' . $this->methodname . 'Response>';
4380
+ }
4381
+ }
4382
+ } else {
4383
+ $this->debug( 'style is not rpc for serialization: assume document' );
4384
+ $payload = $return_val;
4385
+ }
4386
+ } else {
4387
+ $this->debug( 'do not have WSDL for serialization: assume rpc/encoded' );
4388
+ $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4389
+ }
4390
+ $this->result = 'successful';
4391
+ if ( $this->wsdl ) {
4392
+ //if($this->debug_flag){
4393
+ $this->appendDebug( $this->wsdl->getDebug() );
4394
+ // }
4395
+ if ( isset( $this->opData['output']['encodingStyle'] ) ) {
4396
+ $encodingStyle = $this->opData['output']['encodingStyle'];
4397
+ } else {
4398
+ $encodingStyle = '';
4399
+ }
4400
+ // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
4401
+ $this->responseSOAP = $this->serializeEnvelope( $payload, $this->responseHeaders, $this->wsdl->usedNamespaces, $this->opData['style'], $this->opData['output']['use'], $encodingStyle );
4402
+ } else {
4403
+ $this->responseSOAP = $this->serializeEnvelope( $payload, $this->responseHeaders );
4404
+ }
4405
+ $this->debug( "Leaving serialize_return" );
4406
+ }
4407
+
4408
+ /**
4409
+ * sends an HTTP response
4410
+ *
4411
+ * The following fields are set by this function (when successful)
4412
+ *
4413
+ * outgoing_headers
4414
+ * response
4415
+ *
4416
+ * @access private
4417
+ */
4418
+ function send_response() {
4419
+ $this->debug( 'Enter send_response' );
4420
+ if ( $this->fault ) {
4421
+ $payload = $this->fault->serialize();
4422
+ $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
4423
+ $this->outgoing_headers[] = "Status: 500 Internal Server Error";
4424
+ } else {
4425
+ $payload = $this->responseSOAP;
4426
+ // Some combinations of PHP+Web server allow the Status
4427
+ // to come through as a header. Since OK is the default
4428
+ // just do nothing.
4429
+ // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
4430
+ // $this->outgoing_headers[] = "Status: 200 OK";
4431
+ }
4432
+ // add debug data if in debug mode
4433
+ if ( isset( $this->debug_flag ) && $this->debug_flag ) {
4434
+ $payload .= $this->getDebugAsXMLComment();
4435
+ }
4436
+ $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
4437
+ preg_match( '/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev );
4438
+ $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (" . $rev[1] . ")";
4439
+ // Let the Web server decide about this
4440
+ //$this->outgoing_headers[] = "Connection: Close\r\n";
4441
+ $payload = $this->getHTTPBody( $payload );
4442
+ $type = $this->getHTTPContentType();
4443
+ $charset = $this->getHTTPContentTypeCharset();
4444
+ $this->outgoing_headers[] = "Content-Type: $type" . ( $charset ? '; charset=' . $charset : '' );
4445
+ //begin code to compress payload - by John
4446
+ // NOTE: there is no way to know whether the Web server will also compress
4447
+ // this data.
4448
+ if ( strlen( $payload ) > 1024 && isset( $this->headers ) && isset( $this->headers['accept-encoding'] ) ) {
4449
+ if ( strstr( $this->headers['accept-encoding'], 'gzip' ) ) {
4450
+ if ( function_exists( 'gzencode' ) ) {
4451
+ if ( isset( $this->debug_flag ) && $this->debug_flag ) {
4452
+ $payload .= "<!-- Content being gzipped -->";
4453
+ }
4454
+ $this->outgoing_headers[] = "Content-Encoding: gzip";
4455
+ $payload = gzencode( $payload );
4456
+ } else {
4457
+ if ( isset( $this->debug_flag ) && $this->debug_flag ) {
4458
+ $payload .= "<!-- Content will not be gzipped: no gzencode -->";
4459
+ }
4460
+ }
4461
+ } elseif ( strstr( $this->headers['accept-encoding'], 'deflate' ) ) {
4462
+ // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
4463
+ // instead of gzcompress output,
4464
+ // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
4465
+ if ( function_exists( 'gzdeflate' ) ) {
4466
+ if ( isset( $this->debug_flag ) && $this->debug_flag ) {
4467
+ $payload .= "<!-- Content being deflated -->";
4468
+ }
4469
+ $this->outgoing_headers[] = "Content-Encoding: deflate";
4470
+ $payload = gzdeflate( $payload );
4471
+ } else {
4472
+ if ( isset( $this->debug_flag ) && $this->debug_flag ) {
4473
+ $payload .= "<!-- Content will not be deflated: no gzcompress -->";
4474
+ }
4475
+ }
4476
+ }
4477
+ }
4478
+ //end code
4479
+ $this->outgoing_headers[] = "Content-Length: " . strlen( $payload );
4480
+ reset( $this->outgoing_headers );
4481
+ foreach ( $this->outgoing_headers as $hdr ) {
4482
+ header( $hdr, false );
4483
+ }
4484
+ print $payload;
4485
+ $this->response = join( "\r\n", $this->outgoing_headers ) . "\r\n\r\n" . $payload;
4486
+ }
4487
+
4488
+ /**
4489
+ * takes the value that was created by parsing the request
4490
+ * and compares to the method's signature, if available.
4491
+ *
4492
+ * @param string $operation The operation to be invoked
4493
+ * @param array $request The array of parameter values
4494
+ *
4495
+ * @return boolean Whether the operation was found
4496
+ * @access private
4497
+ */
4498
+ function verify_method( $operation, $request ) {
4499
+ if ( isset( $this->wsdl ) && is_object( $this->wsdl ) ) {
4500
+ if ( $this->wsdl->getOperationData( $operation ) ) {
4501
+ return true;
4502
+ }
4503
+ } elseif ( isset( $this->operations[ $operation ] ) ) {
4504
+ return true;
4505
+ }
4506
+
4507
+ return false;
4508
+ }
4509
+
4510
+ /**
4511
+ * processes SOAP message received from client
4512
+ *
4513
+ * @param array $headers The HTTP headers
4514
+ * @param string $data unprocessed request data from client
4515
+ *
4516
+ * @return mixed value of the message, decoded into a PHP type
4517
+ * @access private
4518
+ */
4519
+ function parseRequest( $headers, $data ) {
4520
+ $this->debug( 'Entering parseRequest() for data of length ' . strlen( $data ) . ' headers:' );
4521
+ $this->appendDebug( $this->varDump( $headers ) );
4522
+ if ( ! isset( $headers['content-type'] ) ) {
4523
+ $this->setError( 'Request not of type text/xml (no content-type header)' );
4524
+
4525
+ return false;
4526
+ }
4527
+ if ( ! strstr( $headers['content-type'], 'text/xml' ) ) {
4528
+ $this->setError( 'Request not of type text/xml' );
4529
+
4530
+ return false;
4531
+ }
4532
+ if ( strpos( $headers['content-type'], '=' ) ) {
4533
+ $enc = str_replace( '"', '', substr( strstr( $headers["content-type"], '=' ), 1 ) );
4534
+ $this->debug( 'Got response encoding: ' . $enc );
4535
+ if ( preg_match( '/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc ) ) {
4536
+ $this->xml_encoding = strtoupper( $enc );
4537
+ } else {
4538
+ $this->xml_encoding = 'US-ASCII';
4539
+ }
4540
+ } else {
4541
+ // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4542
+ $this->xml_encoding = 'ISO-8859-1';
4543
+ }
4544
+ $this->debug( 'Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser' );
4545
+ // parse response, get soap parser obj
4546
+ $parser = new nusoap_parser( $data, $this->xml_encoding, '', $this->decode_utf8 );
4547
+ // parser debug
4548
+ $this->debug( "parser debug: \n" . $parser->getDebug() );
4549
+ // if fault occurred during message parsing
4550
+ if ( $err = $parser->getError() ) {
4551
+ $this->result = 'fault: error in msg parsing: ' . $err;
4552
+ $this->fault( 'SOAP-ENV:Client', "error in msg parsing:\n" . $err );
4553
+ // else successfully parsed request into soapval object
4554
+ } else {
4555
+ // get/set methodname
4556
+ $this->methodURI = $parser->root_struct_namespace;
4557
+ $this->methodname = $parser->root_struct_name;
4558
+ $this->debug( 'methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI );
4559
+ $this->debug( 'calling parser->get_soapbody()' );
4560
+ $this->methodparams = $parser->get_soapbody();
4561
+ // get SOAP headers
4562
+ $this->requestHeaders = $parser->getHeaders();
4563
+ // get SOAP Header
4564
+ $this->requestHeader = $parser->get_soapheader();
4565
+ // add document for doclit support
4566
+ $this->document = $parser->document;
4567
+ }
4568
+ }
4569
+
4570
+ /**
4571
+ * gets the HTTP body for the current response.
4572
+ *
4573
+ * @param string $soapmsg The SOAP payload
4574
+ *
4575
+ * @return string The HTTP body, which includes the SOAP payload
4576
+ * @access private
4577
+ */
4578
+ function getHTTPBody( $soapmsg ) {
4579
+ return $soapmsg;
4580
+ }
4581
+
4582
+ /**
4583
+ * gets the HTTP content type for the current response.
4584
+ *
4585
+ * Note: getHTTPBody must be called before this.
4586
+ *
4587
+ * @return string the HTTP content type for the current response.
4588
+ * @access private
4589
+ */
4590
+ function getHTTPContentType() {
4591
+ return 'text/xml';
4592
+ }
4593
+
4594
+ /**
4595
+ * gets the HTTP content type charset for the current response.
4596
+ * returns false for non-text content types.
4597
+ *
4598
+ * Note: getHTTPBody must be called before this.
4599
+ *
4600
+ * @return string the HTTP content type charset for the current response.
4601
+ * @access private
4602
+ */
4603
+ function getHTTPContentTypeCharset() {
4604
+ return $this->soap_defencoding;
4605
+ }
4606
+
4607
+ /**
4608
+ * add a method to the dispatch map (this has been replaced by the register method)
4609
+ *
4610
+ * @param string $methodname
4611
+ * @param string $in array of input values
4612
+ * @param string $out array of output values
4613
+ *
4614
+ * @access public
4615
+ * @deprecated
4616
+ */
4617
+ function add_to_map( $methodname, $in, $out ) {
4618
+ $this->operations[ $methodname ] = array( 'name' => $methodname, 'in' => $in, 'out' => $out );
4619
+ }
4620
+
4621
+ /**
4622
+ * register a service function with the server
4623
+ *
4624
+ * @param string $name the name of the PHP function, class.method or class..method
4625
+ * @param array $in assoc array of input values: key = param name, value = param type
4626
+ * @param array $out assoc array of output values: key = param name, value = param type
4627
+ * @param mixed $namespace the element namespace for the method or false
4628
+ * @param mixed $soapaction the soapaction for the method or false
4629
+ * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
4630
+ * @param mixed $use optional (encoded|literal) or false
4631
+ * @param string $documentation optional Description to include in WSDL
4632
+ * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
4633
+ *
4634
+ * @access public
4635
+ */
4636
+ function register( $name, $in = array(), $out = array(), $namespace = false, $soapaction = false, $style = false, $use = false, $documentation = '', $encodingStyle = '' ) {
4637
+ global $HTTP_SERVER_VARS;
4638
+
4639
+ if ( $this->externalWSDLURL ) {
4640
+ die( 'You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.' );
4641
+ }
4642
+ if ( ! $name ) {
4643
+ die( 'You must specify a name when you register an operation' );
4644
+ }
4645
+ if ( ! is_array( $in ) ) {
4646
+ die( 'You must provide an array for operation inputs' );
4647
+ }
4648
+ if ( ! is_array( $out ) ) {
4649
+ die( 'You must provide an array for operation outputs' );
4650
+ }
4651
+ if ( false == $namespace ) {
4652
+ }
4653
+ if ( false == $soapaction ) {
4654
+ if ( isset( $_SERVER ) ) {
4655
+ $SERVER_NAME = $_SERVER['SERVER_NAME'];
4656
+ $SCRIPT_NAME = isset( $_SERVER['PHP_SELF'] ) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4657
+ $HTTPS = isset( $_SERVER['HTTPS'] ) ? $_SERVER['HTTPS'] : ( isset( $HTTP_SERVER_VARS['HTTPS'] ) ? $HTTP_SERVER_VARS['HTTPS'] : 'off' );
4658
+ } elseif ( isset( $HTTP_SERVER_VARS ) ) {
4659
+ $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4660
+ $SCRIPT_NAME = isset( $HTTP_SERVER_VARS['PHP_SELF'] ) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4661
+ $HTTPS = isset( $HTTP_SERVER_VARS['HTTPS'] ) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4662
+ } else {
4663
+ $this->setError( "Neither _SERVER nor HTTP_SERVER_VARS is available" );
4664
+ }
4665
+ if ( $HTTPS == '1' || $HTTPS == 'on' ) {
4666
+ $SCHEME = 'https';
4667
+ } else {
4668
+ $SCHEME = 'http';
4669
+ }
4670
+ $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
4671
+ }
4672
+ if ( false == $style ) {
4673
+ $style = "rpc";
4674
+ }
4675
+ if ( false == $use ) {
4676
+ $use = "encoded";
4677
+ }
4678
+ if ( $use == 'encoded' && $encodingStyle == '' ) {
4679
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
4680
+ }
4681
+
4682
+ $this->operations[ $name ] = array(
4683
+ 'name' => $name,
4684
+ 'in' => $in,
4685
+ 'out' => $out,
4686
+ 'namespace' => $namespace,
4687
+ 'soapaction' => $soapaction,
4688
+ 'style' => $style
4689
+ );
4690
+ if ( $this->wsdl ) {
4691
+ $this->wsdl->addOperation( $name, $in, $out, $namespace, $soapaction, $style, $use, $documentation, $encodingStyle );
4692
+ }
4693
+
4694
+ return true;
4695
+ }
4696
+
4697
+ /**
4698
+ * Specify a fault to be returned to the client.
4699
+ * This also acts as a flag to the server that a fault has occured.
4700
+ *
4701
+ * @param string $faultcode
4702
+ * @param string $faultstring
4703
+ * @param string $faultactor
4704
+ * @param string $faultdetail
4705
+ *
4706
+ * @access public
4707
+ */
4708
+ function fault( $faultcode, $faultstring, $faultactor = '', $faultdetail = '' ) {
4709
+ if ( $faultdetail == '' && $this->debug_flag ) {
4710
+ $faultdetail = $this->getDebug();
4711
+ }
4712
+ $this->fault = new nusoap_fault( $faultcode, $faultactor, $faultstring, $faultdetail );
4713
+ $this->fault->soap_defencoding = $this->soap_defencoding;
4714
+ }
4715
+
4716
+ /**
4717
+ * Sets up wsdl object.
4718
+ * Acts as a flag to enable internal WSDL generation
4719
+ *
4720
+ * @param string $serviceName , name of the service
4721
+ * @param mixed $namespace optional 'tns' service namespace or false
4722
+ * @param mixed $endpoint optional URL of service endpoint or false
4723
+ * @param string $style optional (rpc|document) WSDL style (also specified by operation)
4724
+ * @param string $transport optional SOAP transport
4725
+ * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false
4726
+ */
4727
+ function configureWSDL( $serviceName, $namespace = false, $endpoint = false, $style = 'rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false ) {
4728
+ global $HTTP_SERVER_VARS;
4729
+
4730
+ if ( isset( $_SERVER ) ) {
4731
+ $SERVER_NAME = $_SERVER['SERVER_NAME'];
4732
+ $SERVER_PORT = $_SERVER['SERVER_PORT'];
4733
+ $SCRIPT_NAME = isset( $_SERVER['PHP_SELF'] ) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4734
+ $HTTPS = isset( $_SERVER['HTTPS'] ) ? $_SERVER['HTTPS'] : ( isset( $HTTP_SERVER_VARS['HTTPS'] ) ? $HTTP_SERVER_VARS['HTTPS'] : 'off' );
4735
+ } elseif ( isset( $HTTP_SERVER_VARS ) ) {
4736
+ $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4737
+ $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
4738
+ $SCRIPT_NAME = isset( $HTTP_SERVER_VARS['PHP_SELF'] ) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4739
+ $HTTPS = isset( $HTTP_SERVER_VARS['HTTPS'] ) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4740
+ } else {
4741
+ $this->setError( "Neither _SERVER nor HTTP_SERVER_VARS is available" );
4742
+ }
4743
+ // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
4744
+ $colon = strpos( $SERVER_NAME, ":" );
4745
+ if ( $colon ) {
4746
+ $SERVER_NAME = substr( $SERVER_NAME, 0, $colon );
4747
+ }
4748
+ if ( $SERVER_PORT == 80 ) {
4749
+ $SERVER_PORT = '';
4750
+ } else {
4751
+ $SERVER_PORT = ':' . $SERVER_PORT;
4752
+ }
4753
+ if ( false == $namespace ) {
4754
+ $namespace = "http://$SERVER_NAME/soap/$serviceName";
4755
+ }
4756
+
4757
+ if ( false == $endpoint ) {
4758
+ if ( $HTTPS == '1' || $HTTPS == 'on' ) {
4759
+ $SCHEME = 'https';
4760
+ } else {
4761
+ $SCHEME = 'http';
4762
+ }
4763
+ $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
4764
+ }
4765
+
4766
+ if ( false == $schemaTargetNamespace ) {
4767
+ $schemaTargetNamespace = $namespace;
4768
+ }
4769
+
4770
+ $this->wsdl = new wsdl;
4771
+ $this->wsdl->serviceName = $serviceName;
4772
+ $this->wsdl->endpoint = $endpoint;
4773
+ $this->wsdl->namespaces['tns'] = $namespace;
4774
+ $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
4775
+ $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
4776
+ if ( $schemaTargetNamespace != $namespace ) {
4777
+ $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4778
+ }
4779
+ $this->wsdl->schemas[ $schemaTargetNamespace ][0] = new nusoap_xmlschema( '', '', $this->wsdl->namespaces );
4780
+ if ( $style == 'document' ) {
4781
+ $this->wsdl->schemas[ $schemaTargetNamespace ][0]->schemaInfo['elementFormDefault'] = 'qualified';
4782
+ }
4783
+ $this->wsdl->schemas[ $schemaTargetNamespace ][0]->schemaTargetNamespace = $schemaTargetNamespace;
4784
+ $this->wsdl->schemas[ $schemaTargetNamespace ][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array(
4785
+ 'location' => '',
4786
+ 'loaded' => true
4787
+ );
4788
+ $this->wsdl->schemas[ $schemaTargetNamespace ][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array(
4789
+ 'location' => '',
4790
+ 'loaded' => true
4791
+ );
4792
+ $this->wsdl->bindings[ $serviceName . 'Binding' ] = array(
4793
+ 'name' => $serviceName . 'Binding',
4794
+ 'style' => $style,
4795
+ 'transport' => $transport,
4796
+ 'portType' => $serviceName . 'PortType'
4797
+ );
4798
+ $this->wsdl->ports[ $serviceName . 'Port' ] = array(
4799
+ 'binding' => $serviceName . 'Binding',
4800
+ 'location' => $endpoint,
4801
+ 'bindingType' => 'http://schemas.xmlsoap.org/wsdl/soap/'
4802
+ );
4803
+ }
4804
+ }
4805
+
4806
+ /**
4807
+ * Backward compatibility
4808
+ */
4809
+ class soap_server extends nusoap_server {
4810
+ }
4811
+
4812
+ ?><?php
4813
+
4814
+
4815
+ /**
4816
+ * parses a WSDL file, allows access to it's data, other utility methods.
4817
+ * also builds WSDL structures programmatically.
4818
+ *
4819
+ * @author Dietrich Ayala <dietrich@ganx4.com>
4820
+ * @author Scott Nichol <snichol@users.sourceforge.net>
4821
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
4822
+ * @access public
4823
+ */
4824
+ class wsdl extends nusoap_base {
4825
+ // URL or filename of the root of this WSDL
4826
+ var $wsdl;
4827
+ // define internal arrays of bindings, ports, operations, messages, etc.
4828
+ var $schemas = array();
4829
+ var $currentSchema;
4830
+ var $message = array();
4831
+ var $complexTypes = array();
4832
+ var $messages = array();
4833
+ var $currentMessage;
4834
+ var $currentOperation;
4835
+ var $portTypes = array();
4836
+ var $currentPortType;
4837
+ var $bindings = array();
4838
+ var $currentBinding;
4839
+ var $ports = array();
4840
+ var $currentPort;
4841
+ var $opData = array();
4842
+ var $status = '';
4843
+ var $documentation = false;
4844
+ var $endpoint = '';
4845
+ // array of wsdl docs to import
4846
+ var $import = array();
4847
+ // parser vars
4848
+ var $parser;
4849
+ var $position = 0;
4850
+ var $depth = 0;
4851
+ var $depth_array = array();
4852
+ // for getting wsdl
4853
+ var $proxyhost = '';
4854
+ var $proxyport = '';
4855
+ var $proxyusername = '';
4856
+ var $proxypassword = '';
4857
+ var $timeout = 0;
4858
+ var $response_timeout = 30;
4859
+ var $curl_options = array(); // User-specified cURL options
4860
+ var $use_curl = false; // whether to always try to use cURL
4861
+ // for HTTP authentication
4862
+ var $username = ''; // Username for HTTP authentication
4863
+ var $password = ''; // Password for HTTP authentication
4864
+ var $authtype = ''; // Type of HTTP authentication
4865
+ var $certRequest = array(); // Certificate for HTTP SSL authentication
4866
+
4867
+ /**
4868
+ * constructor
4869
+ *
4870
+ * @param string $wsdl WSDL document URL
4871
+ * @param string $proxyhost
4872
+ * @param string $proxyport
4873
+ * @param string $proxyusername
4874
+ * @param string $proxypassword
4875
+ * @param integer $timeout set the connection timeout
4876
+ * @param integer $response_timeout set the response timeout
4877
+ * @param array $curl_options user-specified cURL options
4878
+ * @param boolean $use_curl try to use cURL
4879
+ *
4880
+ * @access public
4881
+ */
4882
+ function wsdl( $wsdl = '', $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $curl_options = null, $use_curl = false ) {
4883
+ parent::nusoap_base();
4884
+ $this->debug( "ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout" );
4885
+ $this->proxyhost = $proxyhost;
4886
+ $this->proxyport = $proxyport;
4887
+ $this->proxyusername = $proxyusername;
4888
+ $this->proxypassword = $proxypassword;
4889
+ $this->timeout = $timeout;
4890
+ $this->response_timeout = $response_timeout;
4891
+ if ( is_array( $curl_options ) ) {
4892
+ $this->curl_options = $curl_options;
4893
+ }
4894
+ $this->use_curl = $use_curl;
4895
+ $this->fetchWSDL( $wsdl );
4896
+ }
4897
+
4898
+ /**
4899
+ * fetches the WSDL document and parses it
4900
+ *
4901
+ * @access public
4902
+ */
4903
+ function fetchWSDL( $wsdl ) {
4904
+ $this->debug( "parse and process WSDL path=$wsdl" );
4905
+ $this->wsdl = $wsdl;
4906
+ // parse wsdl file
4907
+ if ( $this->wsdl != "" ) {
4908
+ $this->parseWSDL( $this->wsdl );
4909
+ }
4910
+ // imports
4911
+ // TODO: handle imports more properly, grabbing them in-line and nesting them
4912
+ $imported_urls = array();
4913
+ $imported = 1;
4914
+ while ( $imported > 0 ) {
4915
+ $imported = 0;
4916
+ // Schema imports
4917
+ foreach ( $this->schemas as $ns => $list ) {
4918
+ foreach ( $list as $xs ) {
4919
+ $wsdlparts = parse_url( $this->wsdl ); // this is bogusly simple!
4920
+ foreach ( $xs->imports as $ns2 => $list2 ) {
4921
+ for ( $ii = 0; $ii < count( $list2 ); $ii ++ ) {
4922
+ if ( ! $list2[ $ii ]['loaded'] ) {
4923
+ $this->schemas[ $ns ]->imports[ $ns2 ][ $ii ]['loaded'] = true;
4924
+ $url = $list2[ $ii ]['location'];
4925
+ if ( $url != '' ) {
4926
+ $urlparts = parse_url( $url );
4927
+ if ( ! isset( $urlparts['host'] ) ) {
4928
+ $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . ( isset( $wsdlparts['port'] ) ? ':' . $wsdlparts['port'] : '' ) .
4929
+ substr( $wsdlparts['path'], 0, strrpos( $wsdlparts['path'], '/' ) + 1 ) . $urlparts['path'];
4930
+ }
4931
+ if ( ! in_array( $url, $imported_urls ) ) {
4932
+ $this->parseWSDL( $url );
4933
+ $imported ++;
4934
+ $imported_urls[] = $url;
4935
+ }
4936
+ } else {
4937
+ $this->debug( "Unexpected scenario: empty URL for unloaded import" );
4938
+ }
4939
+ }
4940
+ }
4941
+ }
4942
+ }
4943
+ }
4944
+ // WSDL imports
4945
+ $wsdlparts = parse_url( $this->wsdl ); // this is bogusly simple!
4946
+ foreach ( $this->import as $ns => $list ) {
4947
+ for ( $ii = 0; $ii < count( $list ); $ii ++ ) {
4948
+ if ( ! $list[ $ii ]['loaded'] ) {
4949
+ $this->import[ $ns ][ $ii ]['loaded'] = true;
4950
+ $url = $list[ $ii ]['location'];
4951
+ if ( $url != '' ) {
4952
+ $urlparts = parse_url( $url );
4953
+ if ( ! isset( $urlparts['host'] ) ) {
4954
+ $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . ( isset( $wsdlparts['port'] ) ? ':' . $wsdlparts['port'] : '' ) .
4955
+ substr( $wsdlparts['path'], 0, strrpos( $wsdlparts['path'], '/' ) + 1 ) . $urlparts['path'];
4956
+ }
4957
+ if ( ! in_array( $url, $imported_urls ) ) {
4958
+ $this->parseWSDL( $url );
4959
+ $imported ++;
4960
+ $imported_urls[] = $url;
4961
+ }
4962
+ } else {
4963
+ $this->debug( "Unexpected scenario: empty URL for unloaded import" );
4964
+ }
4965
+ }
4966
+ }
4967
+ }
4968
+ }
4969
+ // add new data to operation data
4970
+ foreach ( $this->bindings as $binding => $bindingData ) {
4971
+ if ( isset( $bindingData['operations'] ) && is_array( $bindingData['operations'] ) ) {
4972
+ foreach ( $bindingData['operations'] as $operation => $data ) {
4973
+ $this->debug( 'post-parse data gathering for ' . $operation );
4974
+ $this->bindings[ $binding ]['operations'][ $operation ]['input'] =
4975
+ isset( $this->bindings[ $binding ]['operations'][ $operation ]['input'] ) ?
4976
+ array_merge( $this->bindings[ $binding ]['operations'][ $operation ]['input'], $this->portTypes[ $bindingData['portType'] ][ $operation ]['input'] ) :
4977
+ $this->portTypes[ $bindingData['portType'] ][ $operation ]['input'];
4978
+ $this->bindings[ $binding ]['operations'][ $operation ]['output'] =
4979
+ isset( $this->bindings[ $binding ]['operations'][ $operation ]['output'] ) ?
4980
+ array_merge( $this->bindings[ $binding ]['operations'][ $operation ]['output'], $this->portTypes[ $bindingData['portType'] ][ $operation ]['output'] ) :
4981
+ $this->portTypes[ $bindingData['portType'] ][ $operation ]['output'];
4982
+ if ( isset( $this->messages[ $this->bindings[ $binding ]['operations'][ $operation ]['input']['message'] ] ) ) {
4983
+ $this->bindings[ $binding ]['operations'][ $operation ]['input']['parts'] = $this->messages[ $this->bindings[ $binding ]['operations'][ $operation ]['input']['message'] ];
4984
+ }
4985
+ if ( isset( $this->messages[ $this->bindings[ $binding ]['operations'][ $operation ]['output']['message'] ] ) ) {
4986
+ $this->bindings[ $binding ]['operations'][ $operation ]['output']['parts'] = $this->messages[ $this->bindings[ $binding ]['operations'][ $operation ]['output']['message'] ];
4987
+ }
4988
+ // Set operation style if necessary, but do not override one already provided
4989
+ if ( isset( $bindingData['style'] ) && ! isset( $this->bindings[ $binding ]['operations'][ $operation ]['style'] ) ) {
4990
+ $this->bindings[ $binding ]['operations'][ $operation ]['style'] = $bindingData['style'];
4991
+ }
4992
+ $this->bindings[ $binding ]['operations'][ $operation ]['transport'] = isset( $bindingData['transport'] ) ? $bindingData['transport'] : '';
4993
+ $this->bindings[ $binding ]['operations'][ $operation ]['documentation'] = isset( $this->portTypes[ $bindingData['portType'] ][ $operation ]['documentation'] ) ? $this->portTypes[ $bindingData['portType'] ][ $operation ]['documentation'] : '';
4994
+ $this->bindings[ $binding ]['operations'][ $operation ]['endpoint'] = isset( $bindingData['endpoint'] ) ? $bindingData['endpoint'] : '';
4995
+ }
4996
+ }
4997
+ }
4998
+ }
4999
+
5000
+ /**
5001
+ * parses the wsdl document
5002
+ *
5003
+ * @param string $wsdl path or URL
5004
+ *
5005
+ * @access private
5006
+ */
5007
+ function parseWSDL( $wsdl = '' ) {
5008
+ $this->debug( "parse WSDL at path=$wsdl" );
5009
+
5010
+ if ( $wsdl == '' ) {
5011
+ $this->debug( 'no wsdl passed to parseWSDL()!!' );
5012
+ $this->setError( 'no wsdl passed to parseWSDL()!!' );
5013
+
5014
+ return false;
5015
+ }
5016
+
5017
+ // parse $wsdl for url format
5018
+ $wsdl_props = parse_url( $wsdl );
5019
+
5020
+ if ( isset( $wsdl_props['scheme'] ) && ( $wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https' ) ) {
5021
+ $this->debug( 'getting WSDL http(s) URL ' . $wsdl );
5022
+ // get wsdl
5023
+ $tr = new soap_transport_http( $wsdl, $this->curl_options, $this->use_curl );
5024
+ $tr->request_method = 'GET';
5025
+ $tr->useSOAPAction = false;
5026
+ if ( $this->proxyhost && $this->proxyport ) {
5027
+ $tr->setProxy( $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword );
5028
+ }
5029
+ if ( $this->authtype != '' ) {
5030
+ $tr->setCredentials( $this->username, $this->password, $this->authtype, array(), $this->certRequest );
5031
+ }
5032
+ $tr->setEncoding( 'gzip, deflate' );
5033
+ $wsdl_string = $tr->send( '', $this->timeout, $this->response_timeout );
5034
+ //$this->debug("WSDL request\n" . $tr->outgoing_payload);
5035
+ //$this->debug("WSDL response\n" . $tr->incoming_payload);
5036
+ $this->appendDebug( $tr->getDebug() );
5037
+ // catch errors
5038
+ if ( $err = $tr->getError() ) {
5039
+ $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: ' . $err;
5040
+ $this->debug( $errstr );
5041
+ $this->setError( $errstr );
5042
+ unset( $tr );
5043
+
5044
+ return false;
5045
+ }
5046
+ unset( $tr );
5047
+ $this->debug( "got WSDL URL" );
5048
+ } else {
5049
+ // $wsdl is not http(s), so treat it as a file URL or plain file path
5050
+ if ( isset( $wsdl_props['scheme'] ) && ( $wsdl_props['scheme'] == 'file' ) && isset( $wsdl_props['path'] ) ) {
5051
+ $path = isset( $wsdl_props['host'] ) ? ( $wsdl_props['host'] . ':' . $wsdl_props['path'] ) : $wsdl_props['path'];
5052
+ } else {
5053
+ $path = $wsdl;
5054
+ }
5055
+ $this->debug( 'getting WSDL file ' . $path );
5056
+ if ( $fp = @fopen( $path, 'r' ) ) {
5057
+ $wsdl_string = '';
5058
+ while ( $data = fread( $fp, 32768 ) ) {
5059
+ $wsdl_string .= $data;
5060
+ }
5061
+ fclose( $fp );
5062
+ } else {
5063
+ $errstr = "Bad path to WSDL file $path";
5064
+ $this->debug( $errstr );
5065
+ $this->setError( $errstr );
5066
+
5067
+ return false;
5068
+ }
5069
+ }
5070
+ $this->debug( 'Parse WSDL' );
5071
+ // end new code added
5072
+ // Create an XML parser.
5073
+ $this->parser = xml_parser_create();
5074
+ // Set the options for parsing the XML data.
5075
+ // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
5076
+ xml_parser_set_option( $this->parser, XML_OPTION_CASE_FOLDING, 0 );
5077
+ // Set the object for the parser.
5078
+ xml_set_object( $this->parser, $this );
5079
+ // Set the element handlers for the parser.
5080
+ xml_set_element_handler( $this->parser, 'start_element', 'end_element' );
5081
+ xml_set_character_data_handler( $this->parser, 'character_data' );
5082
+ // Parse the XML file.
5083
+ if ( ! xml_parse( $this->parser, $wsdl_string, true ) ) {
5084
+ // Display an error message.
5085
+ $errstr = sprintf(
5086
+ 'XML error parsing WSDL from %s on line %d: %s',
5087
+ $wsdl,
5088
+ xml_get_current_line_number( $this->parser ),
5089
+ xml_error_string( xml_get_error_code( $this->parser ) )
5090
+ );
5091
+ $this->debug( $errstr );
5092
+ $this->debug( "XML payload:\n" . $wsdl_string );
5093
+ $this->setError( $errstr );
5094
+
5095
+ return false;
5096
+ }
5097
+ // free the parser
5098
+ xml_parser_free( $this->parser );
5099
+ $this->debug( 'Parsing WSDL done' );
5100
+ // catch wsdl parse errors
5101
+ if ( $this->getError() ) {
5102
+ return false;
5103
+ }
5104
+
5105
+ return true;
5106
+ }
5107
+
5108
+ /**
5109
+ * start-element handler
5110
+ *
5111
+ * @param string $parser XML parser object
5112
+ * @param string $name element name
5113
+ * @param string $attrs associative array of attributes
5114
+ *
5115
+ * @access private
5116
+ */
5117
+ function start_element( $parser, $name, $attrs ) {
5118
+ if ( $this->status == 'schema' ) {
5119
+ $this->currentSchema->schemaStartElement( $parser, $name, $attrs );
5120
+ $this->appendDebug( $this->currentSchema->getDebug() );
5121
+ $this->currentSchema->clearDebug();
5122
+ } elseif ( preg_match( '/schema$/', $name ) ) {
5123
+ $this->debug( 'Parsing WSDL schema' );
5124
+ // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
5125
+ $this->status = 'schema';
5126
+ $this->currentSchema = new nusoap_xmlschema( '', '', $this->namespaces );
5127
+ $this->currentSchema->schemaStartElement( $parser, $name, $attrs );
5128
+ $this->appendDebug( $this->currentSchema->getDebug() );
5129
+ $this->currentSchema->clearDebug();
5130
+ } else {
5131
+ // position in the total number of elements, starting from 0
5132
+ $pos = $this->position ++;
5133
+ $depth = $this->depth ++;
5134
+ // set self as current value for this depth
5135
+ $this->depth_array[ $depth ] = $pos;
5136
+ $this->message[ $pos ] = array( 'cdata' => '' );
5137
+ // process attributes
5138
+ if ( count( $attrs ) > 0 ) {
5139
+ // register namespace declarations
5140
+ foreach ( $attrs as $k => $v ) {
5141
+ if ( preg_match( '/^xmlns/', $k ) ) {
5142
+ if ( $ns_prefix = substr( strrchr( $k, ':' ), 1 ) ) {
5143
+ $this->namespaces[ $ns_prefix ] = $v;
5144
+ } else {
5145
+ $this->namespaces[ 'ns' . ( count( $this->namespaces ) + 1 ) ] = $v;
5146
+ }
5147
+ if ( $v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema' ) {
5148
+ $this->XMLSchemaVersion = $v;
5149
+ $this->namespaces['xsi'] = $v . '-instance';
5150
+ }
5151
+ }
5152
+ }
5153
+ // expand each attribute prefix to its namespace
5154
+ foreach ( $attrs as $k => $v ) {
5155
+ $k = strpos( $k, ':' ) ? $this->expandQname( $k ) : $k;
5156
+ if ( $k != 'location' && $k != 'soapAction' && $k != 'namespace' ) {
5157
+ $v = strpos( $v, ':' ) ? $this->expandQname( $v ) : $v;
5158
+ }
5159
+ $eAttrs[ $k ] = $v;
5160
+ }
5161
+ $attrs = $eAttrs;
5162
+ } else {
5163
+ $attrs = array();
5164
+ }
5165
+ // get element prefix, namespace and name
5166
+ if ( preg_match( '/:/', $name ) ) {
5167
+ // get ns prefix
5168
+ $prefix = substr( $name, 0, strpos( $name, ':' ) );
5169
+ // get ns
5170
+ $namespace = isset( $this->namespaces[ $prefix ] ) ? $this->namespaces[ $prefix ] : '';
5171
+ // get unqualified name
5172
+ $name = substr( strstr( $name, ':' ), 1 );
5173
+ }
5174
+ // process attributes, expanding any prefixes to namespaces
5175
+ // find status, register data
5176
+ switch ( $this->status ) {
5177
+ case 'message':
5178
+ if ( $name == 'part' ) {
5179
+ if ( isset( $attrs['type'] ) ) {
5180
+ $this->debug( "msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode( ',', $attrs ) );
5181
+ $this->messages[ $this->currentMessage ][ $attrs['name'] ] = $attrs['type'];
5182
+ }
5183
+ if ( isset( $attrs['element'] ) ) {
5184
+ $this->debug( "msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode( ',', $attrs ) );
5185
+ $this->messages[ $this->currentMessage ][ $attrs['name'] ] = $attrs['element'] . '^';
5186
+ }
5187
+ }
5188
+ break;
5189
+ case 'portType':
5190
+ switch ( $name ) {
5191
+ case 'operation':
5192
+ $this->currentPortOperation = $attrs['name'];
5193
+ $this->debug( "portType $this->currentPortType operation: $this->currentPortOperation" );
5194
+ if ( isset( $attrs['parameterOrder'] ) ) {
5195
+ $this->portTypes[ $this->currentPortType ][ $attrs['name'] ]['parameterOrder'] = $attrs['parameterOrder'];
5196
+ }
5197
+ break;
5198
+ case 'documentation':
5199
+ $this->documentation = true;
5200
+ break;
5201
+ // merge input/output data
5202
+ default:
5203
+ $m = isset( $attrs['message'] ) ? $this->getLocalPart( $attrs['message'] ) : '';
5204
+ $this->portTypes[ $this->currentPortType ][ $this->currentPortOperation ][ $name ]['message'] = $m;
5205
+ break;
5206
+ }
5207
+ break;
5208
+ case 'binding':
5209
+ switch ( $name ) {
5210
+ case 'binding':
5211
+ // get ns prefix
5212
+ if ( isset( $attrs['style'] ) ) {
5213
+ $this->bindings[ $this->currentBinding ]['prefix'] = $prefix;
5214
+ }
5215
+ $this->bindings[ $this->currentBinding ] = array_merge( $this->bindings[ $this->currentBinding ], $attrs );
5216
+ break;
5217
+ case 'header':
5218
+ $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ][ $this->opStatus ]['headers'][] = $attrs;
5219
+ break;
5220
+ case 'operation':
5221
+ if ( isset( $attrs['soapAction'] ) ) {
5222
+ $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ]['soapAction'] = $attrs['soapAction'];
5223
+ }
5224
+ if ( isset( $attrs['style'] ) ) {
5225
+ $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ]['style'] = $attrs['style'];
5226
+ }
5227
+ if ( isset( $attrs['name'] ) ) {
5228
+ $this->currentOperation = $attrs['name'];
5229
+ $this->debug( "current binding operation: $this->currentOperation" );
5230
+ $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ]['name'] = $attrs['name'];
5231
+ $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ]['binding'] = $this->currentBinding;
5232
+ $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ]['endpoint'] = isset( $this->bindings[ $this->currentBinding ]['endpoint'] ) ? $this->bindings[ $this->currentBinding ]['endpoint'] : '';
5233
+ }
5234
+ break;
5235
+ case 'input':
5236
+ $this->opStatus = 'input';
5237
+ break;
5238
+ case 'output':
5239
+ $this->opStatus = 'output';
5240
+ break;
5241
+ case 'body':
5242
+ if ( isset( $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ][ $this->opStatus ] ) ) {
5243
+ $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ][ $this->opStatus ] = array_merge( $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ][ $this->opStatus ], $attrs );
5244
+ } else {
5245
+ $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ][ $this->opStatus ] = $attrs;
5246
+ }
5247
+ break;
5248
+ }
5249
+ break;
5250
+ case 'service':
5251
+ switch ( $name ) {
5252
+ case 'port':
5253
+ $this->currentPort = $attrs['name'];
5254
+ $this->debug( 'current port: ' . $this->currentPort );
5255
+ $this->ports[ $this->currentPort ]['binding'] = $this->getLocalPart( $attrs['binding'] );
5256
+
5257
+ break;
5258
+ case 'address':
5259
+ $this->ports[ $this->currentPort ]['location'] = $attrs['location'];
5260
+ $this->ports[ $this->currentPort ]['bindingType'] = $namespace;
5261
+ $this->bindings[ $this->ports[ $this->currentPort ]['binding'] ]['bindingType'] = $namespace;
5262
+ $this->bindings[ $this->ports[ $this->currentPort ]['binding'] ]['endpoint'] = $attrs['location'];
5263
+ break;
5264
+ }
5265
+ break;
5266
+ }
5267
+ // set status
5268
+ switch ( $name ) {
5269
+ case 'import':
5270
+ if ( isset( $attrs['location'] ) ) {
5271
+ $this->import[ $attrs['namespace'] ][] = array(
5272
+ 'location' => $attrs['location'],
5273
+ 'loaded' => false
5274
+ );
5275
+ $this->debug( 'parsing import ' . $attrs['namespace'] . ' - ' . $attrs['location'] . ' (' . count( $this->import[ $attrs['namespace'] ] ) . ')' );
5276
+ } else {
5277
+ $this->import[ $attrs['namespace'] ][] = array( 'location' => '', 'loaded' => true );
5278
+ if ( ! $this->getPrefixFromNamespace( $attrs['namespace'] ) ) {
5279
+ $this->namespaces[ 'ns' . ( count( $this->namespaces ) + 1 ) ] = $attrs['namespace'];
5280
+ }
5281
+ $this->debug( 'parsing import ' . $attrs['namespace'] . ' - [no location] (' . count( $this->import[ $attrs['namespace'] ] ) . ')' );
5282
+ }
5283
+ break;
5284
+ //wait for schema
5285
+ //case 'types':
5286
+ // $this->status = 'schema';
5287
+ // break;
5288
+ case 'message':
5289
+ $this->status = 'message';
5290
+ $this->messages[ $attrs['name'] ] = array();
5291
+ $this->currentMessage = $attrs['name'];
5292
+ break;
5293
+ case 'portType':
5294
+ $this->status = 'portType';
5295
+ $this->portTypes[ $attrs['name'] ] = array();
5296
+ $this->currentPortType = $attrs['name'];
5297
+ break;
5298
+ case "binding":
5299
+ if ( isset( $attrs['name'] ) ) {
5300
+ // get binding name
5301
+ if ( strpos( $attrs['name'], ':' ) ) {
5302
+ $this->currentBinding = $this->getLocalPart( $attrs['name'] );
5303
+ } else {
5304
+ $this->currentBinding = $attrs['name'];
5305
+ }
5306
+ $this->status = 'binding';
5307
+ $this->bindings[ $this->currentBinding ]['portType'] = $this->getLocalPart( $attrs['type'] );
5308
+ $this->debug( "current binding: $this->currentBinding of portType: " . $attrs['type'] );
5309
+ }
5310
+ break;
5311
+ case 'service':
5312
+ $this->serviceName = $attrs['name'];
5313
+ $this->status = 'service';
5314
+ $this->debug( 'current service: ' . $this->serviceName );
5315
+ break;
5316
+ case 'definitions':
5317
+ foreach ( $attrs as $name => $value ) {
5318
+ $this->wsdl_info[ $name ] = $value;
5319
+ }
5320
+ break;
5321
+ }
5322
+ }
5323
+ }
5324
+
5325
+ /**
5326
+ * end-element handler
5327
+ *
5328
+ * @param string $parser XML parser object
5329
+ * @param string $name element name
5330
+ *
5331
+ * @access private
5332
+ */
5333
+ function end_element( $parser, $name ) {
5334
+ // unset schema status
5335
+ if (/*preg_match('/types$/', $name) ||*/
5336
+ preg_match( '/schema$/', $name ) ) {
5337
+ $this->status = "";
5338
+ $this->appendDebug( $this->currentSchema->getDebug() );
5339
+ $this->currentSchema->clearDebug();
5340
+ $this->schemas[ $this->currentSchema->schemaTargetNamespace ][] = $this->currentSchema;
5341
+ $this->debug( 'Parsing WSDL schema done' );
5342
+ }
5343
+ if ( $this->status == 'schema' ) {
5344
+ $this->currentSchema->schemaEndElement( $parser, $name );
5345
+ } else {
5346
+ // bring depth down a notch
5347
+ $this->depth --;
5348
+ }
5349
+ // end documentation
5350
+ if ( $this->documentation ) {
5351
+ //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
5352
+ //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
5353
+ $this->documentation = false;
5354
+ }
5355
+ }
5356
+
5357
+ /**
5358
+ * element content handler
5359
+ *
5360
+ * @param string $parser XML parser object
5361
+ * @param string $data element content
5362
+ *
5363
+ * @access private
5364
+ */
5365
+ function character_data( $parser, $data ) {
5366
+ $pos = isset( $this->depth_array[ $this->depth ] ) ? $this->depth_array[ $this->depth ] : 0;
5367
+ if ( isset( $this->message[ $pos ]['cdata'] ) ) {
5368
+ $this->message[ $pos ]['cdata'] .= $data;
5369
+ }
5370
+ if ( $this->documentation ) {
5371
+ $this->documentation .= $data;
5372
+ }
5373
+ }
5374
+
5375
+ /**
5376
+ * if authenticating, set user credentials here
5377
+ *
5378
+ * @param string $username
5379
+ * @param string $password
5380
+ * @param string $authtype (basic|digest|certificate|ntlm)
5381
+ * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
5382
+ *
5383
+ * @access public
5384
+ */
5385
+ function setCredentials( $username, $password, $authtype = 'basic', $certRequest = array() ) {
5386
+ $this->debug( "setCredentials username=$username authtype=$authtype certRequest=" );
5387
+ $this->appendDebug( $this->varDump( $certRequest ) );
5388
+ $this->username = $username;
5389
+ $this->password = $password;
5390
+ $this->authtype = $authtype;
5391
+ $this->certRequest = $certRequest;
5392
+ }
5393
+
5394
+ function getBindingData( $binding ) {
5395
+ if ( is_array( $this->bindings[ $binding ] ) ) {
5396
+ return $this->bindings[ $binding ];
5397
+ }
5398
+ }
5399
+
5400
+ /**
5401
+ * returns an assoc array of operation names => operation data
5402
+ *
5403
+ * @param string $portName WSDL port name
5404
+ * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)
5405
+ *
5406
+ * @return array
5407
+ * @access public
5408
+ */
5409
+ function getOperations( $portName = '', $bindingType = 'soap' ) {
5410
+ $ops = array();
5411
+ if ( $bindingType == 'soap' ) {
5412
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5413
+ } elseif ( $bindingType == 'soap12' ) {
5414
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5415
+ } else {
5416
+ $this->debug( "getOperations bindingType $bindingType may not be supported" );
5417
+ }
5418
+ $this->debug( "getOperations for port '$portName' bindingType $bindingType" );
5419
+ // loop thru ports
5420
+ foreach ( $this->ports as $port => $portData ) {
5421
+ $this->debug( "getOperations checking port $port bindingType " . $portData['bindingType'] );
5422
+ if ( $portName == '' || $port == $portName ) {
5423
+ // binding type of port matches parameter
5424
+ if ( $portData['bindingType'] == $bindingType ) {
5425
+ $this->debug( "getOperations found port $port bindingType $bindingType" );
5426
+ //$this->debug("port data: " . $this->varDump($portData));
5427
+ //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
5428
+ // merge bindings
5429
+ if ( isset( $this->bindings[ $portData['binding'] ]['operations'] ) ) {
5430
+ $ops = array_merge( $ops, $this->bindings[ $portData['binding'] ]['operations'] );
5431
+ }
5432
+ }
5433
+ }
5434
+ }
5435
+ if ( count( $ops ) == 0 ) {
5436
+ $this->debug( "getOperations found no operations for port '$portName' bindingType $bindingType" );
5437
+ }
5438
+
5439
+ return $ops;
5440
+ }
5441
+
5442
+ /**
5443
+ * returns an associative array of data necessary for calling an operation
5444
+ *
5445
+ * @param string $operation name of operation
5446
+ * @param string $bindingType type of binding eg: soap, soap12
5447
+ *
5448
+ * @return array
5449
+ * @access public
5450
+ */
5451
+ function getOperationData( $operation, $bindingType = 'soap' ) {
5452
+ if ( $bindingType == 'soap' ) {
5453
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5454
+ } elseif ( $bindingType == 'soap12' ) {
5455
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5456
+ }
5457
+ // loop thru ports
5458
+ foreach ( $this->ports as $port => $portData ) {
5459
+ // binding type of port matches parameter
5460
+ if ( $portData['bindingType'] == $bindingType ) {
5461
+ // get binding
5462
+ //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5463
+ foreach ( array_keys( $this->bindings[ $portData['binding'] ]['operations'] ) as $bOperation ) {
5464
+ // note that we could/should also check the namespace here
5465
+ if ( $operation == $bOperation ) {
5466
+ $opData = $this->bindings[ $portData['binding'] ]['operations'][ $operation ];
5467
+
5468
+ return $opData;
5469
+ }
5470
+ }
5471
+ }
5472
+ }
5473
+ }
5474
+
5475
+ /**
5476
+ * returns an associative array of data necessary for calling an operation
5477
+ *
5478
+ * @param string $soapAction soapAction for operation
5479
+ * @param string $bindingType type of binding eg: soap, soap12
5480
+ *
5481
+ * @return array
5482
+ * @access public
5483
+ */
5484
+ function getOperationDataForSoapAction( $soapAction, $bindingType = 'soap' ) {
5485
+ if ( $bindingType == 'soap' ) {
5486
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5487
+ } elseif ( $bindingType == 'soap12' ) {
5488
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5489
+ }
5490
+ // loop thru ports
5491
+ foreach ( $this->ports as $port => $portData ) {
5492
+ // binding type of port matches parameter
5493
+ if ( $portData['bindingType'] == $bindingType ) {
5494
+ // loop through operations for the binding
5495
+ foreach ( $this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData ) {
5496
+ if ( $opData['soapAction'] == $soapAction ) {
5497
+ return $opData;
5498
+ }
5499
+ }
5500
+ }
5501
+ }
5502
+ }
5503
+
5504
+ /**
5505
+ * returns an array of information about a given type
5506
+ * returns false if no type exists by the given name
5507
+ *
5508
+ * typeDef = array(
5509
+ * 'elements' => array(), // refs to elements array
5510
+ * 'restrictionBase' => '',
5511
+ * 'phpType' => '',
5512
+ * 'order' => '(sequence|all)',
5513
+ * 'attrs' => array() // refs to attributes array
5514
+ * )
5515
+ *
5516
+ * @param string $type the type
5517
+ * @param string $ns namespace (not prefix) of the type
5518
+ *
5519
+ * @return mixed
5520
+ * @access public
5521
+ * @see nusoap_xmlschema
5522
+ */
5523
+ function getTypeDef( $type, $ns ) {
5524
+ $this->debug( "in getTypeDef: type=$type, ns=$ns" );
5525
+ if ( ( ! $ns ) && isset( $this->namespaces['tns'] ) ) {
5526
+ $ns = $this->namespaces['tns'];
5527
+ $this->debug( "in getTypeDef: type namespace forced to $ns" );
5528
+ }
5529
+ if ( ! isset( $this->schemas[ $ns ] ) ) {
5530
+ foreach ( $this->schemas as $ns0 => $schema0 ) {
5531
+ if ( strcasecmp( $ns, $ns0 ) == 0 ) {
5532
+ $this->debug( "in getTypeDef: replacing schema namespace $ns with $ns0" );
5533
+ $ns = $ns0;
5534
+ break;
5535
+ }
5536
+ }
5537
+ }
5538
+ if ( isset( $this->schemas[ $ns ] ) ) {
5539
+ $this->debug( "in getTypeDef: have schema for namespace $ns" );
5540
+ for ( $i = 0; $i < count( $this->schemas[ $ns ] ); $i ++ ) {
5541
+ $xs = &$this->schemas[ $ns ][ $i ];
5542
+ $t = $xs->getTypeDef( $type );
5543
+ $this->appendDebug( $xs->getDebug() );
5544
+ $xs->clearDebug();
5545
+ if ( $t ) {
5546
+ $this->debug( "in getTypeDef: found type $type" );
5547
+ if ( ! isset( $t['phpType'] ) ) {
5548
+ // get info for type to tack onto the element
5549
+ $uqType = substr( $t['type'], strrpos( $t['type'], ':' ) + 1 );
5550
+ $ns = substr( $t['type'], 0, strrpos( $t['type'], ':' ) );
5551
+ $etype = $this->getTypeDef( $uqType, $ns );
5552
+ if ( $etype ) {
5553
+ $this->debug( "found type for [element] $type:" );
5554
+ $this->debug( $this->varDump( $etype ) );
5555
+ if ( isset( $etype['phpType'] ) ) {
5556
+ $t['phpType'] = $etype['phpType'];
5557
+ }
5558
+ if ( isset( $etype['elements'] ) ) {
5559
+ $t['elements'] = $etype['elements'];
5560
+ }
5561
+ if ( isset( $etype['attrs'] ) ) {
5562
+ $t['attrs'] = $etype['attrs'];
5563
+ }
5564
+ } else {
5565
+ $this->debug( "did not find type for [element] $type" );
5566
+ }
5567
+ }
5568
+
5569
+ return $t;
5570
+ }
5571
+ }
5572
+ $this->debug( "in getTypeDef: did not find type $type" );
5573
+ } else {
5574
+ $this->debug( "in getTypeDef: do not have schema for namespace $ns" );
5575
+ }
5576
+
5577
+ return false;
5578
+ }
5579
+
5580
+ /**
5581
+ * prints html description of services
5582
+ *
5583
+ * @access private
5584
+ */
5585
+ function webDescription() {
5586
+ global $HTTP_SERVER_VARS;
5587
+
5588
+ if ( isset( $_SERVER ) ) {
5589
+ $PHP_SELF = $_SERVER['PHP_SELF'];
5590
+ } elseif ( isset( $HTTP_SERVER_VARS ) ) {
5591
+ $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
5592
+ } else {
5593
+ $this->setError( "Neither _SERVER nor HTTP_SERVER_VARS is available" );
5594
+ }
5595
+
5596
+ $b = '
5597
+ <html><head><title>NuSOAP: ' . $this->serviceName . '</title>
5598
+ <style type="text/css">
5599
+ body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
5600
+ p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
5601
+ pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
5602
+ ul { margin-top: 10px; margin-left: 20px; }
5603
+ li { list-style-type: none; margin-top: 10px; color: #000000; }
5604
+ .content{
5605
+ margin-left: 0px; padding-bottom: 2em; }
5606
+ .nav {
5607
+ padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
5608
+ margin-top: 10px; margin-left: 0px; color: #000000;
5609
+ background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
5610
+ .title {
5611
+ font-family: arial; font-size: 26px; color: #ffffff;
5612
+ background-color: #999999; width: 100%;
5613
+ margin-left: 0px; margin-right: 0px;
5614
+ padding-top: 10px; padding-bottom: 10px;}
5615
+ .hidden {
5616
+ position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
5617
+ font-family: arial; overflow: hidden; width: 600;
5618
+ padding: 20px; font-size: 10px; background-color: #999999;
5619
+ layer-background-color:#FFFFFF; }
5620
+ a,a:active { color: charcoal; font-weight: bold; }
5621
+ a:visited { color: #666666; font-weight: bold; }
5622
+ a:hover { color: cc3300; font-weight: bold; }
5623
+ </style>
5624
+ <script language="JavaScript" type="text/javascript">
5625
+ <!--
5626
+ // POP-UP CAPTIONS...
5627
+ function lib_bwcheck(){ //Browsercheck (needed)
5628
+ this.ver=navigator.appVersion
5629
+ this.agent=navigator.userAgent
5630
+ this.dom=document.getElementById?1:0
5631
+ this.opera5=this.agent.indexOf("Opera 5")>-1
5632
+ this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
5633
+ this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
5634
+ this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
5635
+ this.ie=this.ie4||this.ie5||this.ie6
5636
+ this.mac=this.agent.indexOf("Mac")>-1
5637
+ this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
5638
+ this.ns4=(document.layers && !this.dom)?1:0;
5639
+ this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
5640
+ return this
5641
+ }
5642
+ var bw = new lib_bwcheck()
5643
+ //Makes crossbrowser object.
5644
+ function makeObj(obj){
5645
+ this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
5646
+ if(!this.evnt) return false
5647
+ this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
5648
+ this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
5649
+ this.writeIt=b_writeIt;
5650
+ return this
5651
+ }
5652
+ // A unit of measure that will be added when setting the position of a layer.
5653
+ //var px = bw.ns4||window.opera?"":"px";
5654
+ function b_writeIt(text){
5655
+ if (bw.ns4){this.wref.write(text);this.wref.close()}
5656
+ else this.wref.innerHTML = text
5657
+ }
5658
+ //Shows the messages
5659
+ var oDesc;
5660
+ function popup(divid){
5661
+ if(oDesc = new makeObj(divid)){
5662
+ oDesc.css.visibility = "visible"
5663
+ }
5664
+ }
5665
+ function popout(){ // Hides message
5666
+ if(oDesc) oDesc.css.visibility = "hidden"
5667
+ }
5668
+ //-->
5669
+ </script>
5670
+ </head>
5671
+ <body>
5672
+ <div class=content>
5673
+ <br><br>
5674
+ <div class=title>' . $this->serviceName . '</div>
5675
+ <div class=nav>
5676
+ <p>View the <a href="' . $PHP_SELF . '?wsdl">WSDL</a> for the service.
5677
+ Click on an operation name to view it&apos;s details.</p>
5678
+ <ul>';
5679
+ foreach ( $this->getOperations() as $op => $data ) {
5680
+ $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
5681
+ // create hidden div
5682
+ $b .= "<div id='$op' class='hidden'>
5683
+ <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
5684
+ foreach ( $data as $donnie => $marie ) { // loop through opdata
5685
+ if ( $donnie == 'input' || $donnie == 'output' ) { // show input/output data
5686
+ $b .= "<font color='white'>" . ucfirst( $donnie ) . ':</font><br>';
5687
+ foreach ( $marie as $captain => $tenille ) { // loop through data
5688
+ if ( $captain == 'parts' ) { // loop thru parts
5689
+ $b .= "&nbsp;&nbsp;$captain:<br>";
5690
+ //if(is_array($tenille)){
5691
+ foreach ( $tenille as $joanie => $chachi ) {
5692
+ $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
5693
+ }
5694
+ //}
5695
+ } else {
5696
+ $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
5697
+ }
5698
+ }
5699
+ } else {
5700
+ $b .= "<font color='white'>" . ucfirst( $donnie ) . ":</font> $marie<br>";
5701
+ }
5702
+ }
5703
+ $b .= '</div>';
5704
+ }
5705
+ $b .= '
5706
+ <ul>
5707
+ </div>
5708
+ </div></body></html>';
5709
+
5710
+ return $b;
5711
+ }
5712
+
5713
+ /**
5714
+ * serialize the parsed wsdl
5715
+ *
5716
+ * @param mixed $debug whether to put debug=1 in endpoint URL
5717
+ *
5718
+ * @return string serialization of WSDL
5719
+ * @access public
5720
+ */
5721
+ function serialize( $debug = 0 ) {
5722
+ $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
5723
+ $xml .= "\n<definitions";
5724
+ foreach ( $this->namespaces as $k => $v ) {
5725
+ $xml .= " xmlns:$k=\"$v\"";
5726
+ }
5727
+ // 10.9.02 - add poulter fix for wsdl and tns declarations
5728
+ if ( isset( $this->namespaces['wsdl'] ) ) {
5729
+ $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
5730
+ }
5731
+ if ( isset( $this->namespaces['tns'] ) ) {
5732
+ $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
5733
+ }
5734
+ $xml .= '>';
5735
+ // imports
5736
+ if ( sizeof( $this->import ) > 0 ) {
5737
+ foreach ( $this->import as $ns => $list ) {
5738
+ foreach ( $list as $ii ) {
5739
+ if ( $ii['location'] != '' ) {
5740
+ $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
5741
+ } else {
5742
+ $xml .= '<import namespace="' . $ns . '" />';
5743
+ }
5744
+ }
5745
+ }
5746
+ }
5747
+ // types
5748
+ if ( count( $this->schemas ) >= 1 ) {
5749
+ $xml .= "\n<types>\n";
5750
+ foreach ( $this->schemas as $ns => $list ) {
5751
+ foreach ( $list as $xs ) {
5752
+ $xml .= $xs->serializeSchema();
5753
+ }
5754
+ }
5755
+ $xml .= '</types>';
5756
+ }
5757
+ // messages
5758
+ if ( count( $this->messages ) >= 1 ) {
5759
+ foreach ( $this->messages as $msgName => $msgParts ) {
5760
+ $xml .= "\n<message name=\"" . $msgName . '">';
5761
+ if ( is_array( $msgParts ) ) {
5762
+ foreach ( $msgParts as $partName => $partType ) {
5763
+ // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
5764
+ if ( strpos( $partType, ':' ) ) {
5765
+ $typePrefix = $this->getPrefixFromNamespace( $this->getPrefix( $partType ) );
5766
+ } elseif ( isset( $this->typemap[ $this->namespaces['xsd'] ][ $partType ] ) ) {
5767
+ // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
5768
+ $typePrefix = 'xsd';
5769
+ } else {
5770
+ foreach ( $this->typemap as $ns => $types ) {
5771
+ if ( isset( $types[ $partType ] ) ) {
5772
+ $typePrefix = $this->getPrefixFromNamespace( $ns );
5773
+ }
5774
+ }
5775
+ if ( ! isset( $typePrefix ) ) {
5776
+ die( "$partType has no namespace!" );
5777
+ }
5778
+ }
5779
+ $ns = $this->getNamespaceFromPrefix( $typePrefix );
5780
+ $localPart = $this->getLocalPart( $partType );
5781
+ $typeDef = $this->getTypeDef( $localPart, $ns );
5782
+ if ( $typeDef['typeClass'] == 'element' ) {
5783
+ $elementortype = 'element';
5784
+ if ( substr( $localPart, - 1 ) == '^' ) {
5785
+ $localPart = substr( $localPart, 0, - 1 );
5786
+ }
5787
+ } else {
5788
+ $elementortype = 'type';
5789
+ }
5790
+ $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
5791
+ }
5792
+ }
5793
+ $xml .= '</message>';
5794
+ }
5795
+ }
5796
+ // bindings & porttypes
5797
+ if ( count( $this->bindings ) >= 1 ) {
5798
+ $binding_xml = '';
5799
+ $portType_xml = '';
5800
+ foreach ( $this->bindings as $bindingName => $attrs ) {
5801
+ $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
5802
+ $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
5803
+ $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
5804
+ foreach ( $attrs['operations'] as $opName => $opParts ) {
5805
+ $binding_xml .= "\n" . ' <operation name="' . $opName . '">';
5806
+ $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="' . $opParts['style'] . '"/>';
5807
+ if ( isset( $opParts['input']['encodingStyle'] ) && $opParts['input']['encodingStyle'] != '' ) {
5808
+ $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
5809
+ } else {
5810
+ $enc_style = '';
5811
+ }
5812
+ $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
5813
+ if ( isset( $opParts['output']['encodingStyle'] ) && $opParts['output']['encodingStyle'] != '' ) {
5814
+ $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
5815
+ } else {
5816
+ $enc_style = '';
5817
+ }
5818
+ $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
5819
+ $binding_xml .= "\n" . ' </operation>';
5820
+ $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"';
5821
+ if ( isset( $opParts['parameterOrder'] ) ) {
5822
+ $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
5823
+ }
5824
+ $portType_xml .= '>';
5825
+ if ( isset( $opParts['documentation'] ) && $opParts['documentation'] != '' ) {
5826
+ $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars( $opParts['documentation'] ) . '</documentation>';
5827
+ }
5828
+ $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>';
5829
+ $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>';
5830
+ $portType_xml .= "\n" . ' </operation>';
5831
+ }
5832
+ $portType_xml .= "\n" . '</portType>';
5833
+ $binding_xml .= "\n" . '</binding>';
5834
+ }
5835
+ $xml .= $portType_xml . $binding_xml;
5836
+ }
5837
+ // services
5838
+ $xml .= "\n<service name=\"" . $this->serviceName . '">';
5839
+ if ( count( $this->ports ) >= 1 ) {
5840
+ foreach ( $this->ports as $pName => $attrs ) {
5841
+ $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5842
+ $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ( $debug ? '?debug=1' : '' ) . '"/>';
5843
+ $xml .= "\n" . ' </port>';
5844
+ }
5845
+ }
5846
+ $xml .= "\n" . '</service>';
5847
+
5848
+ return $xml . "\n</definitions>";
5849
+ }
5850
+
5851
+ /**
5852
+ * determine whether a set of parameters are unwrapped
5853
+ * when they are expect to be wrapped, Microsoft-style.
5854
+ *
5855
+ * @param string $type the type (element name) of the wrapper
5856
+ * @param array $parameters the parameter values for the SOAP call
5857
+ *
5858
+ * @return boolean whether they parameters are unwrapped (and should be wrapped)
5859
+ * @access private
5860
+ */
5861
+ function parametersMatchWrapped( $type, &$parameters ) {
5862
+ $this->debug( "in parametersMatchWrapped type=$type, parameters=" );
5863
+ $this->appendDebug( $this->varDump( $parameters ) );
5864
+
5865
+ // split type into namespace:unqualified-type
5866
+ if ( strpos( $type, ':' ) ) {
5867
+ $uqType = substr( $type, strrpos( $type, ':' ) + 1 );
5868
+ $ns = substr( $type, 0, strrpos( $type, ':' ) );
5869
+ $this->debug( "in parametersMatchWrapped: got a prefixed type: $uqType, $ns" );
5870
+ if ( $this->getNamespaceFromPrefix( $ns ) ) {
5871
+ $ns = $this->getNamespaceFromPrefix( $ns );
5872
+ $this->debug( "in parametersMatchWrapped: expanded prefixed type: $uqType, $ns" );
5873
+ }
5874
+ } else {
5875
+ // TODO: should the type be compared to types in XSD, and the namespace
5876
+ // set to XSD if the type matches?
5877
+ $this->debug( "in parametersMatchWrapped: No namespace for type $type" );
5878
+ $ns = '';
5879
+ $uqType = $type;
5880
+ }
5881
+
5882
+ // get the type information
5883
+ if ( ! $typeDef = $this->getTypeDef( $uqType, $ns ) ) {
5884
+ $this->debug( "in parametersMatchWrapped: $type ($uqType) is not a supported type." );
5885
+
5886
+ return false;
5887
+ }
5888
+ $this->debug( "in parametersMatchWrapped: found typeDef=" );
5889
+ $this->appendDebug( $this->varDump( $typeDef ) );
5890
+ if ( substr( $uqType, - 1 ) == '^' ) {
5891
+ $uqType = substr( $uqType, 0, - 1 );
5892
+ }
5893
+ $phpType = $typeDef['phpType'];
5894
+ $arrayType = ( isset( $typeDef['arrayType'] ) ? $typeDef['arrayType'] : '' );
5895
+ $this->debug( "in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType" );
5896
+
5897
+ // we expect a complexType or element of complexType
5898
+ if ( $phpType != 'struct' ) {
5899
+ $this->debug( "in parametersMatchWrapped: not a struct" );
5900
+
5901
+ return false;
5902
+ }
5903
+
5904
+ // see whether the parameter names match the elements
5905
+ if ( isset( $typeDef['elements'] ) && is_array( $typeDef['elements'] ) ) {
5906
+ $elements = 0;
5907
+ $matches = 0;
5908
+ foreach ( $typeDef['elements'] as $name => $attrs ) {
5909
+ if ( isset( $parameters[ $name ] ) ) {
5910
+ $this->debug( "in parametersMatchWrapped: have parameter named $name" );
5911
+ $matches ++;
5912
+ } else {
5913
+ $this->debug( "in parametersMatchWrapped: do not have parameter named $name" );
5914
+ }
5915
+ $elements ++;
5916
+ }
5917
+
5918
+ $this->debug( "in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names" );
5919
+ if ( $matches == 0 ) {
5920
+ return false;
5921
+ }
5922
+
5923
+ return true;
5924
+ }
5925
+
5926
+ // since there are no elements for the type, if the user passed no
5927
+ // parameters, the parameters match wrapped.
5928
+ $this->debug( "in parametersMatchWrapped: no elements type $ns:$uqType" );
5929
+
5930
+ return count( $parameters ) == 0;
5931
+ }
5932
+
5933
+ /**
5934
+ * serialize PHP values according to a WSDL message definition
5935
+ * contrary to the method name, this is not limited to RPC
5936
+ *
5937
+ * TODO
5938
+ * - multi-ref serialization
5939
+ * - validate PHP values against type definitions, return errors if invalid
5940
+ *
5941
+ * @param string $operation operation name
5942
+ * @param string $direction (input|output)
5943
+ * @param mixed $parameters parameter value(s)
5944
+ * @param string $bindingType (soap|soap12)
5945
+ *
5946
+ * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
5947
+ * @access public
5948
+ */
5949
+ function serializeRPCParameters( $operation, $direction, $parameters, $bindingType = 'soap' ) {
5950
+ $this->debug( "in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType" );
5951
+ $this->appendDebug( 'parameters=' . $this->varDump( $parameters ) );
5952
+
5953
+ if ( $direction != 'input' && $direction != 'output' ) {
5954
+ $this->debug( 'The value of the \$direction argument needs to be either "input" or "output"' );
5955
+ $this->setError( 'The value of the \$direction argument needs to be either "input" or "output"' );
5956
+
5957
+ return false;
5958
+ }
5959
+ if ( ! $opData = $this->getOperationData( $operation, $bindingType ) ) {
5960
+ $this->debug( 'Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType );
5961
+ $this->setError( 'Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType );
5962
+
5963
+ return false;
5964
+ }
5965
+ $this->debug( 'in serializeRPCParameters: opData:' );
5966
+ $this->appendDebug( $this->varDump( $opData ) );
5967
+
5968
+ // Get encoding style for output and set to current
5969
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5970
+ if ( ( $direction == 'input' ) && isset( $opData['output']['encodingStyle'] ) && ( $opData['output']['encodingStyle'] != $encodingStyle ) ) {
5971
+ $encodingStyle = $opData['output']['encodingStyle'];
5972
+ $enc_style = $encodingStyle;
5973
+ }
5974
+
5975
+ // set input params
5976
+ $xml = '';
5977
+ if ( isset( $opData[ $direction ]['parts'] ) && sizeof( $opData[ $direction ]['parts'] ) > 0 ) {
5978
+ $parts = &$opData[ $direction ]['parts'];
5979
+ $part_count = sizeof( $parts );
5980
+ $style = $opData['style'];
5981
+ $use = $opData[ $direction ]['use'];
5982
+ $this->debug( "have $part_count part(s) to serialize using $style/$use" );
5983
+ if ( is_array( $parameters ) ) {
5984
+ $parametersArrayType = $this->isArraySimpleOrStruct( $parameters );
5985
+ $parameter_count = count( $parameters );
5986
+ $this->debug( "have $parameter_count parameter(s) provided as $parametersArrayType to serialize" );
5987
+ // check for Microsoft-style wrapped parameters
5988
+ if ( $style == 'document' && $use == 'literal' && $part_count == 1 && isset( $parts['parameters'] ) ) {
5989
+ $this->debug( 'check whether the caller has wrapped the parameters' );
5990
+ if ( $direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1 ) {
5991
+ // TODO: consider checking here for double-wrapping, when
5992
+ // service function wraps, then NuSOAP wraps again
5993
+ $this->debug( "change simple array to associative with 'parameters' element" );
5994
+ $parameters['parameters'] = $parameters[0];
5995
+ unset( $parameters[0] );
5996
+ }
5997
+ if ( ( $parametersArrayType == 'arrayStruct' || $parameter_count == 0 ) && ! isset( $parameters['parameters'] ) ) {
5998
+ $this->debug( 'check whether caller\'s parameters match the wrapped ones' );
5999
+ if ( $this->parametersMatchWrapped( $parts['parameters'], $parameters ) ) {
6000
+ $this->debug( 'wrap the parameters for the caller' );
6001
+ $parameters = array( 'parameters' => $parameters );
6002
+ $parameter_count = 1;
6003
+ }
6004
+ }
6005
+ }
6006
+ foreach ( $parts as $name => $type ) {
6007
+ $this->debug( "serializing part $name of type $type" );
6008
+ // Track encoding style
6009
+ if ( isset( $opData[ $direction ]['encodingStyle'] ) && $encodingStyle != $opData[ $direction ]['encodingStyle'] ) {
6010
+ $encodingStyle = $opData[ $direction ]['encodingStyle'];
6011
+ $enc_style = $encodingStyle;
6012
+ } else {
6013
+ $enc_style = false;
6014
+ }
6015
+ // NOTE: add error handling here
6016
+ // if serializeType returns false, then catch global error and fault
6017
+ if ( $parametersArrayType == 'arraySimple' ) {
6018
+ $p = array_shift( $parameters );
6019
+ $this->debug( 'calling serializeType w/indexed param' );
6020
+ $xml .= $this->serializeType( $name, $type, $p, $use, $enc_style );
6021
+ } elseif ( isset( $parameters[ $name ] ) ) {
6022
+ $this->debug( 'calling serializeType w/named param' );
6023
+ $xml .= $this->serializeType( $name, $type, $parameters[ $name ], $use, $enc_style );
6024
+ } else {
6025
+ // TODO: only send nillable
6026
+ $this->debug( 'calling serializeType w/null param' );
6027
+ $xml .= $this->serializeType( $name, $type, null, $use, $enc_style );
6028
+ }
6029
+ }
6030
+ } else {
6031
+ $this->debug( 'no parameters passed.' );
6032
+ }
6033
+ }
6034
+ $this->debug( "serializeRPCParameters returning: $xml" );
6035
+
6036
+ return $xml;
6037
+ }
6038
+
6039
+ /**
6040
+ * serialize a PHP value according to a WSDL message definition
6041
+ *
6042
+ * TODO
6043
+ * - multi-ref serialization
6044
+ * - validate PHP values against type definitions, return errors if invalid
6045
+ *
6046
+ * @param string $operation operation name
6047
+ * @param string $direction (input|output)
6048
+ * @param mixed $parameters parameter value(s)
6049
+ *
6050
+ * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
6051
+ * @access public
6052
+ * @deprecated
6053
+ */
6054
+ function serializeParameters( $operation, $direction, $parameters ) {
6055
+ $this->debug( "in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion" );
6056
+ $this->appendDebug( 'parameters=' . $this->varDump( $parameters ) );
6057
+
6058
+ if ( $direction != 'input' && $direction != 'output' ) {
6059
+ $this->debug( 'The value of the \$direction argument needs to be either "input" or "output"' );
6060
+ $this->setError( 'The value of the \$direction argument needs to be either "input" or "output"' );
6061
+
6062
+ return false;
6063
+ }
6064
+ if ( ! $opData = $this->getOperationData( $operation ) ) {
6065
+ $this->debug( 'Unable to retrieve WSDL data for operation: ' . $operation );
6066
+ $this->setError( 'Unable to retrieve WSDL data for operation: ' . $operation );
6067
+
6068
+ return false;
6069
+ }
6070
+ $this->debug( 'opData:' );
6071
+ $this->appendDebug( $this->varDump( $opData ) );
6072
+
6073
+ // Get encoding style for output and set to current
6074
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6075
+ if ( ( $direction == 'input' ) && isset( $opData['output']['encodingStyle'] ) && ( $opData['output']['encodingStyle'] != $encodingStyle ) ) {
6076
+ $encodingStyle = $opData['output']['encodingStyle'];
6077
+ $enc_style = $encodingStyle;
6078
+ }
6079
+
6080
+ // set input params
6081
+ $xml = '';
6082
+ if ( isset( $opData[ $direction ]['parts'] ) && sizeof( $opData[ $direction ]['parts'] ) > 0 ) {
6083
+
6084
+ $use = $opData[ $direction ]['use'];
6085
+ $this->debug( "use=$use" );
6086
+ $this->debug( 'got ' . count( $opData[ $direction ]['parts'] ) . ' part(s)' );
6087
+ if ( is_array( $parameters ) ) {
6088
+ $parametersArrayType = $this->isArraySimpleOrStruct( $parameters );
6089
+ $this->debug( 'have ' . $parametersArrayType . ' parameters' );
6090
+ foreach ( $opData[ $direction ]['parts'] as $name => $type ) {
6091
+ $this->debug( 'serializing part "' . $name . '" of type "' . $type . '"' );
6092
+ // Track encoding style
6093
+ if ( isset( $opData[ $direction ]['encodingStyle'] ) && $encodingStyle != $opData[ $direction ]['encodingStyle'] ) {
6094
+ $encodingStyle = $opData[ $direction ]['encodingStyle'];
6095
+ $enc_style = $encodingStyle;
6096
+ } else {
6097
+ $enc_style = false;
6098
+ }
6099
+ // NOTE: add error handling here
6100
+ // if serializeType returns false, then catch global error and fault
6101
+ if ( $parametersArrayType == 'arraySimple' ) {
6102
+ $p = array_shift( $parameters );
6103
+ $this->debug( 'calling serializeType w/indexed param' );
6104
+ $xml .= $this->serializeType( $name, $type, $p, $use, $enc_style );
6105
+ } elseif ( isset( $parameters[ $name ] ) ) {
6106
+ $this->debug( 'calling serializeType w/named param' );
6107
+ $xml .= $this->serializeType( $name, $type, $parameters[ $name ], $use, $enc_style );
6108
+ } else {
6109
+ // TODO: only send nillable
6110
+ $this->debug( 'calling serializeType w/null param' );
6111
+ $xml .= $this->serializeType( $name, $type, null, $use, $enc_style );
6112
+ }
6113
+ }
6114
+ } else {
6115
+ $this->debug( 'no parameters passed.' );
6116
+ }
6117
+ }
6118
+ $this->debug( "serializeParameters returning: $xml" );
6119
+
6120
+ return $xml;
6121
+ }
6122
+
6123
+ /**
6124
+ * serializes a PHP value according a given type definition
6125
+ *
6126
+ * @param string $name name of value (part or element)
6127
+ * @param string $type XML schema type of value (type or element)
6128
+ * @param mixed $value a native PHP value (parameter value)
6129
+ * @param string $use use for part (encoded|literal)
6130
+ * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
6131
+ * @param boolean $unqualified a kludge for what should be XML namespace form handling
6132
+ *
6133
+ * @return string value serialized as an XML string
6134
+ * @access private
6135
+ */
6136
+ function serializeType( $name, $type, $value, $use = 'encoded', $encodingStyle = false, $unqualified = false ) {
6137
+ $this->debug( "in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ( $unqualified ? "unqualified" : "qualified" ) );
6138
+ $this->appendDebug( "value=" . $this->varDump( $value ) );
6139
+ if ( $use == 'encoded' && $encodingStyle ) {
6140
+ $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
6141
+ }
6142
+
6143
+ // if a soapval has been supplied, let its type override the WSDL
6144
+ if ( is_object( $value ) && get_class( $value ) == 'soapval' ) {
6145
+ if ( $value->type_ns ) {
6146
+ $type = $value->type_ns . ':' . $value->type;
6147
+ $forceType = true;
6148
+ $this->debug( "in serializeType: soapval overrides type to $type" );
6149
+ } elseif ( $value->type ) {
6150
+ $type = $value->type;
6151
+ $forceType = true;
6152
+ $this->debug( "in serializeType: soapval overrides type to $type" );
6153
+ } else {
6154
+ $forceType = false;
6155
+ $this->debug( "in serializeType: soapval does not override type" );
6156
+ }
6157
+ $attrs = $value->attributes;
6158
+ $value = $value->value;
6159
+ $this->debug( "in serializeType: soapval overrides value to $value" );
6160
+ if ( $attrs ) {
6161
+ if ( ! is_array( $value ) ) {
6162
+ $value['!'] = $value;
6163
+ }
6164
+ foreach ( $attrs as $n => $v ) {
6165
+ $value[ '!' . $n ] = $v;
6166
+ }
6167
+ $this->debug( "in serializeType: soapval provides attributes" );
6168
+ }
6169
+ } else {
6170
+ $forceType = false;
6171
+ }
6172
+
6173
+ $xml = '';
6174
+ if ( strpos( $type, ':' ) ) {
6175
+ $uqType = substr( $type, strrpos( $type, ':' ) + 1 );
6176
+ $ns = substr( $type, 0, strrpos( $type, ':' ) );
6177
+ $this->debug( "in serializeType: got a prefixed type: $uqType, $ns" );
6178
+ if ( $this->getNamespaceFromPrefix( $ns ) ) {
6179
+ $ns = $this->getNamespaceFromPrefix( $ns );
6180
+ $this->debug( "in serializeType: expanded prefixed type: $uqType, $ns" );
6181
+ }
6182
+
6183
+ if ( $ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/' ) {
6184
+ $this->debug( 'in serializeType: type namespace indicates XML Schema or SOAP Encoding type' );
6185
+ if ( $unqualified && $use == 'literal' ) {
6186
+ $elementNS = " xmlns=\"\"";
6187
+ } else {
6188
+ $elementNS = '';
6189
+ }
6190
+ if ( is_null( $value ) ) {
6191
+ if ( $use == 'literal' ) {
6192
+ // TODO: depends on minOccurs
6193
+ $xml = "<$name$elementNS/>";
6194
+ } else {
6195
+ // TODO: depends on nillable, which should be checked before calling this method
6196
+ $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\"/>";
6197
+ }
6198
+ $this->debug( "in serializeType: returning: $xml" );
6199
+
6200
+ return $xml;
6201
+ }
6202
+ if ( $uqType == 'Array' ) {
6203
+ // JBoss/Axis does this sometimes
6204
+ return $this->serialize_val( $value, $name, false, false, false, false, $use );
6205
+ }
6206
+ if ( $uqType == 'boolean' ) {
6207
+ if ( ( is_string( $value ) && $value == 'false' ) || ( ! $value ) ) {
6208
+ $value = 'false';
6209
+ } else {
6210
+ $value = 'true';
6211
+ }
6212
+ }
6213
+ if ( $uqType == 'string' && gettype( $value ) == 'string' ) {
6214
+ $value = $this->expandEntities( $value );
6215
+ }
6216
+ if ( ( $uqType == 'long' || $uqType == 'unsignedLong' ) && gettype( $value ) == 'double' ) {
6217
+ $value = sprintf( "%.0lf", $value );
6218
+ }
6219
+ // it's a scalar
6220
+ // TODO: what about null/nil values?
6221
+ // check type isn't a custom type extending xmlschema namespace
6222
+ if ( ! $this->getTypeDef( $uqType, $ns ) ) {
6223
+ if ( $use == 'literal' ) {
6224
+ if ( $forceType ) {
6225
+ $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\">$value</$name>";
6226
+ } else {
6227
+ $xml = "<$name$elementNS>$value</$name>";
6228
+ }
6229
+ } else {
6230
+ $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\"$encodingStyle>$value</$name>";
6231
+ }
6232
+ $this->debug( "in serializeType: returning: $xml" );
6233
+
6234
+ return $xml;
6235
+ }
6236
+ $this->debug( 'custom type extends XML Schema or SOAP Encoding namespace (yuck)' );
6237
+ } else if ( $ns == 'http://xml.apache.org/xml-soap' ) {
6238
+ $this->debug( 'in serializeType: appears to be Apache SOAP type' );
6239
+ if ( $uqType == 'Map' ) {
6240
+ $tt_prefix = $this->getPrefixFromNamespace( 'http://xml.apache.org/xml-soap' );
6241
+ if ( ! $tt_prefix ) {
6242
+ $this->debug( 'in serializeType: Add namespace for Apache SOAP type' );
6243
+ $tt_prefix = 'ns' . rand( 1000, 9999 );
6244
+ $this->namespaces[ $tt_prefix ] = 'http://xml.apache.org/xml-soap';
6245
+ // force this to be added to usedNamespaces
6246
+ $tt_prefix = $this->getPrefixFromNamespace( 'http://xml.apache.org/xml-soap' );
6247
+ }
6248
+ $contents = '';
6249
+ foreach ( $value as $k => $v ) {
6250
+ $this->debug( "serializing map element: key $k, value $v" );
6251
+ $contents .= '<item>';
6252
+ $contents .= $this->serialize_val( $k, 'key', false, false, false, false, $use );
6253
+ $contents .= $this->serialize_val( $v, 'value', false, false, false, false, $use );
6254
+ $contents .= '</item>';
6255
+ }
6256
+ if ( $use == 'literal' ) {
6257
+ if ( $forceType ) {
6258
+ $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
6259
+ } else {
6260
+ $xml = "<$name>$contents</$name>";
6261
+ }
6262
+ } else {
6263
+ $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
6264
+ }
6265
+ $this->debug( "in serializeType: returning: $xml" );
6266
+
6267
+ return $xml;
6268
+ }
6269
+ $this->debug( 'in serializeType: Apache SOAP type, but only support Map' );
6270
+ }
6271
+ } else {
6272
+ // TODO: should the type be compared to types in XSD, and the namespace
6273
+ // set to XSD if the type matches?
6274
+ $this->debug( "in serializeType: No namespace for type $type" );
6275
+ $ns = '';
6276
+ $uqType = $type;
6277
+ }
6278
+ if ( ! $typeDef = $this->getTypeDef( $uqType, $ns ) ) {
6279
+ $this->setError( "$type ($uqType) is not a supported type." );
6280
+ $this->debug( "in serializeType: $type ($uqType) is not a supported type." );
6281
+
6282
+ return false;
6283
+ } else {
6284
+ $this->debug( "in serializeType: found typeDef" );
6285
+ $this->appendDebug( 'typeDef=' . $this->varDump( $typeDef ) );
6286
+ if ( substr( $uqType, - 1 ) == '^' ) {
6287
+ $uqType = substr( $uqType, 0, - 1 );
6288
+ }
6289
+ }
6290
+ if ( ! isset( $typeDef['phpType'] ) ) {
6291
+ $this->setError( "$type ($uqType) has no phpType." );
6292
+ $this->debug( "in serializeType: $type ($uqType) has no phpType." );
6293
+
6294
+ return false;
6295
+ }
6296
+ $phpType = $typeDef['phpType'];
6297
+ $this->debug( "in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . ( isset( $typeDef['arrayType'] ) ? $typeDef['arrayType'] : '' ) );
6298
+ // if php type == struct, map value to the <all> element names
6299
+ if ( $phpType == 'struct' ) {
6300
+ if ( isset( $typeDef['typeClass'] ) && $typeDef['typeClass'] == 'element' ) {
6301
+ $elementName = $uqType;
6302
+ if ( isset( $typeDef['form'] ) && ( $typeDef['form'] == 'qualified' ) ) {
6303
+ $elementNS = " xmlns=\"$ns\"";
6304
+ } else {
6305
+ $elementNS = " xmlns=\"\"";
6306
+ }
6307
+ } else {
6308
+ $elementName = $name;
6309
+ if ( $unqualified ) {
6310
+ $elementNS = " xmlns=\"\"";
6311
+ } else {
6312
+ $elementNS = '';
6313
+ }
6314
+ }
6315
+ if ( is_null( $value ) ) {
6316
+ if ( $use == 'literal' ) {
6317
+ // TODO: depends on minOccurs and nillable
6318
+ $xml = "<$elementName$elementNS/>";
6319
+ } else {
6320
+ $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\"/>";
6321
+ }
6322
+ $this->debug( "in serializeType: returning: $xml" );
6323
+
6324
+ return $xml;
6325
+ }
6326
+ if ( is_object( $value ) ) {
6327
+ $value = get_object_vars( $value );
6328
+ }
6329
+ if ( is_array( $value ) ) {
6330
+ $elementAttrs = $this->serializeComplexTypeAttributes( $typeDef, $value, $ns, $uqType );
6331
+ if ( $use == 'literal' ) {
6332
+ if ( $forceType ) {
6333
+ $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\">";
6334
+ } else {
6335
+ $xml = "<$elementName$elementNS$elementAttrs>";
6336
+ }
6337
+ } else {
6338
+ $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\"$encodingStyle>";
6339
+ }
6340
+
6341
+ if ( isset( $typeDef['simpleContent'] ) && $typeDef['simpleContent'] == 'true' ) {
6342
+ if ( isset( $value['!'] ) ) {
6343
+ $xml .= $value['!'];
6344
+ $this->debug( "in serializeType: serialized simpleContent for type $type" );
6345
+ } else {
6346
+ $this->debug( "in serializeType: no simpleContent to serialize for type $type" );
6347
+ }
6348
+ } else {
6349
+ // complexContent
6350
+ $xml .= $this->serializeComplexTypeElements( $typeDef, $value, $ns, $uqType, $use, $encodingStyle );
6351
+ }
6352
+ $xml .= "</$elementName>";
6353
+ } else {
6354
+ $this->debug( "in serializeType: phpType is struct, but value is not an array" );
6355
+ $this->setError( "phpType is struct, but value is not an array: see debug output for details" );
6356
+ $xml = '';
6357
+ }
6358
+ } elseif ( $phpType == 'array' ) {
6359
+ if ( isset( $typeDef['form'] ) && ( $typeDef['form'] == 'qualified' ) ) {
6360
+ $elementNS = " xmlns=\"$ns\"";
6361
+ } else {
6362
+ if ( $unqualified ) {
6363
+ $elementNS = " xmlns=\"\"";
6364
+ } else {
6365
+ $elementNS = '';
6366
+ }
6367
+ }
6368
+ if ( is_null( $value ) ) {
6369
+ if ( $use == 'literal' ) {
6370
+ // TODO: depends on minOccurs
6371
+ $xml = "<$name$elementNS/>";
6372
+ } else {
6373
+ $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
6374
+ $this->getPrefixFromNamespace( 'http://schemas.xmlsoap.org/soap/encoding/' ) .
6375
+ ":Array\" " .
6376
+ $this->getPrefixFromNamespace( 'http://schemas.xmlsoap.org/soap/encoding/' ) .
6377
+ ':arrayType="' .
6378
+ $this->getPrefixFromNamespace( $this->getPrefix( $typeDef['arrayType'] ) ) .
6379
+ ':' .
6380
+ $this->getLocalPart( $typeDef['arrayType'] ) . "[0]\"/>";
6381
+ }
6382
+ $this->debug( "in serializeType: returning: $xml" );
6383
+
6384
+ return $xml;
6385
+ }
6386
+ if ( isset( $typeDef['multidimensional'] ) ) {
6387
+ $nv = array();
6388
+ foreach ( $value as $v ) {
6389
+ $cols = ',' . sizeof( $v );
6390
+ $nv = array_merge( $nv, $v );
6391
+ }
6392
+ $value = $nv;
6393
+ } else {
6394
+ $cols = '';
6395
+ }
6396
+ if ( is_array( $value ) && sizeof( $value ) >= 1 ) {
6397
+ $rows = sizeof( $value );
6398
+ $contents = '';
6399
+ foreach ( $value as $k => $v ) {
6400
+ $this->debug( "serializing array element: $k, $v of type: $typeDef[arrayType]" );
6401
+ //if (strpos($typeDef['arrayType'], ':') ) {
6402
+ if ( ! in_array( $typeDef['arrayType'], $this->typemap['http://www.w3.org/2001/XMLSchema'] ) ) {
6403
+ $contents .= $this->serializeType( 'item', $typeDef['arrayType'], $v, $use );
6404
+ } else {
6405
+ $contents .= $this->serialize_val( $v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use );
6406
+ }
6407
+ }
6408
+ } else {
6409
+ $rows = 0;
6410
+ $contents = null;
6411
+ }
6412
+ // TODO: for now, an empty value will be serialized as a zero element
6413
+ // array. Revisit this when coding the handling of null/nil values.
6414
+ if ( $use == 'literal' ) {
6415
+ $xml = "<$name$elementNS>"
6416
+ . $contents
6417
+ . "</$name>";
6418
+ } else {
6419
+ $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace( 'http://schemas.xmlsoap.org/soap/encoding/' ) . ':Array" ' .
6420
+ $this->getPrefixFromNamespace( 'http://schemas.xmlsoap.org/soap/encoding/' )
6421
+ . ':arrayType="'
6422
+ . $this->getPrefixFromNamespace( $this->getPrefix( $typeDef['arrayType'] ) )
6423
+ . ":" . $this->getLocalPart( $typeDef['arrayType'] ) . "[$rows$cols]\">"
6424
+ . $contents
6425
+ . "</$name>";
6426
+ }
6427
+ } elseif ( $phpType == 'scalar' ) {
6428
+ if ( isset( $typeDef['form'] ) && ( $typeDef['form'] == 'qualified' ) ) {
6429
+ $elementNS = " xmlns=\"$ns\"";
6430
+ } else {
6431
+ if ( $unqualified ) {
6432
+ $elementNS = " xmlns=\"\"";
6433
+ } else {
6434
+ $elementNS = '';
6435
+ }
6436
+ }
6437
+ if ( $use == 'literal' ) {
6438
+ if ( $forceType ) {
6439
+ $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\">$value</$name>";
6440
+ } else {
6441
+ $xml = "<$name$elementNS>$value</$name>";
6442
+ }
6443
+ } else {
6444
+ $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\"$encodingStyle>$value</$name>";
6445
+ }
6446
+ }
6447
+ $this->debug( "in serializeType: returning: $xml" );
6448
+
6449
+ return $xml;
6450
+ }
6451
+
6452
+ /**
6453
+ * serializes the attributes for a complexType
6454
+ *
6455
+ * @param array $typeDef our internal representation of an XML schema type (or element)
6456
+ * @param mixed $value a native PHP value (parameter value)
6457
+ * @param string $ns the namespace of the type
6458
+ * @param string $uqType the local part of the type
6459
+ *
6460
+ * @return string value serialized as an XML string
6461
+ * @access private
6462
+ */
6463
+ function serializeComplexTypeAttributes( $typeDef, $value, $ns, $uqType ) {
6464
+ $this->debug( "serializeComplexTypeAttributes for XML Schema type $ns:$uqType" );
6465
+ $xml = '';
6466
+ if ( isset( $typeDef['extensionBase'] ) ) {
6467
+ $nsx = $this->getPrefix( $typeDef['extensionBase'] );
6468
+ $uqTypex = $this->getLocalPart( $typeDef['extensionBase'] );
6469
+ if ( $this->getNamespaceFromPrefix( $nsx ) ) {
6470
+ $nsx = $this->getNamespaceFromPrefix( $nsx );
6471
+ }
6472
+ if ( $typeDefx = $this->getTypeDef( $uqTypex, $nsx ) ) {
6473
+ $this->debug( "serialize attributes for extension base $nsx:$uqTypex" );
6474
+ $xml .= $this->serializeComplexTypeAttributes( $typeDefx, $value, $nsx, $uqTypex );
6475
+ } else {
6476
+ $this->debug( "extension base $nsx:$uqTypex is not a supported type" );
6477
+ }
6478
+ }
6479
+ if ( isset( $typeDef['attrs'] ) && is_array( $typeDef['attrs'] ) ) {
6480
+ $this->debug( "serialize attributes for XML Schema type $ns:$uqType" );
6481
+ if ( is_array( $value ) ) {
6482
+ $xvalue = $value;
6483
+ } elseif ( is_object( $value ) ) {
6484
+ $xvalue = get_object_vars( $value );
6485
+ } else {
6486
+ $this->debug( "value is neither an array nor an object for XML Schema type $ns:$uqType" );
6487
+ $xvalue = array();
6488
+ }
6489
+ foreach ( $typeDef['attrs'] as $aName => $attrs ) {
6490
+ if ( isset( $xvalue[ '!' . $aName ] ) ) {
6491
+ $xname = '!' . $aName;
6492
+ $this->debug( "value provided for attribute $aName with key $xname" );
6493
+ } elseif ( isset( $xvalue[ $aName ] ) ) {
6494
+ $xname = $aName;
6495
+ $this->debug( "value provided for attribute $aName with key $xname" );
6496
+ } elseif ( isset( $attrs['default'] ) ) {
6497
+ $xname = '!' . $aName;
6498
+ $xvalue[ $xname ] = $attrs['default'];
6499
+ $this->debug( 'use default value of ' . $xvalue[ $aName ] . ' for attribute ' . $aName );
6500
+ } else {
6501
+ $xname = '';
6502
+ $this->debug( "no value provided for attribute $aName" );
6503
+ }
6504
+ if ( $xname ) {
6505
+ $xml .= " $aName=\"" . $this->expandEntities( $xvalue[ $xname ] ) . "\"";
6506
+ }
6507
+ }
6508
+ } else {
6509
+ $this->debug( "no attributes to serialize for XML Schema type $ns:$uqType" );
6510
+ }
6511
+
6512
+ return $xml;
6513
+ }
6514
+
6515
+ /**
6516
+ * serializes the elements for a complexType
6517
+ *
6518
+ * @param array $typeDef our internal representation of an XML schema type (or element)
6519
+ * @param mixed $value a native PHP value (parameter value)
6520
+ * @param string $ns the namespace of the type
6521
+ * @param string $uqType the local part of the type
6522
+ * @param string $use use for part (encoded|literal)
6523
+ * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
6524
+ *
6525
+ * @return string value serialized as an XML string
6526
+ * @access private
6527
+ */
6528
+ function serializeComplexTypeElements( $typeDef, $value, $ns, $uqType, $use = 'encoded', $encodingStyle = false ) {
6529
+ $this->debug( "in serializeComplexTypeElements for XML Schema type $ns:$uqType" );
6530
+ $xml = '';
6531
+ if ( isset( $typeDef['extensionBase'] ) ) {
6532
+ $nsx = $this->getPrefix( $typeDef['extensionBase'] );
6533
+ $uqTypex = $this->getLocalPart( $typeDef['extensionBase'] );
6534
+ if ( $this->getNamespaceFromPrefix( $nsx ) ) {
6535
+ $nsx = $this->getNamespaceFromPrefix( $nsx );
6536
+ }
6537
+ if ( $typeDefx = $this->getTypeDef( $uqTypex, $nsx ) ) {
6538
+ $this->debug( "serialize elements for extension base $nsx:$uqTypex" );
6539
+ $xml .= $this->serializeComplexTypeElements( $typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle );
6540
+ } else {
6541
+ $this->debug( "extension base $nsx:$uqTypex is not a supported type" );
6542
+ }
6543
+ }
6544
+ if ( isset( $typeDef['elements'] ) && is_array( $typeDef['elements'] ) ) {
6545
+ $this->debug( "in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType" );
6546
+ if ( is_array( $value ) ) {
6547
+ $xvalue = $value;
6548
+ } elseif ( is_object( $value ) ) {
6549
+ $xvalue = get_object_vars( $value );
6550
+ } else {
6551
+ $this->debug( "value is neither an array nor an object for XML Schema type $ns:$uqType" );
6552
+ $xvalue = array();
6553
+ }
6554
+ // toggle whether all elements are present - ideally should validate against schema
6555
+ if ( count( $typeDef['elements'] ) != count( $xvalue ) ) {
6556
+ $optionals = true;
6557
+ }
6558
+ foreach ( $typeDef['elements'] as $eName => $attrs ) {
6559
+ if ( ! isset( $xvalue[ $eName ] ) ) {
6560
+ if ( isset( $attrs['default'] ) ) {
6561
+ $xvalue[ $eName ] = $attrs['default'];
6562
+ $this->debug( 'use default value of ' . $xvalue[ $eName ] . ' for element ' . $eName );
6563
+ }
6564
+ }
6565
+ // if user took advantage of a minOccurs=0, then only serialize named parameters
6566
+ if ( isset( $optionals )
6567
+ && ( ! isset( $xvalue[ $eName ] ) )
6568
+ && ( ( ! isset( $attrs['nillable'] ) ) || $attrs['nillable'] != 'true' )
6569
+ ) {
6570
+ if ( isset( $attrs['minOccurs'] ) && $attrs['minOccurs'] <> '0' ) {
6571
+ $this->debug( "apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs'] );
6572
+ }
6573
+ // do nothing
6574
+ $this->debug( "no value provided for complexType element $eName and element is not nillable, so serialize nothing" );
6575
+ } else {
6576
+ // get value
6577
+ if ( isset( $xvalue[ $eName ] ) ) {
6578
+ $v = $xvalue[ $eName ];
6579
+ } else {
6580
+ $v = null;
6581
+ }
6582
+ if ( isset( $attrs['form'] ) ) {
6583
+ $unqualified = ( $attrs['form'] == 'unqualified' );
6584
+ } else {
6585
+ $unqualified = false;
6586
+ }
6587
+ if ( isset( $attrs['maxOccurs'] ) && ( $attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1 ) && isset( $v ) && is_array( $v ) && $this->isArraySimpleOrStruct( $v ) == 'arraySimple' ) {
6588
+ $vv = $v;
6589
+ foreach ( $vv as $k => $v ) {
6590
+ if ( isset( $attrs['type'] ) || isset( $attrs['ref'] ) ) {
6591
+ // serialize schema-defined type
6592
+ $xml .= $this->serializeType( $eName, isset( $attrs['type'] ) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified );
6593
+ } else {
6594
+ // serialize generic type (can this ever really happen?)
6595
+ $this->debug( "calling serialize_val() for $v, $eName, false, false, false, false, $use" );
6596
+ $xml .= $this->serialize_val( $v, $eName, false, false, false, false, $use );
6597
+ }
6598
+ }
6599
+ } else {
6600
+ if ( is_null( $v ) && isset( $attrs['minOccurs'] ) && $attrs['minOccurs'] == '0' ) {
6601
+ // do nothing
6602
+ } elseif ( is_null( $v ) && isset( $attrs['nillable'] ) && $attrs['nillable'] == 'true' ) {
6603
+ // TODO: serialize a nil correctly, but for now serialize schema-defined type
6604
+ $xml .= $this->serializeType( $eName, isset( $attrs['type'] ) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified );
6605
+ } elseif ( isset( $attrs['type'] ) || isset( $attrs['ref'] ) ) {
6606
+ // serialize schema-defined type
6607
+ $xml .= $this->serializeType( $eName, isset( $attrs['type'] ) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified );
6608
+ } else {
6609
+ // serialize generic type (can this ever really happen?)
6610
+ $this->debug( "calling serialize_val() for $v, $eName, false, false, false, false, $use" );
6611
+ $xml .= $this->serialize_val( $v, $eName, false, false, false, false, $use );
6612
+ }
6613
+ }
6614
+ }
6615
+ }
6616
+ } else {
6617
+ $this->debug( "no elements to serialize for XML Schema type $ns:$uqType" );
6618
+ }
6619
+
6620
+ return $xml;
6621
+ }
6622
+
6623
+ /**
6624
+ * adds an XML Schema complex type to the WSDL types
6625
+ *
6626
+ * @param string $name
6627
+ * @param string $typeClass (complexType|simpleType|attribute)
6628
+ * @param string $phpType currently supported are array and struct (php assoc array)
6629
+ * @param string $compositor (all|sequence|choice)
6630
+ * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
6631
+ * @param array $elements e.g. array ( name => array(name=>'',type=>'') )
6632
+ * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
6633
+ * @param string $arrayType as namespace:name (xsd:string)
6634
+ *
6635
+ * @see nusoap_xmlschema
6636
+ * @access public
6637
+ */
6638
+ function addComplexType( $name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '' ) {
6639
+ if ( count( $elements ) > 0 ) {
6640
+ $eElements = array();
6641
+ foreach ( $elements as $n => $e ) {
6642
+ // expand each element
6643
+ $ee = array();
6644
+ foreach ( $e as $k => $v ) {
6645
+ $k = strpos( $k, ':' ) ? $this->expandQname( $k ) : $k;
6646
+ $v = strpos( $v, ':' ) ? $this->expandQname( $v ) : $v;
6647
+ $ee[ $k ] = $v;
6648
+ }
6649
+ $eElements[ $n ] = $ee;
6650
+ }
6651
+ $elements = $eElements;
6652
+ }
6653
+
6654
+ if ( count( $attrs ) > 0 ) {
6655
+ foreach ( $attrs as $n => $a ) {
6656
+ // expand each attribute
6657
+ foreach ( $a as $k => $v ) {
6658
+ $k = strpos( $k, ':' ) ? $this->expandQname( $k ) : $k;
6659
+ $v = strpos( $v, ':' ) ? $this->expandQname( $v ) : $v;
6660
+ $aa[ $k ] = $v;
6661
+ }
6662
+ $eAttrs[ $n ] = $aa;
6663
+ }
6664
+ $attrs = $eAttrs;
6665
+ }
6666
+
6667
+ $restrictionBase = strpos( $restrictionBase, ':' ) ? $this->expandQname( $restrictionBase ) : $restrictionBase;
6668
+ $arrayType = strpos( $arrayType, ':' ) ? $this->expandQname( $arrayType ) : $arrayType;
6669
+
6670
+ $typens = isset( $this->namespaces['types'] ) ? $this->namespaces['types'] : $this->namespaces['tns'];
6671
+ $this->schemas[ $typens ][0]->addComplexType( $name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType );
6672
+ }
6673
+
6674
+ /**
6675
+ * adds an XML Schema simple type to the WSDL types
6676
+ *
6677
+ * @param string $name
6678
+ * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
6679
+ * @param string $typeClass (should always be simpleType)
6680
+ * @param string $phpType (should always be scalar)
6681
+ * @param array $enumeration array of values
6682
+ *
6683
+ * @see nusoap_xmlschema
6684
+ * @access public
6685
+ */
6686
+ function addSimpleType( $name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array() ) {
6687
+ $restrictionBase = strpos( $restrictionBase, ':' ) ? $this->expandQname( $restrictionBase ) : $restrictionBase;
6688
+
6689
+ $typens = isset( $this->namespaces['types'] ) ? $this->namespaces['types'] : $this->namespaces['tns'];
6690
+ $this->schemas[ $typens ][0]->addSimpleType( $name, $restrictionBase, $typeClass, $phpType, $enumeration );
6691
+ }
6692
+
6693
+ /**
6694
+ * adds an element to the WSDL types
6695
+ *
6696
+ * @param array $attrs attributes that must include name and type
6697
+ *
6698
+ * @see nusoap_xmlschema
6699
+ * @access public
6700
+ */
6701
+ function addElement( $attrs ) {
6702
+ $typens = isset( $this->namespaces['types'] ) ? $this->namespaces['types'] : $this->namespaces['tns'];
6703
+ $this->schemas[ $typens ][0]->addElement( $attrs );
6704
+ }
6705
+
6706
+ /**
6707
+ * register an operation with the server
6708
+ *
6709
+ * @param string $name operation (method) name
6710
+ * @param array $in assoc array of input values: key = param name, value = param type
6711
+ * @param array $out assoc array of output values: key = param name, value = param type
6712
+ * @param string $namespace optional The namespace for the operation
6713
+ * @param string $soapaction optional The soapaction for the operation
6714
+ * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically
6715
+ * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)
6716
+ * @param string $documentation optional The description to include in the WSDL
6717
+ * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
6718
+ *
6719
+ * @access public
6720
+ */
6721
+ function addOperation( $name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = '' ) {
6722
+ if ( $use == 'encoded' && $encodingStyle == '' ) {
6723
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6724
+ }
6725
+
6726
+ if ( $style == 'document' ) {
6727
+ $elements = array();
6728
+ foreach ( $in as $n => $t ) {
6729
+ $elements[ $n ] = array( 'name' => $n, 'type' => $t, 'form' => 'unqualified' );
6730
+ }
6731
+ $this->addComplexType( $name . 'RequestType', 'complexType', 'struct', 'all', '', $elements );
6732
+ $this->addElement( array( 'name' => $name, 'type' => $name . 'RequestType' ) );
6733
+ $in = array( 'parameters' => 'tns:' . $name . '^' );
6734
+
6735
+ $elements = array();
6736
+ foreach ( $out as $n => $t ) {
6737
+ $elements[ $n ] = array( 'name' => $n, 'type' => $t, 'form' => 'unqualified' );
6738
+ }
6739
+ $this->addComplexType( $name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements );
6740
+ $this->addElement( array(
6741
+ 'name' => $name . 'Response',
6742
+ 'type' => $name . 'ResponseType',
6743
+ 'form' => 'qualified'
6744
+ ) );
6745
+ $out = array( 'parameters' => 'tns:' . $name . 'Response' . '^' );
6746
+ }
6747
+
6748
+ // get binding
6749
+ $this->bindings[ $this->serviceName . 'Binding' ]['operations'][ $name ] =
6750
+ array(
6751
+ 'name' => $name,
6752
+ 'binding' => $this->serviceName . 'Binding',
6753
+ 'endpoint' => $this->endpoint,
6754
+ 'soapAction' => $soapaction,
6755
+ 'style' => $style,
6756
+ 'input' => array(
6757
+ 'use' => $use,
6758
+ 'namespace' => $namespace,
6759
+ 'encodingStyle' => $encodingStyle,
6760
+ 'message' => $name . 'Request',
6761
+ 'parts' => $in
6762
+ ),
6763
+ 'output' => array(
6764
+ 'use' => $use,
6765
+ 'namespace' => $namespace,
6766
+ 'encodingStyle' => $encodingStyle,
6767
+ 'message' => $name . 'Response',
6768
+ 'parts' => $out
6769
+ ),
6770
+ 'namespace' => $namespace,
6771
+ 'transport' => 'http://schemas.xmlsoap.org/soap/http',
6772
+ 'documentation' => $documentation
6773
+ );
6774
+ // add portTypes
6775
+ // add messages
6776
+ if ( $in ) {
6777
+ foreach ( $in as $pName => $pType ) {
6778
+ if ( strpos( $pType, ':' ) ) {
6779
+ $pType = $this->getNamespaceFromPrefix( $this->getPrefix( $pType ) ) . ":" . $this->getLocalPart( $pType );
6780
+ }
6781
+ $this->messages[ $name . 'Request' ][ $pName ] = $pType;
6782
+ }
6783
+ } else {
6784
+ $this->messages[ $name . 'Request' ] = '0';
6785
+ }
6786
+ if ( $out ) {
6787
+ foreach ( $out as $pName => $pType ) {
6788
+ if ( strpos( $pType, ':' ) ) {
6789
+ $pType = $this->getNamespaceFromPrefix( $this->getPrefix( $pType ) ) . ":" . $this->getLocalPart( $pType );
6790
+ }
6791
+ $this->messages[ $name . 'Response' ][ $pName ] = $pType;
6792
+ }
6793
+ } else {
6794
+ $this->messages[ $name . 'Response' ] = '0';
6795
+ }
6796
+
6797
+ return true;
6798
+ }
6799
+ }
6800
+
6801
+ ?><?php
6802
+
6803
+
6804
+ /**
6805
+ *
6806
+ * nusoap_parser class parses SOAP XML messages into native PHP values
6807
+ *
6808
+ * @author Dietrich Ayala <dietrich@ganx4.com>
6809
+ * @author Scott Nichol <snichol@users.sourceforge.net>
6810
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
6811
+ * @access public
6812
+ */
6813
+ class nusoap_parser extends nusoap_base {
6814
+
6815
+ var $xml = '';
6816
+ var $xml_encoding = '';
6817
+ var $method = '';
6818
+ var $root_struct = '';
6819
+ var $root_struct_name = '';
6820
+ var $root_struct_namespace = '';
6821
+ var $root_header = '';
6822
+ var $document = ''; // incoming SOAP body (text)
6823
+ // determines where in the message we are (envelope,header,body,method)
6824
+ var $status = '';
6825
+ var $position = 0;
6826
+ var $depth = 0;
6827
+ var $default_namespace = '';
6828
+ var $namespaces = array();
6829
+ var $message = array();
6830
+ var $parent = '';
6831
+ var $fault = false;
6832
+ var $fault_code = '';
6833
+ var $fault_str = '';
6834
+ var $fault_detail = '';
6835
+ var $depth_array = array();
6836
+ var $debug_flag = true;
6837
+ var $soapresponse = null; // parsed SOAP Body
6838
+ var $soapheader = null; // parsed SOAP Header
6839
+ var $responseHeaders = ''; // incoming SOAP headers (text)
6840
+ var $body_position = 0;
6841
+ // for multiref parsing:
6842
+ // array of id => pos
6843
+ var $ids = array();
6844
+ // array of id => hrefs => pos
6845
+ var $multirefs = array();
6846
+ // toggle for auto-decoding element content
6847
+ var $decode_utf8 = true;
6848
+
6849
+ /**
6850
+ * constructor that actually does the parsing
6851
+ *
6852
+ * @param string $xml SOAP message
6853
+ * @param string $encoding character encoding scheme of message
6854
+ * @param string $method method for which XML is parsed (unused?)
6855
+ * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
6856
+ *
6857
+ * @access public
6858
+ */
6859
+ function nusoap_parser( $xml, $encoding = 'UTF-8', $method = '', $decode_utf8 = true ) {
6860
+ parent::nusoap_base();
6861
+ $this->xml = $xml;
6862
+ $this->xml_encoding = $encoding;
6863
+ $this->method = $method;
6864
+ $this->decode_utf8 = $decode_utf8;
6865
+
6866
+ // Check whether content has been read.
6867
+ if ( ! empty( $xml ) ) {
6868
+ // Check XML encoding
6869
+ $pos_xml = strpos( $xml, '<?xml' );
6870
+ if ( $pos_xml !== false ) {
6871
+ $xml_decl = substr( $xml, $pos_xml, strpos( $xml, '?>', $pos_xml + 2 ) - $pos_xml + 1 );
6872
+ if ( preg_match( "/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res ) ) {
6873
+ $xml_encoding = $res[1];
6874
+ if ( strtoupper( $xml_encoding ) != $encoding ) {
6875
+ $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
6876
+ $this->debug( $err );
6877
+ if ( $encoding != 'ISO-8859-1' || strtoupper( $xml_encoding ) != 'UTF-8' ) {
6878
+ $this->setError( $err );
6879
+
6880
+ return;
6881
+ }
6882
+ // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
6883
+ } else {
6884
+ $this->debug( 'Charset from HTTP Content-Type matches encoding from XML declaration' );
6885
+ }
6886
+ } else {
6887
+ $this->debug( 'No encoding specified in XML declaration' );
6888
+ }
6889
+ } else {
6890
+ $this->debug( 'No XML declaration' );
6891
+ }
6892
+ $this->debug( 'Entering nusoap_parser(), length=' . strlen( $xml ) . ', encoding=' . $encoding );
6893
+ // Create an XML parser - why not xml_parser_create_ns?
6894
+ $this->parser = xml_parser_create( $this->xml_encoding );
6895
+ // Set the options for parsing the XML data.
6896
+ //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
6897
+ xml_parser_set_option( $this->parser, XML_OPTION_CASE_FOLDING, 0 );
6898
+ xml_parser_set_option( $this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding );
6899
+ // Set the object for the parser.
6900
+ xml_set_object( $this->parser, $this );
6901
+ // Set the element handlers for the parser.
6902
+ xml_set_element_handler( $this->parser, 'start_element', 'end_element' );
6903
+ xml_set_character_data_handler( $this->parser, 'character_data' );
6904
+
6905
+ // Parse the XML file.
6906
+ if ( ! xml_parse( $this->parser, $xml, true ) ) {
6907
+ // Display an error message.
6908
+ $err = sprintf( 'XML error parsing SOAP payload on line %d: %s',
6909
+ xml_get_current_line_number( $this->parser ),
6910
+ xml_error_string( xml_get_error_code( $this->parser ) ) );
6911
+ $this->debug( $err );
6912
+ $this->debug( "XML payload:\n" . $xml );
6913
+ $this->setError( $err );
6914
+ } else {
6915
+ $this->debug( 'in nusoap_parser ctor, message:' );
6916
+ $this->appendDebug( $this->varDump( $this->message ) );
6917
+ $this->debug( 'parsed successfully, found root struct: ' . $this->root_struct . ' of name ' . $this->root_struct_name );
6918
+ // get final value
6919
+ $this->soapresponse = $this->message[ $this->root_struct ]['result'];
6920
+ // get header value
6921
+ if ( $this->root_header != '' && isset( $this->message[ $this->root_header ]['result'] ) ) {
6922
+ $this->soapheader = $this->message[ $this->root_header ]['result'];
6923
+ }
6924
+ // resolve hrefs/ids
6925
+ if ( sizeof( $this->multirefs ) > 0 ) {
6926
+ foreach ( $this->multirefs as $id => $hrefs ) {
6927
+ $this->debug( 'resolving multirefs for id: ' . $id );
6928
+ $idVal = $this->buildVal( $this->ids[ $id ] );
6929
+ if ( is_array( $idVal ) && isset( $idVal['!id'] ) ) {
6930
+ unset( $idVal['!id'] );
6931
+ }
6932
+ foreach ( $hrefs as $refPos => $ref ) {
6933
+ $this->debug( 'resolving href at pos ' . $refPos );
6934
+ $this->multirefs[ $id ][ $refPos ] = $idVal;
6935
+ }
6936
+ }
6937
+ }
6938
+ }
6939
+ xml_parser_free( $this->parser );
6940
+ } else {
6941
+ $this->debug( 'xml was empty, didn\'t parse!' );
6942
+ $this->setError( 'xml was empty, didn\'t parse!' );
6943
+ }
6944
+ }
6945
+
6946
+ /**
6947
+ * start-element handler
6948
+ *
6949
+ * @param resource $parser XML parser object
6950
+ * @param string $name element name
6951
+ * @param array $attrs associative array of attributes
6952
+ *
6953
+ * @access private
6954
+ */
6955
+ function start_element( $parser, $name, $attrs ) {
6956
+ // position in a total number of elements, starting from 0
6957
+ // update class level pos
6958
+ $pos = $this->position ++;
6959
+ // and set mine
6960
+ $this->message[ $pos ] = array( 'pos' => $pos, 'children' => '', 'cdata' => '' );
6961
+ // depth = how many levels removed from root?
6962
+ // set mine as current global depth and increment global depth value
6963
+ $this->message[ $pos ]['depth'] = $this->depth ++;
6964
+
6965
+ // else add self as child to whoever the current parent is
6966
+ if ( $pos != 0 ) {
6967
+ $this->message[ $this->parent ]['children'] .= '|' . $pos;
6968
+ }
6969
+ // set my parent
6970
+ $this->message[ $pos ]['parent'] = $this->parent;
6971
+ // set self as current parent
6972
+ $this->parent = $pos;
6973
+ // set self as current value for this depth
6974
+ $this->depth_array[ $this->depth ] = $pos;
6975
+ // get element prefix
6976
+ if ( strpos( $name, ':' ) ) {
6977
+ // get ns prefix
6978
+ $prefix = substr( $name, 0, strpos( $name, ':' ) );
6979
+ // get unqualified name
6980
+ $name = substr( strstr( $name, ':' ), 1 );
6981
+ }
6982
+ // set status
6983
+ if ( $name == 'Envelope' && $this->status == '' ) {
6984
+ $this->status = 'envelope';
6985
+ } elseif ( $name == 'Header' && $this->status == 'envelope' ) {
6986
+ $this->root_header = $pos;
6987
+ $this->status = 'header';
6988
+ } elseif ( $name == 'Body' && $this->status == 'envelope' ) {
6989
+ $this->status = 'body';
6990
+ $this->body_position = $pos;
6991
+ // set method
6992
+ } elseif ( $this->status == 'body' && $pos == ( $this->body_position + 1 ) ) {
6993
+ $this->status = 'method';
6994
+ $this->root_struct_name = $name;
6995
+ $this->root_struct = $pos;
6996
+ $this->message[ $pos ]['type'] = 'struct';
6997
+ $this->debug( "found root struct $this->root_struct_name, pos $this->root_struct" );
6998
+ }
6999
+ // set my status
7000
+ $this->message[ $pos ]['status'] = $this->status;
7001
+ // set name
7002
+ $this->message[ $pos ]['name'] = htmlspecialchars( $name );
7003
+ // set attrs
7004
+ $this->message[ $pos ]['attrs'] = $attrs;
7005
+
7006
+ // loop through atts, logging ns and type declarations
7007
+ $attstr = '';
7008
+ foreach ( $attrs as $key => $value ) {
7009
+ $key_prefix = $this->getPrefix( $key );
7010
+ $key_localpart = $this->getLocalPart( $key );
7011
+ // if ns declarations, add to class level array of valid namespaces
7012
+ if ( $key_prefix == 'xmlns' ) {
7013
+ if ( preg_match( '/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/', $value ) ) {
7014
+ $this->XMLSchemaVersion = $value;
7015
+ $this->namespaces['xsd'] = $this->XMLSchemaVersion;
7016
+ $this->namespaces['xsi'] = $this->XMLSchemaVersion . '-instance';
7017
+ }
7018
+ $this->namespaces[ $key_localpart ] = $value;
7019
+ // set method namespace
7020
+ if ( $name == $this->root_struct_name ) {
7021
+ $this->methodNamespace = $value;
7022
+ }
7023
+ // if it's a type declaration, set type
7024
+ } elseif ( $key_localpart == 'type' ) {
7025
+ if ( isset( $this->message[ $pos ]['type'] ) && $this->message[ $pos ]['type'] == 'array' ) {
7026
+ // do nothing: already processed arrayType
7027
+ } else {
7028
+ $value_prefix = $this->getPrefix( $value );
7029
+ $value_localpart = $this->getLocalPart( $value );
7030
+ $this->message[ $pos ]['type'] = $value_localpart;
7031
+ $this->message[ $pos ]['typePrefix'] = $value_prefix;
7032
+ if ( isset( $this->namespaces[ $value_prefix ] ) ) {
7033
+ $this->message[ $pos ]['type_namespace'] = $this->namespaces[ $value_prefix ];
7034
+ } else if ( isset( $attrs[ 'xmlns:' . $value_prefix ] ) ) {
7035
+ $this->message[ $pos ]['type_namespace'] = $attrs[ 'xmlns:' . $value_prefix ];
7036
+ }
7037
+ // should do something here with the namespace of specified type?
7038
+ }
7039
+ } elseif ( $key_localpart == 'arrayType' ) {
7040
+ $this->message[ $pos ]['type'] = 'array';
7041
+ /* do arrayType ereg here
7042
+ [1] arrayTypeValue ::= atype asize
7043
+ [2] atype ::= QName rank*
7044
+ [3] rank ::= '[' (',')* ']'
7045
+ [4] asize ::= '[' length~ ']'
7046
+ [5] length ::= nextDimension* Digit+
7047
+ [6] nextDimension ::= Digit+ ','
7048
+ */
7049
+ $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
7050
+ if ( preg_match( $expr, $value, $regs ) ) {
7051
+ $this->message[ $pos ]['typePrefix'] = $regs[1];
7052
+ $this->message[ $pos ]['arrayTypePrefix'] = $regs[1];
7053
+ if ( isset( $this->namespaces[ $regs[1] ] ) ) {
7054
+ $this->message[ $pos ]['arrayTypeNamespace'] = $this->namespaces[ $regs[1] ];
7055
+ } else if ( isset( $attrs[ 'xmlns:' . $regs[1] ] ) ) {
7056
+ $this->message[ $pos ]['arrayTypeNamespace'] = $attrs[ 'xmlns:' . $regs[1] ];
7057
+ }
7058
+ $this->message[ $pos ]['arrayType'] = $regs[2];
7059
+ $this->message[ $pos ]['arraySize'] = $regs[3];
7060
+ $this->message[ $pos ]['arrayCols'] = $regs[4];
7061
+ }
7062
+ // specifies nil value (or not)
7063
+ } elseif ( $key_localpart == 'nil' ) {
7064
+ $this->message[ $pos ]['nil'] = ( $value == 'true' || $value == '1' );
7065
+ // some other attribute
7066
+ } elseif ( $key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root' ) {
7067
+ $this->message[ $pos ]['xattrs'][ '!' . $key ] = $value;
7068
+ }
7069
+
7070
+ if ( $key == 'xmlns' ) {
7071
+ $this->default_namespace = $value;
7072
+ }
7073
+ // log id
7074
+ if ( $key == 'id' ) {
7075
+ $this->ids[ $value ] = $pos;
7076
+ }
7077
+ // root
7078
+ if ( $key_localpart == 'root' && $value == 1 ) {
7079
+ $this->status = 'method';
7080
+ $this->root_struct_name = $name;
7081
+ $this->root_struct = $pos;
7082
+ $this->debug( "found root struct $this->root_struct_name, pos $pos" );
7083
+ }
7084
+ // for doclit
7085
+ $attstr .= " $key=\"$value\"";
7086
+ }
7087
+ // get namespace - must be done after namespace atts are processed
7088
+ if ( isset( $prefix ) ) {
7089
+ $this->message[ $pos ]['namespace'] = $this->namespaces[ $prefix ];
7090
+ $this->default_namespace = $this->namespaces[ $prefix ];
7091
+ } else {
7092
+ $this->message[ $pos ]['namespace'] = $this->default_namespace;
7093
+ }
7094
+ if ( $this->status == 'header' ) {
7095
+ if ( $this->root_header != $pos ) {
7096
+ $this->responseHeaders .= "<" . ( isset( $prefix ) ? $prefix . ':' : '' ) . "$name$attstr>";
7097
+ }
7098
+ } elseif ( $this->root_struct_name != '' ) {
7099
+ $this->document .= "<" . ( isset( $prefix ) ? $prefix . ':' : '' ) . "$name$attstr>";
7100
+ }
7101
+ }
7102
+
7103
+ /**
7104
+ * end-element handler
7105
+ *
7106
+ * @param resource $parser XML parser object
7107
+ * @param string $name element name
7108
+ *
7109
+ * @access private
7110
+ */
7111
+ function end_element( $parser, $name ) {
7112
+ // position of current element is equal to the last value left in depth_array for my depth
7113
+ $pos = $this->depth_array[ $this->depth -- ];
7114
+
7115
+ // get element prefix
7116
+ if ( strpos( $name, ':' ) ) {
7117
+ // get ns prefix
7118
+ $prefix = substr( $name, 0, strpos( $name, ':' ) );
7119
+ // get unqualified name
7120
+ $name = substr( strstr( $name, ':' ), 1 );
7121
+ }
7122
+
7123
+ // build to native type
7124
+ if ( isset( $this->body_position ) && $pos > $this->body_position ) {
7125
+ // deal w/ multirefs
7126
+ if ( isset( $this->message[ $pos ]['attrs']['href'] ) ) {
7127
+ // get id
7128
+ $id = substr( $this->message[ $pos ]['attrs']['href'], 1 );
7129
+ // add placeholder to href array
7130
+ $this->multirefs[ $id ][ $pos ] = 'placeholder';
7131
+ // add set a reference to it as the result value
7132
+ $this->message[ $pos ]['result'] =& $this->multirefs[ $id ][ $pos ];
7133
+ // build complexType values
7134
+ } elseif ( $this->message[ $pos ]['children'] != '' ) {
7135
+ // if result has already been generated (struct/array)
7136
+ if ( ! isset( $this->message[ $pos ]['result'] ) ) {
7137
+ $this->message[ $pos ]['result'] = $this->buildVal( $pos );
7138
+ }
7139
+ // build complexType values of attributes and possibly simpleContent
7140
+ } elseif ( isset( $this->message[ $pos ]['xattrs'] ) ) {
7141
+ if ( isset( $this->message[ $pos ]['nil'] ) && $this->message[ $pos ]['nil'] ) {
7142
+ $this->message[ $pos ]['xattrs']['!'] = null;
7143
+ } elseif ( isset( $this->message[ $pos ]['cdata'] ) && trim( $this->message[ $pos ]['cdata'] ) != '' ) {
7144
+ if ( isset( $this->message[ $pos ]['type'] ) ) {
7145
+ $this->message[ $pos ]['xattrs']['!'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $pos ]['type'], isset( $this->message[ $pos ]['type_namespace'] ) ? $this->message[ $pos ]['type_namespace'] : '' );
7146
+ } else {
7147
+ $parent = $this->message[ $pos ]['parent'];
7148
+ if ( isset( $this->message[ $parent ]['type'] ) && ( $this->message[ $parent ]['type'] == 'array' ) && isset( $this->message[ $parent ]['arrayType'] ) ) {
7149
+ $this->message[ $pos ]['xattrs']['!'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $parent ]['arrayType'], isset( $this->message[ $parent ]['arrayTypeNamespace'] ) ? $this->message[ $parent ]['arrayTypeNamespace'] : '' );
7150
+ } else {
7151
+ $this->message[ $pos ]['xattrs']['!'] = $this->message[ $pos ]['cdata'];
7152
+ }
7153
+ }
7154
+ }
7155
+ $this->message[ $pos ]['result'] = $this->message[ $pos ]['xattrs'];
7156
+ // set value of simpleType (or nil complexType)
7157
+ } else {
7158
+ //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
7159
+ if ( isset( $this->message[ $pos ]['nil'] ) && $this->message[ $pos ]['nil'] ) {
7160
+ $this->message[ $pos ]['xattrs']['!'] = null;
7161
+ } elseif ( isset( $this->message[ $pos ]['type'] ) ) {
7162
+ $this->message[ $pos ]['result'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $pos ]['type'], isset( $this->message[ $pos ]['type_namespace'] ) ? $this->message[ $pos ]['type_namespace'] : '' );
7163
+ } else {
7164
+ $parent = $this->message[ $pos ]['parent'];
7165
+ if ( isset( $this->message[ $parent ]['type'] ) && ( $this->message[ $parent ]['type'] == 'array' ) && isset( $this->message[ $parent ]['arrayType'] ) ) {
7166
+ $this->message[ $pos ]['result'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $parent ]['arrayType'], isset( $this->message[ $parent ]['arrayTypeNamespace'] ) ? $this->message[ $parent ]['arrayTypeNamespace'] : '' );
7167
+ } else {
7168
+ $this->message[ $pos ]['result'] = $this->message[ $pos ]['cdata'];
7169
+ }
7170
+ }
7171
+
7172
+ /* add value to parent's result, if parent is struct/array
7173
+ $parent = $this->message[$pos]['parent'];
7174
+ if($this->message[$parent]['type'] != 'map'){
7175
+ if(strtolower($this->message[$parent]['type']) == 'array'){
7176
+ $this->message[$parent]['result'][] = $this->message[$pos]['result'];
7177
+ } else {
7178
+ $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
7179
+ }
7180
+ }
7181
+ */
7182
+ }
7183
+ }
7184
+
7185
+ // for doclit
7186
+ if ( $this->status == 'header' ) {
7187
+ if ( $this->root_header != $pos ) {
7188
+ $this->responseHeaders .= "</" . ( isset( $prefix ) ? $prefix . ':' : '' ) . "$name>";
7189
+ }
7190
+ } elseif ( $pos >= $this->root_struct ) {
7191
+ $this->document .= "</" . ( isset( $prefix ) ? $prefix . ':' : '' ) . "$name>";
7192
+ }
7193
+ // switch status
7194
+ if ( $pos == $this->root_struct ) {
7195
+ $this->status = 'body';
7196
+ $this->root_struct_namespace = $this->message[ $pos ]['namespace'];
7197
+ } elseif ( $pos == $this->root_header ) {
7198
+ $this->status = 'envelope';
7199
+ } elseif ( $name == 'Body' && $this->status == 'body' ) {
7200
+ $this->status = 'envelope';
7201
+ } elseif ( $name == 'Header' && $this->status == 'header' ) { // will never happen
7202
+ $this->status = 'envelope';
7203
+ } elseif ( $name == 'Envelope' && $this->status == 'envelope' ) {
7204
+ $this->status = '';
7205
+ }
7206
+ // set parent back to my parent
7207
+ $this->parent = $this->message[ $pos ]['parent'];
7208
+ }
7209
+
7210
+ /**
7211
+ * element content handler
7212
+ *
7213
+ * @param resource $parser XML parser object
7214
+ * @param string $data element content
7215
+ *
7216
+ * @access private
7217
+ */
7218
+ function character_data( $parser, $data ) {
7219
+ $pos = $this->depth_array[ $this->depth ];
7220
+ if ( $this->xml_encoding == 'UTF-8' ) {
7221
+ // TODO: add an option to disable this for folks who want
7222
+ // raw UTF-8 that, e.g., might not map to iso-8859-1
7223
+ // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
7224
+ if ( $this->decode_utf8 ) {
7225
+ $data = utf8_decode( $data );
7226
+ }
7227
+ }
7228
+ $this->message[ $pos ]['cdata'] .= $data;
7229
+ // for doclit
7230
+ if ( $this->status == 'header' ) {
7231
+ $this->responseHeaders .= $data;
7232
+ } else {
7233
+ $this->document .= $data;
7234
+ }
7235
+ }
7236
+
7237
+ /**
7238
+ * get the parsed message (SOAP Body)
7239
+ *
7240
+ * @return mixed
7241
+ * @access public
7242
+ * @deprecated use get_soapbody instead
7243
+ */
7244
+ function get_response() {
7245
+ return $this->soapresponse;
7246
+ }
7247
+
7248
+ /**
7249
+ * get the parsed SOAP Body (NULL if there was none)
7250
+ *
7251
+ * @return mixed
7252
+ * @access public
7253
+ */
7254
+ function get_soapbody() {
7255
+ return $this->soapresponse;
7256
+ }
7257
+
7258
+ /**
7259
+ * get the parsed SOAP Header (NULL if there was none)
7260
+ *
7261
+ * @return mixed
7262
+ * @access public
7263
+ */
7264
+ function get_soapheader() {
7265
+ return $this->soapheader;
7266
+ }
7267
+
7268
+ /**
7269
+ * get the unparsed SOAP Header
7270
+ *
7271
+ * @return string XML or empty if no Header
7272
+ * @access public
7273
+ */
7274
+ function getHeaders() {
7275
+ return $this->responseHeaders;
7276
+ }
7277
+
7278
+ /**
7279
+ * decodes simple types into PHP variables
7280
+ *
7281
+ * @param string $value value to decode
7282
+ * @param string $type XML type to decode
7283
+ * @param string $typens XML type namespace to decode
7284
+ *
7285
+ * @return mixed PHP value
7286
+ * @access private
7287
+ */
7288
+ function decodeSimple( $value, $type, $typens ) {
7289
+ // TODO: use the namespace!
7290
+ if ( ( ! isset( $type ) ) || $type == 'string' || $type == 'long' || $type == 'unsignedLong' ) {
7291
+ return (string) $value;
7292
+ }
7293
+ if ( $type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte' ) {
7294
+ return (int) $value;
7295
+ }
7296
+ if ( $type == 'float' || $type == 'double' || $type == 'decimal' ) {
7297
+ return (double) $value;
7298
+ }
7299
+ if ( $type == 'boolean' ) {
7300
+ if ( strtolower( $value ) == 'false' || strtolower( $value ) == 'f' ) {
7301
+ return false;
7302
+ }
7303
+
7304
+ return (boolean) $value;
7305
+ }
7306
+ if ( $type == 'base64' || $type == 'base64Binary' ) {
7307
+ $this->debug( 'Decode base64 value' );
7308
+
7309
+ return base64_decode( $value );
7310
+ }
7311
+ // obscure numeric types
7312
+ if ( $type == 'nonPositiveInteger' || $type == 'negativeInteger'
7313
+ || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
7314
+ || $type == 'unsignedInt'
7315
+ || $type == 'unsignedShort' || $type == 'unsignedByte' ) {
7316
+ return (int) $value;
7317
+ }
7318
+ // bogus: parser treats array with no elements as a simple type
7319
+ if ( $type == 'array' ) {
7320
+ return array();
7321
+ }
7322
+
7323
+ // everything else
7324
+ return (string) $value;
7325
+ }
7326
+
7327
+ /**
7328
+ * builds response structures for compound values (arrays/structs)
7329
+ * and scalars
7330
+ *
7331
+ * @param integer $pos position in node tree
7332
+ *
7333
+ * @return mixed PHP value
7334
+ * @access private
7335
+ */
7336
+ function buildVal( $pos ) {
7337
+ if ( ! isset( $this->message[ $pos ]['type'] ) ) {
7338
+ $this->message[ $pos ]['type'] = '';
7339
+ }
7340
+ $this->debug( 'in buildVal() for ' . $this->message[ $pos ]['name'] . "(pos $pos) of type " . $this->message[ $pos ]['type'] );
7341
+ // if there are children...
7342
+ if ( $this->message[ $pos ]['children'] != '' ) {
7343
+ $this->debug( 'in buildVal, there are children' );
7344
+ $children = explode( '|', $this->message[ $pos ]['children'] );
7345
+ array_shift( $children ); // knock off empty
7346
+ // md array
7347
+ if ( isset( $this->message[ $pos ]['arrayCols'] ) && $this->message[ $pos ]['arrayCols'] != '' ) {
7348
+ $r = 0; // rowcount
7349
+ $c = 0; // colcount
7350
+ foreach ( $children as $child_pos ) {
7351
+ $this->debug( "in buildVal, got an MD array element: $r, $c" );
7352
+ $params[ $r ][] = $this->message[ $child_pos ]['result'];
7353
+ $c ++;
7354
+ if ( $c == $this->message[ $pos ]['arrayCols'] ) {
7355
+ $c = 0;
7356
+ $r ++;
7357
+ }
7358
+ }
7359
+ // array
7360
+ } elseif ( $this->message[ $pos ]['type'] == 'array' || $this->message[ $pos ]['type'] == 'Array' ) {
7361
+ $this->debug( 'in buildVal, adding array ' . $this->message[ $pos ]['name'] );
7362
+ foreach ( $children as $child_pos ) {
7363
+ $params[] = &$this->message[ $child_pos ]['result'];
7364
+ }
7365
+ // apache Map type: java hashtable
7366
+ } elseif ( $this->message[ $pos ]['type'] == 'Map' && $this->message[ $pos ]['type_namespace'] == 'http://xml.apache.org/xml-soap' ) {
7367
+ $this->debug( 'in buildVal, Java Map ' . $this->message[ $pos ]['name'] );
7368
+ foreach ( $children as $child_pos ) {
7369
+ $kv = explode( "|", $this->message[ $child_pos ]['children'] );
7370
+ $params[ $this->message[ $kv[1] ]['result'] ] = &$this->message[ $kv[2] ]['result'];
7371
+ }
7372
+ // generic compound type
7373
+ //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
7374
+ } else {
7375
+ // Apache Vector type: treat as an array
7376
+ $this->debug( 'in buildVal, adding Java Vector or generic compound type ' . $this->message[ $pos ]['name'] );
7377
+ if ( $this->message[ $pos ]['type'] == 'Vector' && $this->message[ $pos ]['type_namespace'] == 'http://xml.apache.org/xml-soap' ) {
7378
+ $notstruct = 1;
7379
+ } else {
7380
+ $notstruct = 0;
7381
+ }
7382
+ //
7383
+ foreach ( $children as $child_pos ) {
7384
+ if ( $notstruct ) {
7385
+ $params[] = &$this->message[ $child_pos ]['result'];
7386
+ } else {
7387
+ if ( isset( $params[ $this->message[ $child_pos ]['name'] ] ) ) {
7388
+ // de-serialize repeated element name into an array
7389
+ if ( ( ! is_array( $params[ $this->message[ $child_pos ]['name'] ] ) ) || ( ! isset( $params[ $this->message[ $child_pos ]['name'] ][0] ) ) ) {
7390
+ $params[ $this->message[ $child_pos ]['name'] ] = array( $params[ $this->message[ $child_pos ]['name'] ] );
7391
+ }
7392
+ $params[ $this->message[ $child_pos ]['name'] ][] = &$this->message[ $child_pos ]['result'];
7393
+ } else {
7394
+ $params[ $this->message[ $child_pos ]['name'] ] = &$this->message[ $child_pos ]['result'];
7395
+ }
7396
+ }
7397
+ }
7398
+ }
7399
+ if ( isset( $this->message[ $pos ]['xattrs'] ) ) {
7400
+ $this->debug( 'in buildVal, handling attributes' );
7401
+ foreach ( $this->message[ $pos ]['xattrs'] as $n => $v ) {
7402
+ $params[ $n ] = $v;
7403
+ }
7404
+ }
7405
+ // handle simpleContent
7406
+ if ( isset( $this->message[ $pos ]['cdata'] ) && trim( $this->message[ $pos ]['cdata'] ) != '' ) {
7407
+ $this->debug( 'in buildVal, handling simpleContent' );
7408
+ if ( isset( $this->message[ $pos ]['type'] ) ) {
7409
+ $params['!'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $pos ]['type'], isset( $this->message[ $pos ]['type_namespace'] ) ? $this->message[ $pos ]['type_namespace'] : '' );
7410
+ } else {
7411
+ $parent = $this->message[ $pos ]['parent'];
7412
+ if ( isset( $this->message[ $parent ]['type'] ) && ( $this->message[ $parent ]['type'] == 'array' ) && isset( $this->message[ $parent ]['arrayType'] ) ) {
7413
+ $params['!'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $parent ]['arrayType'], isset( $this->message[ $parent ]['arrayTypeNamespace'] ) ? $this->message[ $parent ]['arrayTypeNamespace'] : '' );
7414
+ } else {
7415
+ $params['!'] = $this->message[ $pos ]['cdata'];
7416
+ }
7417
+ }
7418
+ }
7419
+ $ret = is_array( $params ) ? $params : array();
7420
+ $this->debug( 'in buildVal, return:' );
7421
+ $this->appendDebug( $this->varDump( $ret ) );
7422
+
7423
+ return $ret;
7424
+ } else {
7425
+ $this->debug( 'in buildVal, no children, building scalar' );
7426
+ $cdata = isset( $this->message[ $pos ]['cdata'] ) ? $this->message[ $pos ]['cdata'] : '';
7427
+ if ( isset( $this->message[ $pos ]['type'] ) ) {
7428
+ $ret = $this->decodeSimple( $cdata, $this->message[ $pos ]['type'], isset( $this->message[ $pos ]['type_namespace'] ) ? $this->message[ $pos ]['type_namespace'] : '' );
7429
+ $this->debug( "in buildVal, return: $ret" );
7430
+
7431
+ return $ret;
7432
+ }
7433
+ $parent = $this->message[ $pos ]['parent'];
7434
+ if ( isset( $this->message[ $parent ]['type'] ) && ( $this->message[ $parent ]['type'] == 'array' ) && isset( $this->message[ $parent ]['arrayType'] ) ) {
7435
+ $ret = $this->decodeSimple( $cdata, $this->message[ $parent ]['arrayType'], isset( $this->message[ $parent ]['arrayTypeNamespace'] ) ? $this->message[ $parent ]['arrayTypeNamespace'] : '' );
7436
+ $this->debug( "in buildVal, return: $ret" );
7437
+
7438
+ return $ret;
7439
+ }
7440
+ $ret = $this->message[ $pos ]['cdata'];
7441
+ $this->debug( "in buildVal, return: $ret" );
7442
+
7443
+ return $ret;
7444
+ }
7445
+ }
7446
+ }
7447
+
7448
+ /**
7449
+ * Backward compatibility
7450
+ */
7451
+ class soap_parser extends nusoap_parser {
7452
+ }
7453
+
7454
+ ?><?php
7455
+
7456
+
7457
+ /**
7458
+ *
7459
+ * [nu]soapclient higher level class for easy usage.
7460
+ *
7461
+ * usage:
7462
+ *
7463
+ * // instantiate client with server info
7464
+ * $soapclient = new nusoap_client( string path [ ,mixed wsdl] );
7465
+ *
7466
+ * // call method, get results
7467
+ * echo $soapclient->call( string methodname [ ,array parameters] );
7468
+ *
7469
+ * // bye bye client
7470
+ * unset($soapclient);
7471
+ *
7472
+ * @author Dietrich Ayala <dietrich@ganx4.com>
7473
+ * @author Scott Nichol <snichol@users.sourceforge.net>
7474
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
7475
+ * @access public
7476
+ */
7477
+ class nusoap_client extends nusoap_base {
7478
+
7479
+ var $username = ''; // Username for HTTP authentication
7480
+ var $password = ''; // Password for HTTP authentication
7481
+ var $authtype = ''; // Type of HTTP authentication
7482
+ var $certRequest = array(); // Certificate for HTTP SSL authentication
7483
+ var $requestHeaders = false; // SOAP headers in request (text)
7484
+ var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
7485
+ var $responseHeader = null; // SOAP Header from response (parsed)
7486
+ var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
7487
+ var $endpoint;
7488
+ var $forceEndpoint = ''; // overrides WSDL endpoint
7489
+ var $proxyhost = '';
7490
+ var $proxyport = '';
7491
+ var $proxyusername = '';
7492
+ var $proxypassword = '';
7493
+ var $portName = ''; // port name to use in WSDL
7494
+ var $xml_encoding = ''; // character set encoding of incoming (response) messages
7495
+ var $http_encoding = false;
7496
+ var $timeout = 0; // HTTP connection timeout
7497
+ var $response_timeout = 30; // HTTP response timeout
7498
+ var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error
7499
+ var $persistentConnection = false;
7500
+ var $defaultRpcParams = false; // This is no longer used
7501
+ var $request = ''; // HTTP request
7502
+ var $response = ''; // HTTP response
7503
+ var $responseData = ''; // SOAP payload of response
7504
+ var $cookies = array(); // Cookies from response or for request
7505
+ var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
7506
+ var $operations = array(); // WSDL operations, empty for WSDL initialization error
7507
+ var $curl_options = array(); // User-specified cURL options
7508
+ var $bindingType = ''; // WSDL operation binding type
7509
+ var $use_curl = false; // whether to always try to use cURL
7510
+
7511
+ /*
7512
+ * fault related variables
7513
+ */
7514
+ /**
7515
+ * @var fault
7516
+ * @access public
7517
+ */
7518
+ var $fault;
7519
+ /**
7520
+ * @var faultcode
7521
+ * @access public
7522
+ */
7523
+ var $faultcode;
7524
+ /**
7525
+ * @var faultstring
7526
+ * @access public
7527
+ */
7528
+ var $faultstring;
7529
+ /**
7530
+ * @var faultdetail
7531
+ * @access public
7532
+ */
7533
+ var $faultdetail;
7534
+
7535
+ /**
7536
+ * constructor
7537
+ *
7538
+ * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object)
7539
+ * @param mixed $wsdl optional, set to 'wsdl' or true if using WSDL
7540
+ * @param string $proxyhost optional
7541
+ * @param string $proxyport optional
7542
+ * @param string $proxyusername optional
7543
+ * @param string $proxypassword optional
7544
+ * @param integer $timeout set the connection timeout
7545
+ * @param integer $response_timeout set the response timeout
7546
+ * @param string $portName optional portName in WSDL document
7547
+ *
7548
+ * @access public
7549
+ */
7550
+ function nusoap_client( $endpoint, $wsdl = false, $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = '' ) {
7551
+ parent::nusoap_base();
7552
+ $this->endpoint = $endpoint;
7553
+ $this->proxyhost = $proxyhost;
7554
+ $this->proxyport = $proxyport;
7555
+ $this->proxyusername = $proxyusername;
7556
+ $this->proxypassword = $proxypassword;
7557
+ $this->timeout = $timeout;
7558
+ $this->response_timeout = $response_timeout;
7559
+ $this->portName = $portName;
7560
+
7561
+ $this->debug( "ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout" );
7562
+ $this->appendDebug( 'endpoint=' . $this->varDump( $endpoint ) );
7563
+
7564
+ // make values
7565
+ if ( $wsdl ) {
7566
+ if ( is_object( $endpoint ) && ( get_class( $endpoint ) == 'wsdl' ) ) {
7567
+ $this->wsdl = $endpoint;
7568
+ $this->endpoint = $this->wsdl->wsdl;
7569
+ $this->wsdlFile = $this->endpoint;
7570
+ $this->debug( 'existing wsdl instance created from ' . $this->endpoint );
7571
+ $this->checkWSDL();
7572
+ } else {
7573
+ $this->wsdlFile = $this->endpoint;
7574
+ $this->wsdl = null;
7575
+ $this->debug( 'will use lazy evaluation of wsdl from ' . $this->endpoint );
7576
+ }
7577
+ $this->endpointType = 'wsdl';
7578
+ } else {
7579
+ $this->debug( "instantiate SOAP with endpoint at $endpoint" );
7580
+ $this->endpointType = 'soap';
7581
+ }
7582
+ }
7583
+
7584
+ /**
7585
+ * calls method, returns PHP native type
7586
+ *
7587
+ * @param string $operation SOAP server URL or path
7588
+ * @param mixed $params An array, associative or simple, of the parameters
7589
+ * for the method call, or a string that is the XML
7590
+ * for the call. For rpc style, this call will
7591
+ * wrap the XML in a tag named after the method, as
7592
+ * well as the SOAP Envelope and Body. For document
7593
+ * style, this will only wrap with the Envelope and Body.
7594
+ * IMPORTANT: when using an array with document style,
7595
+ * in which case there
7596
+ * is really one parameter, the root of the fragment
7597
+ * used in the call, which encloses what programmers
7598
+ * normally think of parameters. A parameter array
7599
+ * *must* include the wrapper.
7600
+ * @param string $namespace optional method namespace (WSDL can override)
7601
+ * @param string $soapAction optional SOAPAction value (WSDL can override)
7602
+ * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
7603
+ * @param boolean $rpcParams optional (no longer used)
7604
+ * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override)
7605
+ * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override)
7606
+ *
7607
+ * @return mixed response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors
7608
+ * @access public
7609
+ */
7610
+ function call( $operation, $params = array(), $namespace = 'http://tempuri.org', $soapAction = '', $headers = false, $rpcParams = null, $style = 'rpc', $use = 'encoded' ) {
7611
+ $this->operation = $operation;
7612
+ $this->fault = false;
7613
+ $this->setError( '' );
7614
+ $this->request = '';
7615
+ $this->response = '';
7616
+ $this->responseData = '';
7617
+ $this->faultstring = '';
7618
+ $this->faultcode = '';
7619
+ $this->opData = array();
7620
+
7621
+ $this->debug( "call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType" );
7622
+ $this->appendDebug( 'params=' . $this->varDump( $params ) );
7623
+ $this->appendDebug( 'headers=' . $this->varDump( $headers ) );
7624
+ if ( $headers ) {
7625
+ $this->requestHeaders = $headers;
7626
+ }
7627
+ if ( $this->endpointType == 'wsdl' && is_null( $this->wsdl ) ) {
7628
+ $this->loadWSDL();
7629
+ if ( $this->getError() ) {
7630
+ return false;
7631
+ }
7632
+ }
7633
+ // serialize parameters
7634
+ if ( $this->endpointType == 'wsdl' && $opData = $this->getOperationData( $operation ) ) {
7635
+ // use WSDL for operation
7636
+ $this->opData = $opData;
7637
+ $this->debug( "found operation" );
7638
+ $this->appendDebug( 'opData=' . $this->varDump( $opData ) );
7639
+ if ( isset( $opData['soapAction'] ) ) {
7640
+ $soapAction = $opData['soapAction'];
7641
+ }
7642
+ if ( ! $this->forceEndpoint ) {
7643
+ $this->endpoint = $opData['endpoint'];
7644
+ } else {
7645
+ $this->endpoint = $this->forceEndpoint;
7646
+ }
7647
+ $namespace = isset( $opData['input']['namespace'] ) ? $opData['input']['namespace'] : $namespace;
7648
+ $style = $opData['style'];
7649
+ $use = $opData['input']['use'];
7650
+ // add ns to ns array
7651
+ if ( $namespace != '' && ! isset( $this->wsdl->namespaces[ $namespace ] ) ) {
7652
+ $nsPrefix = 'ns' . rand( 1000, 9999 );
7653
+ $this->wsdl->namespaces[ $nsPrefix ] = $namespace;
7654
+ }
7655
+ $nsPrefix = $this->wsdl->getPrefixFromNamespace( $namespace );
7656
+ // serialize payload
7657
+ if ( is_string( $params ) ) {
7658
+ $this->debug( "serializing param string for WSDL operation $operation" );
7659
+ $payload = $params;
7660
+ } elseif ( is_array( $params ) ) {
7661
+ $this->debug( "serializing param array for WSDL operation $operation" );
7662
+ $payload = $this->wsdl->serializeRPCParameters( $operation, 'input', $params, $this->bindingType );
7663
+ } else {
7664
+ $this->debug( 'params must be array or string' );
7665
+ $this->setError( 'params must be array or string' );
7666
+
7667
+ return false;
7668
+ }
7669
+ $usedNamespaces = $this->wsdl->usedNamespaces;
7670
+ if ( isset( $opData['input']['encodingStyle'] ) ) {
7671
+ $encodingStyle = $opData['input']['encodingStyle'];
7672
+ } else {
7673
+ $encodingStyle = '';
7674
+ }
7675
+ $this->appendDebug( $this->wsdl->getDebug() );
7676
+ $this->wsdl->clearDebug();
7677
+ if ( $errstr = $this->wsdl->getError() ) {
7678
+ $this->debug( 'got wsdl error: ' . $errstr );
7679
+ $this->setError( 'wsdl error: ' . $errstr );
7680
+
7681
+ return false;
7682
+ }
7683
+ } elseif ( $this->endpointType == 'wsdl' ) {
7684
+ // operation not in WSDL
7685
+ $this->appendDebug( $this->wsdl->getDebug() );
7686
+ $this->wsdl->clearDebug();
7687
+ $this->setError( 'operation ' . $operation . ' not present in WSDL.' );
7688
+ $this->debug( "operation '$operation' not present in WSDL." );
7689
+
7690
+ return false;
7691
+ } else {
7692
+ // no WSDL
7693
+ //$this->namespaces['ns1'] = $namespace;
7694
+ $nsPrefix = 'ns' . rand( 1000, 9999 );
7695
+ // serialize
7696
+ $payload = '';
7697
+ if ( is_string( $params ) ) {
7698
+ $this->debug( "serializing param string for operation $operation" );
7699
+ $payload = $params;
7700
+ } elseif ( is_array( $params ) ) {
7701
+ $this->debug( "serializing param array for operation $operation" );
7702
+ foreach ( $params as $k => $v ) {
7703
+ $payload .= $this->serialize_val( $v, $k, false, false, false, false, $use );
7704
+ }
7705
+ } else {
7706
+ $this->debug( 'params must be array or string' );
7707
+ $this->setError( 'params must be array or string' );
7708
+
7709
+ return false;
7710
+ }
7711
+ $usedNamespaces = array();
7712
+ if ( $use == 'encoded' ) {
7713
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7714
+ } else {
7715
+ $encodingStyle = '';
7716
+ }
7717
+ }
7718
+ // wrap RPC calls with method element
7719
+ if ( $style == 'rpc' ) {
7720
+ if ( $use == 'literal' ) {
7721
+ $this->debug( "wrapping RPC request with literal method element" );
7722
+ if ( $namespace ) {
7723
+ // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
7724
+ $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7725
+ $payload .
7726
+ "</$nsPrefix:$operation>";
7727
+ } else {
7728
+ $payload = "<$operation>" . $payload . "</$operation>";
7729
+ }
7730
+ } else {
7731
+ $this->debug( "wrapping RPC request with encoded method element" );
7732
+ if ( $namespace ) {
7733
+ $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7734
+ $payload .
7735
+ "</$nsPrefix:$operation>";
7736
+ } else {
7737
+ $payload = "<$operation>" .
7738
+ $payload .
7739
+ "</$operation>";
7740
+ }
7741
+ }
7742
+ }
7743
+ // serialize envelope
7744
+ $soapmsg = $this->serializeEnvelope( $payload, $this->requestHeaders, $usedNamespaces, $style, $use, $encodingStyle );
7745
+ $this->debug( "endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle" );
7746
+ $this->debug( 'SOAP message length=' . strlen( $soapmsg ) . ' contents (max 1000 bytes)=' . substr( $soapmsg, 0, 1000 ) );
7747
+ // send
7748
+ $return = $this->send( $this->getHTTPBody( $soapmsg ), $soapAction, $this->timeout, $this->response_timeout );
7749
+ if ( $errstr = $this->getError() ) {
7750
+ $this->debug( 'Error: ' . $errstr );
7751
+
7752
+ return false;
7753
+ } else {
7754
+ $this->return = $return;
7755
+ $this->debug( 'sent message successfully and got a(n) ' . gettype( $return ) );
7756
+ $this->appendDebug( 'return=' . $this->varDump( $return ) );
7757
+
7758
+ // fault?
7759
+ if ( is_array( $return ) && isset( $return['faultcode'] ) ) {
7760
+ $this->debug( 'got fault' );
7761
+ $this->setError( $return['faultcode'] . ': ' . $return['faultstring'] );
7762
+ $this->fault = true;
7763
+ foreach ( $return as $k => $v ) {
7764
+ $this->$k = $v;
7765
+ $this->debug( "$k = $v<br>" );
7766
+ }
7767
+
7768
+ return $return;
7769
+ } elseif ( $style == 'document' ) {
7770
+ // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
7771
+ // we are only going to return the first part here...sorry about that
7772
+ return $return;
7773
+ } else {
7774
+ // array of return values
7775
+ if ( is_array( $return ) ) {
7776
+ // multiple 'out' parameters, which we return wrapped up
7777
+ // in the array
7778
+ if ( sizeof( $return ) > 1 ) {
7779
+ return $return;
7780
+ }
7781
+ // single 'out' parameter (normally the return value)
7782
+ $return = array_shift( $return );
7783
+ $this->debug( 'return shifted value: ' );
7784
+ $this->appendDebug( $this->varDump( $return ) );
7785
+
7786
+ return $return;
7787
+ // nothing returned (ie, echoVoid)
7788
+ } else {
7789
+ return "";
7790
+ }
7791
+ }
7792
+ }
7793
+ }
7794
+
7795
+ /**
7796
+ * check WSDL passed as an instance or pulled from an endpoint
7797
+ *
7798
+ * @access private
7799
+ */
7800
+ function checkWSDL() {
7801
+ $this->appendDebug( $this->wsdl->getDebug() );
7802
+ $this->wsdl->clearDebug();
7803
+ $this->debug( 'checkWSDL' );
7804
+ // catch errors
7805
+ if ( $errstr = $this->wsdl->getError() ) {
7806
+ $this->appendDebug( $this->wsdl->getDebug() );
7807
+ $this->wsdl->clearDebug();
7808
+ $this->debug( 'got wsdl error: ' . $errstr );
7809
+ $this->setError( 'wsdl error: ' . $errstr );
7810
+ } elseif ( $this->operations = $this->wsdl->getOperations( $this->portName, 'soap' ) ) {
7811
+ $this->appendDebug( $this->wsdl->getDebug() );
7812
+ $this->wsdl->clearDebug();
7813
+ $this->bindingType = 'soap';
7814
+ $this->debug( 'got ' . count( $this->operations ) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType );
7815
+ } elseif ( $this->operations = $this->wsdl->getOperations( $this->portName, 'soap12' ) ) {
7816
+ $this->appendDebug( $this->wsdl->getDebug() );
7817
+ $this->wsdl->clearDebug();
7818
+ $this->bindingType = 'soap12';
7819
+ $this->debug( 'got ' . count( $this->operations ) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType );
7820
+ $this->debug( '**************** WARNING: SOAP 1.2 BINDING *****************' );
7821
+ } else {
7822
+ $this->appendDebug( $this->wsdl->getDebug() );
7823
+ $this->wsdl->clearDebug();
7824
+ $this->debug( 'getOperations returned false' );
7825
+ $this->setError( 'no operations defined in the WSDL document!' );
7826
+ }
7827
+ }
7828
+
7829
+ /**
7830
+ * instantiate wsdl object and parse wsdl file
7831
+ *
7832
+ * @access public
7833
+ */
7834
+ function loadWSDL() {
7835
+ $this->debug( 'instantiating wsdl class with doc: ' . $this->wsdlFile );
7836
+ $this->wsdl = new wsdl( '', $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword, $this->timeout, $this->response_timeout, $this->curl_options, $this->use_curl );
7837
+ $this->wsdl->setCredentials( $this->username, $this->password, $this->authtype, $this->certRequest );
7838
+ $this->wsdl->fetchWSDL( $this->wsdlFile );
7839
+ $this->checkWSDL();
7840
+ }
7841
+
7842
+ /**
7843
+ * get available data pertaining to an operation
7844
+ *
7845
+ * @param string $operation operation name
7846
+ *
7847
+ * @return array array of data pertaining to the operation
7848
+ * @access public
7849
+ */
7850
+ function getOperationData( $operation ) {
7851
+ if ( $this->endpointType == 'wsdl' && is_null( $this->wsdl ) ) {
7852
+ $this->loadWSDL();
7853
+ if ( $this->getError() ) {
7854
+ return false;
7855
+ }
7856
+ }
7857
+ if ( isset( $this->operations[ $operation ] ) ) {
7858
+ return $this->operations[ $operation ];
7859
+ }
7860
+ $this->debug( "No data for operation: $operation" );
7861
+ }
7862
+
7863
+ /**
7864
+ * send the SOAP message
7865
+ *
7866
+ * Note: if the operation has multiple return values
7867
+ * the return value of this method will be an array
7868
+ * of those values.
7869
+ *
7870
+ * @param string $msg a SOAPx4 soapmsg object
7871
+ * @param string $soapaction SOAPAction value
7872
+ * @param integer $timeout set connection timeout in seconds
7873
+ * @param integer $response_timeout set response timeout in seconds
7874
+ *
7875
+ * @return mixed native PHP types.
7876
+ * @access private
7877
+ */
7878
+ function send( $msg, $soapaction = '', $timeout = 0, $response_timeout = 30 ) {
7879
+ $this->checkCookies();
7880
+ // detect transport
7881
+ switch ( true ) {
7882
+ // http(s)
7883
+ case preg_match( '/^http/', $this->endpoint ):
7884
+ $this->debug( 'transporting via HTTP' );
7885
+ if ( $this->persistentConnection == true && is_object( $this->persistentConnection ) ) {
7886
+ $http =& $this->persistentConnection;
7887
+ } else {
7888
+ $http = new soap_transport_http( $this->endpoint, $this->curl_options, $this->use_curl );
7889
+ if ( $this->persistentConnection ) {
7890
+ $http->usePersistentConnection();
7891
+ }
7892
+ }
7893
+ $http->setContentType( $this->getHTTPContentType(), $this->getHTTPContentTypeCharset() );
7894
+ $http->setSOAPAction( $soapaction );
7895
+ if ( $this->proxyhost && $this->proxyport ) {
7896
+ $http->setProxy( $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword );
7897
+ }
7898
+ if ( $this->authtype != '' ) {
7899
+ $http->setCredentials( $this->username, $this->password, $this->authtype, array(), $this->certRequest );
7900
+ }
7901
+ if ( $this->http_encoding != '' ) {
7902
+ $http->setEncoding( $this->http_encoding );
7903
+ }
7904
+ $this->debug( 'sending message, length=' . strlen( $msg ) );
7905
+ if ( preg_match( '/^http:/', $this->endpoint ) ) {
7906
+ //if(strpos($this->endpoint,'http:')){
7907
+ $this->responseData = $http->send( $msg, $timeout, $response_timeout, $this->cookies );
7908
+ } elseif ( preg_match( '/^https/', $this->endpoint ) ) {
7909
+ //} elseif(strpos($this->endpoint,'https:')){
7910
+ //if(phpversion() == '4.3.0-dev'){
7911
+ //$response = $http->send($msg,$timeout,$response_timeout);
7912
+ //$this->request = $http->outgoing_payload;
7913
+ //$this->response = $http->incoming_payload;
7914
+ //} else
7915
+ $this->responseData = $http->sendHTTPS( $msg, $timeout, $response_timeout, $this->cookies );
7916
+ } else {
7917
+ $this->setError( 'no http/s in endpoint url' );
7918
+ }
7919
+ $this->request = $http->outgoing_payload;
7920
+ $this->response = $http->incoming_payload;
7921
+ $this->appendDebug( $http->getDebug() );
7922
+ $this->UpdateCookies( $http->incoming_cookies );
7923
+
7924
+ // save transport object if using persistent connections
7925
+ if ( $this->persistentConnection ) {
7926
+ $http->clearDebug();
7927
+ if ( ! is_object( $this->persistentConnection ) ) {
7928
+ $this->persistentConnection = $http;
7929
+ }
7930
+ }
7931
+
7932
+ if ( $err = $http->getError() ) {
7933
+ $this->setError( 'HTTP Error: ' . $err );
7934
+
7935
+ return false;
7936
+ } elseif ( $this->getError() ) {
7937
+ return false;
7938
+ } else {
7939
+ $this->debug( 'got response, length=' . strlen( $this->responseData ) . ' type=' . $http->incoming_headers['content-type'] );
7940
+
7941
+ return $this->parseResponse( $http->incoming_headers, $this->responseData );
7942
+ }
7943
+ break;
7944
+ default:
7945
+ $this->setError( 'no transport found, or selected transport is not yet supported!' );
7946
+
7947
+ return false;
7948
+ break;
7949
+ }
7950
+ }
7951
+
7952
+ /**
7953
+ * processes SOAP message returned from server
7954
+ *
7955
+ * @param array $headers The HTTP headers
7956
+ * @param string $data unprocessed response data from server
7957
+ *
7958
+ * @return mixed value of the message, decoded into a PHP type
7959
+ * @access private
7960
+ */
7961
+ function parseResponse( $headers, $data ) {
7962
+ $this->debug( 'Entering parseResponse() for data of length ' . strlen( $data ) . ' headers:' );
7963
+ $this->appendDebug( $this->varDump( $headers ) );
7964
+ if ( ! isset( $headers['content-type'] ) ) {
7965
+ $this->setError( 'Response not of type text/xml (no content-type header)' );
7966
+
7967
+ return false;
7968
+ }
7969
+ if ( ! strstr( $headers['content-type'], 'text/xml' ) ) {
7970
+ $this->setError( 'Response not of type text/xml: ' . $headers['content-type'] );
7971
+
7972
+ return false;
7973
+ }
7974
+ if ( strpos( $headers['content-type'], '=' ) ) {
7975
+ $enc = str_replace( '"', '', substr( strstr( $headers["content-type"], '=' ), 1 ) );
7976
+ $this->debug( 'Got response encoding: ' . $enc );
7977
+ if ( preg_match( '/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc ) ) {
7978
+ $this->xml_encoding = strtoupper( $enc );
7979
+ } else {
7980
+ $this->xml_encoding = 'US-ASCII';
7981
+ }
7982
+ } else {
7983
+ // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
7984
+ $this->xml_encoding = 'ISO-8859-1';
7985
+ }
7986
+ $this->debug( 'Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser' );
7987
+ $parser = new nusoap_parser( $data, $this->xml_encoding, $this->operation, $this->decode_utf8 );
7988
+ // add parser debug data to our debug
7989
+ $this->appendDebug( $parser->getDebug() );
7990
+ // if parse errors
7991
+ if ( $errstr = $parser->getError() ) {
7992
+ $this->setError( $errstr );
7993
+ // destroy the parser object
7994
+ unset( $parser );
7995
+
7996
+ return false;
7997
+ } else {
7998
+ // get SOAP headers
7999
+ $this->responseHeaders = $parser->getHeaders();
8000
+ // get SOAP headers
8001
+ $this->responseHeader = $parser->get_soapheader();
8002
+ // get decoded message
8003
+ $return = $parser->get_soapbody();
8004
+ // add document for doclit support
8005
+ $this->document = $parser->document;
8006
+ // destroy the parser object
8007
+ unset( $parser );
8008
+
8009
+ // return decode message
8010
+ return $return;
8011
+ }
8012
+ }
8013
+
8014
+ /**
8015
+ * sets user-specified cURL options
8016
+ *
8017
+ * @param mixed $option The cURL option (always integer?)
8018
+ * @param mixed $value The cURL option value
8019
+ *
8020
+ * @access public
8021
+ */
8022
+ function setCurlOption( $option, $value ) {
8023
+ $this->debug( "setCurlOption option=$option, value=" );
8024
+ $this->appendDebug( $this->varDump( $value ) );
8025
+ $this->curl_options[ $option ] = $value;
8026
+ }
8027
+
8028
+ /**
8029
+ * sets the SOAP endpoint, which can override WSDL
8030
+ *
8031
+ * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override
8032
+ *
8033
+ * @access public
8034
+ */
8035
+ function setEndpoint( $endpoint ) {
8036
+ $this->debug( "setEndpoint(\"$endpoint\")" );
8037
+ $this->forceEndpoint = $endpoint;
8038
+ }
8039
+
8040
+ /**
8041
+ * set the SOAP headers
8042
+ *
8043
+ * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers
8044
+ *
8045
+ * @access public
8046
+ */
8047
+ function setHeaders( $headers ) {
8048
+ $this->debug( "setHeaders headers=" );
8049
+ $this->appendDebug( $this->varDump( $headers ) );
8050
+ $this->requestHeaders = $headers;
8051
+ }
8052
+
8053
+ /**
8054
+ * get the SOAP response headers (namespace resolution incomplete)
8055
+ *
8056
+ * @return string
8057
+ * @access public
8058
+ */
8059
+ function getHeaders() {
8060
+ return $this->responseHeaders;
8061
+ }
8062
+
8063
+ /**
8064
+ * get the SOAP response Header (parsed)
8065
+ *
8066
+ * @return mixed
8067
+ * @access public
8068
+ */
8069
+ function getHeader() {
8070
+ return $this->responseHeader;
8071
+ }
8072
+
8073
+ /**
8074
+ * set proxy info here
8075
+ *
8076
+ * @param string $proxyhost
8077
+ * @param string $proxyport
8078
+ * @param string $proxyusername
8079
+ * @param string $proxypassword
8080
+ *
8081
+ * @access public
8082
+ */
8083
+ function setHTTPProxy( $proxyhost, $proxyport, $proxyusername = '', $proxypassword = '' ) {
8084
+ $this->proxyhost = $proxyhost;
8085
+ $this->proxyport = $proxyport;
8086
+ $this->proxyusername = $proxyusername;
8087
+ $this->proxypassword = $proxypassword;
8088
+ }
8089
+
8090
+ /**
8091
+ * if authenticating, set user credentials here
8092
+ *
8093
+ * @param string $username
8094
+ * @param string $password
8095
+ * @param string $authtype (basic|digest|certificate|ntlm)
8096
+ * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
8097
+ *
8098
+ * @access public
8099
+ */
8100
+ function setCredentials( $username, $password, $authtype = 'basic', $certRequest = array() ) {
8101
+ $this->debug( "setCredentials username=$username authtype=$authtype certRequest=" );
8102
+ $this->appendDebug( $this->varDump( $certRequest ) );
8103
+ $this->username = $username;
8104
+ $this->password = $password;
8105
+ $this->authtype = $authtype;
8106
+ $this->certRequest = $certRequest;
8107
+ }
8108
+
8109
+ /**
8110
+ * use HTTP encoding
8111
+ *
8112
+ * @param string $enc HTTP encoding
8113
+ *
8114
+ * @access public
8115
+ */
8116
+ function setHTTPEncoding( $enc = 'gzip, deflate' ) {
8117
+ $this->debug( "setHTTPEncoding(\"$enc\")" );
8118
+ $this->http_encoding = $enc;
8119
+ }
8120
+
8121
+ /**
8122
+ * Set whether to try to use cURL connections if possible
8123
+ *
8124
+ * @param boolean $use Whether to try to use cURL
8125
+ *
8126
+ * @access public
8127
+ */
8128
+ function setUseCURL( $use ) {
8129
+ $this->debug( "setUseCURL($use)" );
8130
+ $this->use_curl = $use;
8131
+ }
8132
+
8133
+ /**
8134
+ * use HTTP persistent connections if possible
8135
+ *
8136
+ * @access public
8137
+ */
8138
+ function useHTTPPersistentConnection() {
8139
+ $this->debug( "useHTTPPersistentConnection" );
8140
+ $this->persistentConnection = true;
8141
+ }
8142
+
8143
+ /**
8144
+ * gets the default RPC parameter setting.
8145
+ * If true, default is that call params are like RPC even for document style.
8146
+ * Each call() can override this value.
8147
+ *
8148
+ * This is no longer used.
8149
+ *
8150
+ * @return boolean
8151
+ * @access public
8152
+ * @deprecated
8153
+ */
8154
+ function getDefaultRpcParams() {
8155
+ return $this->defaultRpcParams;
8156
+ }
8157
+
8158
+ /**
8159
+ * sets the default RPC parameter setting.
8160
+ * If true, default is that call params are like RPC even for document style
8161
+ * Each call() can override this value.
8162
+ *
8163
+ * This is no longer used.
8164
+ *
8165
+ * @param boolean $rpcParams
8166
+ *
8167
+ * @access public
8168
+ * @deprecated
8169
+ */
8170
+ function setDefaultRpcParams( $rpcParams ) {
8171
+ $this->defaultRpcParams = $rpcParams;
8172
+ }
8173
+
8174
+ /**
8175
+ * dynamically creates an instance of a proxy class,
8176
+ * allowing user to directly call methods from wsdl
8177
+ *
8178
+ * @return object soap_proxy object
8179
+ * @access public
8180
+ */
8181
+ function getProxy() {
8182
+ $r = rand();
8183
+ $evalStr = $this->_getProxyClassCode( $r );
8184
+ //$this->debug("proxy class: $evalStr");
8185
+ if ( $this->getError() ) {
8186
+ $this->debug( "Error from _getProxyClassCode, so return NULL" );
8187
+
8188
+ return null;
8189
+ }
8190
+ // eval the class
8191
+ eval( $evalStr );
8192
+ // instantiate proxy object
8193
+ eval( "\$proxy = new nusoap_proxy_$r('');" );
8194
+ // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
8195
+ $proxy->endpointType = 'wsdl';
8196
+ $proxy->wsdlFile = $this->wsdlFile;
8197
+ $proxy->wsdl = $this->wsdl;
8198
+ $proxy->operations = $this->operations;
8199
+ $proxy->defaultRpcParams = $this->defaultRpcParams;
8200
+ // transfer other state
8201
+ $proxy->soap_defencoding = $this->soap_defencoding;
8202
+ $proxy->username = $this->username;
8203
+ $proxy->password = $this->password;
8204
+ $proxy->authtype = $this->authtype;
8205
+ $proxy->certRequest = $this->certRequest;
8206
+ $proxy->requestHeaders = $this->requestHeaders;
8207
+ $proxy->endpoint = $this->endpoint;
8208
+ $proxy->forceEndpoint = $this->forceEndpoint;
8209
+ $proxy->proxyhost = $this->proxyhost;
8210
+ $proxy->proxyport = $this->proxyport;
8211
+ $proxy->proxyusername = $this->proxyusername;
8212
+ $proxy->proxypassword = $this->proxypassword;
8213
+ $proxy->http_encoding = $this->http_encoding;
8214
+ $proxy->timeout = $this->timeout;
8215
+ $proxy->response_timeout = $this->response_timeout;
8216
+ $proxy->persistentConnection = &$this->persistentConnection;
8217
+ $proxy->decode_utf8 = $this->decode_utf8;
8218
+ $proxy->curl_options = $this->curl_options;
8219
+ $proxy->bindingType = $this->bindingType;
8220
+ $proxy->use_curl = $this->use_curl;
8221
+
8222
+ return $proxy;
8223
+ }
8224
+
8225
+ /**
8226
+ * dynamically creates proxy class code
8227
+ *
8228
+ * @return string PHP/NuSOAP code for the proxy class
8229
+ * @access private
8230
+ */
8231
+ function _getProxyClassCode( $r ) {
8232
+ $this->debug( "in getProxy endpointType=$this->endpointType" );
8233
+ $this->appendDebug( "wsdl=" . $this->varDump( $this->wsdl ) );
8234
+ if ( $this->endpointType != 'wsdl' ) {
8235
+ $evalStr = 'A proxy can only be created for a WSDL client';
8236
+ $this->setError( $evalStr );
8237
+ $evalStr = "echo \"$evalStr\";";
8238
+
8239
+ return $evalStr;
8240
+ }
8241
+ if ( $this->endpointType == 'wsdl' && is_null( $this->wsdl ) ) {
8242
+ $this->loadWSDL();
8243
+ if ( $this->getError() ) {
8244
+ return "echo \"" . $this->getError() . "\";";
8245
+ }
8246
+ }
8247
+ $evalStr = '';
8248
+ foreach ( $this->operations as $operation => $opData ) {
8249
+ if ( $operation != '' ) {
8250
+ // create param string and param comment string
8251
+ if ( sizeof( $opData['input']['parts'] ) > 0 ) {
8252
+ $paramStr = '';
8253
+ $paramArrayStr = '';
8254
+ $paramCommentStr = '';
8255
+ foreach ( $opData['input']['parts'] as $name => $type ) {
8256
+ $paramStr .= "\$$name, ";
8257
+ $paramArrayStr .= "'$name' => \$$name, ";
8258
+ $paramCommentStr .= "$type \$$name, ";
8259
+ }
8260
+ $paramStr = substr( $paramStr, 0, strlen( $paramStr ) - 2 );
8261
+ $paramArrayStr = substr( $paramArrayStr, 0, strlen( $paramArrayStr ) - 2 );
8262
+ $paramCommentStr = substr( $paramCommentStr, 0, strlen( $paramCommentStr ) - 2 );
8263
+ } else {
8264
+ $paramStr = '';
8265
+ $paramArrayStr = '';
8266
+ $paramCommentStr = 'void';
8267
+ }
8268
+ $opData['namespace'] = ! isset( $opData['namespace'] ) ? 'http://testuri.com' : $opData['namespace'];
8269
+ $evalStr .= "// $paramCommentStr
8270
+ function " . str_replace( '.', '__', $operation ) . "($paramStr) {
8271
+ \$params = array($paramArrayStr);
8272
+ return \$this->call('$operation', \$params, '" . $opData['namespace'] . "', '" . ( isset( $opData['soapAction'] ) ? $opData['soapAction'] : '' ) . "');
8273
+ }
8274
+ ";
8275
+ unset( $paramStr );
8276
+ unset( $paramCommentStr );
8277
+ }
8278
+ }
8279
+ $evalStr = 'class nusoap_proxy_' . $r . ' extends nusoap_client {
8280
+ ' . $evalStr . '
8281
+ }';
8282
+
8283
+ return $evalStr;
8284
+ }
8285
+
8286
+ /**
8287
+ * dynamically creates proxy class code
8288
+ *
8289
+ * @return string PHP/NuSOAP code for the proxy class
8290
+ * @access public
8291
+ */
8292
+ function getProxyClassCode() {
8293
+ $r = rand();
8294
+
8295
+ return $this->_getProxyClassCode( $r );
8296
+ }
8297
+
8298
+ /**
8299
+ * gets the HTTP body for the current request.
8300
+ *
8301
+ * @param string $soapmsg The SOAP payload
8302
+ *
8303
+ * @return string The HTTP body, which includes the SOAP payload
8304
+ * @access private
8305
+ */
8306
+ function getHTTPBody( $soapmsg ) {
8307
+ return $soapmsg;
8308
+ }
8309
+
8310
+ /**
8311
+ * gets the HTTP content type for the current request.
8312
+ *
8313
+ * Note: getHTTPBody must be called before this.
8314
+ *
8315
+ * @return string the HTTP content type for the current request.
8316
+ * @access private
8317
+ */
8318
+ function getHTTPContentType() {
8319
+ return 'text/xml';
8320
+ }
8321
+
8322
+ /**
8323
+ * gets the HTTP content type charset for the current request.
8324
+ * returns false for non-text content types.
8325
+ *
8326
+ * Note: getHTTPBody must be called before this.
8327
+ *
8328
+ * @return string the HTTP content type charset for the current request.
8329
+ * @access private
8330
+ */
8331
+ function getHTTPContentTypeCharset() {
8332
+ return $this->soap_defencoding;
8333
+ }
8334
+
8335
+ /*
8336
+ * whether or not parser should decode utf8 element content
8337
+ *
8338
+ * @return always returns true
8339
+ * @access public
8340
+ */
8341
+ function decodeUTF8( $bool ) {
8342
+ $this->decode_utf8 = $bool;
8343
+
8344
+ return true;
8345
+ }
8346
+
8347
+ /**
8348
+ * adds a new Cookie into $this->cookies array
8349
+ *
8350
+ * @param string $name Cookie Name
8351
+ * @param string $value Cookie Value
8352
+ *
8353
+ * @return boolean if cookie-set was successful returns true, else false
8354
+ * @access public
8355
+ */
8356
+ function setCookie( $name, $value ) {
8357
+ if ( strlen( $name ) == 0 ) {
8358
+ return false;
8359
+ }
8360
+ $this->cookies[] = array( 'name' => $name, 'value' => $value );
8361
+
8362
+ return true;
8363
+ }
8364
+
8365
+ /**
8366
+ * gets all Cookies
8367
+ *
8368
+ * @return array with all internal cookies
8369
+ * @access public
8370
+ */
8371
+ function getCookies() {
8372
+ return $this->cookies;
8373
+ }
8374
+
8375
+ /**
8376
+ * checks all Cookies and delete those which are expired
8377
+ *
8378
+ * @return boolean always return true
8379
+ * @access private
8380
+ */
8381
+ function checkCookies() {
8382
+ if ( sizeof( $this->cookies ) == 0 ) {
8383
+ return true;
8384
+ }
8385
+ $this->debug( 'checkCookie: check ' . sizeof( $this->cookies ) . ' cookies' );
8386
+ $curr_cookies = $this->cookies;
8387
+ $this->cookies = array();
8388
+ foreach ( $curr_cookies as $cookie ) {
8389
+ if ( ! is_array( $cookie ) ) {
8390
+ $this->debug( 'Remove cookie that is not an array' );
8391
+ continue;
8392
+ }
8393
+ if ( ( isset( $cookie['expires'] ) ) && ( ! empty( $cookie['expires'] ) ) ) {
8394
+ if ( strtotime( $cookie['expires'] ) > time() ) {
8395
+ $this->cookies[] = $cookie;
8396
+ } else {
8397
+ $this->debug( 'Remove expired cookie ' . $cookie['name'] );
8398
+ }
8399
+ } else {
8400
+ $this->cookies[] = $cookie;
8401
+ }
8402
+ }
8403
+ $this->debug( 'checkCookie: ' . sizeof( $this->cookies ) . ' cookies left in array' );
8404
+
8405
+ return true;
8406
+ }
8407
+
8408
+ /**
8409
+ * updates the current cookies with a new set
8410
+ *
8411
+ * @param array $cookies new cookies with which to update current ones
8412
+ *
8413
+ * @return boolean always return true
8414
+ * @access private
8415
+ */
8416
+ function UpdateCookies( $cookies ) {
8417
+ if ( sizeof( $this->cookies ) == 0 ) {
8418
+ // no existing cookies: take whatever is new
8419
+ if ( sizeof( $cookies ) > 0 ) {
8420
+ $this->debug( 'Setting new cookie(s)' );
8421
+ $this->cookies = $cookies;
8422
+ }
8423
+
8424
+ return true;
8425
+ }
8426
+ if ( sizeof( $cookies ) == 0 ) {
8427
+ // no new cookies: keep what we've got
8428
+ return true;
8429
+ }
8430
+ // merge
8431
+ foreach ( $cookies as $newCookie ) {
8432
+ if ( ! is_array( $newCookie ) ) {
8433
+ continue;
8434
+ }
8435
+ if ( ( ! isset( $newCookie['name'] ) ) || ( ! isset( $newCookie['value'] ) ) ) {
8436
+ continue;
8437
+ }
8438
+ $newName = $newCookie['name'];
8439
+
8440
+ $found = false;
8441
+ for ( $i = 0; $i < count( $this->cookies ); $i ++ ) {
8442
+ $cookie = $this->cookies[ $i ];
8443
+ if ( ! is_array( $cookie ) ) {
8444
+ continue;
8445
+ }
8446
+ if ( ! isset( $cookie['name'] ) ) {
8447
+ continue;
8448
+ }
8449
+ if ( $newName != $cookie['name'] ) {
8450
+ continue;
8451
+ }
8452
+ $newDomain = isset( $newCookie['domain'] ) ? $newCookie['domain'] : 'NODOMAIN';
8453
+ $domain = isset( $cookie['domain'] ) ? $cookie['domain'] : 'NODOMAIN';
8454
+ if ( $newDomain != $domain ) {
8455
+ continue;
8456
+ }
8457
+ $newPath = isset( $newCookie['path'] ) ? $newCookie['path'] : 'NOPATH';
8458
+ $path = isset( $cookie['path'] ) ? $cookie['path'] : 'NOPATH';
8459
+ if ( $newPath != $path ) {
8460
+ continue;
8461
+ }
8462
+ $this->cookies[ $i ] = $newCookie;
8463
+ $found = true;
8464
+ $this->debug( 'Update cookie ' . $newName . '=' . $newCookie['value'] );
8465
+ break;
8466
+ }
8467
+ if ( ! $found ) {
8468
+ $this->debug( 'Add cookie ' . $newName . '=' . $newCookie['value'] );
8469
+ $this->cookies[] = $newCookie;
8470
+ }
8471
+ }
8472
+
8473
+ return true;
8474
+ }
8475
+ }
8476
+
8477
+ if ( ! extension_loaded( 'soap' ) ) {
8478
+ /**
8479
+ * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.
8480
+ */
8481
+ class soapclient extends nusoap_client {
8482
+ }
8483
+ }
8484
+ ?>
includes/lib/nusoap-php7.php ADDED
@@ -0,0 +1,8339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
5
+
6
+ NuSOAP - Web Services Toolkit for PHP
7
+
8
+ Copyright (c) 2002 NuSphere Corporation
9
+
10
+ This library is free software; you can redistribute it and/or
11
+ modify it under the terms of the GNU Lesser General Public
12
+ License as published by the Free Software Foundation; either
13
+ version 2.1 of the License, or (at your option) any later version.
14
+
15
+ This library is distributed in the hope that it will be useful,
16
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
+ Lesser General Public License for more details.
19
+
20
+ You should have received a copy of the GNU Lesser General Public
21
+ License along with this library; if not, write to the Free Software
22
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
+
24
+ The NuSOAP project home is:
25
+ http://sourceforge.net/projects/nusoap/
26
+
27
+ The primary support for NuSOAP is the Help forum on the project home page.
28
+
29
+ If you have any questions or comments, please email:
30
+
31
+ Dietrich Ayala
32
+ dietrich@ganx4.com
33
+ http://dietrich.ganx4.com/nusoap
34
+
35
+ NuSphere Corporation
36
+ http://www.nusphere.com
37
+
38
+ */
39
+
40
+ /*
41
+ * Some of the standards implmented in whole or part by NuSOAP:
42
+ *
43
+ * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
44
+ * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
45
+ * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
46
+ * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
47
+ * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
48
+ * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
49
+ * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
50
+ * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
51
+ * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
52
+ */
53
+
54
+ /* load classes
55
+
56
+ // necessary classes
57
+ require_once('class.soapclient.php');
58
+ require_once('class.soap_val.php');
59
+ require_once('class.soap_parser.php');
60
+ require_once('class.soap_fault.php');
61
+
62
+ // transport classes
63
+ require_once('class.soap_transport_http.php');
64
+
65
+ // optional add-on classes
66
+ require_once('class.xmlschema.php');
67
+ require_once('class.wsdl.php');
68
+
69
+ // server class
70
+ require_once('class.soap_server.php');*/
71
+
72
+ // class variable emulation
73
+ // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
74
+ $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9;
75
+
76
+
77
+ /**
78
+ *
79
+ * nusoap_base
80
+ *
81
+ * @author Dietrich Ayala <dietrich@ganx4.com>
82
+ * @author Scott Nichol <snichol@users.sourceforge.net>
83
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
84
+ * @access public
85
+ */
86
+ class nusoap_base
87
+ {
88
+ /**
89
+ * Identification for HTTP headers.
90
+ *
91
+ * @var string
92
+ * @access private
93
+ */
94
+ var $title = 'NuSOAP';
95
+ /**
96
+ * Version for HTTP headers.
97
+ *
98
+ * @var string
99
+ * @access private
100
+ */
101
+ var $version = '0.9.5';
102
+ /**
103
+ * CVS revision for HTTP headers.
104
+ *
105
+ * @var string
106
+ * @access private
107
+ */
108
+ var $revision = '$Revision: 1.123 $';
109
+ /**
110
+ * Current error string (manipulated by getError/setError)
111
+ *
112
+ * @var string
113
+ * @access private
114
+ */
115
+ var $error_str = '';
116
+ /**
117
+ * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
118
+ *
119
+ * @var string
120
+ * @access private
121
+ */
122
+ var $debug_str = '';
123
+ /**
124
+ * toggles automatic encoding of special characters as entities
125
+ * (should always be true, I think)
126
+ *
127
+ * @var boolean
128
+ * @access private
129
+ */
130
+ var $charencoding = true;
131
+ /**
132
+ * the debug level for this instance
133
+ *
134
+ * @var integer
135
+ * @access private
136
+ */
137
+ var $debugLevel;
138
+
139
+ /**
140
+ * set schema version
141
+ *
142
+ * @var string
143
+ * @access public
144
+ */
145
+ var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
146
+
147
+ /**
148
+ * charset encoding for outgoing messages
149
+ *
150
+ * @var string
151
+ * @access public
152
+ */
153
+ var $soap_defencoding = 'ISO-8859-1';
154
+ //var $soap_defencoding = 'UTF-8';
155
+
156
+ /**
157
+ * namespaces in an array of prefix => uri
158
+ *
159
+ * this is "seeded" by a set of constants, but it may be altered by code
160
+ *
161
+ * @var array
162
+ * @access public
163
+ */
164
+ var $namespaces = array(
165
+ 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
166
+ 'xsd' => 'http://www.w3.org/2001/XMLSchema',
167
+ 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
168
+ 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
169
+ );
170
+
171
+ /**
172
+ * namespaces used in the current context, e.g. during serialization
173
+ *
174
+ * @var array
175
+ * @access private
176
+ */
177
+ var $usedNamespaces = array();
178
+
179
+ /**
180
+ * XML Schema types in an array of uri => (array of xml type => php type)
181
+ * is this legacy yet?
182
+ * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
183
+ *
184
+ * @var array
185
+ * @access public
186
+ */
187
+ var $typemap = array(
188
+ 'http://www.w3.org/2001/XMLSchema' => array(
189
+ 'string' => 'string', 'boolean' => 'boolean', 'float' => 'double', 'double' => 'double', 'decimal' => 'double',
190
+ 'duration' => '', 'dateTime' => 'string', 'time' => 'string', 'date' => 'string', 'gYearMonth' => '',
191
+ 'gYear' => '', 'gMonthDay' => '', 'gDay' => '', 'gMonth' => '', 'hexBinary' => 'string', 'base64Binary' => 'string',
192
+ // abstract "any" types
193
+ 'anyType' => 'string', 'anySimpleType' => 'string',
194
+ // derived datatypes
195
+ 'normalizedString' => 'string', 'token' => 'string', 'language' => '', 'NMTOKEN' => '', 'NMTOKENS' => '', 'Name' => '', 'NCName' => '', 'ID' => '',
196
+ 'IDREF' => '', 'IDREFS' => '', 'ENTITY' => '', 'ENTITIES' => '', 'integer' => 'integer', 'nonPositiveInteger' => 'integer',
197
+ 'negativeInteger' => 'integer', 'long' => 'integer', 'int' => 'integer', 'short' => 'integer', 'byte' => 'integer', 'nonNegativeInteger' => 'integer',
198
+ 'unsignedLong' => '', 'unsignedInt' => '', 'unsignedShort' => '', 'unsignedByte' => '', 'positiveInteger' => ''),
199
+ 'http://www.w3.org/2000/10/XMLSchema' => array(
200
+ 'i4' => '', 'int' => 'integer', 'boolean' => 'boolean', 'string' => 'string', 'double' => 'double',
201
+ 'float' => 'double', 'dateTime' => 'string',
202
+ 'timeInstant' => 'string', 'base64Binary' => 'string', 'base64' => 'string', 'ur-type' => 'array'),
203
+ 'http://www.w3.org/1999/XMLSchema' => array(
204
+ 'i4' => '', 'int' => 'integer', 'boolean' => 'boolean', 'string' => 'string', 'double' => 'double',
205
+ 'float' => 'double', 'dateTime' => 'string',
206
+ 'timeInstant' => 'string', 'base64Binary' => 'string', 'base64' => 'string', 'ur-type' => 'array'),
207
+ 'http://soapinterop.org/xsd' => array('SOAPStruct' => 'struct'),
208
+ 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64' => 'string', 'array' => 'array', 'Array' => 'array'),
209
+ 'http://xml.apache.org/xml-soap' => array('Map')
210
+ );
211
+
212
+ /**
213
+ * XML entities to convert
214
+ *
215
+ * @var array
216
+ * @access public
217
+ * @deprecated
218
+ * @see expandEntities
219
+ */
220
+ var $xmlEntities = array('quot' => '"', 'amp' => '&',
221
+ 'lt' => '<', 'gt' => '>', 'apos' => "'");
222
+
223
+ /**
224
+ * constructor
225
+ *
226
+ * @access public
227
+ */
228
+ function __construct()
229
+ {
230
+ $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
231
+ }
232
+
233
+ /**
234
+ * gets the global debug level, which applies to future instances
235
+ *
236
+ * @return integer Debug level 0-9, where 0 turns off
237
+ * @access public
238
+ */
239
+ function getGlobalDebugLevel()
240
+ {
241
+ return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
242
+ }
243
+
244
+ /**
245
+ * sets the global debug level, which applies to future instances
246
+ *
247
+ * @param int $level Debug level 0-9, where 0 turns off
248
+ * @access public
249
+ */
250
+ function setGlobalDebugLevel($level)
251
+ {
252
+ $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
253
+ }
254
+
255
+ /**
256
+ * gets the debug level for this instance
257
+ *
258
+ * @return int Debug level 0-9, where 0 turns off
259
+ * @access public
260
+ */
261
+ function getDebugLevel()
262
+ {
263
+ return $this->debugLevel;
264
+ }
265
+
266
+ /**
267
+ * sets the debug level for this instance
268
+ *
269
+ * @param int $level Debug level 0-9, where 0 turns off
270
+ * @access public
271
+ */
272
+ function setDebugLevel($level)
273
+ {
274
+ $this->debugLevel = $level;
275
+ }
276
+
277
+ /**
278
+ * adds debug data to the instance debug string with formatting
279
+ *
280
+ * @param string $string debug data
281
+ * @access private
282
+ */
283
+ function debug($string)
284
+ {
285
+ if ($this->debugLevel > 0) {
286
+ $this->appendDebug($this->getmicrotime() . ' ' . get_class($this) . ": $string\n");
287
+ }
288
+ }
289
+
290
+ /**
291
+ * adds debug data to the instance debug string without formatting
292
+ *
293
+ * @param string $string debug data
294
+ * @access public
295
+ */
296
+ function appendDebug($string)
297
+ {
298
+ if ($this->debugLevel > 0) {
299
+ // it would be nice to use a memory stream here to use
300
+ // memory more efficiently
301
+ $this->debug_str .= $string;
302
+ }
303
+ }
304
+
305
+ /**
306
+ * clears the current debug data for this instance
307
+ *
308
+ * @access public
309
+ */
310
+ function clearDebug()
311
+ {
312
+ // it would be nice to use a memory stream here to use
313
+ // memory more efficiently
314
+ $this->debug_str = '';
315
+ }
316
+
317
+ /**
318
+ * gets the current debug data for this instance
319
+ *
320
+ * @return debug data
321
+ * @access public
322
+ */
323
+ function &getDebug()
324
+ {
325
+ // it would be nice to use a memory stream here to use
326
+ // memory more efficiently
327
+ return $this->debug_str;
328
+ }
329
+
330
+ /**
331
+ * gets the current debug data for this instance as an XML comment
332
+ * this may change the contents of the debug data
333
+ *
334
+ * @return debug data as an XML comment
335
+ * @access public
336
+ */
337
+ function &getDebugAsXMLComment()
338
+ {
339
+ // it would be nice to use a memory stream here to use
340
+ // memory more efficiently
341
+ while (strpos($this->debug_str, '--')) {
342
+ $this->debug_str = str_replace('--', '- -', $this->debug_str);
343
+ }
344
+ $ret = "<!--\n" . $this->debug_str . "\n-->";
345
+ return $ret;
346
+ }
347
+
348
+ /**
349
+ * expands entities, e.g. changes '<' to '&lt;'.
350
+ *
351
+ * @param string $val The string in which to expand entities.
352
+ * @access private
353
+ */
354
+ function expandEntities($val)
355
+ {
356
+ if ($this->charencoding) {
357
+ $val = str_replace('&', '&amp;', $val);
358
+ $val = str_replace("'", '&apos;', $val);
359
+ $val = str_replace('"', '&quot;', $val);
360
+ $val = str_replace('<', '&lt;', $val);
361
+ $val = str_replace('>', '&gt;', $val);
362
+ }
363
+ return $val;
364
+ }
365
+
366
+ /**
367
+ * returns error string if present
368
+ *
369
+ * @return mixed error string or false
370
+ * @access public
371
+ */
372
+ function getError()
373
+ {
374
+ if ($this->error_str != '') {
375
+ return $this->error_str;
376
+ }
377
+ return false;
378
+ }
379
+
380
+ /**
381
+ * sets error string
382
+ *
383
+ * @return boolean $string error string
384
+ * @access private
385
+ */
386
+ function setError($str)
387
+ {
388
+ $this->error_str = $str;
389
+ }
390
+
391
+ /**
392
+ * detect if array is a simple array or a struct (associative array)
393
+ *
394
+ * @param mixed $val The PHP array
395
+ * @return string (arraySimple|arrayStruct)
396
+ * @access private
397
+ */
398
+ function isArraySimpleOrStruct($val)
399
+ {
400
+ $keyList = array_keys($val);
401
+ foreach ($keyList as $keyListValue) {
402
+ if (!is_int($keyListValue)) {
403
+ return 'arrayStruct';
404
+ }
405
+ }
406
+ return 'arraySimple';
407
+ }
408
+
409
+ /**
410
+ * serializes PHP values in accordance w/ section 5. Type information is
411
+ * not serialized if $use == 'literal'.
412
+ *
413
+ * @param mixed $val The value to serialize
414
+ * @param string $name The name (local part) of the XML element
415
+ * @param string $type The XML schema type (local part) for the element
416
+ * @param string $name_ns The namespace for the name of the XML element
417
+ * @param string $type_ns The namespace for the type of the element
418
+ * @param array $attributes The attributes to serialize as name=>value pairs
419
+ * @param string $use The WSDL "use" (encoded|literal)
420
+ * @param boolean $soapval Whether this is called from soapval.
421
+ * @return string The serialized element, possibly with child elements
422
+ * @access public
423
+ */
424
+ function serialize_val($val, $name = false, $type = false, $name_ns = false, $type_ns = false, $attributes = false, $use = 'encoded', $soapval = false)
425
+ {
426
+ $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
427
+ $this->appendDebug('value=' . $this->varDump($val));
428
+ $this->appendDebug('attributes=' . $this->varDump($attributes));
429
+
430
+ if (is_object($val) && get_class($val) == 'soapval' && (!$soapval)) {
431
+ $this->debug("serialize_val: serialize soapval");
432
+ $xml = $val->serialize($use);
433
+ $this->appendDebug($val->getDebug());
434
+ $val->clearDebug();
435
+ $this->debug("serialize_val of soapval returning $xml");
436
+ return $xml;
437
+ }
438
+ // force valid name if necessary
439
+ if (is_numeric($name)) {
440
+ $name = '__numeric_' . $name;
441
+ } elseif (!$name) {
442
+ $name = 'noname';
443
+ }
444
+ // if name has ns, add ns prefix to name
445
+ $xmlns = '';
446
+ if ($name_ns) {
447
+ $prefix = 'nu' . rand(1000, 9999);
448
+ $name = $prefix . ':' . $name;
449
+ $xmlns .= " xmlns:$prefix=\"$name_ns\"";
450
+ }
451
+ // if type is prefixed, create type prefix
452
+ if ($type_ns != '' && $type_ns == $this->namespaces['xsd']) {
453
+ // need to fix this. shouldn't default to xsd if no ns specified
454
+ // w/o checking against typemap
455
+ $type_prefix = 'xsd';
456
+ } elseif ($type_ns) {
457
+ $type_prefix = 'ns' . rand(1000, 9999);
458
+ $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
459
+ }
460
+ // serialize attributes if present
461
+ $atts = '';
462
+ if ($attributes) {
463
+ foreach ($attributes as $k => $v) {
464
+ $atts .= " $k=\"" . $this->expandEntities($v) . '"';
465
+ }
466
+ }
467
+ // serialize null value
468
+ if (is_null($val)) {
469
+ $this->debug("serialize_val: serialize null");
470
+ if ($use == 'literal') {
471
+ // TODO: depends on minOccurs
472
+ $xml = "<$name$xmlns$atts/>";
473
+ $this->debug("serialize_val returning $xml");
474
+ return $xml;
475
+ } else {
476
+ if (isset($type) && isset($type_prefix)) {
477
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
478
+ } else {
479
+ $type_str = '';
480
+ }
481
+ $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
482
+ $this->debug("serialize_val returning $xml");
483
+ return $xml;
484
+ }
485
+ }
486
+ // serialize if an xsd built-in primitive type
487
+ if ($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])) {
488
+ $this->debug("serialize_val: serialize xsd built-in primitive type");
489
+ if (is_bool($val)) {
490
+ if ($type == 'boolean') {
491
+ $val = $val ? 'true' : 'false';
492
+ } elseif (!$val) {
493
+ $val = 0;
494
+ }
495
+ } elseif (is_string($val)) {
496
+ $val = $this->expandEntities($val);
497
+ }
498
+ if ($use == 'literal') {
499
+ $xml = "<$name$xmlns$atts>$val</$name>";
500
+ $this->debug("serialize_val returning $xml");
501
+ return $xml;
502
+ } else {
503
+ $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
504
+ $this->debug("serialize_val returning $xml");
505
+ return $xml;
506
+ }
507
+ }
508
+ // detect type and serialize
509
+ $xml = '';
510
+ switch (true) {
511
+ case (is_bool($val) || $type == 'boolean'):
512
+ $this->debug("serialize_val: serialize boolean");
513
+ if ($type == 'boolean') {
514
+ $val = $val ? 'true' : 'false';
515
+ } elseif (!$val) {
516
+ $val = 0;
517
+ }
518
+ if ($use == 'literal') {
519
+ $xml .= "<$name$xmlns$atts>$val</$name>";
520
+ } else {
521
+ $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
522
+ }
523
+ break;
524
+ case (is_int($val) || is_long($val) || $type == 'int'):
525
+ $this->debug("serialize_val: serialize int");
526
+ if ($use == 'literal') {
527
+ $xml .= "<$name$xmlns$atts>$val</$name>";
528
+ } else {
529
+ $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
530
+ }
531
+ break;
532
+ case (is_float($val) || is_double($val) || $type == 'float'):
533
+ $this->debug("serialize_val: serialize float");
534
+ if ($use == 'literal') {
535
+ $xml .= "<$name$xmlns$atts>$val</$name>";
536
+ } else {
537
+ $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
538
+ }
539
+ break;
540
+ case (is_string($val) || $type == 'string'):
541
+ $this->debug("serialize_val: serialize string");
542
+ $val = $this->expandEntities($val);
543
+ if ($use == 'literal') {
544
+ $xml .= "<$name$xmlns$atts>$val</$name>";
545
+ } else {
546
+ $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
547
+ }
548
+ break;
549
+ case is_object($val):
550
+ $this->debug("serialize_val: serialize object");
551
+ if (get_class($val) == 'soapval') {
552
+ $this->debug("serialize_val: serialize soapval object");
553
+ $pXml = $val->serialize($use);
554
+ $this->appendDebug($val->getDebug());
555
+ $val->clearDebug();
556
+ } else {
557
+ if (!$name) {
558
+ $name = get_class($val);
559
+ $this->debug("In serialize_val, used class name $name as element name");
560
+ } else {
561
+ $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
562
+ }
563
+ foreach (get_object_vars($val) as $k => $v) {
564
+ $pXml = isset($pXml) ? $pXml . $this->serialize_val($v, $k, false, false, false, false, $use) : $this->serialize_val($v, $k, false, false, false, false, $use);
565
+ }
566
+ }
567
+ if (isset($type) && isset($type_prefix)) {
568
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
569
+ } else {
570
+ $type_str = '';
571
+ }
572
+ if ($use == 'literal') {
573
+ $xml .= "<$name$xmlns$atts>$pXml</$name>";
574
+ } else {
575
+ $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
576
+ }
577
+ break;
578
+ break;
579
+ case (is_array($val) || $type):
580
+ // detect if struct or array
581
+ $valueType = $this->isArraySimpleOrStruct($val);
582
+ if ($valueType == 'arraySimple' || preg_match('/^ArrayOf/', $type)) {
583
+ $this->debug("serialize_val: serialize array");
584
+ $i = 0;
585
+ if (is_array($val) && count($val) > 0) {
586
+ foreach ($val as $v) {
587
+ if (is_object($v) && get_class($v) == 'soapval') {
588
+ $tt_ns = $v->type_ns;
589
+ $tt = $v->type;
590
+ } elseif (is_array($v)) {
591
+ $tt = $this->isArraySimpleOrStruct($v);
592
+ } else {
593
+ $tt = gettype($v);
594
+ }
595
+ $array_types[$tt] = 1;
596
+ // TODO: for literal, the name should be $name
597
+ $xml .= $this->serialize_val($v, 'item', false, false, false, false, $use);
598
+ ++$i;
599
+ }
600
+ if (count($array_types) > 1) {
601
+ $array_typename = 'xsd:anyType';
602
+ } elseif (isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
603
+ if ($tt == 'integer') {
604
+ $tt = 'int';
605
+ }
606
+ $array_typename = 'xsd:' . $tt;
607
+ } elseif (isset($tt) && $tt == 'arraySimple') {
608
+ $array_typename = 'SOAP-ENC:Array';
609
+ } elseif (isset($tt) && $tt == 'arrayStruct') {
610
+ $array_typename = 'unnamed_struct_use_soapval';
611
+ } else {
612
+ // if type is prefixed, create type prefix
613
+ if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']) {
614
+ $array_typename = 'xsd:' . $tt;
615
+ } elseif ($tt_ns) {
616
+ $tt_prefix = 'ns' . rand(1000, 9999);
617
+ $array_typename = "$tt_prefix:$tt";
618
+ $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
619
+ } else {
620
+ $array_typename = $tt;
621
+ }
622
+ }
623
+ $array_type = $i;
624
+ if ($use == 'literal') {
625
+ $type_str = '';
626
+ } elseif (isset($type) && isset($type_prefix)) {
627
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
628
+ } else {
629
+ $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"" . $array_typename . "[$array_type]\"";
630
+ }
631
+ // empty array
632
+ } else {
633
+ if ($use == 'literal') {
634
+ $type_str = '';
635
+ } elseif (isset($type) && isset($type_prefix)) {
636
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
637
+ } else {
638
+ $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
639
+ }
640
+ }
641
+ // TODO: for array in literal, there is no wrapper here
642
+ $xml = "<$name$xmlns$type_str$atts>" . $xml . "</$name>";
643
+ } else {
644
+ // got a struct
645
+ $this->debug("serialize_val: serialize struct");
646
+ if (isset($type) && isset($type_prefix)) {
647
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
648
+ } else {
649
+ $type_str = '';
650
+ }
651
+ if ($use == 'literal') {
652
+ $xml .= "<$name$xmlns$atts>";
653
+ } else {
654
+ $xml .= "<$name$xmlns$type_str$atts>";
655
+ }
656
+ foreach ($val as $k => $v) {
657
+ // Apache Map
658
+ if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
659
+ $xml .= '<item>';
660
+ $xml .= $this->serialize_val($k, 'key', false, false, false, false, $use);
661
+ $xml .= $this->serialize_val($v, 'value', false, false, false, false, $use);
662
+ $xml .= '</item>';
663
+ } else {
664
+ $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
665
+ }
666
+ }
667
+ $xml .= "</$name>";
668
+ }
669
+ break;
670
+ default:
671
+ $this->debug("serialize_val: serialize unknown");
672
+ $xml .= 'not detected, got ' . gettype($val) . ' for ' . $val;
673
+ break;
674
+ }
675
+ $this->debug("serialize_val returning $xml");
676
+ return $xml;
677
+ }
678
+
679
+ /**
680
+ * serializes a message
681
+ *
682
+ * @param string $body the XML of the SOAP body
683
+ * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
684
+ * @param array $namespaces optional the namespaces used in generating the body and headers
685
+ * @param string $style optional (rpc|document)
686
+ * @param string $use optional (encoded|literal)
687
+ * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
688
+ * @return string the message
689
+ * @access public
690
+ */
691
+ function serializeEnvelope($body, $headers = false, $namespaces = array(), $style = 'rpc', $use = 'encoded', $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/')
692
+ {
693
+ // TODO: add an option to automatically run utf8_encode on $body and $headers
694
+ // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
695
+ // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
696
+
697
+ $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
698
+ $this->debug("headers:");
699
+ $this->appendDebug($this->varDump($headers));
700
+ $this->debug("namespaces:");
701
+ $this->appendDebug($this->varDump($namespaces));
702
+
703
+ // serialize namespaces
704
+ $ns_string = '';
705
+ foreach (array_merge($this->namespaces, $namespaces) as $k => $v) {
706
+ $ns_string .= " xmlns:$k=\"$v\"";
707
+ }
708
+ if ($encodingStyle) {
709
+ $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
710
+ }
711
+
712
+ // serialize headers
713
+ if ($headers) {
714
+ if (is_array($headers)) {
715
+ $xml = '';
716
+ foreach ($headers as $k => $v) {
717
+ if (is_object($v) && get_class($v) == 'soapval') {
718
+ $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
719
+ } else {
720
+ $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
721
+ }
722
+ }
723
+ $headers = $xml;
724
+ $this->debug("In serializeEnvelope, serialized array of headers to $headers");
725
+ }
726
+ $headers = "<SOAP-ENV:Header>" . $headers . "</SOAP-ENV:Header>";
727
+ }
728
+ // serialize envelope
729
+ return
730
+ '<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?' . ">" .
731
+ '<SOAP-ENV:Envelope' . $ns_string . ">" .
732
+ $headers .
733
+ "<SOAP-ENV:Body>" .
734
+ $body .
735
+ "</SOAP-ENV:Body>" .
736
+ "</SOAP-ENV:Envelope>";
737
+ }
738
+
739
+ /**
740
+ * formats a string to be inserted into an HTML stream
741
+ *
742
+ * @param string $str The string to format
743
+ * @return string The formatted string
744
+ * @access public
745
+ * @deprecated
746
+ */
747
+ function formatDump($str)
748
+ {
749
+ $str = htmlspecialchars($str);
750
+ return nl2br($str);
751
+ }
752
+
753
+ /**
754
+ * contracts (changes namespace to prefix) a qualified name
755
+ *
756
+ * @param string $qname qname
757
+ * @return string contracted qname
758
+ * @access private
759
+ */
760
+ function contractQname($qname)
761
+ {
762
+ // get element namespace
763
+ //$this->xdebug("Contract $qname");
764
+ if (strrpos($qname, ':')) {
765
+ // get unqualified name
766
+ $name = substr($qname, strrpos($qname, ':') + 1);
767
+ // get ns
768
+ $ns = substr($qname, 0, strrpos($qname, ':'));
769
+ $p = $this->getPrefixFromNamespace($ns);
770
+ if ($p) {
771
+ return $p . ':' . $name;
772
+ }
773
+ return $qname;
774
+ } else {
775
+ return $qname;
776
+ }
777
+ }
778
+
779
+ /**
780
+ * expands (changes prefix to namespace) a qualified name
781
+ *
782
+ * @param string $qname qname
783
+ * @return string expanded qname
784
+ * @access private
785
+ */
786
+ function expandQname($qname)
787
+ {
788
+ // get element prefix
789
+ if (strpos($qname, ':') && !preg_match('/^http:\/\//', $qname)) {
790
+ // get unqualified name
791
+ $name = substr(strstr($qname, ':'), 1);
792
+ // get ns prefix
793
+ $prefix = substr($qname, 0, strpos($qname, ':'));
794
+ if (isset($this->namespaces[$prefix])) {
795
+ return $this->namespaces[$prefix] . ':' . $name;
796
+ } else {
797
+ return $qname;
798
+ }
799
+ } else {
800
+ return $qname;
801
+ }
802
+ }
803
+
804
+ /**
805
+ * returns the local part of a prefixed string
806
+ * returns the original string, if not prefixed
807
+ *
808
+ * @param string $str The prefixed string
809
+ * @return string The local part
810
+ * @access public
811
+ */
812
+ function getLocalPart($str)
813
+ {
814
+ if ($sstr = strrchr($str, ':')) {
815
+ // get unqualified name
816
+ return substr($sstr, 1);
817
+ } else {
818
+ return $str;
819
+ }
820
+ }
821
+
822
+ /**
823
+ * returns the prefix part of a prefixed string
824
+ * returns false, if not prefixed
825
+ *
826
+ * @param string $str The prefixed string
827
+ * @return mixed The prefix or false if there is no prefix
828
+ * @access public
829
+ */
830
+ function getPrefix($str)
831
+ {
832
+ if ($pos = strrpos($str, ':')) {
833
+ // get prefix
834
+ return substr($str, 0, $pos);
835
+ }
836
+ return false;
837
+ }
838
+
839
+ /**
840
+ * pass it a prefix, it returns a namespace
841
+ *
842
+ * @param string $prefix The prefix
843
+ * @return mixed The namespace, false if no namespace has the specified prefix
844
+ * @access public
845
+ */
846
+ function getNamespaceFromPrefix($prefix)
847
+ {
848
+ if (isset($this->namespaces[$prefix])) {
849
+ return $this->namespaces[$prefix];
850
+ }
851
+ //$this->setError("No namespace registered for prefix '$prefix'");
852
+ return false;
853
+ }
854
+
855
+ /**
856
+ * returns the prefix for a given namespace (or prefix)
857
+ * or false if no prefixes registered for the given namespace
858
+ *
859
+ * @param string $ns The namespace
860
+ * @return mixed The prefix, false if the namespace has no prefixes
861
+ * @access public
862
+ */
863
+ function getPrefixFromNamespace($ns)
864
+ {
865
+ foreach ($this->namespaces as $p => $n) {
866
+ if ($ns == $n || $ns == $p) {
867
+ $this->usedNamespaces[$p] = $n;
868
+ return $p;
869
+ }
870
+ }
871
+ return false;
872
+ }
873
+
874
+ /**
875
+ * returns the time in ODBC canonical form with microseconds
876
+ *
877
+ * @return string The time in ODBC canonical form with microseconds
878
+ * @access public
879
+ */
880
+ function getmicrotime()
881
+ {
882
+ if (function_exists('gettimeofday')) {
883
+ $tod = gettimeofday();
884
+ $sec = $tod['sec'];
885
+ $usec = $tod['usec'];
886
+ } else {
887
+ $sec = time();
888
+ $usec = 0;
889
+ }
890
+ return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
891
+ }
892
+
893
+ /**
894
+ * Returns a string with the output of var_dump
895
+ *
896
+ * @param mixed $data The variable to var_dump
897
+ * @return string The output of var_dump
898
+ * @access public
899
+ */
900
+ function varDump($data)
901
+ {
902
+ ob_start();
903
+ var_dump($data);
904
+ $ret_val = ob_get_contents();
905
+ ob_end_clean();
906
+ return $ret_val;
907
+ }
908
+
909
+ /**
910
+ * represents the object as a string
911
+ *
912
+ * @return string
913
+ * @access public
914
+ */
915
+ function __toString()
916
+ {
917
+ return $this->varDump($this);
918
+ }
919
+ }
920
+
921
+ // XML Schema Datatype Helper Functions
922
+
923
+ //xsd:dateTime helpers
924
+
925
+ /**
926
+ * convert unix timestamp to ISO 8601 compliant date string
927
+ *
928
+ * @param int $timestamp Unix time stamp
929
+ * @param boolean $utc Whether the time stamp is UTC or local
930
+ * @return mixed ISO 8601 date string or false
931
+ * @access public
932
+ */
933
+ function timestamp_to_iso8601($timestamp, $utc = true)
934
+ {
935
+ $datestr = date('Y-m-d\TH:i:sO', $timestamp);
936
+ $pos = strrpos($datestr, "+");
937
+ if ($pos === false) {
938
+ $pos = strrpos($datestr, "-");
939
+ }
940
+ if ($pos !== false) {
941
+ if (strlen($datestr) == $pos + 5) {
942
+ $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2);
943
+ }
944
+ }
945
+ if ($utc) {
946
+ $pattern = '/' .
947
+ '([0-9]{4})-' . // centuries & years CCYY-
948
+ '([0-9]{2})-' . // months MM-
949
+ '([0-9]{2})' . // days DD
950
+ 'T' . // separator T
951
+ '([0-9]{2}):' . // hours hh:
952
+ '([0-9]{2}):' . // minutes mm:
953
+ '([0-9]{2})(\.[0-9]*)?' . // seconds ss.ss...
954
+ '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
955
+ '/';
956
+
957
+ if (preg_match($pattern, $datestr, $regs)) {
958
+ return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ', $regs[1], $regs[2], $regs[3], $regs[4], $regs[5], $regs[6]);
959
+ }
960
+ return false;
961
+ } else {
962
+ return $datestr;
963
+ }
964
+ }
965
+
966
+ /**
967
+ * convert ISO 8601 compliant date string to unix timestamp
968
+ *
969
+ * @param string $datestr ISO 8601 compliant date string
970
+ * @return mixed Unix timestamp (int) or false
971
+ * @access public
972
+ */
973
+ function iso8601_to_timestamp($datestr)
974
+ {
975
+ $pattern = '/' .
976
+ '([0-9]{4})-' . // centuries & years CCYY-
977
+ '([0-9]{2})-' . // months MM-
978
+ '([0-9]{2})' . // days DD
979
+ 'T' . // separator T
980
+ '([0-9]{2}):' . // hours hh:
981
+ '([0-9]{2}):' . // minutes mm:
982
+ '([0-9]{2})(\.[0-9]+)?' . // seconds ss.ss...
983
+ '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
984
+ '/';
985
+ if (preg_match($pattern, $datestr, $regs)) {
986
+ // not utc
987
+ if ($regs[8] != 'Z') {
988
+ $op = substr($regs[8], 0, 1);
989
+ $h = substr($regs[8], 1, 2);
990
+ $m = substr($regs[8], strlen($regs[8]) - 2, 2);
991
+ if ($op == '-') {
992
+ $regs[4] = $regs[4] + $h;
993
+ $regs[5] = $regs[5] + $m;
994
+ } elseif ($op == '+') {
995
+ $regs[4] = $regs[4] - $h;
996
+ $regs[5] = $regs[5] - $m;
997
+ }
998
+ }
999
+ return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1000
+ // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
1001
+ } else {
1002
+ return false;
1003
+ }
1004
+ }
1005
+
1006
+ /**
1007
+ * sleeps some number of microseconds
1008
+ *
1009
+ * @param string $usec the number of microseconds to sleep
1010
+ * @access public
1011
+ * @deprecated
1012
+ */
1013
+ function usleepWindows($usec)
1014
+ {
1015
+ $start = gettimeofday();
1016
+
1017
+ do {
1018
+ $stop = gettimeofday();
1019
+ $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
1020
+ + $stop['usec'] - $start['usec'];
1021
+ } while ($timePassed < $usec);
1022
+ }
1023
+
1024
+
1025
+ /**
1026
+ * Contains information for a SOAP fault.
1027
+ * Mainly used for returning faults from deployed functions
1028
+ * in a server instance.
1029
+ *
1030
+ * @author Dietrich Ayala <dietrich@ganx4.com>
1031
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
1032
+ * @access public
1033
+ */
1034
+ class nusoap_fault extends nusoap_base
1035
+ {
1036
+ /**
1037
+ * The fault code (client|server)
1038
+ *
1039
+ * @var string
1040
+ * @access private
1041
+ */
1042
+ var $faultcode;
1043
+ /**
1044
+ * The fault actor
1045
+ *
1046
+ * @var string
1047
+ * @access private
1048
+ */
1049
+ var $faultactor;
1050
+ /**
1051
+ * The fault string, a description of the fault
1052
+ *
1053
+ * @var string
1054
+ * @access private
1055
+ */
1056
+ var $faultstring;
1057
+ /**
1058
+ * The fault detail, typically a string or array of string
1059
+ *
1060
+ * @var mixed
1061
+ * @access private
1062
+ */
1063
+ var $faultdetail;
1064
+
1065
+ /**
1066
+ * constructor
1067
+ *
1068
+ * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server)
1069
+ * @param string $faultactor only used when msg routed between multiple actors
1070
+ * @param string $faultstring human readable error message
1071
+ * @param mixed $faultdetail detail, typically a string or array of string
1072
+ */
1073
+ function __construct($faultcode, $faultactor = '', $faultstring = '', $faultdetail = '')
1074
+ {
1075
+ parent::__construct();
1076
+ $this->faultcode = $faultcode;
1077
+ $this->faultactor = $faultactor;
1078
+ $this->faultstring = $faultstring;
1079
+ $this->faultdetail = $faultdetail;
1080
+ }
1081
+
1082
+ /**
1083
+ * serialize a fault
1084
+ *
1085
+ * @return string The serialization of the fault instance.
1086
+ * @access public
1087
+ */
1088
+ function serialize()
1089
+ {
1090
+ $ns_string = '';
1091
+ foreach ($this->namespaces as $k => $v) {
1092
+ $ns_string .= "\n xmlns:$k=\"$v\"";
1093
+ }
1094
+ $return_msg =
1095
+ '<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?>' .
1096
+ '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string . ">\n" .
1097
+ '<SOAP-ENV:Body>' .
1098
+ '<SOAP-ENV:Fault>' .
1099
+ $this->serialize_val($this->faultcode, 'faultcode') .
1100
+ $this->serialize_val($this->faultactor, 'faultactor') .
1101
+ $this->serialize_val($this->faultstring, 'faultstring') .
1102
+ $this->serialize_val($this->faultdetail, 'detail') .
1103
+ '</SOAP-ENV:Fault>' .
1104
+ '</SOAP-ENV:Body>' .
1105
+ '</SOAP-ENV:Envelope>';
1106
+ return $return_msg;
1107
+ }
1108
+ }
1109
+
1110
+
1111
+ /**
1112
+ * Backward compatibility
1113
+ */
1114
+ class soap_fault extends nusoap_fault
1115
+ {
1116
+ }
1117
+
1118
+
1119
+ /**
1120
+ * parses an XML Schema, allows access to it's data, other utility methods.
1121
+ * imperfect, no validation... yet, but quite functional.
1122
+ *
1123
+ * @author Dietrich Ayala <dietrich@ganx4.com>
1124
+ * @author Scott Nichol <snichol@users.sourceforge.net>
1125
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
1126
+ * @access public
1127
+ */
1128
+ class nusoap_xmlschema extends nusoap_base
1129
+ {
1130
+
1131
+ // files
1132
+ var $schema = '';
1133
+ var $xml = '';
1134
+ // namespaces
1135
+ var $enclosingNamespaces;
1136
+ // schema info
1137
+ var $schemaInfo = array();
1138
+ var $schemaTargetNamespace = '';
1139
+ // types, elements, attributes defined by the schema
1140
+ var $attributes = array();
1141
+ var $complexTypes = array();
1142
+ var $complexTypeStack = array();
1143
+ var $currentComplexType = null;
1144
+ var $elements = array();
1145
+ var $elementStack = array();
1146
+ var $currentElement = null;
1147
+ var $simpleTypes = array();
1148
+ var $simpleTypeStack = array();
1149
+ var $currentSimpleType = null;
1150
+ // imports
1151
+ var $imports = array();
1152
+ // parser vars
1153
+ var $parser;
1154
+ var $position = 0;
1155
+ var $depth = 0;
1156
+ var $depth_array = array();
1157
+ var $message = array();
1158
+ var $defaultNamespace = array();
1159
+
1160
+ /**
1161
+ * constructor
1162
+ *
1163
+ * @param string $schema schema document URI
1164
+ * @param string $xml xml document URI
1165
+ * @param string $namespaces namespaces defined in enclosing XML
1166
+ * @access public
1167
+ */
1168
+ function __construct($schema = '', $xml = '', $namespaces = array())
1169
+ {
1170
+ parent::__construct();
1171
+ $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1172
+ // files
1173
+ $this->schema = $schema;
1174
+ $this->xml = $xml;
1175
+
1176
+ // namespaces
1177
+ $this->enclosingNamespaces = $namespaces;
1178
+ $this->namespaces = array_merge($this->namespaces, $namespaces);
1179
+
1180
+ // parse schema file
1181
+ if ($schema != '') {
1182
+ $this->debug('initial schema file: ' . $schema);
1183
+ $this->parseFile($schema, 'schema');
1184
+ }
1185
+
1186
+ // parse xml file
1187
+ if ($xml != '') {
1188
+ $this->debug('initial xml file: ' . $xml);
1189
+ $this->parseFile($xml, 'xml');
1190
+ }
1191
+
1192
+ }
1193
+
1194
+ /**
1195
+ * parse an XML file
1196
+ *
1197
+ * @param string $xml path/URL to XML file
1198
+ * @param string $type (schema | xml)
1199
+ * @return boolean
1200
+ * @access public
1201
+ */
1202
+ function parseFile($xml, $type)
1203
+ {
1204
+ // parse xml file
1205
+ if ($xml != "") {
1206
+ $xmlStr = @join("", @file($xml));
1207
+ if ($xmlStr == "") {
1208
+ $msg = 'Error reading XML from ' . $xml;
1209
+ $this->setError($msg);
1210
+ $this->debug($msg);
1211
+ return false;
1212
+ } else {
1213
+ $this->debug("parsing $xml");
1214
+ $this->parseString($xmlStr, $type);
1215
+ $this->debug("done parsing $xml");
1216
+ return true;
1217
+ }
1218
+ }
1219
+ return false;
1220
+ }
1221
+
1222
+ /**
1223
+ * parse an XML string
1224
+ *
1225
+ * @param string $xml path or URL
1226
+ * @param string $type (schema|xml)
1227
+ * @access private
1228
+ */
1229
+ function parseString($xml, $type)
1230
+ {
1231
+ // parse xml string
1232
+ if ($xml != "") {
1233
+
1234
+ // Create an XML parser.
1235
+ $this->parser = xml_parser_create();
1236
+ // Set the options for parsing the XML data.
1237
+ xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1238
+
1239
+ // Set the object for the parser.
1240
+ xml_set_object($this->parser, $this);
1241
+
1242
+ // Set the element handlers for the parser.
1243
+ if ($type == "schema") {
1244
+ xml_set_element_handler($this->parser, 'schemaStartElement', 'schemaEndElement');
1245
+ xml_set_character_data_handler($this->parser, 'schemaCharacterData');
1246
+ } elseif ($type == "xml") {
1247
+ xml_set_element_handler($this->parser, 'xmlStartElement', 'xmlEndElement');
1248
+ xml_set_character_data_handler($this->parser, 'xmlCharacterData');
1249
+ }
1250
+
1251
+ // Parse the XML file.
1252
+ if (!xml_parse($this->parser, $xml, true)) {
1253
+ // Display an error message.
1254
+ $errstr = sprintf('XML error parsing XML schema on line %d: %s',
1255
+ xml_get_current_line_number($this->parser),
1256
+ xml_error_string(xml_get_error_code($this->parser))
1257
+ );
1258
+ $this->debug($errstr);
1259
+ $this->debug("XML payload:\n" . $xml);
1260
+ $this->setError($errstr);
1261
+ }
1262
+
1263
+ xml_parser_free($this->parser);
1264
+ unset($this->parser);
1265
+ } else {
1266
+ $this->debug('no xml passed to parseString()!!');
1267
+ $this->setError('no xml passed to parseString()!!');
1268
+ }
1269
+ }
1270
+
1271
+ /**
1272
+ * gets a type name for an unnamed type
1273
+ *
1274
+ * @param string Element name
1275
+ * @return string A type name for an unnamed type
1276
+ * @access private
1277
+ */
1278
+ function CreateTypeName($ename)
1279
+ {
1280
+ $scope = '';
1281
+ for ($i = 0; $i < count($this->complexTypeStack); $i++) {
1282
+ $scope .= $this->complexTypeStack[$i] . '_';
1283
+ }
1284
+ return $scope . $ename . '_ContainedType';
1285
+ }
1286
+
1287
+ /**
1288
+ * start-element handler
1289
+ *
1290
+ * @param string $parser XML parser object
1291
+ * @param string $name element name
1292
+ * @param string $attrs associative array of attributes
1293
+ * @access private
1294
+ */
1295
+ function schemaStartElement($parser, $name, $attrs)
1296
+ {
1297
+
1298
+ // position in the total number of elements, starting from 0
1299
+ $pos = $this->position++;
1300
+ $depth = $this->depth++;
1301
+ // set self as current value for this depth
1302
+ $this->depth_array[$depth] = $pos;
1303
+ $this->message[$pos] = array('cdata' => '');
1304
+ if ($depth > 0) {
1305
+ $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1306
+ } else {
1307
+ $this->defaultNamespace[$pos] = false;
1308
+ }
1309
+
1310
+ // get element prefix
1311
+ if ($prefix = $this->getPrefix($name)) {
1312
+ // get unqualified name
1313
+ $name = $this->getLocalPart($name);
1314
+ } else {
1315
+ $prefix = '';
1316
+ }
1317
+
1318
+ // loop thru attributes, expanding, and registering namespace declarations
1319
+ if (count($attrs) > 0) {
1320
+ foreach ($attrs as $k => $v) {
1321
+ // if ns declarations, add to class level array of valid namespaces
1322
+ if (preg_match('/^xmlns/', $k)) {
1323
+ //$this->xdebug("$k: $v");
1324
+ //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1325
+ if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
1326
+ //$this->xdebug("Add namespace[$ns_prefix] = $v");
1327
+ $this->namespaces[$ns_prefix] = $v;
1328
+ } else {
1329
+ $this->defaultNamespace[$pos] = $v;
1330
+ if (!$this->getPrefixFromNamespace($v)) {
1331
+ $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
1332
+ }
1333
+ }
1334
+ if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
1335
+ $this->XMLSchemaVersion = $v;
1336
+ $this->namespaces['xsi'] = $v . '-instance';
1337
+ }
1338
+ }
1339
+ }
1340
+ foreach ($attrs as $k => $v) {
1341
+ // expand each attribute
1342
+ $k = strpos($k, ':') ? $this->expandQname($k) : $k;
1343
+ $v = strpos($v, ':') ? $this->expandQname($v) : $v;
1344
+ $eAttrs[$k] = $v;
1345
+ }
1346
+ $attrs = $eAttrs;
1347
+ } else {
1348
+ $attrs = array();
1349
+ }
1350
+ // find status, register data
1351
+ switch ($name) {
1352
+ case 'all': // (optional) compositor content for a complexType
1353
+ case 'choice':
1354
+ case 'group':
1355
+ case 'sequence':
1356
+ //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1357
+ $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1358
+ //if($name == 'all' || $name == 'sequence'){
1359
+ // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1360
+ //}
1361
+ break;
1362
+ case 'attribute': // complexType attribute
1363
+ //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1364
+ $this->xdebug("parsing attribute:");
1365
+ $this->appendDebug($this->varDump($attrs));
1366
+ if (!isset($attrs['form'])) {
1367
+ // TODO: handle globals
1368
+ $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1369
+ }
1370
+ if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1371
+ $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1372
+ if (!strpos($v, ':')) {
1373
+ // no namespace in arrayType attribute value...
1374
+ if ($this->defaultNamespace[$pos]) {
1375
+ // ...so use the default
1376
+ $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1377
+ }
1378
+ }
1379
+ }
1380
+ if (isset($attrs['name'])) {
1381
+ $this->attributes[$attrs['name']] = $attrs;
1382
+ $aname = $attrs['name'];
1383
+ } elseif (isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType') {
1384
+ if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1385
+ $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1386
+ } else {
1387
+ $aname = '';
1388
+ }
1389
+ } elseif (isset($attrs['ref'])) {
1390
+ $aname = $attrs['ref'];
1391
+ $this->attributes[$attrs['ref']] = $attrs;
1392
+ }
1393
+
1394
+ if ($this->currentComplexType) { // This should *always* be
1395
+ $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1396
+ }
1397
+ // arrayType attribute
1398
+ if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType') {
1399
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1400
+ $prefix = $this->getPrefix($aname);
1401
+ if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1402
+ $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1403
+ } else {
1404
+ $v = '';
1405
+ }
1406
+ if (strpos($v, '[,]')) {
1407
+ $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1408
+ }
1409
+ $v = substr($v, 0, strpos($v, '[')); // clip the []
1410
+ if (!strpos($v, ':') && isset($this->typemap[$this->XMLSchemaVersion][$v])) {
1411
+ $v = $this->XMLSchemaVersion . ':' . $v;
1412
+ }
1413
+ $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1414
+ }
1415
+ break;
1416
+ case 'complexContent': // (optional) content for a complexType
1417
+ $this->xdebug("do nothing for element $name");
1418
+ break;
1419
+ case 'complexType':
1420
+ array_push($this->complexTypeStack, $this->currentComplexType);
1421
+ if (isset($attrs['name'])) {
1422
+ // TODO: what is the scope of named complexTypes that appear
1423
+ // nested within other c complexTypes?
1424
+ $this->xdebug('processing named complexType ' . $attrs['name']);
1425
+ //$this->currentElement = false;
1426
+ $this->currentComplexType = $attrs['name'];
1427
+ $this->complexTypes[$this->currentComplexType] = $attrs;
1428
+ $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1429
+ // This is for constructs like
1430
+ // <complexType name="ListOfString" base="soap:Array">
1431
+ // <sequence>
1432
+ // <element name="string" type="xsd:string"
1433
+ // minOccurs="0" maxOccurs="unbounded" />
1434
+ // </sequence>
1435
+ // </complexType>
1436
+ if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
1437
+ $this->xdebug('complexType is unusual array');
1438
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1439
+ } else {
1440
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1441
+ }
1442
+ } else {
1443
+ $name = $this->CreateTypeName($this->currentElement);
1444
+ $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
1445
+ $this->currentComplexType = $name;
1446
+ //$this->currentElement = false;
1447
+ $this->complexTypes[$this->currentComplexType] = $attrs;
1448
+ $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1449
+ // This is for constructs like
1450
+ // <complexType name="ListOfString" base="soap:Array">
1451
+ // <sequence>
1452
+ // <element name="string" type="xsd:string"
1453
+ // minOccurs="0" maxOccurs="unbounded" />
1454
+ // </sequence>
1455
+ // </complexType>
1456
+ if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
1457
+ $this->xdebug('complexType is unusual array');
1458
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1459
+ } else {
1460
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1461
+ }
1462
+ }
1463
+ $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false';
1464
+ break;
1465
+ case 'element':
1466
+ array_push($this->elementStack, $this->currentElement);
1467
+ if (!isset($attrs['form'])) {
1468
+ if ($this->currentComplexType) {
1469
+ $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1470
+ } else {
1471
+ // global
1472
+ $attrs['form'] = 'qualified';
1473
+ }
1474
+ }
1475
+ if (isset($attrs['type'])) {
1476
+ $this->xdebug("processing typed element " . $attrs['name'] . " of type " . $attrs['type']);
1477
+ if (!$this->getPrefix($attrs['type'])) {
1478
+ if ($this->defaultNamespace[$pos]) {
1479
+ $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1480
+ $this->xdebug('used default namespace to make type ' . $attrs['type']);
1481
+ }
1482
+ }
1483
+ // This is for constructs like
1484
+ // <complexType name="ListOfString" base="soap:Array">
1485
+ // <sequence>
1486
+ // <element name="string" type="xsd:string"
1487
+ // minOccurs="0" maxOccurs="unbounded" />
1488
+ // </sequence>
1489
+ // </complexType>
1490
+ if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
1491
+ $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1492
+ $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1493
+ }
1494
+ $this->currentElement = $attrs['name'];
1495
+ $ename = $attrs['name'];
1496
+ } elseif (isset($attrs['ref'])) {
1497
+ $this->xdebug("processing element as ref to " . $attrs['ref']);
1498
+ $this->currentElement = "ref to " . $attrs['ref'];
1499
+ $ename = $this->getLocalPart($attrs['ref']);
1500
+ } else {
1501
+ $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
1502
+ $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
1503
+ $this->currentElement = $attrs['name'];
1504
+ $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
1505
+ $ename = $attrs['name'];
1506
+ }
1507
+ if (isset($ename) && $this->currentComplexType) {
1508
+ $this->xdebug("add element $ename to complexType $this->currentComplexType");
1509
+ $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1510
+ } elseif (!isset($attrs['ref'])) {
1511
+ $this->xdebug("add element $ename to elements array");
1512
+ $this->elements[$attrs['name']] = $attrs;
1513
+ $this->elements[$attrs['name']]['typeClass'] = 'element';
1514
+ }
1515
+ break;
1516
+ case 'enumeration': // restriction value list member
1517
+ $this->xdebug('enumeration ' . $attrs['value']);
1518
+ if ($this->currentSimpleType) {
1519
+ $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1520
+ } elseif ($this->currentComplexType) {
1521
+ $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1522
+ }
1523
+ break;
1524
+ case 'extension': // simpleContent or complexContent type extension
1525
+ $this->xdebug('extension ' . $attrs['base']);
1526
+ if ($this->currentComplexType) {
1527
+ $ns = $this->getPrefix($attrs['base']);
1528
+ if ($ns == '') {
1529
+ $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
1530
+ } else {
1531
+ $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1532
+ }
1533
+ } else {
1534
+ $this->xdebug('no current complexType to set extensionBase');
1535
+ }
1536
+ break;
1537
+ case 'import':
1538
+ if (isset($attrs['schemaLocation'])) {
1539
+ $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1540
+ $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1541
+ } else {
1542
+ $this->xdebug('import namespace ' . $attrs['namespace']);
1543
+ $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1544
+ if (!$this->getPrefixFromNamespace($attrs['namespace'])) {
1545
+ $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace'];
1546
+ }
1547
+ }
1548
+ break;
1549
+ case 'include':
1550
+ if (isset($attrs['schemaLocation'])) {
1551
+ $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']);
1552
+ $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1553
+ } else {
1554
+ $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute');
1555
+ }
1556
+ break;
1557
+ case 'list': // simpleType value list
1558
+ $this->xdebug("do nothing for element $name");
1559
+ break;
1560
+ case 'restriction': // simpleType, simpleContent or complexContent value restriction
1561
+ $this->xdebug('restriction ' . $attrs['base']);
1562
+ if ($this->currentSimpleType) {
1563
+ $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1564
+ } elseif ($this->currentComplexType) {
1565
+ $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1566
+ if (strstr($attrs['base'], ':') == ':Array') {
1567
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1568
+ }
1569
+ }
1570
+ break;
1571
+ case 'schema':
1572
+ $this->schemaInfo = $attrs;
1573
+ $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1574
+ if (isset($attrs['targetNamespace'])) {
1575
+ $this->schemaTargetNamespace = $attrs['targetNamespace'];
1576
+ }
1577
+ if (!isset($attrs['elementFormDefault'])) {
1578
+ $this->schemaInfo['elementFormDefault'] = 'unqualified';
1579
+ }
1580
+ if (!isset($attrs['attributeFormDefault'])) {
1581
+ $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1582
+ }
1583
+ break;
1584
+ case 'simpleContent': // (optional) content for a complexType
1585
+ if ($this->currentComplexType) { // This should *always* be
1586
+ $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true';
1587
+ } else {
1588
+ $this->xdebug("do nothing for element $name because there is no current complexType");
1589
+ }
1590
+ break;
1591
+ case 'simpleType':
1592
+ array_push($this->simpleTypeStack, $this->currentSimpleType);
1593
+ if (isset($attrs['name'])) {
1594
+ $this->xdebug("processing simpleType for name " . $attrs['name']);
1595
+ $this->currentSimpleType = $attrs['name'];
1596
+ $this->simpleTypes[$attrs['name']] = $attrs;
1597
+ $this->simpleTypes[$attrs['name']]['typeClass'] = 'simpleType';
1598
+ $this->simpleTypes[$attrs['name']]['phpType'] = 'scalar';
1599
+ } else {
1600
+ $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
1601
+ $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
1602
+ $this->currentSimpleType = $name;
1603
+ //$this->currentElement = false;
1604
+ $this->simpleTypes[$this->currentSimpleType] = $attrs;
1605
+ $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1606
+ }
1607
+ break;
1608
+ case 'union': // simpleType type list
1609
+ $this->xdebug("do nothing for element $name");
1610
+ break;
1611
+ default:
1612
+ $this->xdebug("do not have any logic to process element $name");
1613
+ }
1614
+ }
1615
+
1616
+ /**
1617
+ * end-element handler
1618
+ *
1619
+ * @param string $parser XML parser object
1620
+ * @param string $name element name
1621
+ * @access private
1622
+ */
1623
+ function schemaEndElement($parser, $name)
1624
+ {
1625
+ // bring depth down a notch
1626
+ $this->depth--;
1627
+ // position of current element is equal to the last value left in depth_array for my depth
1628
+ if (isset($this->depth_array[$this->depth])) {
1629
+ $pos = $this->depth_array[$this->depth];
1630
+ }
1631
+ // get element prefix
1632
+ if ($prefix = $this->getPrefix($name)) {
1633
+ // get unqualified name
1634
+ $name = $this->getLocalPart($name);
1635
+ } else {
1636
+ $prefix = '';
1637
+ }
1638
+ // move on...
1639
+ if ($name == 'complexType') {
1640
+ $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
1641
+ $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType]));
1642
+ $this->currentComplexType = array_pop($this->complexTypeStack);
1643
+ //$this->currentElement = false;
1644
+ }
1645
+ if ($name == 'element') {
1646
+ $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
1647
+ $this->currentElement = array_pop($this->elementStack);
1648
+ }
1649
+ if ($name == 'simpleType') {
1650
+ $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
1651
+ $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType]));
1652
+ $this->currentSimpleType = array_pop($this->simpleTypeStack);
1653
+ }
1654
+ }
1655
+
1656
+ /**
1657
+ * element content handler
1658
+ *
1659
+ * @param string $parser XML parser object
1660
+ * @param string $data element content
1661
+ * @access private
1662
+ */
1663
+ function schemaCharacterData($parser, $data)
1664
+ {
1665
+ $pos = $this->depth_array[$this->depth - 1];
1666
+ $this->message[$pos]['cdata'] .= $data;
1667
+ }
1668
+
1669
+ /**
1670
+ * serialize the schema
1671
+ *
1672
+ * @access public
1673
+ */
1674
+ function serializeSchema()
1675
+ {
1676
+
1677
+ $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1678
+ $xml = '';
1679
+ // imports
1680
+ if (sizeof($this->imports) > 0) {
1681
+ foreach ($this->imports as $ns => $list) {
1682
+ foreach ($list as $ii) {
1683
+ if ($ii['location'] != '') {
1684
+ $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1685
+ } else {
1686
+ $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1687
+ }
1688
+ }
1689
+ }
1690
+ }
1691
+ // complex types
1692
+ foreach ($this->complexTypes as $typeName => $attrs) {
1693
+ $contentStr = '';
1694
+ // serialize child elements
1695
+ if (isset($attrs['elements']) && (count($attrs['elements']) > 0)) {
1696
+ foreach ($attrs['elements'] as $element => $eParts) {
1697
+ if (isset($eParts['ref'])) {
1698
+ $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
1699
+ } else {
1700
+ $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
1701
+ foreach ($eParts as $aName => $aValue) {
1702
+ // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1703
+ if ($aName != 'name' && $aName != 'type') {
1704
+ $contentStr .= " $aName=\"$aValue\"";
1705
+ }
1706
+ }
1707
+ $contentStr .= "/>\n";
1708
+ }
1709
+ }
1710
+ // compositor wraps elements
1711
+ if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
1712
+ $contentStr = " <$schemaPrefix:$attrs[compositor]>\n" . $contentStr . " </$schemaPrefix:$attrs[compositor]>\n";
1713
+ }
1714
+ }
1715
+ // attributes
1716
+ if (isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)) {
1717
+ foreach ($attrs['attrs'] as $attr => $aParts) {
1718
+ $contentStr .= " <$schemaPrefix:attribute";
1719
+ foreach ($aParts as $a => $v) {
1720
+ if ($a == 'ref' || $a == 'type') {
1721
+ $contentStr .= " $a=\"" . $this->contractQName($v) . '"';
1722
+ } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
1723
+ $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1724
+ $contentStr .= ' wsdl:arrayType="' . $this->contractQName($v) . '"';
1725
+ } else {
1726
+ $contentStr .= " $a=\"$v\"";
1727
+ }
1728
+ }
1729
+ $contentStr .= "/>\n";
1730
+ }
1731
+ }
1732
+ // if restriction
1733
+ if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != '') {
1734
+ $contentStr = " <$schemaPrefix:restriction base=\"" . $this->contractQName($attrs['restrictionBase']) . "\">\n" . $contentStr . " </$schemaPrefix:restriction>\n";
1735
+ // complex or simple content
1736
+ if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)) {
1737
+ $contentStr = " <$schemaPrefix:complexContent>\n" . $contentStr . " </$schemaPrefix:complexContent>\n";
1738
+ }
1739
+ }
1740
+ // finalize complex type
1741
+ if ($contentStr != '') {
1742
+ $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n" . $contentStr . " </$schemaPrefix:complexType>\n";
1743
+ } else {
1744
+ $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1745
+ }
1746
+ $xml .= $contentStr;
1747
+ }
1748
+ // simple types
1749
+ if (isset($this->simpleTypes) && count($this->simpleTypes) > 0) {
1750
+ foreach ($this->simpleTypes as $typeName => $eParts) {
1751
+ $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"" . $this->contractQName($eParts['type']) . "\">\n";
1752
+ if (isset($eParts['enumeration'])) {
1753
+ foreach ($eParts['enumeration'] as $e) {
1754
+ $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
1755
+ }
1756
+ }
1757
+ $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
1758
+ }
1759
+ }
1760
+ // elements
1761
+ if (isset($this->elements) && count($this->elements) > 0) {
1762
+ foreach ($this->elements as $element => $eParts) {
1763
+ $xml .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"/>\n";
1764
+ }
1765
+ }
1766
+ // attributes
1767
+ if (isset($this->attributes) && count($this->attributes) > 0) {
1768
+ foreach ($this->attributes as $attr => $aParts) {
1769
+ $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"" . $this->contractQName($aParts['type']) . "\"\n/>";
1770
+ }
1771
+ }
1772
+ // finish 'er up
1773
+ $attr = '';
1774
+ foreach ($this->schemaInfo as $k => $v) {
1775
+ if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
1776
+ $attr .= " $k=\"$v\"";
1777
+ }
1778
+ }
1779
+ $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
1780
+ foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1781
+ $el .= " xmlns:$nsp=\"$ns\"";
1782
+ }
1783
+ $xml = $el . ">\n" . $xml . "</$schemaPrefix:schema>\n";
1784
+ return $xml;
1785
+ }
1786
+
1787
+ /**
1788
+ * adds debug data to the clas level debug string
1789
+ *
1790
+ * @param string $string debug data
1791
+ * @access private
1792
+ */
1793
+ function xdebug($string)
1794
+ {
1795
+ $this->debug('<' . $this->schemaTargetNamespace . '> ' . $string);
1796
+ }
1797
+
1798
+ /**
1799
+ * get the PHP type of a user defined type in the schema
1800
+ * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
1801
+ * returns false if no type exists, or not w/ the given namespace
1802
+ * else returns a string that is either a native php type, or 'struct'
1803
+ *
1804
+ * @param string $type name of defined type
1805
+ * @param string $ns namespace of type
1806
+ * @return mixed
1807
+ * @access public
1808
+ * @deprecated
1809
+ */
1810
+ function getPHPType($type, $ns)
1811
+ {
1812
+ if (isset($this->typemap[$ns][$type])) {
1813
+ //print "found type '$type' and ns $ns in typemap<br>";
1814
+ return $this->typemap[$ns][$type];
1815
+ } elseif (isset($this->complexTypes[$type])) {
1816
+ //print "getting type '$type' and ns $ns from complexTypes array<br>";
1817
+ return $this->complexTypes[$type]['phpType'];
1818
+ }
1819
+ return false;
1820
+ }
1821
+
1822
+ /**
1823
+ * returns an associative array of information about a given type
1824
+ * returns false if no type exists by the given name
1825
+ *
1826
+ * For a complexType typeDef = array(
1827
+ * 'restrictionBase' => '',
1828
+ * 'phpType' => '',
1829
+ * 'compositor' => '(sequence|all)',
1830
+ * 'elements' => array(), // refs to elements array
1831
+ * 'attrs' => array() // refs to attributes array
1832
+ * ... and so on (see addComplexType)
1833
+ * )
1834
+ *
1835
+ * For simpleType or element, the array has different keys.
1836
+ *
1837
+ * @param string $type
1838
+ * @return mixed
1839
+ * @access public
1840
+ * @see addComplexType
1841
+ * @see addSimpleType
1842
+ * @see addElement
1843
+ */
1844
+ function getTypeDef($type)
1845
+ {
1846
+ //$this->debug("in getTypeDef for type $type");
1847
+ if (substr($type, -1) == '^') {
1848
+ $is_element = 1;
1849
+ $type = substr($type, 0, -1);
1850
+ } else {
1851
+ $is_element = 0;
1852
+ }
1853
+
1854
+ if ((!$is_element) && isset($this->complexTypes[$type])) {
1855
+ $this->xdebug("in getTypeDef, found complexType $type");
1856
+ return $this->complexTypes[$type];
1857
+ } elseif ((!$is_element) && isset($this->simpleTypes[$type])) {
1858
+ $this->xdebug("in getTypeDef, found simpleType $type");
1859
+ if (!isset($this->simpleTypes[$type]['phpType'])) {
1860
+ // get info for type to tack onto the simple type
1861
+ // TODO: can this ever really apply (i.e. what is a simpleType really?)
1862
+ $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1863
+ $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1864
+ $etype = $this->getTypeDef($uqType);
1865
+ if ($etype) {
1866
+ $this->xdebug("in getTypeDef, found type for simpleType $type:");
1867
+ $this->xdebug($this->varDump($etype));
1868
+ if (isset($etype['phpType'])) {
1869
+ $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1870
+ }
1871
+ if (isset($etype['elements'])) {
1872
+ $this->simpleTypes[$type]['elements'] = $etype['elements'];
1873
+ }
1874
+ }
1875
+ }
1876
+ return $this->simpleTypes[$type];
1877
+ } elseif (isset($this->elements[$type])) {
1878
+ $this->xdebug("in getTypeDef, found element $type");
1879
+ if (!isset($this->elements[$type]['phpType'])) {
1880
+ // get info for type to tack onto the element
1881
+ $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1882
+ $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1883
+ $etype = $this->getTypeDef($uqType);
1884
+ if ($etype) {
1885
+ $this->xdebug("in getTypeDef, found type for element $type:");
1886
+ $this->xdebug($this->varDump($etype));
1887
+ if (isset($etype['phpType'])) {
1888
+ $this->elements[$type]['phpType'] = $etype['phpType'];
1889
+ }
1890
+ if (isset($etype['elements'])) {
1891
+ $this->elements[$type]['elements'] = $etype['elements'];
1892
+ }
1893
+ if (isset($etype['extensionBase'])) {
1894
+ $this->elements[$type]['extensionBase'] = $etype['extensionBase'];
1895
+ }
1896
+ } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
1897
+ $this->xdebug("in getTypeDef, element $type is an XSD type");
1898
+ $this->elements[$type]['phpType'] = 'scalar';
1899
+ }
1900
+ }
1901
+ return $this->elements[$type];
1902
+ } elseif (isset($this->attributes[$type])) {
1903
+ $this->xdebug("in getTypeDef, found attribute $type");
1904
+ return $this->attributes[$type];
1905
+ } elseif (preg_match('/_ContainedType$/', $type)) {
1906
+ $this->xdebug("in getTypeDef, have an untyped element $type");
1907
+ $typeDef['typeClass'] = 'simpleType';
1908
+ $typeDef['phpType'] = 'scalar';
1909
+ $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
1910
+ return $typeDef;
1911
+ }
1912
+ $this->xdebug("in getTypeDef, did not find $type");
1913
+ return false;
1914
+ }
1915
+
1916
+ /**
1917
+ * returns a sample serialization of a given type, or false if no type by the given name
1918
+ *
1919
+ * @param string $type name of type
1920
+ * @return mixed
1921
+ * @access public
1922
+ * @deprecated
1923
+ */
1924
+ function serializeTypeDef($type)
1925
+ {
1926
+ //print "in sTD() for type $type<br>";
1927
+ if ($typeDef = $this->getTypeDef($type)) {
1928
+ $str .= '<' . $type;
1929
+ if (is_array($typeDef['attrs'])) {
1930
+ foreach ($typeDef['attrs'] as $attName => $data) {
1931
+ $str .= " $attName=\"{type = " . $data['type'] . "}\"";
1932
+ }
1933
+ }
1934
+ $str .= " xmlns=\"" . $this->schema['targetNamespace'] . "\"";
1935
+ if (count($typeDef['elements']) > 0) {
1936
+ $str .= ">";
1937
+ foreach ($typeDef['elements'] as $element => $eData) {
1938
+ $str .= $this->serializeTypeDef($element);
1939
+ }
1940
+ $str .= "</$type>";
1941
+ } elseif ($typeDef['typeClass'] == 'element') {
1942
+ $str .= "></$type>";
1943
+ } else {
1944
+ $str .= "/>";
1945
+ }
1946
+ return $str;
1947
+ }
1948
+ return false;
1949
+ }
1950
+
1951
+ /**
1952
+ * returns HTML form elements that allow a user
1953
+ * to enter values for creating an instance of the given type.
1954
+ *
1955
+ * @param string $name name for type instance
1956
+ * @param string $type name of type
1957
+ * @return string
1958
+ * @access public
1959
+ * @deprecated
1960
+ */
1961
+ function typeToForm($name, $type)
1962
+ {
1963
+ // get typedef
1964
+ if ($typeDef = $this->getTypeDef($type)) {
1965
+ // if struct
1966
+ if ($typeDef['phpType'] == 'struct') {
1967
+ $buffer .= '<table>';
1968
+ foreach ($typeDef['elements'] as $child => $childDef) {
1969
+ $buffer .= "
1970
+ <tr><td align='right'>$childDef[name] (type: " . $this->getLocalPart($childDef['type']) . "):</td>
1971
+ <td><input type='text' name='parameters[" . $name . "][$childDef[name]]'></td></tr>";
1972
+ }
1973
+ $buffer .= '</table>';
1974
+ // if array
1975
+ } elseif ($typeDef['phpType'] == 'array') {
1976
+ $buffer .= '<table>';
1977
+ for ($i = 0; $i < 3; $i++) {
1978
+ $buffer .= "
1979
+ <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1980
+ <td><input type='text' name='parameters[" . $name . "][]'></td></tr>";
1981
+ }
1982
+ $buffer .= '</table>';
1983
+ // if scalar
1984
+ } else {
1985
+ $buffer .= "<input type='text' name='parameters[$name]'>";
1986
+ }
1987
+ } else {
1988
+ $buffer .= "<input type='text' name='parameters[$name]'>";
1989
+ }
1990
+ return $buffer;
1991
+ }
1992
+
1993
+ /**
1994
+ * adds a complex type to the schema
1995
+ *
1996
+ * example: array
1997
+ *
1998
+ * addType(
1999
+ * 'ArrayOfstring',
2000
+ * 'complexType',
2001
+ * 'array',
2002
+ * '',
2003
+ * 'SOAP-ENC:Array',
2004
+ * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
2005
+ * 'xsd:string'
2006
+ * );
2007
+ *
2008
+ * example: PHP associative array ( SOAP Struct )
2009
+ *
2010
+ * addType(
2011
+ * 'SOAPStruct',
2012
+ * 'complexType',
2013
+ * 'struct',
2014
+ * 'all',
2015
+ * array('myVar'=> array('name'=>'myVar','type'=>'string')
2016
+ * );
2017
+ *
2018
+ * @param name
2019
+ * @param typeClass (complexType|simpleType|attribute)
2020
+ * @param phpType : currently supported are array and struct (php assoc array)
2021
+ * @param compositor (all|sequence|choice)
2022
+ * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2023
+ * @param elements = array ( name = array(name=>'',type=>'') )
2024
+ * @param attrs = array(
2025
+ * array(
2026
+ * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
2027
+ * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
2028
+ * )
2029
+ * )
2030
+ * @param arrayType : namespace:name (http://www.w3.org/2001/XMLSchema:string)
2031
+ * @access public
2032
+ * @see getTypeDef
2033
+ */
2034
+ function addComplexType($name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '')
2035
+ {
2036
+ $this->complexTypes[$name] = array(
2037
+ 'name' => $name,
2038
+ 'typeClass' => $typeClass,
2039
+ 'phpType' => $phpType,
2040
+ 'compositor' => $compositor,
2041
+ 'restrictionBase' => $restrictionBase,
2042
+ 'elements' => $elements,
2043
+ 'attrs' => $attrs,
2044
+ 'arrayType' => $arrayType
2045
+ );
2046
+
2047
+ $this->xdebug("addComplexType $name:");
2048
+ $this->appendDebug($this->varDump($this->complexTypes[$name]));
2049
+ }
2050
+
2051
+ /**
2052
+ * adds a simple type to the schema
2053
+ *
2054
+ * @param string $name
2055
+ * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2056
+ * @param string $typeClass (should always be simpleType)
2057
+ * @param string $phpType (should always be scalar)
2058
+ * @param array $enumeration array of values
2059
+ * @access public
2060
+ * @see nusoap_xmlschema
2061
+ * @see getTypeDef
2062
+ */
2063
+ function addSimpleType($name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array())
2064
+ {
2065
+ $this->simpleTypes[$name] = array(
2066
+ 'name' => $name,
2067
+ 'typeClass' => $typeClass,
2068
+ 'phpType' => $phpType,
2069
+ 'type' => $restrictionBase,
2070
+ 'enumeration' => $enumeration
2071
+ );
2072
+
2073
+ $this->xdebug("addSimpleType $name:");
2074
+ $this->appendDebug($this->varDump($this->simpleTypes[$name]));
2075
+ }
2076
+
2077
+ /**
2078
+ * adds an element to the schema
2079
+ *
2080
+ * @param array $attrs attributes that must include name and type
2081
+ * @see nusoap_xmlschema
2082
+ * @access public
2083
+ */
2084
+ function addElement($attrs)
2085
+ {
2086
+ if (!$this->getPrefix($attrs['type'])) {
2087
+ $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
2088
+ }
2089
+ $this->elements[$attrs['name']] = $attrs;
2090
+ $this->elements[$attrs['name']]['typeClass'] = 'element';
2091
+
2092
+ $this->xdebug("addElement " . $attrs['name']);
2093
+ $this->appendDebug($this->varDump($this->elements[$attrs['name']]));
2094
+ }
2095
+ }
2096
+
2097
+ /**
2098
+ * Backward compatibility
2099
+ */
2100
+ class XMLSchema extends nusoap_xmlschema
2101
+ {
2102
+ }
2103
+
2104
+
2105
+ /**
2106
+ * For creating serializable abstractions of native PHP types. This class
2107
+ * allows element name/namespace, XSD type, and XML attributes to be
2108
+ * associated with a value. This is extremely useful when WSDL is not
2109
+ * used, but is also useful when WSDL is used with polymorphic types, including
2110
+ * xsd:anyType and user-defined types.
2111
+ *
2112
+ * @author Dietrich Ayala <dietrich@ganx4.com>
2113
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
2114
+ * @access public
2115
+ */
2116
+ class soapval extends nusoap_base
2117
+ {
2118
+ /**
2119
+ * The XML element name
2120
+ *
2121
+ * @var string
2122
+ * @access private
2123
+ */
2124
+ var $name;
2125
+ /**
2126
+ * The XML type name (string or false)
2127
+ *
2128
+ * @var mixed
2129
+ * @access private
2130
+ */
2131
+ var $type;
2132
+ /**
2133
+ * The PHP value
2134
+ *
2135
+ * @var mixed
2136
+ * @access private
2137
+ */
2138
+ var $value;
2139
+ /**
2140
+ * The XML element namespace (string or false)
2141
+ *
2142
+ * @var mixed
2143
+ * @access private
2144
+ */
2145
+ var $element_ns;
2146
+ /**
2147
+ * The XML type namespace (string or false)
2148
+ *
2149
+ * @var mixed
2150
+ * @access private
2151
+ */
2152
+ var $type_ns;
2153
+ /**
2154
+ * The XML element attributes (array or false)
2155
+ *
2156
+ * @var mixed
2157
+ * @access private
2158
+ */
2159
+ var $attributes;
2160
+
2161
+ /**
2162
+ * constructor
2163
+ *
2164
+ * @param string $name optional name
2165
+ * @param mixed $type optional type name
2166
+ * @param mixed $value optional value
2167
+ * @param mixed $element_ns optional namespace of value
2168
+ * @param mixed $type_ns optional namespace of type
2169
+ * @param mixed $attributes associative array of attributes to add to element serialization
2170
+ * @access public
2171
+ */
2172
+ function __construct($name = 'soapval', $type = false, $value = -1, $element_ns = false, $type_ns = false, $attributes = false)
2173
+ {
2174
+ parent::__construct();
2175
+ $this->name = $name;
2176
+ $this->type = $type;
2177
+ $this->value = $value;
2178
+ $this->element_ns = $element_ns;
2179
+ $this->type_ns = $type_ns;
2180
+ $this->attributes = $attributes;
2181
+ }
2182
+
2183
+ /**
2184
+ * return serialized value
2185
+ *
2186
+ * @param string $use The WSDL use value (encoded|literal)
2187
+ * @return string XML data
2188
+ * @access public
2189
+ */
2190
+ function serialize($use = 'encoded')
2191
+ {
2192
+ return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2193
+ }
2194
+
2195
+ /**
2196
+ * decodes a soapval object into a PHP native type
2197
+ *
2198
+ * @return mixed
2199
+ * @access public
2200
+ */
2201
+ function decode()
2202
+ {
2203
+ return $this->value;
2204
+ }
2205
+ }
2206
+
2207
+
2208
+ /**
2209
+ * transport class for sending/receiving data via HTTP and HTTPS
2210
+ * NOTE: PHP must be compiled with the CURL extension for HTTPS support
2211
+ *
2212
+ * @author Dietrich Ayala <dietrich@ganx4.com>
2213
+ * @author Scott Nichol <snichol@users.sourceforge.net>
2214
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
2215
+ * @access public
2216
+ */
2217
+ class soap_transport_http extends nusoap_base
2218
+ {
2219
+
2220
+ var $url = '';
2221
+ var $uri = '';
2222
+ var $digest_uri = '';
2223
+ var $scheme = '';
2224
+ var $host = '';
2225
+ var $port = '';
2226
+ var $path = '';
2227
+ var $request_method = 'POST';
2228
+ var $protocol_version = '1.0';
2229
+ var $encoding = '';
2230
+ var $outgoing_headers = array();
2231
+ var $incoming_headers = array();
2232
+ var $incoming_cookies = array();
2233
+ var $outgoing_payload = '';
2234
+ var $incoming_payload = '';
2235
+ var $response_status_line; // HTTP response status line
2236
+ var $useSOAPAction = true;
2237
+ var $persistentConnection = false;
2238
+ var $ch = false; // cURL handle
2239
+ var $ch_options = array(); // cURL custom options
2240
+ var $use_curl = false; // force cURL use
2241
+ var $proxy = null; // proxy information (associative array)
2242
+ var $username = '';
2243
+ var $password = '';
2244
+ var $authtype = '';
2245
+ var $digestRequest = array();
2246
+ var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
2247
+ // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2248
+ // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2249
+ // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2250
+ // passphrase: SSL key password/passphrase
2251
+ // certpassword: SSL certificate password
2252
+ // verifypeer: default is 1
2253
+ // verifyhost: default is 1
2254
+
2255
+ /**
2256
+ * constructor
2257
+ *
2258
+ * @param string $url The URL to which to connect
2259
+ * @param array $curl_options User-specified cURL options
2260
+ * @param boolean $use_curl Whether to try to force cURL use
2261
+ * @access public
2262
+ */
2263
+ function __construct($url, $curl_options = null, $use_curl = false)
2264
+ {
2265
+ parent::__construct();
2266
+ $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
2267
+ $this->appendDebug($this->varDump($curl_options));
2268
+ $this->setURL($url);
2269
+ if (is_array($curl_options)) {
2270
+ $this->ch_options = $curl_options;
2271
+ }
2272
+ $this->use_curl = $use_curl;
2273
+ preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
2274
+ $this->setHeader('User-Agent', $this->title . '/' . $this->version . ' (' . $rev[1] . ')');
2275
+ }
2276
+
2277
+ /**
2278
+ * sets a cURL option
2279
+ *
2280
+ * @param mixed $option The cURL option (always integer?)
2281
+ * @param mixed $value The cURL option value
2282
+ * @access private
2283
+ */
2284
+ function setCurlOption($option, $value)
2285
+ {
2286
+ $this->debug("setCurlOption option=$option, value=");
2287
+ $this->appendDebug($this->varDump($value));
2288
+ curl_setopt($this->ch, $option, $value);
2289
+ }
2290
+
2291
+ /**
2292
+ * sets an HTTP header
2293
+ *
2294
+ * @param string $name The name of the header
2295
+ * @param string $value The value of the header
2296
+ * @access private
2297
+ */
2298
+ function setHeader($name, $value)
2299
+ {
2300
+ $this->outgoing_headers[$name] = $value;
2301
+ $this->debug("set header $name: $value");
2302
+ }
2303
+
2304
+ /**
2305
+ * unsets an HTTP header
2306
+ *
2307
+ * @param string $name The name of the header
2308
+ * @access private
2309
+ */
2310
+ function unsetHeader($name)
2311
+ {
2312
+ if (isset($this->outgoing_headers[$name])) {
2313
+ $this->debug("unset header $name");
2314
+ unset($this->outgoing_headers[$name]);
2315
+ }
2316
+ }
2317
+
2318
+ /**
2319
+ * sets the URL to which to connect
2320
+ *
2321
+ * @param string $url The URL to which to connect
2322
+ * @access private
2323
+ */
2324
+ function setURL($url)
2325
+ {
2326
+ $this->url = $url;
2327
+
2328
+ $u = parse_url($url);
2329
+ foreach ($u as $k => $v) {
2330
+ $this->debug("parsed URL $k = $v");
2331
+ $this->$k = $v;
2332
+ }
2333
+
2334
+ // add any GET params to path
2335
+ if (isset($u['query']) && $u['query'] != '') {
2336
+ $this->path .= '?' . $u['query'];
2337
+ }
2338
+
2339
+ // set default port
2340
+ if (!isset($u['port'])) {
2341
+ if ($u['scheme'] == 'https') {
2342
+ $this->port = 443;
2343
+ } else {
2344
+ $this->port = 80;
2345
+ }
2346
+ }
2347
+
2348
+ $this->uri = $this->path;
2349
+ $this->digest_uri = $this->uri;
2350
+
2351
+ // build headers
2352
+ if (!isset($u['port'])) {
2353
+ $this->setHeader('Host', $this->host);
2354
+ } else {
2355
+ $this->setHeader('Host', $this->host . ':' . $this->port);
2356
+ }
2357
+
2358
+ if (isset($u['user']) && $u['user'] != '') {
2359
+ $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2360
+ }
2361
+ }
2362
+
2363
+ /**
2364
+ * gets the I/O method to use
2365
+ *
2366
+ * @return string I/O method to use (socket|curl|unknown)
2367
+ * @access private
2368
+ */
2369
+ function io_method()
2370
+ {
2371
+ if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) {
2372
+ return 'curl';
2373
+ }
2374
+ if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) {
2375
+ return 'socket';
2376
+ }
2377
+ return 'unknown';
2378
+ }
2379
+
2380
+ /**
2381
+ * establish an HTTP connection
2382
+ *
2383
+ * @param integer $timeout set connection timeout in seconds
2384
+ * @param integer $response_timeout set response timeout in seconds
2385
+ * @return boolean true if connected, false if not
2386
+ * @access private
2387
+ */
2388
+ function connect($connection_timeout = 0, $response_timeout = 30)
2389
+ {
2390
+ // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2391
+ // "regular" socket.
2392
+ // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2393
+ // loaded), and until PHP5 stream_get_wrappers is not available.
2394
+ // if ($this->scheme == 'https') {
2395
+ // if (version_compare(phpversion(), '4.3.0') >= 0) {
2396
+ // if (extension_loaded('openssl')) {
2397
+ // $this->scheme = 'ssl';
2398
+ // $this->debug('Using SSL over OpenSSL');
2399
+ // }
2400
+ // }
2401
+ // }
2402
+ $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2403
+ if ($this->io_method() == 'socket') {
2404
+ if (!is_array($this->proxy)) {
2405
+ $host = $this->host;
2406
+ $port = $this->port;
2407
+ } else {
2408
+ $host = $this->proxy['host'];
2409
+ $port = $this->proxy['port'];
2410
+ }
2411
+
2412
+ // use persistent connection
2413
+ if ($this->persistentConnection && isset($this->fp) && is_resource($this->fp)) {
2414
+ if (!feof($this->fp)) {
2415
+ $this->debug('Re-use persistent connection');
2416
+ return true;
2417
+ }
2418
+ fclose($this->fp);
2419
+ $this->debug('Closed persistent connection at EOF');
2420
+ }
2421
+
2422
+ // munge host if using OpenSSL
2423
+ if ($this->scheme == 'ssl') {
2424
+ $host = 'ssl://' . $host;
2425
+ }
2426
+ $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2427
+
2428
+ // open socket
2429
+ if ($connection_timeout > 0) {
2430
+ $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str, $connection_timeout);
2431
+ } else {
2432
+ $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str);
2433
+ }
2434
+
2435
+ // test pointer
2436
+ if (!$this->fp) {
2437
+ $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2438
+ if ($this->errno) {
2439
+ $msg .= ', Error (' . $this->errno . '): ' . $this->error_str;
2440
+ } else {
2441
+ $msg .= ' prior to connect(). This is often a problem looking up the host name.';
2442
+ }
2443
+ $this->debug($msg);
2444
+ $this->setError($msg);
2445
+ return false;
2446
+ }
2447
+
2448
+ // set response timeout
2449
+ $this->debug('set response timeout to ' . $response_timeout);
2450
+ socket_set_timeout($this->fp, $response_timeout);
2451
+
2452
+ $this->debug('socket connected');
2453
+ return true;
2454
+ } elseif ($this->io_method() == 'curl') {
2455
+ if (!extension_loaded('curl')) {
2456
+ // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
2457
+ $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.');
2458
+ return false;
2459
+ }
2460
+ // Avoid warnings when PHP does not have these options
2461
+ if (defined('CURLOPT_CONNECTIONTIMEOUT')) {
2462
+ $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
2463
+ } else {
2464
+ $CURLOPT_CONNECTIONTIMEOUT = 78;
2465
+ }
2466
+ if (defined('CURLOPT_HTTPAUTH')) {
2467
+ $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
2468
+ } else {
2469
+ $CURLOPT_HTTPAUTH = 107;
2470
+ }
2471
+ if (defined('CURLOPT_PROXYAUTH')) {
2472
+ $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
2473
+ } else {
2474
+ $CURLOPT_PROXYAUTH = 111;
2475
+ }
2476
+ if (defined('CURLAUTH_BASIC')) {
2477
+ $CURLAUTH_BASIC = CURLAUTH_BASIC;
2478
+ } else {
2479
+ $CURLAUTH_BASIC = 1;
2480
+ }
2481
+ if (defined('CURLAUTH_DIGEST')) {
2482
+ $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
2483
+ } else {
2484
+ $CURLAUTH_DIGEST = 2;
2485
+ }
2486
+ if (defined('CURLAUTH_NTLM')) {
2487
+ $CURLAUTH_NTLM = CURLAUTH_NTLM;
2488
+ } else {
2489
+ $CURLAUTH_NTLM = 8;
2490
+ }
2491
+
2492
+ $this->debug('connect using cURL');
2493
+ // init CURL
2494
+ $this->ch = curl_init();
2495
+ // set url
2496
+ $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
2497
+ // add path
2498
+ $hostURL .= $this->path;
2499
+ $this->setCurlOption(CURLOPT_URL, $hostURL);
2500
+ // follow location headers (re-directs)
2501
+ if (ini_get('safe_mode') || ini_get('open_basedir')) {
2502
+ $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
2503
+ $this->debug('safe_mode = ');
2504
+ $this->appendDebug($this->varDump(ini_get('safe_mode')));
2505
+ $this->debug('open_basedir = ');
2506
+ $this->appendDebug($this->varDump(ini_get('open_basedir')));
2507
+ } else {
2508
+ $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
2509
+ }
2510
+ // ask for headers in the response output
2511
+ $this->setCurlOption(CURLOPT_HEADER, 1);
2512
+ // ask for the response output as the return value
2513
+ $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
2514
+ // encode
2515
+ // We manage this ourselves through headers and encoding
2516
+ // if(function_exists('gzuncompress')){
2517
+ // $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
2518
+ // }
2519
+ // persistent connection
2520
+ if ($this->persistentConnection) {
2521
+ // I believe the following comment is now bogus, having applied to
2522
+ // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
2523
+ // The way we send data, we cannot use persistent connections, since
2524
+ // there will be some "junk" at the end of our request.
2525
+ //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
2526
+ $this->persistentConnection = false;
2527
+ $this->setHeader('Connection', 'close');
2528
+ }
2529
+ // set timeouts
2530
+ if ($connection_timeout != 0) {
2531
+ $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2532
+ }
2533
+ if ($response_timeout != 0) {
2534
+ $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
2535
+ }
2536
+
2537
+ if ($this->scheme == 'https') {
2538
+ $this->debug('set cURL SSL verify options');
2539
+ // recent versions of cURL turn on peer/host checking by default,
2540
+ // while PHP binaries are not compiled with a default location for the
2541
+ // CA cert bundle, so disable peer/host checking.
2542
+ //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
2543
+ $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
2544
+ $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
2545
+
2546
+ // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2547
+ if ($this->authtype == 'certificate') {
2548
+ $this->debug('set cURL certificate options');
2549
+ if (isset($this->certRequest['cainfofile'])) {
2550
+ $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2551
+ }
2552
+ if (isset($this->certRequest['verifypeer'])) {
2553
+ $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2554
+ } else {
2555
+ $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
2556
+ }
2557
+ if (isset($this->certRequest['verifyhost'])) {
2558
+ $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2559
+ } else {
2560
+ $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
2561
+ }
2562
+ if (isset($this->certRequest['sslcertfile'])) {
2563
+ $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2564
+ }
2565
+ if (isset($this->certRequest['sslkeyfile'])) {
2566
+ $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2567
+ }
2568
+ if (isset($this->certRequest['passphrase'])) {
2569
+ $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
2570
+ }
2571
+ if (isset($this->certRequest['certpassword'])) {
2572
+ $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
2573
+ }
2574
+ }
2575
+ }
2576
+ if ($this->authtype && ($this->authtype != 'certificate')) {
2577
+ if ($this->username) {
2578
+ $this->debug('set cURL username/password');
2579
+ $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
2580
+ }
2581
+ if ($this->authtype == 'basic') {
2582
+ $this->debug('set cURL for Basic authentication');
2583
+ $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
2584
+ }
2585
+ if ($this->authtype == 'digest') {
2586
+ $this->debug('set cURL for digest authentication');
2587
+ $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
2588
+ }
2589
+ if ($this->authtype == 'ntlm') {
2590
+ $this->debug('set cURL for NTLM authentication');
2591
+ $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
2592
+ }
2593
+ }
2594
+ if (is_array($this->proxy)) {
2595
+ $this->debug('set cURL proxy options');
2596
+ if ($this->proxy['port'] != '') {
2597
+ $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'] . ':' . $this->proxy['port']);
2598
+ } else {
2599
+ $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
2600
+ }
2601
+ if ($this->proxy['username'] || $this->proxy['password']) {
2602
+ $this->debug('set cURL proxy authentication options');
2603
+ $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'] . ':' . $this->proxy['password']);
2604
+ if ($this->proxy['authtype'] == 'basic') {
2605
+ $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
2606
+ }
2607
+ if ($this->proxy['authtype'] == 'ntlm') {
2608
+ $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
2609
+ }
2610
+ }
2611
+ }
2612
+ $this->debug('cURL connection set up');
2613
+ return true;
2614
+ } else {
2615
+ $this->setError('Unknown scheme ' . $this->scheme);
2616
+ $this->debug('Unknown scheme ' . $this->scheme);
2617
+ return false;
2618
+ }
2619
+ }
2620
+
2621
+ /**
2622
+ * sends the SOAP request and gets the SOAP response via HTTP[S]
2623
+ *
2624
+ * @param string $data message data
2625
+ * @param integer $timeout set connection timeout in seconds
2626
+ * @param integer $response_timeout set response timeout in seconds
2627
+ * @param array $cookies cookies to send
2628
+ * @return string data
2629
+ * @access public
2630
+ */
2631
+ function send($data, $timeout = 0, $response_timeout = 30, $cookies = null)
2632
+ {
2633
+
2634
+ $this->debug('entered send() with data of length: ' . strlen($data));
2635
+
2636
+ $this->tryagain = true;
2637
+ $tries = 0;
2638
+ while ($this->tryagain) {
2639
+ $this->tryagain = false;
2640
+ if ($tries++ < 2) {
2641
+ // make connnection
2642
+ if (!$this->connect($timeout, $response_timeout)) {
2643
+ return false;
2644
+ }
2645
+
2646
+ // send request
2647
+ if (!$this->sendRequest($data, $cookies)) {
2648
+ return false;
2649
+ }
2650
+
2651
+ // get response
2652
+ $respdata = $this->getResponse();
2653
+ } else {
2654
+ $this->setError("Too many tries to get an OK response ($this->response_status_line)");
2655
+ }
2656
+ }
2657
+ $this->debug('end of send()');
2658
+ return $respdata;
2659
+ }
2660
+
2661
+
2662
+ /**
2663
+ * sends the SOAP request and gets the SOAP response via HTTPS using CURL
2664
+ *
2665
+ * @param string $data message data
2666
+ * @param integer $timeout set connection timeout in seconds
2667
+ * @param integer $response_timeout set response timeout in seconds
2668
+ * @param array $cookies cookies to send
2669
+ * @return string data
2670
+ * @access public
2671
+ * @deprecated
2672
+ */
2673
+ function sendHTTPS($data, $timeout = 0, $response_timeout = 30, $cookies)
2674
+ {
2675
+ return $this->send($data, $timeout, $response_timeout, $cookies);
2676
+ }
2677
+
2678
+ /**
2679
+ * if authenticating, set user credentials here
2680
+ *
2681
+ * @param string $username
2682
+ * @param string $password
2683
+ * @param string $authtype (basic|digest|certificate|ntlm)
2684
+ * @param array $digestRequest (keys must be nonce, nc, realm, qop)
2685
+ * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
2686
+ * @access public
2687
+ */
2688
+ function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array())
2689
+ {
2690
+ $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
2691
+ $this->appendDebug($this->varDump($digestRequest));
2692
+ $this->debug("certRequest=");
2693
+ $this->appendDebug($this->varDump($certRequest));
2694
+ // cf. RFC 2617
2695
+ if ($authtype == 'basic') {
2696
+ $this->setHeader('Authorization', 'Basic ' . base64_encode(str_replace(':', '', $username) . ':' . $password));
2697
+ } elseif ($authtype == 'digest') {
2698
+ if (isset($digestRequest['nonce'])) {
2699
+ $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2700
+
2701
+ // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2702
+
2703
+ // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2704
+ $A1 = $username . ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
2705
+
2706
+ // H(A1) = MD5(A1)
2707
+ $HA1 = md5($A1);
2708
+
2709
+ // A2 = Method ":" digest-uri-value
2710
+ $A2 = $this->request_method . ':' . $this->digest_uri;
2711
+
2712
+ // H(A2)
2713
+ $HA2 = md5($A2);
2714
+
2715
+ // KD(secret, data) = H(concat(secret, ":", data))
2716
+ // if qop == auth:
2717
+ // request-digest = <"> < KD ( H(A1), unq(nonce-value)
2718
+ // ":" nc-value
2719
+ // ":" unq(cnonce-value)
2720
+ // ":" unq(qop-value)
2721
+ // ":" H(A2)
2722
+ // ) <">
2723
+ // if qop is missing,
2724
+ // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2725
+
2726
+ $unhashedDigest = '';
2727
+ $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
2728
+ $cnonce = $nonce;
2729
+ if ($digestRequest['qop'] != '') {
2730
+ $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2731
+ } else {
2732
+ $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2733
+ }
2734
+
2735
+ $hashedDigest = md5($unhashedDigest);
2736
+
2737
+ $opaque = '';
2738
+ if (isset($digestRequest['opaque'])) {
2739
+ $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
2740
+ }
2741
+
2742
+ $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"');
2743
+ }
2744
+ } elseif ($authtype == 'certificate') {
2745
+ $this->certRequest = $certRequest;
2746
+ $this->debug('Authorization header not set for certificate');
2747
+ } elseif ($authtype == 'ntlm') {
2748
+ // do nothing
2749
+ $this->debug('Authorization header not set for ntlm');
2750
+ }
2751
+ $this->username = $username;
2752
+ $this->password = $password;
2753
+ $this->authtype = $authtype;
2754
+ $this->digestRequest = $digestRequest;
2755
+ }
2756
+
2757
+ /**
2758
+ * set the soapaction value
2759
+ *
2760
+ * @param string $soapaction
2761
+ * @access public
2762
+ */
2763
+ function setSOAPAction($soapaction)
2764
+ {
2765
+ $this->setHeader('SOAPAction', '"' . $soapaction . '"');
2766
+ }
2767
+
2768
+ /**
2769
+ * use http encoding
2770
+ *
2771
+ * @param string $enc encoding style. supported values: gzip, deflate, or both
2772
+ * @access public
2773
+ */
2774
+ function setEncoding($enc = 'gzip, deflate')
2775
+ {
2776
+ if (function_exists('gzdeflate')) {
2777
+ $this->protocol_version = '1.1';
2778
+ $this->setHeader('Accept-Encoding', $enc);
2779
+ if (!isset($this->outgoing_headers['Connection'])) {
2780
+ $this->setHeader('Connection', 'close');
2781
+ $this->persistentConnection = false;
2782
+ }
2783
+ // deprecated as of PHP 5.3.0
2784
+ //set_magic_quotes_runtime(0);
2785
+ $this->encoding = $enc;
2786
+ }
2787
+ }
2788
+
2789
+ /**
2790
+ * set proxy info here
2791
+ *
2792
+ * @param string $proxyhost use an empty string to remove proxy
2793
+ * @param string $proxyport
2794
+ * @param string $proxyusername
2795
+ * @param string $proxypassword
2796
+ * @param string $proxyauthtype (basic|ntlm)
2797
+ * @access public
2798
+ */
2799
+ function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic')
2800
+ {
2801
+ if ($proxyhost) {
2802
+ $this->proxy = array(
2803
+ 'host' => $proxyhost,
2804
+ 'port' => $proxyport,
2805
+ 'username' => $proxyusername,
2806
+ 'password' => $proxypassword,
2807
+ 'authtype' => $proxyauthtype
2808
+ );
2809
+ if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
2810
+ $this->setHeader('Proxy-Authorization', ' Basic ' . base64_encode($proxyusername . ':' . $proxypassword));
2811
+ }
2812
+ } else {
2813
+ $this->debug('remove proxy');
2814
+ $proxy = null;
2815
+ unsetHeader('Proxy-Authorization');
2816
+ }
2817
+ }
2818
+
2819
+
2820
+ /**
2821
+ * Test if the given string starts with a header that is to be skipped.
2822
+ * Skippable headers result from chunked transfer and proxy requests.
2823
+ *
2824
+ * @param string $data The string to check.
2825
+ * @returns boolean Whether a skippable header was found.
2826
+ * @access private
2827
+ */
2828
+ function isSkippableCurlHeader(&$data)
2829
+ {
2830
+ $skipHeaders = array('HTTP/1.1 100',
2831
+ 'HTTP/1.0 301',
2832
+ 'HTTP/1.1 301',
2833
+ 'HTTP/1.0 302',
2834
+ 'HTTP/1.1 302',
2835
+ 'HTTP/1.0 401',
2836
+ 'HTTP/1.1 401',
2837
+ 'HTTP/1.0 200 Connection established');
2838
+ foreach ($skipHeaders as $hd) {
2839
+ $prefix = substr($data, 0, strlen($hd));
2840
+ if ($prefix == $hd) {
2841
+ return true;
2842
+ }
2843
+ }
2844
+
2845
+ return false;
2846
+ }
2847
+
2848
+ /**
2849
+ * decode a string that is encoded w/ "chunked' transfer encoding
2850
+ * as defined in RFC2068 19.4.6
2851
+ *
2852
+ * @param string $buffer
2853
+ * @param string $lb
2854
+ * @returns string
2855
+ * @access public
2856
+ * @deprecated
2857
+ */
2858
+ function decodeChunked($buffer, $lb)
2859
+ {
2860
+ // length := 0
2861
+ $length = 0;
2862
+ $new = '';
2863
+
2864
+ // read chunk-size, chunk-extension (if any) and CRLF
2865
+ // get the position of the linebreak
2866
+ $chunkend = strpos($buffer, $lb);
2867
+ if ($chunkend == false) {
2868
+ $this->debug('no linebreak found in decodeChunked');
2869
+ return $new;
2870
+ }
2871
+ $temp = substr($buffer, 0, $chunkend);
2872
+ $chunk_size = hexdec(trim($temp));
2873
+ $chunkstart = $chunkend + strlen($lb);
2874
+ // while (chunk-size > 0) {
2875
+ while ($chunk_size > 0) {
2876
+ $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
2877
+ $chunkend = strpos($buffer, $lb, $chunkstart + $chunk_size);
2878
+
2879
+ // Just in case we got a broken connection
2880
+ if ($chunkend == false) {
2881
+ $chunk = substr($buffer, $chunkstart);
2882
+ // append chunk-data to entity-body
2883
+ $new .= $chunk;
2884
+ $length += strlen($chunk);
2885
+ break;
2886
+ }
2887
+
2888
+ // read chunk-data and CRLF
2889
+ $chunk = substr($buffer, $chunkstart, $chunkend - $chunkstart);
2890
+ // append chunk-data to entity-body
2891
+ $new .= $chunk;
2892
+ // length := length + chunk-size
2893
+ $length += strlen($chunk);
2894
+ // read chunk-size and CRLF
2895
+ $chunkstart = $chunkend + strlen($lb);
2896
+
2897
+ $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
2898
+ if ($chunkend == false) {
2899
+ break; //Just in case we got a broken connection
2900
+ }
2901
+ $temp = substr($buffer, $chunkstart, $chunkend - $chunkstart);
2902
+ $chunk_size = hexdec(trim($temp));
2903
+ $chunkstart = $chunkend;
2904
+ }
2905
+ return $new;
2906
+ }
2907
+
2908
+ /**
2909
+ * Writes the payload, including HTTP headers, to $this->outgoing_payload.
2910
+ *
2911
+ * @param string $data HTTP body
2912
+ * @param string $cookie_str data for HTTP Cookie header
2913
+ * @return void
2914
+ * @access private
2915
+ */
2916
+ function buildPayload($data, $cookie_str = '')
2917
+ {
2918
+ // Note: for cURL connections, $this->outgoing_payload is ignored,
2919
+ // as is the Content-Length header, but these are still created as
2920
+ // debugging guides.
2921
+
2922
+ // add content-length header
2923
+ if ($this->request_method != 'GET') {
2924
+ $this->setHeader('Content-Length', strlen($data));
2925
+ }
2926
+
2927
+ // start building outgoing payload:
2928
+ if ($this->proxy) {
2929
+ $uri = $this->url;
2930
+ } else {
2931
+ $uri = $this->uri;
2932
+ }
2933
+ $req = "$this->request_method $uri HTTP/$this->protocol_version";
2934
+ $this->debug("HTTP request: $req");
2935
+ $this->outgoing_payload = "$req\r\n";
2936
+
2937
+ // loop thru headers, serializing
2938
+ foreach ($this->outgoing_headers as $k => $v) {
2939
+ $hdr = $k . ': ' . $v;
2940
+ $this->debug("HTTP header: $hdr");
2941
+ $this->outgoing_payload .= "$hdr\r\n";
2942
+ }
2943
+
2944
+ // add any cookies
2945
+ if ($cookie_str != '') {
2946
+ $hdr = 'Cookie: ' . $cookie_str;
2947
+ $this->debug("HTTP header: $hdr");
2948
+ $this->outgoing_payload .= "$hdr\r\n";
2949
+ }
2950
+
2951
+ // header/body separator
2952
+ $this->outgoing_payload .= "\r\n";
2953
+
2954
+ // add data
2955
+ $this->outgoing_payload .= $data;
2956
+ }
2957
+
2958
+ /**
2959
+ * sends the SOAP request via HTTP[S]
2960
+ *
2961
+ * @param string $data message data
2962
+ * @param array $cookies cookies to send
2963
+ * @return boolean true if OK, false if problem
2964
+ * @access private
2965
+ */
2966
+ function sendRequest($data, $cookies = null)
2967
+ {
2968
+ // build cookie string
2969
+ $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
2970
+
2971
+ // build payload
2972
+ $this->buildPayload($data, $cookie_str);
2973
+
2974
+ if ($this->io_method() == 'socket') {
2975
+ // send payload
2976
+ if (!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
2977
+ $this->setError('couldn\'t write message data to socket');
2978
+ $this->debug('couldn\'t write message data to socket');
2979
+ return false;
2980
+ }
2981
+ $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
2982
+ return true;
2983
+ } elseif ($this->io_method() == 'curl') {
2984
+ // set payload
2985
+ // cURL does say this should only be the verb, and in fact it
2986
+ // turns out that the URI and HTTP version are appended to this, which
2987
+ // some servers refuse to work with (so we no longer use this method!)
2988
+ //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
2989
+ $curl_headers = array();
2990
+ foreach ($this->outgoing_headers as $k => $v) {
2991
+ if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
2992
+ $this->debug("Skip cURL header $k: $v");
2993
+ } else {
2994
+ $curl_headers[] = "$k: $v";
2995
+ }
2996
+ }
2997
+ if ($cookie_str != '') {
2998
+ $curl_headers[] = 'Cookie: ' . $cookie_str;
2999
+ }
3000
+ $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
3001
+ $this->debug('set cURL HTTP headers');
3002
+ if ($this->request_method == "POST") {
3003
+ $this->setCurlOption(CURLOPT_POST, 1);
3004
+ $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
3005
+ $this->debug('set cURL POST data');
3006
+ } else {
3007
+ }
3008
+ // insert custom user-set cURL options
3009
+ foreach ($this->ch_options as $key => $val) {
3010
+ $this->setCurlOption($key, $val);
3011
+ }
3012
+
3013
+ $this->debug('set cURL payload');
3014
+ return true;
3015
+ }
3016
+ }
3017
+
3018
+ /**
3019
+ * gets the SOAP response via HTTP[S]
3020
+ *
3021
+ * @return string the response (also sets member variables like incoming_payload)
3022
+ * @access private
3023
+ */
3024
+ function getResponse()
3025
+ {
3026
+ $this->incoming_payload = '';
3027
+
3028
+ if ($this->io_method() == 'socket') {
3029
+ // loop until headers have been retrieved
3030
+ $data = '';
3031
+ while (!isset($lb)) {
3032
+
3033
+ // We might EOF during header read.
3034
+ if (feof($this->fp)) {
3035
+ $this->incoming_payload = $data;
3036
+ $this->debug('found no headers before EOF after length ' . strlen($data));
3037
+ $this->debug("received before EOF:\n" . $data);
3038
+ $this->setError('server failed to send headers');
3039
+ return false;
3040
+ }
3041
+
3042
+ $tmp = fgets($this->fp, 256);
3043
+ $tmplen = strlen($tmp);
3044
+ $this->debug("read line of $tmplen bytes: " . trim($tmp));
3045
+
3046
+ if ($tmplen == 0) {
3047
+ $this->incoming_payload = $data;
3048
+ $this->debug('socket read of headers timed out after length ' . strlen($data));
3049
+ $this->debug("read before timeout: " . $data);
3050
+ $this->setError('socket read of headers timed out');
3051
+ return false;
3052
+ }
3053
+
3054
+ $data .= $tmp;
3055
+ $pos = strpos($data, "\r\n\r\n");
3056
+ if ($pos > 1) {
3057
+ $lb = "\r\n";
3058
+ } else {
3059
+ $pos = strpos($data, "\n\n");
3060
+ if ($pos > 1) {
3061
+ $lb = "\n";
3062
+ }
3063
+ }
3064
+ // remove 100 headers
3065
+ if (isset($lb) && preg_match('/^HTTP\/1.1 100/', $data)) {
3066
+ unset($lb);
3067
+ $data = '';
3068
+ }//
3069
+ }
3070
+ // store header data
3071
+ $this->incoming_payload .= $data;
3072
+ $this->debug('found end of headers after length ' . strlen($data));
3073
+ // process headers
3074
+ $header_data = trim(substr($data, 0, $pos));
3075
+ $header_array = explode($lb, $header_data);
3076
+ $this->incoming_headers = array();
3077
+ $this->incoming_cookies = array();
3078
+ foreach ($header_array as $header_line) {
3079
+ $arr = explode(':', $header_line, 2);
3080
+ if (count($arr) > 1) {
3081
+ $header_name = strtolower(trim($arr[0]));
3082
+ $this->incoming_headers[$header_name] = trim($arr[1]);
3083
+ if ($header_name == 'set-cookie') {
3084
+ // TODO: allow multiple cookies from parseCookie
3085
+ $cookie = $this->parseCookie(trim($arr[1]));
3086
+ if ($cookie) {
3087
+ $this->incoming_cookies[] = $cookie;
3088
+ $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3089
+ } else {
3090
+ $this->debug('did not find cookie in ' . trim($arr[1]));
3091
+ }
3092
+ }
3093
+ } elseif (isset($header_name)) {
3094
+ // append continuation line to previous header
3095
+ $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3096
+ }
3097
+ }
3098
+
3099
+ // loop until msg has been received
3100
+ if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
3101
+ $content_length = 2147483647; // ignore any content-length header
3102
+ $chunked = true;
3103
+ $this->debug("want to read chunked content");
3104
+ } elseif (isset($this->incoming_headers['content-length'])) {
3105
+ $content_length = $this->incoming_headers['content-length'];
3106
+ $chunked = false;
3107
+ $this->debug("want to read content of length $content_length");
3108
+ } else {
3109
+ $content_length = 2147483647;
3110
+ $chunked = false;
3111
+ $this->debug("want to read content to EOF");
3112
+ }
3113
+ $data = '';
3114
+ do {
3115
+ if ($chunked) {
3116
+ $tmp = fgets($this->fp, 256);
3117
+ $tmplen = strlen($tmp);
3118
+ $this->debug("read chunk line of $tmplen bytes");
3119
+ if ($tmplen == 0) {
3120
+ $this->incoming_payload = $data;
3121
+ $this->debug('socket read of chunk length timed out after length ' . strlen($data));
3122
+ $this->debug("read before timeout:\n" . $data);
3123
+ $this->setError('socket read of chunk length timed out');
3124
+ return false;
3125
+ }
3126
+ $content_length = hexdec(trim($tmp));
3127
+ $this->debug("chunk length $content_length");
3128
+ }
3129
+ $strlen = 0;
3130
+ while (($strlen < $content_length) && (!feof($this->fp))) {
3131
+ $readlen = min(8192, $content_length - $strlen);
3132
+ $tmp = fread($this->fp, $readlen);
3133
+ $tmplen = strlen($tmp);
3134
+ $this->debug("read buffer of $tmplen bytes");
3135
+ if (($tmplen == 0) && (!feof($this->fp))) {
3136
+ $this->incoming_payload = $data;
3137
+ $this->debug('socket read of body timed out after length ' . strlen($data));
3138
+ $this->debug("read before timeout:\n" . $data);
3139
+ $this->setError('socket read of body timed out');
3140
+ return false;
3141
+ }
3142
+ $strlen += $tmplen;
3143
+ $data .= $tmp;
3144
+ }
3145
+ if ($chunked && ($content_length > 0)) {
3146
+ $tmp = fgets($this->fp, 256);
3147
+ $tmplen = strlen($tmp);
3148
+ $this->debug("read chunk terminator of $tmplen bytes");
3149
+ if ($tmplen == 0) {
3150
+ $this->incoming_payload = $data;
3151
+ $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
3152
+ $this->debug("read before timeout:\n" . $data);
3153
+ $this->setError('socket read of chunk terminator timed out');
3154
+ return false;
3155
+ }
3156
+ }
3157
+ } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
3158
+ if (feof($this->fp)) {
3159
+ $this->debug('read to EOF');
3160
+ }
3161
+ $this->debug('read body of length ' . strlen($data));
3162
+ $this->incoming_payload .= $data;
3163
+ $this->debug('received a total of ' . strlen($this->incoming_payload) . ' bytes of data from server');
3164
+
3165
+ // close filepointer
3166
+ if (
3167
+ (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
3168
+ (!$this->persistentConnection) || feof($this->fp)
3169
+ ) {
3170
+ fclose($this->fp);
3171
+ $this->fp = false;
3172
+ $this->debug('closed socket');
3173
+ }
3174
+
3175
+ // connection was closed unexpectedly
3176
+ if ($this->incoming_payload == '') {
3177
+ $this->setError('no response from server');
3178
+ return false;
3179
+ }
3180
+
3181
+ // decode transfer-encoding
3182
+ // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
3183
+ // if(!$data = $this->decodeChunked($data, $lb)){
3184
+ // $this->setError('Decoding of chunked data failed');
3185
+ // return false;
3186
+ // }
3187
+ //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
3188
+ // set decoded payload
3189
+ // $this->incoming_payload = $header_data.$lb.$lb.$data;
3190
+ // }
3191
+
3192
+ } elseif ($this->io_method() == 'curl') {
3193
+ // send and receive
3194
+ $this->debug('send and receive with cURL');
3195
+ $this->incoming_payload = curl_exec($this->ch);
3196
+ $data = $this->incoming_payload;
3197
+
3198
+ $cErr = curl_error($this->ch);
3199
+ if ($cErr != '') {
3200
+ $err = 'cURL ERROR: ' . curl_errno($this->ch) . ': ' . $cErr . '<br>';
3201
+ // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
3202
+ foreach (curl_getinfo($this->ch) as $k => $v) {
3203
+ $err .= "$k: $v<br>";
3204
+ }
3205
+ $this->debug($err);
3206
+ $this->setError($err);
3207
+ curl_close($this->ch);
3208
+ return false;
3209
+ } else {
3210
+ //echo '<pre>';
3211
+ //var_dump(curl_getinfo($this->ch));
3212
+ //echo '</pre>';
3213
+ }
3214
+ // close curl
3215
+ $this->debug('No cURL error, closing cURL');
3216
+ curl_close($this->ch);
3217
+
3218
+ // try removing skippable headers
3219
+ $savedata = $data;
3220
+ while ($this->isSkippableCurlHeader($data)) {
3221
+ $this->debug("Found HTTP header to skip");
3222
+ if ($pos = strpos($data, "\r\n\r\n")) {
3223
+ $data = ltrim(substr($data, $pos));
3224
+ } elseif ($pos = strpos($data, "\n\n")) {
3225
+ $data = ltrim(substr($data, $pos));
3226
+ }
3227
+ }
3228
+
3229
+ if ($data == '') {
3230
+ // have nothing left; just remove 100 header(s)
3231
+ $data = $savedata;
3232
+ while (preg_match('/^HTTP\/1.1 100/', $data)) {
3233
+ if ($pos = strpos($data, "\r\n\r\n")) {
3234
+ $data = ltrim(substr($data, $pos));
3235
+ } elseif ($pos = strpos($data, "\n\n")) {
3236
+ $data = ltrim(substr($data, $pos));
3237
+ }
3238
+ }
3239
+ }
3240
+
3241
+ // separate content from HTTP headers
3242
+ if ($pos = strpos($data, "\r\n\r\n")) {
3243
+ $lb = "\r\n";
3244
+ } elseif ($pos = strpos($data, "\n\n")) {
3245
+ $lb = "\n";
3246
+ } else {
3247
+ $this->debug('no proper separation of headers and document');
3248
+ $this->setError('no proper separation of headers and document');
3249
+ return false;
3250
+ }
3251
+ $header_data = trim(substr($data, 0, $pos));
3252
+ $header_array = explode($lb, $header_data);
3253
+ $data = ltrim(substr($data, $pos));
3254
+ $this->debug('found proper separation of headers and document');
3255
+ $this->debug('cleaned data, stringlen: ' . strlen($data));
3256
+ // clean headers
3257
+ foreach ($header_array as $header_line) {
3258
+ $arr = explode(':', $header_line, 2);
3259
+ if (count($arr) > 1) {
3260
+ $header_name = strtolower(trim($arr[0]));
3261
+ $this->incoming_headers[$header_name] = trim($arr[1]);
3262
+ if ($header_name == 'set-cookie') {
3263
+ // TODO: allow multiple cookies from parseCookie
3264
+ $cookie = $this->parseCookie(trim($arr[1]));
3265
+ if ($cookie) {
3266
+ $this->incoming_cookies[] = $cookie;
3267
+ $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3268
+ } else {
3269
+ $this->debug('did not find cookie in ' . trim($arr[1]));
3270
+ }
3271
+ }
3272
+ } elseif (isset($header_name)) {
3273
+ // append continuation line to previous header
3274
+ $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3275
+ }
3276
+ }
3277
+ }
3278
+
3279
+ $this->response_status_line = $header_array[0];
3280
+ $arr = explode(' ', $this->response_status_line, 3);
3281
+ $http_version = $arr[0];
3282
+ $http_status = intval($arr[1]);
3283
+ $http_reason = count($arr) > 2 ? $arr[2] : '';
3284
+
3285
+ // see if we need to resend the request with http digest authentication
3286
+ if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
3287
+ $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
3288
+ $this->setURL($this->incoming_headers['location']);
3289
+ $this->tryagain = true;
3290
+ return false;
3291
+ }
3292
+
3293
+ // see if we need to resend the request with http digest authentication
3294
+ if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
3295
+ $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
3296
+ if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
3297
+ $this->debug('Server wants digest authentication');
3298
+ // remove "Digest " from our elements
3299
+ $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
3300
+
3301
+ // parse elements into array
3302
+ $digestElements = explode(',', $digestString);
3303
+ foreach ($digestElements as $val) {
3304
+ $tempElement = explode('=', trim($val), 2);
3305
+ $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
3306
+ }
3307
+
3308
+ // should have (at least) qop, realm, nonce
3309
+ if (isset($digestRequest['nonce'])) {
3310
+ $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
3311
+ $this->tryagain = true;
3312
+ return false;
3313
+ }
3314
+ }
3315
+ $this->debug('HTTP authentication failed');
3316
+ $this->setError('HTTP authentication failed');
3317
+ return false;
3318
+ }
3319
+
3320
+ if (
3321
+ ($http_status >= 300 && $http_status <= 307) ||
3322
+ ($http_status >= 400 && $http_status <= 417) ||
3323
+ ($http_status >= 501 && $http_status <= 505)
3324
+ ) {
3325
+ $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
3326
+ return false;
3327
+ }
3328
+
3329
+ // decode content-encoding
3330
+ if (isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != '') {
3331
+ if (strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip') {
3332
+ // if decoding works, use it. else assume data wasn't gzencoded
3333
+ if (function_exists('gzinflate')) {
3334
+ //$timer->setMarker('starting decoding of gzip/deflated content');
3335
+ // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
3336
+ // this means there are no Zlib headers, although there should be
3337
+ $this->debug('The gzinflate function exists');
3338
+ $datalen = strlen($data);
3339
+ if ($this->incoming_headers['content-encoding'] == 'deflate') {
3340
+ if ($degzdata = @gzinflate($data)) {
3341
+ $data = $degzdata;
3342
+ $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
3343
+ if (strlen($data) < $datalen) {
3344
+ // test for the case that the payload has been compressed twice
3345
+ $this->debug('The inflated payload is smaller than the gzipped one; try again');
3346
+ if ($degzdata = @gzinflate($data)) {
3347
+ $data = $degzdata;
3348
+ $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
3349
+ }
3350
+ }
3351
+ } else {
3352
+ $this->debug('Error using gzinflate to inflate the payload');
3353
+ $this->setError('Error using gzinflate to inflate the payload');
3354
+ }
3355
+ } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
3356
+ if ($degzdata = @gzinflate(substr($data, 10))) { // do our best
3357
+ $data = $degzdata;
3358
+ $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
3359
+ if (strlen($data) < $datalen) {
3360
+ // test for the case that the payload has been compressed twice
3361
+ $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
3362
+ if ($degzdata = @gzinflate(substr($data, 10))) {
3363
+ $data = $degzdata;
3364
+ $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
3365
+ }
3366
+ }
3367
+ } else {
3368
+ $this->debug('Error using gzinflate to un-gzip the payload');
3369
+ $this->setError('Error using gzinflate to un-gzip the payload');
3370
+ }
3371
+ }
3372
+ //$timer->setMarker('finished decoding of gzip/deflated content');
3373
+ //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
3374
+ // set decoded payload
3375
+ $this->incoming_payload = $header_data . $lb . $lb . $data;
3376
+ } else {
3377
+ $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3378
+ $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3379
+ }
3380
+ } else {
3381
+ $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3382
+ $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3383
+ }
3384
+ } else {
3385
+ $this->debug('No Content-Encoding header');
3386
+ }
3387
+
3388
+ if (strlen($data) == 0) {
3389
+ $this->debug('no data after headers!');
3390
+ $this->setError('no data present after HTTP headers');
3391
+ return false;
3392
+ }
3393
+
3394
+ return $data;
3395
+ }
3396
+
3397
+ /**
3398
+ * sets the content-type for the SOAP message to be sent
3399
+ *
3400
+ * @param string $type the content type, MIME style
3401
+ * @param mixed $charset character set used for encoding (or false)
3402
+ * @access public
3403
+ */
3404
+ function setContentType($type, $charset = false)
3405
+ {
3406
+ $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
3407
+ }
3408
+
3409
+ /**
3410
+ * specifies that an HTTP persistent connection should be used
3411
+ *
3412
+ * @return boolean whether the request was honored by this method.
3413
+ * @access public
3414
+ */
3415
+ function usePersistentConnection()
3416
+ {
3417
+ if (isset($this->outgoing_headers['Accept-Encoding'])) {
3418
+ return false;
3419
+ }
3420
+ $this->protocol_version = '1.1';
3421
+ $this->persistentConnection = true;
3422
+ $this->setHeader('Connection', 'Keep-Alive');
3423
+ return true;
3424
+ }
3425
+
3426
+ /**
3427
+ * parse an incoming Cookie into it's parts
3428
+ *
3429
+ * @param string $cookie_str content of cookie
3430
+ * @return array with data of that cookie
3431
+ * @access private
3432
+ */
3433
+ /*
3434
+ * TODO: allow a Set-Cookie string to be parsed into multiple cookies
3435
+ */
3436
+ function parseCookie($cookie_str)
3437
+ {
3438
+ $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
3439
+ $data = preg_split('/;/', $cookie_str);
3440
+ $value_str = $data[0];
3441
+
3442
+ $cookie_param = 'domain=';
3443
+ $start = strpos($cookie_str, $cookie_param);
3444
+ if ($start > 0) {
3445
+ $domain = substr($cookie_str, $start + strlen($cookie_param));
3446
+ $domain = substr($domain, 0, strpos($domain, ';'));
3447
+ } else {
3448
+ $domain = '';
3449
+ }
3450
+
3451
+ $cookie_param = 'expires=';
3452
+ $start = strpos($cookie_str, $cookie_param);
3453
+ if ($start > 0) {
3454
+ $expires = substr($cookie_str, $start + strlen($cookie_param));
3455
+ $expires = substr($expires, 0, strpos($expires, ';'));
3456
+ } else {
3457
+ $expires = '';
3458
+ }
3459
+
3460
+ $cookie_param = 'path=';
3461
+ $start = strpos($cookie_str, $cookie_param);
3462
+ if ($start > 0) {
3463
+ $path = substr($cookie_str, $start + strlen($cookie_param));
3464
+ $path = substr($path, 0, strpos($path, ';'));
3465
+ } else {
3466
+ $path = '/';
3467
+ }
3468
+
3469
+ $cookie_param = ';secure;';
3470
+ if (strpos($cookie_str, $cookie_param) !== false) {
3471
+ $secure = true;
3472
+ } else {
3473
+ $secure = false;
3474
+ }
3475
+
3476
+ $sep_pos = strpos($value_str, '=');
3477
+
3478
+ if ($sep_pos) {
3479
+ $name = substr($value_str, 0, $sep_pos);
3480
+ $value = substr($value_str, $sep_pos + 1);
3481
+ $cookie = array('name' => $name,
3482
+ 'value' => $value,
3483
+ 'domain' => $domain,
3484
+ 'path' => $path,
3485
+ 'expires' => $expires,
3486
+ 'secure' => $secure
3487
+ );
3488
+ return $cookie;
3489
+ }
3490
+ return false;
3491
+ }
3492
+
3493
+ /**
3494
+ * sort out cookies for the current request
3495
+ *
3496
+ * @param array $cookies array with all cookies
3497
+ * @param boolean $secure is the send-content secure or not?
3498
+ * @return string for Cookie-HTTP-Header
3499
+ * @access private
3500
+ */
3501
+ function getCookiesForRequest($cookies, $secure = false)
3502
+ {
3503
+ $cookie_str = '';
3504
+ if ((!is_null($cookies)) && (is_array($cookies))) {
3505
+ foreach ($cookies as $cookie) {
3506
+ if (!is_array($cookie)) {
3507
+ continue;
3508
+ }
3509
+ $this->debug("check cookie for validity: " . $cookie['name'] . '=' . $cookie['value']);
3510
+ if ((isset($cookie['expires'])) && (!empty($cookie['expires']))) {
3511
+ if (strtotime($cookie['expires']) <= time()) {
3512
+ $this->debug('cookie has expired');
3513
+ continue;
3514
+ }
3515
+ }
3516
+ if ((isset($cookie['domain'])) && (!empty($cookie['domain']))) {
3517
+ $domain = preg_quote($cookie['domain']);
3518
+ if (!preg_match("'.*$domain$'i", $this->host)) {
3519
+ $this->debug('cookie has different domain');
3520
+ continue;
3521
+ }
3522
+ }
3523
+ if ((isset($cookie['path'])) && (!empty($cookie['path']))) {
3524
+ $path = preg_quote($cookie['path']);
3525
+ if (!preg_match("'^$path.*'i", $this->path)) {
3526
+ $this->debug('cookie is for a different path');
3527
+ continue;
3528
+ }
3529
+ }
3530
+ if ((!$secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
3531
+ $this->debug('cookie is secure, transport is not');
3532
+ continue;
3533
+ }
3534
+ $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3535
+ $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3536
+ }
3537
+ }
3538
+ return $cookie_str;
3539
+ }
3540
+ }
3541
+
3542
+
3543
+ /**
3544
+ *
3545
+ * nusoap_server allows the user to create a SOAP server
3546
+ * that is capable of receiving messages and returning responses
3547
+ *
3548
+ * @author Dietrich Ayala <dietrich@ganx4.com>
3549
+ * @author Scott Nichol <snichol@users.sourceforge.net>
3550
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
3551
+ * @access public
3552
+ */
3553
+ class nusoap_server extends nusoap_base
3554
+ {
3555
+ /**
3556
+ * HTTP headers of request
3557
+ *
3558
+ * @var array
3559
+ * @access private
3560
+ */
3561
+ var $headers = array();
3562
+ /**
3563
+ * HTTP request
3564
+ *
3565
+ * @var string
3566
+ * @access private
3567
+ */
3568
+ var $request = '';
3569
+ /**
3570
+ * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
3571
+ *
3572
+ * @var string
3573
+ * @access public
3574
+ */
3575
+ var $requestHeaders = '';
3576
+ /**
3577
+ * SOAP Headers from request (parsed)
3578
+ *
3579
+ * @var mixed
3580
+ * @access public
3581
+ */
3582
+ var $requestHeader = null;
3583
+ /**
3584
+ * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
3585
+ *
3586
+ * @var string
3587
+ * @access public
3588
+ */
3589
+ var $document = '';
3590
+ /**
3591
+ * SOAP payload for request (text)
3592
+ *
3593
+ * @var string
3594
+ * @access public
3595
+ */
3596
+ var $requestSOAP = '';
3597
+ /**
3598
+ * requested method namespace URI
3599
+ *
3600
+ * @var string
3601
+ * @access private
3602
+ */
3603
+ var $methodURI = '';
3604
+ /**
3605
+ * name of method requested
3606
+ *
3607
+ * @var string
3608
+ * @access private
3609
+ */
3610
+ var $methodname = '';
3611
+ /**
3612
+ * method parameters from request
3613
+ *
3614
+ * @var array
3615
+ * @access private
3616
+ */
3617
+ var $methodparams = array();
3618
+ /**
3619
+ * SOAP Action from request
3620
+ *
3621
+ * @var string
3622
+ * @access private
3623
+ */
3624
+ var $SOAPAction = '';
3625
+ /**
3626
+ * character set encoding of incoming (request) messages
3627
+ *
3628
+ * @var string
3629
+ * @access public
3630
+ */
3631
+ var $xml_encoding = '';
3632
+ /**
3633
+ * toggles whether the parser decodes element content w/ utf8_decode()
3634
+ *
3635
+ * @var boolean
3636
+ * @access public
3637
+ */
3638
+ var $decode_utf8 = true;
3639
+
3640
+ /**
3641
+ * HTTP headers of response
3642
+ *
3643
+ * @var array
3644
+ * @access public
3645
+ */
3646
+ var $outgoing_headers = array();
3647
+ /**
3648
+ * HTTP response
3649
+ *
3650
+ * @var string
3651
+ * @access private
3652
+ */
3653
+ var $response = '';
3654
+ /**
3655
+ * SOAP headers for response (text or array of soapval or associative array)
3656
+ *
3657
+ * @var mixed
3658
+ * @access public
3659
+ */
3660
+ var $responseHeaders = '';
3661
+ /**
3662
+ * SOAP payload for response (text)
3663
+ *
3664
+ * @var string
3665
+ * @access private
3666
+ */
3667
+ var $responseSOAP = '';
3668
+ /**
3669
+ * method return value to place in response
3670
+ *
3671
+ * @var mixed
3672
+ * @access private
3673
+ */
3674
+ var $methodreturn = false;
3675
+ /**
3676
+ * whether $methodreturn is a string of literal XML
3677
+ *
3678
+ * @var boolean
3679
+ * @access public
3680
+ */
3681
+ var $methodreturnisliteralxml = false;
3682
+ /**
3683
+ * SOAP fault for response (or false)
3684
+ *
3685
+ * @var mixed
3686
+ * @access private
3687
+ */
3688
+ var $fault = false;
3689
+ /**
3690
+ * text indication of result (for debugging)
3691
+ *
3692
+ * @var string
3693
+ * @access private
3694
+ */
3695
+ var $result = 'successful';
3696
+
3697
+ /**
3698
+ * assoc array of operations => opData; operations are added by the register()
3699
+ * method or by parsing an external WSDL definition
3700
+ *
3701
+ * @var array
3702
+ * @access private
3703
+ */
3704
+ var $operations = array();
3705
+ /**
3706
+ * wsdl instance (if one)
3707
+ *
3708
+ * @var mixed
3709
+ * @access private
3710
+ */
3711
+ var $wsdl = false;
3712
+ /**
3713
+ * URL for WSDL (if one)
3714
+ *
3715
+ * @var mixed
3716
+ * @access private
3717
+ */
3718
+ var $externalWSDLURL = false;
3719
+ /**
3720
+ * whether to append debug to response as XML comment
3721
+ *
3722
+ * @var boolean
3723
+ * @access public
3724
+ */
3725
+ var $debug_flag = false;
3726
+
3727
+
3728
+ /**
3729
+ * constructor
3730
+ * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
3731
+ *
3732
+ * @param mixed $wsdl file path or URL (string), or wsdl instance (object)
3733
+ * @access public
3734
+ */
3735
+ function __construct($wsdl = false)
3736
+ {
3737
+ parent::__construct();
3738
+ // turn on debugging?
3739
+ global $debug;
3740
+ global $HTTP_SERVER_VARS;
3741
+
3742
+ if (isset($_SERVER)) {
3743
+ $this->debug("_SERVER is defined:");
3744
+ $this->appendDebug($this->varDump($_SERVER));
3745
+ } elseif (isset($HTTP_SERVER_VARS)) {
3746
+ $this->debug("HTTP_SERVER_VARS is defined:");
3747
+ $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
3748
+ } else {
3749
+ $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
3750
+ }
3751
+
3752
+ if (isset($debug)) {
3753
+ $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
3754
+ $this->debug_flag = $debug;
3755
+ } elseif (isset($_SERVER['QUERY_STRING'])) {
3756
+ $qs = explode('&', $_SERVER['QUERY_STRING']);
3757
+ foreach ($qs as $v) {
3758
+ if (substr($v, 0, 6) == 'debug=') {
3759
+ $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
3760
+ $this->debug_flag = substr($v, 6);
3761
+ }
3762
+ }
3763
+ } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3764
+ $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
3765
+ foreach ($qs as $v) {
3766
+ if (substr($v, 0, 6) == 'debug=') {
3767
+ $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
3768
+ $this->debug_flag = substr($v, 6);
3769
+ }
3770
+ }
3771
+ }
3772
+
3773
+ // wsdl
3774
+ if ($wsdl) {
3775
+ $this->debug("In nusoap_server, WSDL is specified");
3776
+ if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
3777
+ $this->wsdl = $wsdl;
3778
+ $this->externalWSDLURL = $this->wsdl->wsdl;
3779
+ $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3780
+ } else {
3781
+ $this->debug('Create wsdl from ' . $wsdl);
3782
+ $this->wsdl = new wsdl($wsdl);
3783
+ $this->externalWSDLURL = $wsdl;
3784
+ }
3785
+ $this->appendDebug($this->wsdl->getDebug());
3786
+ $this->wsdl->clearDebug();
3787
+ if ($err = $this->wsdl->getError()) {
3788
+ die('WSDL ERROR: ' . $err);
3789
+ }
3790
+ }
3791
+ }
3792
+
3793
+ /**
3794
+ * processes request and returns response
3795
+ *
3796
+ * @param string $data usually is the value of $HTTP_RAW_POST_DATA
3797
+ * @access public
3798
+ */
3799
+ function service($data)
3800
+ {
3801
+ global $HTTP_SERVER_VARS;
3802
+
3803
+ if (isset($_SERVER['REQUEST_METHOD'])) {
3804
+ $rm = $_SERVER['REQUEST_METHOD'];
3805
+ } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) {
3806
+ $rm = $HTTP_SERVER_VARS['REQUEST_METHOD'];
3807
+ } else {
3808
+ $rm = '';
3809
+ }
3810
+
3811
+ if (isset($_SERVER['QUERY_STRING'])) {
3812
+ $qs = $_SERVER['QUERY_STRING'];
3813
+ } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3814
+ $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3815
+ } else {
3816
+ $qs = '';
3817
+ }
3818
+ $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data));
3819
+
3820
+ if ($rm == 'POST') {
3821
+ $this->debug("In service, invoke the request");
3822
+ $this->parse_request($data);
3823
+ if (!$this->fault) {
3824
+ $this->invoke_method();
3825
+ }
3826
+ if (!$this->fault) {
3827
+ $this->serialize_return();
3828
+ }
3829
+ $this->send_response();
3830
+ } elseif (preg_match('/wsdl/', $qs)) {
3831
+ $this->debug("In service, this is a request for WSDL");
3832
+ if ($this->externalWSDLURL) {
3833
+ if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL
3834
+ $this->debug("In service, re-direct for WSDL");
3835
+ header('Location: ' . $this->externalWSDLURL);
3836
+ } else { // assume file
3837
+ $this->debug("In service, use file passthru for WSDL");
3838
+ header("Content-Type: text/xml\r\n");
3839
+ $pos = strpos($this->externalWSDLURL, "file://");
3840
+ if ($pos === false) {
3841
+ $filename = $this->externalWSDLURL;
3842
+ } else {
3843
+ $filename = substr($this->externalWSDLURL, $pos + 7);
3844
+ }
3845
+ $fp = fopen($this->externalWSDLURL, 'r');
3846
+ fpassthru($fp);
3847
+ }
3848
+ } elseif ($this->wsdl) {
3849
+ $this->debug("In service, serialize WSDL");
3850
+ header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
3851
+ print $this->wsdl->serialize($this->debug_flag);
3852
+ if ($this->debug_flag) {
3853
+ $this->debug('wsdl:');
3854
+ $this->appendDebug($this->varDump($this->wsdl));
3855
+ print $this->getDebugAsXMLComment();
3856
+ }
3857
+ } else {
3858
+ $this->debug("In service, there is no WSDL");
3859
+ header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3860
+ print "This service does not provide WSDL";
3861
+ }
3862
+ } elseif ($this->wsdl) {
3863
+ $this->debug("In service, return Web description");
3864
+ print $this->wsdl->webDescription();
3865
+ } else {
3866
+ $this->debug("In service, no Web description");
3867
+ header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3868
+ print "This service does not provide a Web description";
3869
+ }
3870
+ }
3871
+
3872
+ /**
3873
+ * parses HTTP request headers.
3874
+ *
3875
+ * The following fields are set by this function (when successful)
3876
+ *
3877
+ * headers
3878
+ * request
3879
+ * xml_encoding
3880
+ * SOAPAction
3881
+ *
3882
+ * @access private
3883
+ */
3884
+ function parse_http_headers()
3885
+ {
3886
+ global $HTTP_SERVER_VARS;
3887
+
3888
+ $this->request = '';
3889
+ $this->SOAPAction = '';
3890
+ if (function_exists('getallheaders')) {
3891
+ $this->debug("In parse_http_headers, use getallheaders");
3892
+ $headers = getallheaders();
3893
+ foreach ($headers as $k => $v) {
3894
+ $k = strtolower($k);
3895
+ $this->headers[$k] = $v;
3896
+ $this->request .= "$k: $v\r\n";
3897
+ $this->debug("$k: $v");
3898
+ }
3899
+ // get SOAPAction header
3900
+ if (isset($this->headers['soapaction'])) {
3901
+ $this->SOAPAction = str_replace('"', '', $this->headers['soapaction']);
3902
+ }
3903
+ // get the character encoding of the incoming request
3904
+ if (isset($this->headers['content-type']) && strpos($this->headers['content-type'], '=')) {
3905
+ $enc = str_replace('"', '', substr(strstr($this->headers["content-type"], '='), 1));
3906
+ if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3907
+ $this->xml_encoding = strtoupper($enc);
3908
+ } else {
3909
+ $this->xml_encoding = 'US-ASCII';
3910
+ }
3911
+ } else {
3912
+ // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3913
+ $this->xml_encoding = 'ISO-8859-1';
3914
+ }
3915
+ } elseif (isset($_SERVER) && is_array($_SERVER)) {
3916
+ $this->debug("In parse_http_headers, use _SERVER");
3917
+ foreach ($_SERVER as $k => $v) {
3918
+ if (substr($k, 0, 5) == 'HTTP_') {
3919
+ $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3920
+ } else {
3921
+ $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3922
+ }
3923
+ if ($k == 'soapaction') {
3924
+ // get SOAPAction header
3925
+ $k = 'SOAPAction';
3926
+ $v = str_replace('"', '', $v);
3927
+ $v = str_replace('\\', '', $v);
3928
+ $this->SOAPAction = $v;
3929
+ } elseif ($k == 'content-type') {
3930
+ // get the character encoding of the incoming request
3931
+ if (strpos($v, '=')) {
3932
+ $enc = substr(strstr($v, '='), 1);
3933
+ $enc = str_replace('"', '', $enc);
3934
+ $enc = str_replace('\\', '', $enc);
3935
+ if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3936
+ $this->xml_encoding = strtoupper($enc);
3937
+ } else {
3938
+ $this->xml_encoding = 'US-ASCII';
3939
+ }
3940
+ } else {
3941
+ // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3942
+ $this->xml_encoding = 'ISO-8859-1';
3943
+ }
3944
+ }
3945
+ $this->headers[$k] = $v;
3946
+ $this->request .= "$k: $v\r\n";
3947
+ $this->debug("$k: $v");
3948
+ }
3949
+ } elseif (is_array($HTTP_SERVER_VARS)) {
3950
+ $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
3951
+ foreach ($HTTP_SERVER_VARS as $k => $v) {
3952
+ if (substr($k, 0, 5) == 'HTTP_') {
3953
+ $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3954
+ $k = strtolower(substr($k, 5));
3955
+ } else {
3956
+ $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3957
+ $k = strtolower($k);
3958
+ }
3959
+ if ($k == 'soapaction') {
3960
+ // get SOAPAction header
3961
+ $k = 'SOAPAction';
3962
+ $v = str_replace('"', '', $v);
3963
+ $v = str_replace('\\', '', $v);
3964
+ $this->SOAPAction = $v;
3965
+ } elseif ($k == 'content-type') {
3966
+ // get the character encoding of the incoming request
3967
+ if (strpos($v, '=')) {
3968
+ $enc = substr(strstr($v, '='), 1);
3969
+ $enc = str_replace('"', '', $enc);
3970
+ $enc = str_replace('\\', '', $enc);
3971
+ if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3972
+ $this->xml_encoding = strtoupper($enc);
3973
+ } else {
3974
+ $this->xml_encoding = 'US-ASCII';
3975
+ }
3976
+ } else {
3977
+ // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3978
+ $this->xml_encoding = 'ISO-8859-1';
3979
+ }
3980
+ }
3981
+ $this->headers[$k] = $v;
3982
+ $this->request .= "$k: $v\r\n";
3983
+ $this->debug("$k: $v");
3984
+ }
3985
+ } else {
3986
+ $this->debug("In parse_http_headers, HTTP headers not accessible");
3987
+ $this->setError("HTTP headers not accessible");
3988
+ }
3989
+ }
3990
+
3991
+ /**
3992
+ * parses a request
3993
+ *
3994
+ * The following fields are set by this function (when successful)
3995
+ *
3996
+ * headers
3997
+ * request
3998
+ * xml_encoding
3999
+ * SOAPAction
4000
+ * request
4001
+ * requestSOAP
4002
+ * methodURI
4003
+ * methodname
4004
+ * methodparams
4005
+ * requestHeaders
4006
+ * document
4007
+ *
4008
+ * This sets the fault field on error
4009
+ *
4010
+ * @param string $data XML string
4011
+ * @access private
4012
+ */
4013
+ function parse_request($data = '')
4014
+ {
4015
+ $this->debug('entering parse_request()');
4016
+ $this->parse_http_headers();
4017
+ $this->debug('got character encoding: ' . $this->xml_encoding);
4018
+ // uncompress if necessary
4019
+ if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
4020
+ $this->debug('got content encoding: ' . $this->headers['content-encoding']);
4021
+ if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
4022
+ // if decoding works, use it. else assume data wasn't gzencoded
4023
+ if (function_exists('gzuncompress')) {
4024
+ if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
4025
+ $data = $degzdata;
4026
+ } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
4027
+ $data = $degzdata;
4028
+ } else {
4029
+ $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
4030
+ return;
4031
+ }
4032
+ } else {
4033
+ $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
4034
+ return;
4035
+ }
4036
+ }
4037
+ }
4038
+ $this->request .= "\r\n" . $data;
4039
+ $data = $this->parseRequest($this->headers, $data);
4040
+ $this->requestSOAP = $data;
4041
+ $this->debug('leaving parse_request');
4042
+ }
4043
+
4044
+ /**
4045
+ * invokes a PHP function for the requested SOAP method
4046
+ *
4047
+ * The following fields are set by this function (when successful)
4048
+ *
4049
+ * methodreturn
4050
+ *
4051
+ * Note that the PHP function that is called may also set the following
4052
+ * fields to affect the response sent to the client
4053
+ *
4054
+ * responseHeaders
4055
+ * outgoing_headers
4056
+ *
4057
+ * This sets the fault field on error
4058
+ *
4059
+ * @access private
4060
+ */
4061
+ function invoke_method()
4062
+ {
4063
+ $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
4064
+
4065
+ //
4066
+ // if you are debugging in this area of the code, your service uses a class to implement methods,
4067
+ // you use SOAP RPC, and the client is .NET, please be aware of the following...
4068
+ // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the
4069
+ // method name. that is fine for naming the .NET methods. it is not fine for properly constructing
4070
+ // the XML request and reading the XML response. you need to add the RequestElementName and
4071
+ // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe
4072
+ // generates for the method. these parameters are used to specify the correct XML element names
4073
+ // for .NET to use, i.e. the names with the '.' in them.
4074
+ //
4075
+ $orig_methodname = $this->methodname;
4076
+ if ($this->wsdl) {
4077
+ if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
4078
+ $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
4079
+ $this->appendDebug('opData=' . $this->varDump($this->opData));
4080
+ } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
4081
+ // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
4082
+ $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
4083
+ $this->appendDebug('opData=' . $this->varDump($this->opData));
4084
+ $this->methodname = $this->opData['name'];
4085
+ } else {
4086
+ $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
4087
+ $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
4088
+ return;
4089
+ }
4090
+ } else {
4091
+ $this->debug('in invoke_method, no WSDL to validate method');
4092
+ }
4093
+
4094
+ // if a . is present in $this->methodname, we see if there is a class in scope,
4095
+ // which could be referred to. We will also distinguish between two deliminators,
4096
+ // to allow methods to be called a the class or an instance
4097
+ if (strpos($this->methodname, '..') > 0) {
4098
+ $delim = '..';
4099
+ } elseif (strpos($this->methodname, '.') > 0) {
4100
+ $delim = '.';
4101
+ } else {
4102
+ $delim = '';
4103
+ }
4104
+ $this->debug("in invoke_method, delim=$delim");
4105
+
4106
+ $class = '';
4107
+ $method = '';
4108
+ if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) {
4109
+ $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim));
4110
+ if (class_exists($try_class)) {
4111
+ // get the class and method name
4112
+ $class = $try_class;
4113
+ $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
4114
+ $this->debug("in invoke_method, class=$class method=$method delim=$delim");
4115
+ } else {
4116
+ $this->debug("in invoke_method, class=$try_class not found");
4117
+ }
4118
+ } elseif (strlen($delim) > 0 && substr_count($this->methodname, $delim) > 1) {
4119
+ $split = explode($delim, $this->methodname);
4120
+ $method = array_pop($split);
4121
+ $class = implode('\\', $split);
4122
+ } else {
4123
+ $try_class = '';
4124
+ $this->debug("in invoke_method, no class to try");
4125
+ }
4126
+
4127
+ // does method exist?
4128
+ if ($class == '') {
4129
+ if (!function_exists($this->methodname)) {
4130
+ $this->debug("in invoke_method, function '$this->methodname' not found!");
4131
+ $this->result = 'fault: method not found';
4132
+ $this->fault('SOAP-ENV:Client', "method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')");
4133
+ return;
4134
+ }
4135
+ } else {
4136
+ $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
4137
+ if (!in_array($method_to_compare, get_class_methods($class))) {
4138
+ $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
4139
+ $this->result = 'fault: method not found';
4140
+ $this->fault('SOAP-ENV:Client', "method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')");
4141
+ return;
4142
+ }
4143
+ }
4144
+
4145
+ // evaluate message, getting back parameters
4146
+ // verify that request parameters match the method's signature
4147
+ if (!$this->verify_method($this->methodname, $this->methodparams)) {
4148
+ // debug
4149
+ $this->debug('ERROR: request not verified against method signature');
4150
+ $this->result = 'fault: request failed validation against method signature';
4151
+ // return fault
4152
+ $this->fault('SOAP-ENV:Client', "Operation '$this->methodname' not defined in service.");
4153
+ return;
4154
+ }
4155
+
4156
+ // if there are parameters to pass
4157
+ $this->debug('in invoke_method, params:');
4158
+ $this->appendDebug($this->varDump($this->methodparams));
4159
+ $this->debug("in invoke_method, calling '$this->methodname'");
4160
+ if (!function_exists('call_user_func_array')) {
4161
+ if ($class == '') {
4162
+ $this->debug('in invoke_method, calling function using eval()');
4163
+ $funcCall = "\$this->methodreturn = $this->methodname(";
4164
+ } else {
4165
+ if ($delim == '..') {
4166
+ $this->debug('in invoke_method, calling class method using eval()');
4167
+ $funcCall = "\$this->methodreturn = " . $class . "::" . $method . "(";
4168
+ } else {
4169
+ $this->debug('in invoke_method, calling instance method using eval()');
4170
+ // generate unique instance name
4171
+ $instname = "\$inst_" . time();
4172
+ $funcCall = $instname . " = new " . $class . "(); ";
4173
+ $funcCall .= "\$this->methodreturn = " . $instname . "->" . $method . "(";
4174
+ }
4175
+ }
4176
+ if ($this->methodparams) {
4177
+ foreach ($this->methodparams as $param) {
4178
+ if (is_array($param) || is_object($param)) {
4179
+ $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
4180
+ return;
4181
+ }
4182
+ $funcCall .= "\"$param\",";
4183
+ }
4184
+ $funcCall = substr($funcCall, 0, -1);
4185
+ }
4186
+ $funcCall .= ');';
4187
+ $this->debug('in invoke_method, function call: ' . $funcCall);
4188
+ @eval($funcCall);
4189
+ } else {
4190
+ if ($class == '') {
4191
+ $this->debug('in invoke_method, calling function using call_user_func_array()');
4192
+ $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array()
4193
+ } elseif ($delim == '..') {
4194
+ $this->debug('in invoke_method, calling class method using call_user_func_array()');
4195
+ $call_arg = array($class, $method);
4196
+ } else {
4197
+ $this->debug('in invoke_method, calling instance method using call_user_func_array()');
4198
+ $instance = new $class ();
4199
+ $call_arg = array(&$instance, $method);
4200
+ }
4201
+ if (is_array($this->methodparams)) {
4202
+ $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
4203
+ } else {
4204
+ $this->methodreturn = call_user_func_array($call_arg, array());
4205
+ }
4206
+ }
4207
+ $this->debug('in invoke_method, methodreturn:');
4208
+ $this->appendDebug($this->varDump($this->methodreturn));
4209
+ $this->debug("in invoke_method, called method $this->methodname, received data of type " . gettype($this->methodreturn));
4210
+ }
4211
+
4212
+ /**
4213
+ * serializes the return value from a PHP function into a full SOAP Envelope
4214
+ *
4215
+ * The following fields are set by this function (when successful)
4216
+ *
4217
+ * responseSOAP
4218
+ *
4219
+ * This sets the fault field on error
4220
+ *
4221
+ * @access private
4222
+ */
4223
+ function serialize_return()
4224
+ {
4225
+ $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4226
+ // if fault
4227
+ if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) {
4228
+ $this->debug('got a fault object from method');
4229
+ $this->fault = $this->methodreturn;
4230
+ return;
4231
+ } elseif ($this->methodreturnisliteralxml) {
4232
+ $return_val = $this->methodreturn;
4233
+ // returned value(s)
4234
+ } else {
4235
+ $this->debug('got a(n) ' . gettype($this->methodreturn) . ' from method');
4236
+ $this->debug('serializing return value');
4237
+ if ($this->wsdl) {
4238
+ if (sizeof($this->opData['output']['parts']) > 1) {
4239
+ $this->debug('more than one output part, so use the method return unchanged');
4240
+ $opParams = $this->methodreturn;
4241
+ } elseif (sizeof($this->opData['output']['parts']) == 1) {
4242
+ $this->debug('exactly one output part, so wrap the method return in a simple array');
4243
+ // TODO: verify that it is not already wrapped!
4244
+ //foreach ($this->opData['output']['parts'] as $name => $type) {
4245
+ // $this->debug('wrap in element named ' . $name);
4246
+ //}
4247
+ $opParams = array($this->methodreturn);
4248
+ }
4249
+ $return_val = $this->wsdl->serializeRPCParameters($this->methodname, 'output', $opParams);
4250
+ $this->appendDebug($this->wsdl->getDebug());
4251
+ $this->wsdl->clearDebug();
4252
+ if ($errstr = $this->wsdl->getError()) {
4253
+ $this->debug('got wsdl error: ' . $errstr);
4254
+ $this->fault('SOAP-ENV:Server', 'unable to serialize result');
4255
+ return;
4256
+ }
4257
+ } else {
4258
+ if (isset($this->methodreturn)) {
4259
+ $return_val = $this->serialize_val($this->methodreturn, 'return');
4260
+ } else {
4261
+ $return_val = '';
4262
+ $this->debug('in absence of WSDL, assume void return for backward compatibility');
4263
+ }
4264
+ }
4265
+ }
4266
+ $this->debug('return value:');
4267
+ $this->appendDebug($this->varDump($return_val));
4268
+
4269
+ $this->debug('serializing response');
4270
+ if ($this->wsdl) {
4271
+ $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
4272
+ if ($this->opData['style'] == 'rpc') {
4273
+ $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
4274
+ if ($this->opData['output']['use'] == 'literal') {
4275
+ // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
4276
+ if ($this->methodURI) {
4277
+ $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4278
+ } else {
4279
+ $payload = '<' . $this->methodname . 'Response>' . $return_val . '</' . $this->methodname . 'Response>';
4280
+ }
4281
+ } else {
4282
+ if ($this->methodURI) {
4283
+ $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4284
+ } else {
4285
+ $payload = '<' . $this->methodname . 'Response>' . $return_val . '</' . $this->methodname . 'Response>';
4286
+ }
4287
+ }
4288
+ } else {
4289
+ $this->debug('style is not rpc for serialization: assume document');
4290
+ $payload = $return_val;
4291
+ }
4292
+ } else {
4293
+ $this->debug('do not have WSDL for serialization: assume rpc/encoded');
4294
+ $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4295
+ }
4296
+ $this->result = 'successful';
4297
+ if ($this->wsdl) {
4298
+ //if($this->debug_flag){
4299
+ $this->appendDebug($this->wsdl->getDebug());
4300
+ // }
4301
+ if (isset($this->opData['output']['encodingStyle'])) {
4302
+ $encodingStyle = $this->opData['output']['encodingStyle'];
4303
+ } else {
4304
+ $encodingStyle = '';
4305
+ }
4306
+ // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
4307
+ $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders, $this->wsdl->usedNamespaces, $this->opData['style'], $this->opData['output']['use'], $encodingStyle);
4308
+ } else {
4309
+ $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders);
4310
+ }
4311
+ $this->debug("Leaving serialize_return");
4312
+ }
4313
+
4314
+ /**
4315
+ * sends an HTTP response
4316
+ *
4317
+ * The following fields are set by this function (when successful)
4318
+ *
4319
+ * outgoing_headers
4320
+ * response
4321
+ *
4322
+ * @access private
4323
+ */
4324
+ function send_response()
4325
+ {
4326
+ $this->debug('Enter send_response');
4327
+ if ($this->fault) {
4328
+ $payload = $this->fault->serialize();
4329
+ $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
4330
+ $this->outgoing_headers[] = "Status: 500 Internal Server Error";
4331
+ } else {
4332
+ $payload = $this->responseSOAP;
4333
+ // Some combinations of PHP+Web server allow the Status
4334
+ // to come through as a header. Since OK is the default
4335
+ // just do nothing.
4336
+ // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
4337
+ // $this->outgoing_headers[] = "Status: 200 OK";
4338
+ }
4339
+ // add debug data if in debug mode
4340
+ if (isset($this->debug_flag) && $this->debug_flag) {
4341
+ $payload .= $this->getDebugAsXMLComment();
4342
+ }
4343
+ $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
4344
+ preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
4345
+ $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (" . $rev[1] . ")";
4346
+ // Let the Web server decide about this
4347
+ //$this->outgoing_headers[] = "Connection: Close\r\n";
4348
+ $payload = $this->getHTTPBody($payload);
4349
+ $type = $this->getHTTPContentType();
4350
+ $charset = $this->getHTTPContentTypeCharset();
4351
+ $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
4352
+ //begin code to compress payload - by John
4353
+ // NOTE: there is no way to know whether the Web server will also compress
4354
+ // this data.
4355
+ if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
4356
+ if (strstr($this->headers['accept-encoding'], 'gzip')) {
4357
+ if (function_exists('gzencode')) {
4358
+ if (isset($this->debug_flag) && $this->debug_flag) {
4359
+ $payload .= "<!-- Content being gzipped -->";
4360
+ }
4361
+ $this->outgoing_headers[] = "Content-Encoding: gzip";
4362
+ $payload = gzencode($payload);
4363
+ } else {
4364
+ if (isset($this->debug_flag) && $this->debug_flag) {
4365
+ $payload .= "<!-- Content will not be gzipped: no gzencode -->";
4366
+ }
4367
+ }
4368
+ } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
4369
+ // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
4370
+ // instead of gzcompress output,
4371
+ // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
4372
+ if (function_exists('gzdeflate')) {
4373
+ if (isset($this->debug_flag) && $this->debug_flag) {
4374
+ $payload .= "<!-- Content being deflated -->";
4375
+ }
4376
+ $this->outgoing_headers[] = "Content-Encoding: deflate";
4377
+ $payload = gzdeflate($payload);
4378
+ } else {
4379
+ if (isset($this->debug_flag) && $this->debug_flag) {
4380
+ $payload .= "<!-- Content will not be deflated: no gzcompress -->";
4381
+ }
4382
+ }
4383
+ }
4384
+ }
4385
+ //end code
4386
+ $this->outgoing_headers[] = "Content-Length: " . strlen($payload);
4387
+ reset($this->outgoing_headers);
4388
+ foreach ($this->outgoing_headers as $hdr) {
4389
+ header($hdr, false);
4390
+ }
4391
+ print $payload;
4392
+ $this->response = join("\r\n", $this->outgoing_headers) . "\r\n\r\n" . $payload;
4393
+ }
4394
+
4395
+ /**
4396
+ * takes the value that was created by parsing the request
4397
+ * and compares to the method's signature, if available.
4398
+ *
4399
+ * @param string $operation The operation to be invoked
4400
+ * @param array $request The array of parameter values
4401
+ * @return boolean Whether the operation was found
4402
+ * @access private
4403
+ */
4404
+ function verify_method($operation, $request)
4405
+ {
4406
+ if (isset($this->wsdl) && is_object($this->wsdl)) {
4407
+ if ($this->wsdl->getOperationData($operation)) {
4408
+ return true;
4409
+ }
4410
+ } elseif (isset($this->operations[$operation])) {
4411
+ return true;
4412
+ }
4413
+ return false;
4414
+ }
4415
+
4416
+ /**
4417
+ * processes SOAP message received from client
4418
+ *
4419
+ * @param array $headers The HTTP headers
4420
+ * @param string $data unprocessed request data from client
4421
+ * @return mixed value of the message, decoded into a PHP type
4422
+ * @access private
4423
+ */
4424
+ function parseRequest($headers, $data)
4425
+ {
4426
+ $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:');
4427
+ $this->appendDebug($this->varDump($headers));
4428
+ if (!isset($headers['content-type'])) {
4429
+ $this->setError('Request not of type text/xml (no content-type header)');
4430
+ return false;
4431
+ }
4432
+ if (!strstr($headers['content-type'], 'text/xml')) {
4433
+ $this->setError('Request not of type text/xml');
4434
+ return false;
4435
+ }
4436
+ if (strpos($headers['content-type'], '=')) {
4437
+ $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
4438
+ $this->debug('Got response encoding: ' . $enc);
4439
+ if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4440
+ $this->xml_encoding = strtoupper($enc);
4441
+ } else {
4442
+ $this->xml_encoding = 'US-ASCII';
4443
+ }
4444
+ } else {
4445
+ // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4446
+ $this->xml_encoding = 'ISO-8859-1';
4447
+ }
4448
+ $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
4449
+ // parse response, get soap parser obj
4450
+ $parser = new nusoap_parser($data, $this->xml_encoding, '', $this->decode_utf8);
4451
+ // parser debug
4452
+ $this->debug("parser debug: \n" . $parser->getDebug());
4453
+ // if fault occurred during message parsing
4454
+ if ($err = $parser->getError()) {
4455
+ $this->result = 'fault: error in msg parsing: ' . $err;
4456
+ $this->fault('SOAP-ENV:Client', "error in msg parsing:\n" . $err);
4457
+ // else successfully parsed request into soapval object
4458
+ } else {
4459
+ // get/set methodname
4460
+ $this->methodURI = $parser->root_struct_namespace;
4461
+ $this->methodname = $parser->root_struct_name;
4462
+ $this->debug('methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4463
+ $this->debug('calling parser->get_soapbody()');
4464
+ $this->methodparams = $parser->get_soapbody();
4465
+ // get SOAP headers
4466
+ $this->requestHeaders = $parser->getHeaders();
4467
+ // get SOAP Header
4468
+ $this->requestHeader = $parser->get_soapheader();
4469
+ // add document for doclit support
4470
+ $this->document = $parser->document;
4471
+ }
4472
+ }
4473
+
4474
+ /**
4475
+ * gets the HTTP body for the current response.
4476
+ *
4477
+ * @param string $soapmsg The SOAP payload
4478
+ * @return string The HTTP body, which includes the SOAP payload
4479
+ * @access private
4480
+ */
4481
+ function getHTTPBody($soapmsg)
4482
+ {
4483
+ return $soapmsg;
4484
+ }
4485
+
4486
+ /**
4487
+ * gets the HTTP content type for the current response.
4488
+ *
4489
+ * Note: getHTTPBody must be called before this.
4490
+ *
4491
+ * @return string the HTTP content type for the current response.
4492
+ * @access private
4493
+ */
4494
+ function getHTTPContentType()
4495
+ {
4496
+ return 'text/xml';
4497
+ }
4498
+
4499
+ /**
4500
+ * gets the HTTP content type charset for the current response.
4501
+ * returns false for non-text content types.
4502
+ *
4503
+ * Note: getHTTPBody must be called before this.
4504
+ *
4505
+ * @return string the HTTP content type charset for the current response.
4506
+ * @access private
4507
+ */
4508
+ function getHTTPContentTypeCharset()
4509
+ {
4510
+ return $this->soap_defencoding;
4511
+ }
4512
+
4513
+ /**
4514
+ * add a method to the dispatch map (this has been replaced by the register method)
4515
+ *
4516
+ * @param string $methodname
4517
+ * @param string $in array of input values
4518
+ * @param string $out array of output values
4519
+ * @access public
4520
+ * @deprecated
4521
+ */
4522
+ function add_to_map($methodname, $in, $out)
4523
+ {
4524
+ $this->operations[$methodname] = array('name' => $methodname, 'in' => $in, 'out' => $out);
4525
+ }
4526
+
4527
+ /**
4528
+ * register a service function with the server
4529
+ *
4530
+ * @param string $name the name of the PHP function, class.method or class..method
4531
+ * @param array $in assoc array of input values: key = param name, value = param type
4532
+ * @param array $out assoc array of output values: key = param name, value = param type
4533
+ * @param mixed $namespace the element namespace for the method or false
4534
+ * @param mixed $soapaction the soapaction for the method or false
4535
+ * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
4536
+ * @param mixed $use optional (encoded|literal) or false
4537
+ * @param string $documentation optional Description to include in WSDL
4538
+ * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
4539
+ * @access public
4540
+ */
4541
+ function register($name, $in = array(), $out = array(), $namespace = false, $soapaction = false, $style = false, $use = false, $documentation = '', $encodingStyle = '')
4542
+ {
4543
+ global $HTTP_SERVER_VARS;
4544
+
4545
+ if ($this->externalWSDLURL) {
4546
+ die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
4547
+ }
4548
+ if (!$name) {
4549
+ die('You must specify a name when you register an operation');
4550
+ }
4551
+ if (!is_array($in)) {
4552
+ die('You must provide an array for operation inputs');
4553
+ }
4554
+ if (!is_array($out)) {
4555
+ die('You must provide an array for operation outputs');
4556
+ }
4557
+ if (false == $namespace) {
4558
+ }
4559
+ if (false == $soapaction) {
4560
+ if (isset($_SERVER)) {
4561
+ $SERVER_NAME = $_SERVER['SERVER_NAME'];
4562
+ $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4563
+ $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4564
+ } elseif (isset($HTTP_SERVER_VARS)) {
4565
+ $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4566
+ $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4567
+ $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4568
+ } else {
4569
+ $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4570
+ }
4571
+ if ($HTTPS == '1' || $HTTPS == 'on') {
4572
+ $SCHEME = 'https';
4573
+ } else {
4574
+ $SCHEME = 'http';
4575
+ }
4576
+ $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
4577
+ }
4578
+ if (false == $style) {
4579
+ $style = "rpc";
4580
+ }
4581
+ if (false == $use) {
4582
+ $use = "encoded";
4583
+ }
4584
+ if ($use == 'encoded' && $encodingStyle == '') {
4585
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
4586
+ }
4587
+
4588
+ $this->operations[$name] = array(
4589
+ 'name' => $name,
4590
+ 'in' => $in,
4591
+ 'out' => $out,
4592
+ 'namespace' => $namespace,
4593
+ 'soapaction' => $soapaction,
4594
+ 'style' => $style);
4595
+ if ($this->wsdl) {
4596
+ $this->wsdl->addOperation($name, $in, $out, $namespace, $soapaction, $style, $use, $documentation, $encodingStyle);
4597
+ }
4598
+ return true;
4599
+ }
4600
+
4601
+ /**
4602
+ * Specify a fault to be returned to the client.
4603
+ * This also acts as a flag to the server that a fault has occured.
4604
+ *
4605
+ * @param string $faultcode
4606
+ * @param string $faultstring
4607
+ * @param string $faultactor
4608
+ * @param string $faultdetail
4609
+ * @access public
4610
+ */
4611
+ function fault($faultcode, $faultstring, $faultactor = '', $faultdetail = '')
4612
+ {
4613
+ if ($faultdetail == '' && $this->debug_flag) {
4614
+ $faultdetail = $this->getDebug();
4615
+ }
4616
+ $this->fault = new nusoap_fault($faultcode, $faultactor, $faultstring, $faultdetail);
4617
+ $this->fault->soap_defencoding = $this->soap_defencoding;
4618
+ }
4619
+
4620
+ /**
4621
+ * Sets up wsdl object.
4622
+ * Acts as a flag to enable internal WSDL generation
4623
+ *
4624
+ * @param string $serviceName , name of the service
4625
+ * @param mixed $namespace optional 'tns' service namespace or false
4626
+ * @param mixed $endpoint optional URL of service endpoint or false
4627
+ * @param string $style optional (rpc|document) WSDL style (also specified by operation)
4628
+ * @param string $transport optional SOAP transport
4629
+ * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false
4630
+ */
4631
+ function configureWSDL($serviceName, $namespace = false, $endpoint = false, $style = 'rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
4632
+ {
4633
+ global $HTTP_SERVER_VARS;
4634
+
4635
+ if (isset($_SERVER)) {
4636
+ $SERVER_NAME = $_SERVER['SERVER_NAME'];
4637
+ $SERVER_PORT = $_SERVER['SERVER_PORT'];
4638
+ $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4639
+ $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4640
+ } elseif (isset($HTTP_SERVER_VARS)) {
4641
+ $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4642
+ $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
4643
+ $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4644
+ $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4645
+ } else {
4646
+ $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4647
+ }
4648
+ // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
4649
+ $colon = strpos($SERVER_NAME, ":");
4650
+ if ($colon) {
4651
+ $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
4652
+ }
4653
+ if ($SERVER_PORT == 80) {
4654
+ $SERVER_PORT = '';
4655
+ } else {
4656
+ $SERVER_PORT = ':' . $SERVER_PORT;
4657
+ }
4658
+ if (false == $namespace) {
4659
+ $namespace = "http://$SERVER_NAME/soap/$serviceName";
4660
+ }
4661
+
4662
+ if (false == $endpoint) {
4663
+ if ($HTTPS == '1' || $HTTPS == 'on') {
4664
+ $SCHEME = 'https';
4665
+ } else {
4666
+ $SCHEME = 'http';
4667
+ }
4668
+ $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
4669
+ }
4670
+
4671
+ if (false == $schemaTargetNamespace) {
4672
+ $schemaTargetNamespace = $namespace;
4673
+ }
4674
+
4675
+ $this->wsdl = new wsdl;
4676
+ $this->wsdl->serviceName = $serviceName;
4677
+ $this->wsdl->endpoint = $endpoint;
4678
+ $this->wsdl->namespaces['tns'] = $namespace;
4679
+ $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
4680
+ $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
4681
+ if ($schemaTargetNamespace != $namespace) {
4682
+ $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4683
+ }
4684
+ $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
4685
+ if ($style == 'document') {
4686
+ $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
4687
+ }
4688
+ $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
4689
+ $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
4690
+ $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
4691
+ $this->wsdl->bindings[$serviceName . 'Binding'] = array(
4692
+ 'name' => $serviceName . 'Binding',
4693
+ 'style' => $style,
4694
+ 'transport' => $transport,
4695
+ 'portType' => $serviceName . 'PortType');
4696
+ $this->wsdl->ports[$serviceName . 'Port'] = array(
4697
+ 'binding' => $serviceName . 'Binding',
4698
+ 'location' => $endpoint,
4699
+ 'bindingType' => 'http://schemas.xmlsoap.org/wsdl/soap/');
4700
+ }
4701
+ }
4702
+
4703
+ /**
4704
+ * Backward compatibility
4705
+ */
4706
+ class soap_server extends nusoap_server
4707
+ {
4708
+ }
4709
+
4710
+
4711
+ /**
4712
+ * parses a WSDL file, allows access to it's data, other utility methods.
4713
+ * also builds WSDL structures programmatically.
4714
+ *
4715
+ * @author Dietrich Ayala <dietrich@ganx4.com>
4716
+ * @author Scott Nichol <snichol@users.sourceforge.net>
4717
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
4718
+ * @access public
4719
+ */
4720
+ class wsdl extends nusoap_base
4721
+ {
4722
+ // URL or filename of the root of this WSDL
4723
+ var $wsdl;
4724
+ // define internal arrays of bindings, ports, operations, messages, etc.
4725
+ var $schemas = array();
4726
+ var $currentSchema;
4727
+ var $message = array();
4728
+ var $complexTypes = array();
4729
+ var $messages = array();
4730
+ var $currentMessage;
4731
+ var $currentOperation;
4732
+ var $portTypes = array();
4733
+ var $currentPortType;
4734
+ var $bindings = array();
4735
+ var $currentBinding;
4736
+ var $ports = array();
4737
+ var $currentPort;
4738
+ var $opData = array();
4739
+ var $status = '';
4740
+ var $documentation = false;
4741
+ var $endpoint = '';
4742
+ // array of wsdl docs to import
4743
+ var $import = array();
4744
+ // parser vars
4745
+ var $parser;
4746
+ var $position = 0;
4747
+ var $depth = 0;
4748
+ var $depth_array = array();
4749
+ // for getting wsdl
4750
+ var $proxyhost = '';
4751
+ var $proxyport = '';
4752
+ var $proxyusername = '';
4753
+ var $proxypassword = '';
4754
+ var $timeout = 0;
4755
+ var $response_timeout = 30;
4756
+ var $curl_options = array(); // User-specified cURL options
4757
+ var $use_curl = false; // whether to always try to use cURL
4758
+ // for HTTP authentication
4759
+ var $username = ''; // Username for HTTP authentication
4760
+ var $password = ''; // Password for HTTP authentication
4761
+ var $authtype = ''; // Type of HTTP authentication
4762
+ var $certRequest = array(); // Certificate for HTTP SSL authentication
4763
+
4764
+ /**
4765
+ * constructor
4766
+ *
4767
+ * @param string $wsdl WSDL document URL
4768
+ * @param string $proxyhost
4769
+ * @param string $proxyport
4770
+ * @param string $proxyusername
4771
+ * @param string $proxypassword
4772
+ * @param integer $timeout set the connection timeout
4773
+ * @param integer $response_timeout set the response timeout
4774
+ * @param array $curl_options user-specified cURL options
4775
+ * @param boolean $use_curl try to use cURL
4776
+ * @access public
4777
+ */
4778
+ function __construct($wsdl = '', $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $curl_options = null, $use_curl = false)
4779
+ {
4780
+ parent::__construct();
4781
+ $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
4782
+ $this->proxyhost = $proxyhost;
4783
+ $this->proxyport = $proxyport;
4784
+ $this->proxyusername = $proxyusername;
4785
+ $this->proxypassword = $proxypassword;
4786
+ $this->timeout = $timeout;
4787
+ $this->response_timeout = $response_timeout;
4788
+ if (is_array($curl_options)) {
4789
+ $this->curl_options = $curl_options;
4790
+ }
4791
+ $this->use_curl = $use_curl;
4792
+ $this->fetchWSDL($wsdl);
4793
+ }
4794
+
4795
+ /**
4796
+ * fetches the WSDL document and parses it
4797
+ *
4798
+ * @access public
4799
+ */
4800
+ function fetchWSDL($wsdl)
4801
+ {
4802
+ $this->debug("parse and process WSDL path=$wsdl");
4803
+ $this->wsdl = $wsdl;
4804
+ // parse wsdl file
4805
+ if ($this->wsdl != "") {
4806
+ $this->parseWSDL($this->wsdl);
4807
+ }
4808
+ // imports
4809
+ // TODO: handle imports more properly, grabbing them in-line and nesting them
4810
+ $imported_urls = array();
4811
+ $imported = 1;
4812
+ while ($imported > 0) {
4813
+ $imported = 0;
4814
+ // Schema imports
4815
+ foreach ($this->schemas as $ns => $list) {
4816
+ foreach ($list as $xs) {
4817
+ $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4818
+ foreach ($xs->imports as $ns2 => $list2) {
4819
+ for ($ii = 0; $ii < count($list2); $ii++) {
4820
+ if (!$list2[$ii]['loaded']) {
4821
+ $this->schemas[$ns][$ns2]->imports[$ns2][$ii]['loaded'] = true;
4822
+ $url = $list2[$ii]['location'];
4823
+ if ($url != '') {
4824
+ $urlparts = parse_url($url);
4825
+ if (!isset($urlparts['host'])) {
4826
+ $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4827
+ substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
4828
+ }
4829
+ if (!in_array($url, $imported_urls)) {
4830
+ $this->parseWSDL($url);
4831
+ $imported++;
4832
+ $imported_urls[] = $url;
4833
+ }
4834
+ } else {
4835
+ $this->debug("Unexpected scenario: empty URL for unloaded import");
4836
+ }
4837
+ }
4838
+ }
4839
+ }
4840
+ }
4841
+ }
4842
+ // WSDL imports
4843
+ $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4844
+ foreach ($this->import as $ns => $list) {
4845
+ for ($ii = 0; $ii < count($list); $ii++) {
4846
+ if (!$list[$ii]['loaded']) {
4847
+ $this->import[$ns][$ii]['loaded'] = true;
4848
+ $url = $list[$ii]['location'];
4849
+ if ($url != '') {
4850
+ $urlparts = parse_url($url);
4851
+ if (!isset($urlparts['host'])) {
4852
+ $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4853
+ substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
4854
+ }
4855
+ if (!in_array($url, $imported_urls)) {
4856
+ $this->parseWSDL($url);
4857
+ $imported++;
4858
+ $imported_urls[] = $url;
4859
+ }
4860
+ } else {
4861
+ $this->debug("Unexpected scenario: empty URL for unloaded import");
4862
+ }
4863
+ }
4864
+ }
4865
+ }
4866
+ }
4867
+ // add new data to operation data
4868
+ foreach ($this->bindings as $binding => $bindingData) {
4869
+ if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
4870
+ foreach ($bindingData['operations'] as $operation => $data) {
4871
+ $this->debug('post-parse data gathering for ' . $operation);
4872
+ $this->bindings[$binding]['operations'][$operation]['input'] =
4873
+ isset($this->bindings[$binding]['operations'][$operation]['input']) ?
4874
+ array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[$bindingData['portType']][$operation]['input']) :
4875
+ $this->portTypes[$bindingData['portType']][$operation]['input'];
4876
+ $this->bindings[$binding]['operations'][$operation]['output'] =
4877
+ isset($this->bindings[$binding]['operations'][$operation]['output']) ?
4878
+ array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[$bindingData['portType']][$operation]['output']) :
4879
+ $this->portTypes[$bindingData['portType']][$operation]['output'];
4880
+ if (isset($this->messages[$this->bindings[$binding]['operations'][$operation]['input']['message']])) {
4881
+ $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[$this->bindings[$binding]['operations'][$operation]['input']['message']];
4882
+ }
4883
+ if (isset($this->messages[$this->bindings[$binding]['operations'][$operation]['output']['message']])) {
4884
+ $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[$this->bindings[$binding]['operations'][$operation]['output']['message']];
4885
+ }
4886
+ // Set operation style if necessary, but do not override one already provided
4887
+ if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
4888
+ $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
4889
+ }
4890
+ $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
4891
+ $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[$bindingData['portType']][$operation]['documentation']) ? $this->portTypes[$bindingData['portType']][$operation]['documentation'] : '';
4892
+ $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
4893
+ }
4894
+ }
4895
+ }
4896
+ }
4897
+
4898
+ /**
4899
+ * parses the wsdl document
4900
+ *
4901
+ * @param string $wsdl path or URL
4902
+ * @access private
4903
+ */
4904
+ function parseWSDL($wsdl = '')
4905
+ {
4906
+ $this->debug("parse WSDL at path=$wsdl");
4907
+
4908
+ if ($wsdl == '') {
4909
+ $this->debug('no wsdl passed to parseWSDL()!!');
4910
+ $this->setError('no wsdl passed to parseWSDL()!!');
4911
+ return false;
4912
+ }
4913
+
4914
+ // parse $wsdl for url format
4915
+ $wsdl_props = parse_url($wsdl);
4916
+
4917
+ if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
4918
+ $this->debug('getting WSDL http(s) URL ' . $wsdl);
4919
+ // get wsdl
4920
+ $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
4921
+ $tr->request_method = 'GET';
4922
+ $tr->useSOAPAction = false;
4923
+ if ($this->proxyhost && $this->proxyport) {
4924
+ $tr->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
4925
+ }
4926
+ if ($this->authtype != '') {
4927
+ $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
4928
+ }
4929
+ $tr->setEncoding('gzip, deflate');
4930
+ $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
4931
+ //$this->debug("WSDL request\n" . $tr->outgoing_payload);
4932
+ //$this->debug("WSDL response\n" . $tr->incoming_payload);
4933
+ $this->appendDebug($tr->getDebug());
4934
+ // catch errors
4935
+ if ($err = $tr->getError()) {
4936
+ $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: ' . $err;
4937
+ $this->debug($errstr);
4938
+ $this->setError($errstr);
4939
+ unset($tr);
4940
+ return false;
4941
+ }
4942
+ unset($tr);
4943
+ $this->debug("got WSDL URL");
4944
+ } else {
4945
+ // $wsdl is not http(s), so treat it as a file URL or plain file path
4946
+ if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
4947
+ $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
4948
+ } else {
4949
+ $path = $wsdl;
4950
+ }
4951
+ $this->debug('getting WSDL file ' . $path);
4952
+ if ($fp = @fopen($path, 'r')) {
4953
+ $wsdl_string = '';
4954
+ while ($data = fread($fp, 32768)) {
4955
+ $wsdl_string .= $data;
4956
+ }
4957
+ fclose($fp);
4958
+ } else {
4959
+ $errstr = "Bad path to WSDL file $path";
4960
+ $this->debug($errstr);
4961
+ $this->setError($errstr);
4962
+ return false;
4963
+ }
4964
+ }
4965
+ $this->debug('Parse WSDL');
4966
+ // end new code added
4967
+ // Create an XML parser.
4968
+ $this->parser = xml_parser_create();
4969
+ // Set the options for parsing the XML data.
4970
+ // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
4971
+ xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
4972
+ // Set the object for the parser.
4973
+ xml_set_object($this->parser, $this);
4974
+ // Set the element handlers for the parser.
4975
+ xml_set_element_handler($this->parser, 'start_element', 'end_element');
4976
+ xml_set_character_data_handler($this->parser, 'character_data');
4977
+ // Parse the XML file.
4978
+ if (!xml_parse($this->parser, $wsdl_string, true)) {
4979
+ // Display an error message.
4980
+ $errstr = sprintf(
4981
+ 'XML error parsing WSDL from %s on line %d: %s',
4982
+ $wsdl,
4983
+ xml_get_current_line_number($this->parser),
4984
+ xml_error_string(xml_get_error_code($this->parser))
4985
+ );
4986
+ $this->debug($errstr);
4987
+ $this->debug("XML payload:\n" . $wsdl_string);
4988
+ $this->setError($errstr);
4989
+ xml_parser_free($this->parser);
4990
+ unset($this->parser);
4991
+ return false;
4992
+ }
4993
+ // free the parser
4994
+ xml_parser_free($this->parser);
4995
+ unset($this->parser);
4996
+ $this->debug('Parsing WSDL done');
4997
+ // catch wsdl parse errors
4998
+ if ($this->getError()) {
4999
+ return false;
5000
+ }
5001
+ return true;
5002
+ }
5003
+
5004
+ /**
5005
+ * start-element handler
5006
+ *
5007
+ * @param string $parser XML parser object
5008
+ * @param string $name element name
5009
+ * @param string $attrs associative array of attributes
5010
+ * @access private
5011
+ */
5012
+ function start_element($parser, $name, $attrs)
5013
+ {
5014
+ if ($this->status == 'schema') {
5015
+ $this->currentSchema->schemaStartElement($parser, $name, $attrs);
5016
+ $this->appendDebug($this->currentSchema->getDebug());
5017
+ $this->currentSchema->clearDebug();
5018
+ } elseif (preg_match('/schema$/', $name)) {
5019
+ $this->debug('Parsing WSDL schema');
5020
+ // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
5021
+ $this->status = 'schema';
5022
+ $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
5023
+ $this->currentSchema->schemaStartElement($parser, $name, $attrs);
5024
+ $this->appendDebug($this->currentSchema->getDebug());
5025
+ $this->currentSchema->clearDebug();
5026
+ } else {
5027
+ // position in the total number of elements, starting from 0
5028
+ $pos = $this->position++;
5029
+ $depth = $this->depth++;
5030
+ // set self as current value for this depth
5031
+ $this->depth_array[$depth] = $pos;
5032
+ $this->message[$pos] = array('cdata' => '');
5033
+ // process attributes
5034
+ if (count($attrs) > 0) {
5035
+ // register namespace declarations
5036
+ foreach ($attrs as $k => $v) {
5037
+ if (preg_match('/^xmlns/', $k)) {
5038
+ if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
5039
+ $this->namespaces[$ns_prefix] = $v;
5040
+ } else {
5041
+ $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
5042
+ }
5043
+ if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
5044
+ $this->XMLSchemaVersion = $v;
5045
+ $this->namespaces['xsi'] = $v . '-instance';
5046
+ }
5047
+ }
5048
+ }
5049
+ // expand each attribute prefix to its namespace
5050
+ foreach ($attrs as $k => $v) {
5051
+ $k = strpos($k, ':') ? $this->expandQname($k) : $k;
5052
+ if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
5053
+ $v = strpos($v, ':') ? $this->expandQname($v) : $v;
5054
+ }
5055
+ $eAttrs[$k] = $v;
5056
+ }
5057
+ $attrs = $eAttrs;
5058
+ } else {
5059
+ $attrs = array();
5060
+ }
5061
+ // get element prefix, namespace and name
5062
+ if (preg_match('/:/', $name)) {
5063
+ // get ns prefix
5064
+ $prefix = substr($name, 0, strpos($name, ':'));
5065
+ // get ns
5066
+ $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
5067
+ // get unqualified name
5068
+ $name = substr(strstr($name, ':'), 1);
5069
+ }
5070
+ // process attributes, expanding any prefixes to namespaces
5071
+ // find status, register data
5072
+ switch ($this->status) {
5073
+ case 'message':
5074
+ if ($name == 'part') {
5075
+ if (isset($attrs['type'])) {
5076
+ $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
5077
+ $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
5078
+ }
5079
+ if (isset($attrs['element'])) {
5080
+ $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
5081
+ $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
5082
+ }
5083
+ }
5084
+ break;
5085
+ case 'portType':
5086
+ switch ($name) {
5087
+ case 'operation':
5088
+ $this->currentPortOperation = $attrs['name'];
5089
+ $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
5090
+ if (isset($attrs['parameterOrder'])) {
5091
+ $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
5092
+ }
5093
+ break;
5094
+ case 'documentation':
5095
+ $this->documentation = true;
5096
+ break;
5097
+ // merge input/output data
5098
+ default:
5099
+ $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
5100
+ $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
5101
+ break;
5102
+ }
5103
+ break;
5104
+ case 'binding':
5105
+ switch ($name) {
5106
+ case 'binding':
5107
+ // get ns prefix
5108
+ if (isset($attrs['style'])) {
5109
+ $this->bindings[$this->currentBinding]['prefix'] = $prefix;
5110
+ }
5111
+ $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
5112
+ break;
5113
+ case 'header':
5114
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
5115
+ break;
5116
+ case 'operation':
5117
+ if (isset($attrs['soapAction'])) {
5118
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
5119
+ }
5120
+ if (isset($attrs['style'])) {
5121
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
5122
+ }
5123
+ if (isset($attrs['name'])) {
5124
+ $this->currentOperation = $attrs['name'];
5125
+ $this->debug("current binding operation: $this->currentOperation");
5126
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
5127
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
5128
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
5129
+ }
5130
+ break;
5131
+ case 'input':
5132
+ $this->opStatus = 'input';
5133
+ break;
5134
+ case 'output':
5135
+ $this->opStatus = 'output';
5136
+ break;
5137
+ case 'body':
5138
+ if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
5139
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
5140
+ } else {
5141
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
5142
+ }
5143
+ break;
5144
+ }
5145
+ break;
5146
+ case 'service':
5147
+ switch ($name) {
5148
+ case 'port':
5149
+ $this->currentPort = $attrs['name'];
5150
+ $this->debug('current port: ' . $this->currentPort);
5151
+ $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
5152
+
5153
+ break;
5154
+ case 'address':
5155
+ $this->ports[$this->currentPort]['location'] = $attrs['location'];
5156
+ $this->ports[$this->currentPort]['bindingType'] = $namespace;
5157
+ $this->bindings[$this->ports[$this->currentPort]['binding']]['bindingType'] = $namespace;
5158
+ $this->bindings[$this->ports[$this->currentPort]['binding']]['endpoint'] = $attrs['location'];
5159
+ break;
5160
+ }
5161
+ break;
5162
+ }
5163
+ // set status
5164
+ switch ($name) {
5165
+ case 'import':
5166
+ if (isset($attrs['location'])) {
5167
+ $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
5168
+ $this->debug('parsing import ' . $attrs['namespace'] . ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]) . ')');
5169
+ } else {
5170
+ $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
5171
+ if (!$this->getPrefixFromNamespace($attrs['namespace'])) {
5172
+ $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace'];
5173
+ }
5174
+ $this->debug('parsing import ' . $attrs['namespace'] . ' - [no location] (' . count($this->import[$attrs['namespace']]) . ')');
5175
+ }
5176
+ break;
5177
+ //wait for schema
5178
+ //case 'types':
5179
+ // $this->status = 'schema';
5180
+ // break;
5181
+ case 'message':
5182
+ $this->status = 'message';
5183
+ $this->messages[$attrs['name']] = array();
5184
+ $this->currentMessage = $attrs['name'];
5185
+ break;
5186
+ case 'portType':
5187
+ $this->status = 'portType';
5188
+ $this->portTypes[$attrs['name']] = array();
5189
+ $this->currentPortType = $attrs['name'];
5190
+ break;
5191
+ case "binding":
5192
+ if (isset($attrs['name'])) {
5193
+ // get binding name
5194
+ if (strpos($attrs['name'], ':')) {
5195
+ $this->currentBinding = $this->getLocalPart($attrs['name']);
5196
+ } else {
5197
+ $this->currentBinding = $attrs['name'];
5198
+ }
5199
+ $this->status = 'binding';
5200
+ $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
5201
+ $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
5202
+ }
5203
+ break;
5204
+ case 'service':
5205
+ $this->serviceName = $attrs['name'];
5206
+ $this->status = 'service';
5207
+ $this->debug('current service: ' . $this->serviceName);
5208
+ break;
5209
+ case 'definitions':
5210
+ foreach ($attrs as $name => $value) {
5211
+ $this->wsdl_info[$name] = $value;
5212
+ }
5213
+ break;
5214
+ }
5215
+ }
5216
+ }
5217
+
5218
+ /**
5219
+ * end-element handler
5220
+ *
5221
+ * @param string $parser XML parser object
5222
+ * @param string $name element name
5223
+ * @access private
5224
+ */
5225
+ function end_element($parser, $name)
5226
+ {
5227
+ // unset schema status
5228
+ if (/*preg_match('/types$/', $name) ||*/
5229
+ preg_match('/schema$/', $name)
5230
+ ) {
5231
+ $this->status = "";
5232
+ $this->appendDebug($this->currentSchema->getDebug());
5233
+ $this->currentSchema->clearDebug();
5234
+ $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
5235
+ $this->debug('Parsing WSDL schema done');
5236
+ }
5237
+ if ($this->status == 'schema') {
5238
+ $this->currentSchema->schemaEndElement($parser, $name);
5239
+ } else {
5240
+ // bring depth down a notch
5241
+ $this->depth--;
5242
+ }
5243
+ // end documentation
5244
+ if ($this->documentation) {
5245
+ //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
5246
+ //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
5247
+ $this->documentation = false;
5248
+ }
5249
+ }
5250
+
5251
+ /**
5252
+ * element content handler
5253
+ *
5254
+ * @param string $parser XML parser object
5255
+ * @param string $data element content
5256
+ * @access private
5257
+ */
5258
+ function character_data($parser, $data)
5259
+ {
5260
+ $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
5261
+ if (isset($this->message[$pos]['cdata'])) {
5262
+ $this->message[$pos]['cdata'] .= $data;
5263
+ }
5264
+ if ($this->documentation) {
5265
+ $this->documentation .= $data;
5266
+ }
5267
+ }
5268
+
5269
+ /**
5270
+ * if authenticating, set user credentials here
5271
+ *
5272
+ * @param string $username
5273
+ * @param string $password
5274
+ * @param string $authtype (basic|digest|certificate|ntlm)
5275
+ * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
5276
+ * @access public
5277
+ */
5278
+ function setCredentials($username, $password, $authtype = 'basic', $certRequest = array())
5279
+ {
5280
+ $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
5281
+ $this->appendDebug($this->varDump($certRequest));
5282
+ $this->username = $username;
5283
+ $this->password = $password;
5284
+ $this->authtype = $authtype;
5285
+ $this->certRequest = $certRequest;
5286
+ }
5287
+
5288
+ function getBindingData($binding)
5289
+ {
5290
+ if (is_array($this->bindings[$binding])) {
5291
+ return $this->bindings[$binding];
5292
+ }
5293
+ }
5294
+
5295
+ /**
5296
+ * returns an assoc array of operation names => operation data
5297
+ *
5298
+ * @param string $portName WSDL port name
5299
+ * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)
5300
+ * @return array
5301
+ * @access public
5302
+ */
5303
+ function getOperations($portName = '', $bindingType = 'soap')
5304
+ {
5305
+ $ops = array();
5306
+ if ($bindingType == 'soap') {
5307
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5308
+ } elseif ($bindingType == 'soap12') {
5309
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5310
+ } else {
5311
+ $this->debug("getOperations bindingType $bindingType may not be supported");
5312
+ }
5313
+ $this->debug("getOperations for port '$portName' bindingType $bindingType");
5314
+ // loop thru ports
5315
+ foreach ($this->ports as $port => $portData) {
5316
+ $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']);
5317
+ if ($portName == '' || $port == $portName) {
5318
+ // binding type of port matches parameter
5319
+ if ($portData['bindingType'] == $bindingType) {
5320
+ $this->debug("getOperations found port $port bindingType $bindingType");
5321
+ //$this->debug("port data: " . $this->varDump($portData));
5322
+ //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
5323
+ // merge bindings
5324
+ if (isset($this->bindings[$portData['binding']]['operations'])) {
5325
+ $ops = array_merge($ops, $this->bindings[$portData['binding']]['operations']);
5326
+ }
5327
+ }
5328
+ }
5329
+ }
5330
+ if (count($ops) == 0) {
5331
+ $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType");
5332
+ }
5333
+ return $ops;
5334
+ }
5335
+
5336
+ /**
5337
+ * returns an associative array of data necessary for calling an operation
5338
+ *
5339
+ * @param string $operation name of operation
5340
+ * @param string $bindingType type of binding eg: soap, soap12
5341
+ * @return array
5342
+ * @access public
5343
+ */
5344
+ function getOperationData($operation, $bindingType = 'soap')
5345
+ {
5346
+ if ($bindingType == 'soap') {
5347
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5348
+ } elseif ($bindingType == 'soap12') {
5349
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5350
+ }
5351
+ // loop thru ports
5352
+ foreach ($this->ports as $port => $portData) {
5353
+ // binding type of port matches parameter
5354
+ if ($portData['bindingType'] == $bindingType) {
5355
+ // get binding
5356
+ //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5357
+ foreach (array_keys($this->bindings[$portData['binding']]['operations']) as $bOperation) {
5358
+ // note that we could/should also check the namespace here
5359
+ if ($operation == $bOperation) {
5360
+ $opData = $this->bindings[$portData['binding']]['operations'][$operation];
5361
+ return $opData;
5362
+ }
5363
+ }
5364
+ }
5365
+ }
5366
+ }
5367
+
5368
+ /**
5369
+ * returns an associative array of data necessary for calling an operation
5370
+ *
5371
+ * @param string $soapAction soapAction for operation
5372
+ * @param string $bindingType type of binding eg: soap, soap12
5373
+ * @return array
5374
+ * @access public
5375
+ */
5376
+ function getOperationDataForSoapAction($soapAction, $bindingType = 'soap')
5377
+ {
5378
+ if ($bindingType == 'soap') {
5379
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5380
+ } elseif ($bindingType == 'soap12') {
5381
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5382
+ }
5383
+ // loop thru ports
5384
+ foreach ($this->ports as $port => $portData) {
5385
+ // binding type of port matches parameter
5386
+ if ($portData['bindingType'] == $bindingType) {
5387
+ // loop through operations for the binding
5388
+ foreach ($this->bindings[$portData['binding']]['operations'] as $bOperation => $opData) {
5389
+ if ($opData['soapAction'] == $soapAction) {
5390
+ return $opData;
5391
+ }
5392
+ }
5393
+ }
5394
+ }
5395
+ }
5396
+
5397
+ /**
5398
+ * returns an array of information about a given type
5399
+ * returns false if no type exists by the given name
5400
+ *
5401
+ * typeDef = array(
5402
+ * 'elements' => array(), // refs to elements array
5403
+ * 'restrictionBase' => '',
5404
+ * 'phpType' => '',
5405
+ * 'order' => '(sequence|all)',
5406
+ * 'attrs' => array() // refs to attributes array
5407
+ * )
5408
+ *
5409
+ * @param string $type the type
5410
+ * @param string $ns namespace (not prefix) of the type
5411
+ * @return mixed
5412
+ * @access public
5413
+ * @see nusoap_xmlschema
5414
+ */
5415
+ function getTypeDef($type, $ns)
5416
+ {
5417
+ $this->debug("in getTypeDef: type=$type, ns=$ns");
5418
+ if ((!$ns) && isset($this->namespaces['tns'])) {
5419
+ $ns = $this->namespaces['tns'];
5420
+ $this->debug("in getTypeDef: type namespace forced to $ns");
5421
+ }
5422
+ if (!isset($this->schemas[$ns])) {
5423
+ foreach ($this->schemas as $ns0 => $schema0) {
5424
+ if (strcasecmp($ns, $ns0) == 0) {
5425
+ $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
5426
+ $ns = $ns0;
5427
+ break;
5428
+ }
5429
+ }
5430
+ }
5431
+ if (isset($this->schemas[$ns])) {
5432
+ $this->debug("in getTypeDef: have schema for namespace $ns");
5433
+ for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
5434
+ $xs = &$this->schemas[$ns][$i];
5435
+ $t = $xs->getTypeDef($type);
5436
+ $this->appendDebug($xs->getDebug());
5437
+ $xs->clearDebug();
5438
+ if ($t) {
5439
+ $this->debug("in getTypeDef: found type $type");
5440
+ if (!isset($t['phpType'])) {
5441
+ // get info for type to tack onto the element
5442
+ $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
5443
+ $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
5444
+ $etype = $this->getTypeDef($uqType, $ns);
5445
+ if ($etype) {
5446
+ $this->debug("found type for [element] $type:");
5447
+ $this->debug($this->varDump($etype));
5448
+ if (isset($etype['phpType'])) {
5449
+ $t['phpType'] = $etype['phpType'];
5450
+ }
5451
+ if (isset($etype['elements'])) {
5452
+ $t['elements'] = $etype['elements'];
5453
+ }
5454
+ if (isset($etype['attrs'])) {
5455
+ $t['attrs'] = $etype['attrs'];
5456
+ }
5457
+ } else {
5458
+ $this->debug("did not find type for [element] $type");
5459
+ }
5460
+ }
5461
+ return $t;
5462
+ }
5463
+ }
5464
+ $this->debug("in getTypeDef: did not find type $type");
5465
+ } else {
5466
+ $this->debug("in getTypeDef: do not have schema for namespace $ns");
5467
+ }
5468
+ return false;
5469
+ }
5470
+
5471
+ /**
5472
+ * prints html description of services
5473
+ *
5474
+ * @access private
5475
+ */
5476
+ function webDescription()
5477
+ {
5478
+ global $HTTP_SERVER_VARS;
5479
+
5480
+ if (isset($_SERVER)) {
5481
+ $PHP_SELF = $_SERVER['PHP_SELF'];
5482
+ } elseif (isset($HTTP_SERVER_VARS)) {
5483
+ $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
5484
+ } else {
5485
+ $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
5486
+ }
5487
+
5488
+ $b = '
5489
+ <html><head><title>NuSOAP: ' . $this->serviceName . '</title>
5490
+ <style type="text/css">
5491
+ body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
5492
+ p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
5493
+ pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
5494
+ ul { margin-top: 10px; margin-left: 20px; }
5495
+ li { list-style-type: none; margin-top: 10px; color: #000000; }
5496
+ .content{
5497
+ margin-left: 0px; padding-bottom: 2em; }
5498
+ .nav {
5499
+ padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
5500
+ margin-top: 10px; margin-left: 0px; color: #000000;
5501
+ background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
5502
+ .title {
5503
+ font-family: arial; font-size: 26px; color: #ffffff;
5504
+ background-color: #999999; width: 100%;
5505
+ margin-left: 0px; margin-right: 0px;
5506
+ padding-top: 10px; padding-bottom: 10px;}
5507
+ .hidden {
5508
+ position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
5509
+ font-family: arial; overflow: hidden; width: 600;
5510
+ padding: 20px; font-size: 10px; background-color: #999999;
5511
+ layer-background-color:#FFFFFF; }
5512
+ a,a:active { color: charcoal; font-weight: bold; }
5513
+ a:visited { color: #666666; font-weight: bold; }
5514
+ a:hover { color: cc3300; font-weight: bold; }
5515
+ </style>
5516
+ <script language="JavaScript" type="text/javascript">
5517
+ <!--
5518
+ // POP-UP CAPTIONS...
5519
+ function lib_bwcheck(){ //Browsercheck (needed)
5520
+ this.ver=navigator.appVersion
5521
+ this.agent=navigator.userAgent
5522
+ this.dom=document.getElementById?1:0
5523
+ this.opera5=this.agent.indexOf("Opera 5")>-1
5524
+ this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
5525
+ this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
5526
+ this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
5527
+ this.ie=this.ie4||this.ie5||this.ie6
5528
+ this.mac=this.agent.indexOf("Mac")>-1
5529
+ this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
5530
+ this.ns4=(document.layers && !this.dom)?1:0;
5531
+ this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
5532
+ return this
5533
+ }
5534
+ var bw = new lib_bwcheck()
5535
+ //Makes crossbrowser object.
5536
+ function makeObj(obj){
5537
+ this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
5538
+ if(!this.evnt) return false
5539
+ this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
5540
+ this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
5541
+ this.writeIt=b_writeIt;
5542
+ return this
5543
+ }
5544
+ // A unit of measure that will be added when setting the position of a layer.
5545
+ //var px = bw.ns4||window.opera?"":"px";
5546
+ function b_writeIt(text){
5547
+ if (bw.ns4){this.wref.write(text);this.wref.close()}
5548
+ else this.wref.innerHTML = text
5549
+ }
5550
+ //Shows the messages
5551
+ var oDesc;
5552
+ function popup(divid){
5553
+ if(oDesc = new makeObj(divid)){
5554
+ oDesc.css.visibility = "visible"
5555
+ }
5556
+ }
5557
+ function popout(){ // Hides message
5558
+ if(oDesc) oDesc.css.visibility = "hidden"
5559
+ }
5560
+ //-->
5561
+ </script>
5562
+ </head>
5563
+ <body>
5564
+ <div class=content>
5565
+ <br><br>
5566
+ <div class=title>' . $this->serviceName . '</div>
5567
+ <div class=nav>
5568
+ <p>View the <a href="' . $PHP_SELF . '?wsdl">WSDL</a> for the service.
5569
+ Click on an operation name to view it&apos;s details.</p>
5570
+ <ul>';
5571
+ foreach ($this->getOperations() as $op => $data) {
5572
+ $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
5573
+ // create hidden div
5574
+ $b .= "<div id='$op' class='hidden'>
5575
+ <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
5576
+ foreach ($data as $donnie => $marie) { // loop through opdata
5577
+ if ($donnie == 'input' || $donnie == 'output') { // show input/output data
5578
+ $b .= "<font color='white'>" . ucfirst($donnie) . ':</font><br>';
5579
+ foreach ($marie as $captain => $tenille) { // loop through data
5580
+ if ($captain == 'parts') { // loop thru parts
5581
+ $b .= "&nbsp;&nbsp;$captain:<br>";
5582
+ //if(is_array($tenille)){
5583
+ foreach ($tenille as $joanie => $chachi) {
5584
+ $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
5585
+ }
5586
+ //}
5587
+ } else {
5588
+ $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
5589
+ }
5590
+ }
5591
+ } else {
5592
+ $b .= "<font color='white'>" . ucfirst($donnie) . ":</font> $marie<br>";
5593
+ }
5594
+ }
5595
+ $b .= '</div>';
5596
+ }
5597
+ $b .= '
5598
+ <ul>
5599
+ </div>
5600
+ </div></body></html>';
5601
+ return $b;
5602
+ }
5603
+
5604
+ /**
5605
+ * serialize the parsed wsdl
5606
+ *
5607
+ * @param mixed $debug whether to put debug=1 in endpoint URL
5608
+ * @return string serialization of WSDL
5609
+ * @access public
5610
+ */
5611
+ function serialize($debug = 0)
5612
+ {
5613
+ $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
5614
+ $xml .= "\n<definitions";
5615
+ foreach ($this->namespaces as $k => $v) {
5616
+ $xml .= " xmlns:$k=\"$v\"";
5617
+ }
5618
+ // 10.9.02 - add poulter fix for wsdl and tns declarations
5619
+ if (isset($this->namespaces['wsdl'])) {
5620
+ $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
5621
+ }
5622
+ if (isset($this->namespaces['tns'])) {
5623
+ $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
5624
+ }
5625
+ $xml .= '>';
5626
+ // imports
5627
+ if (sizeof($this->import) > 0) {
5628
+ foreach ($this->import as $ns => $list) {
5629
+ foreach ($list as $ii) {
5630
+ if ($ii['location'] != '') {
5631
+ $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
5632
+ } else {
5633
+ $xml .= '<import namespace="' . $ns . '" />';
5634
+ }
5635
+ }
5636
+ }
5637
+ }
5638
+ // types
5639
+ if (count($this->schemas) >= 1) {
5640
+ $xml .= "\n<types>\n";
5641
+ foreach ($this->schemas as $ns => $list) {
5642
+ foreach ($list as $xs) {
5643
+ $xml .= $xs->serializeSchema();
5644
+ }
5645
+ }
5646
+ $xml .= '</types>';
5647
+ }
5648
+ // messages
5649
+ if (count($this->messages) >= 1) {
5650
+ foreach ($this->messages as $msgName => $msgParts) {
5651
+ $xml .= "\n<message name=\"" . $msgName . '">';
5652
+ if (is_array($msgParts)) {
5653
+ foreach ($msgParts as $partName => $partType) {
5654
+ // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
5655
+ if (strpos($partType, ':')) {
5656
+ $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
5657
+ } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
5658
+ // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
5659
+ $typePrefix = 'xsd';
5660
+ } else {
5661
+ foreach ($this->typemap as $ns => $types) {
5662
+ if (isset($types[$partType])) {
5663
+ $typePrefix = $this->getPrefixFromNamespace($ns);
5664
+ }
5665
+ }
5666
+ if (!isset($typePrefix)) {
5667
+ die("$partType has no namespace!");
5668
+ }
5669
+ }
5670
+ $ns = $this->getNamespaceFromPrefix($typePrefix);
5671
+ $localPart = $this->getLocalPart($partType);
5672
+ $typeDef = $this->getTypeDef($localPart, $ns);
5673
+ if ($typeDef['typeClass'] == 'element') {
5674
+ $elementortype = 'element';
5675
+ if (substr($localPart, -1) == '^') {
5676
+ $localPart = substr($localPart, 0, -1);
5677
+ }
5678
+ } else {
5679
+ $elementortype = 'type';
5680
+ }
5681
+ $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
5682
+ }
5683
+ }
5684
+ $xml .= '</message>';
5685
+ }
5686
+ }
5687
+ // bindings & porttypes
5688
+ if (count($this->bindings) >= 1) {
5689
+ $binding_xml = '';
5690
+ $portType_xml = '';
5691
+ foreach ($this->bindings as $bindingName => $attrs) {
5692
+ $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
5693
+ $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
5694
+ $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
5695
+ foreach ($attrs['operations'] as $opName => $opParts) {
5696
+ $binding_xml .= "\n" . ' <operation name="' . $opName . '">';
5697
+ $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="' . $opParts['style'] . '"/>';
5698
+ if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
5699
+ $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
5700
+ } else {
5701
+ $enc_style = '';
5702
+ }
5703
+ $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
5704
+ if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
5705
+ $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
5706
+ } else {
5707
+ $enc_style = '';
5708
+ }
5709
+ $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
5710
+ $binding_xml .= "\n" . ' </operation>';
5711
+ $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"';
5712
+ if (isset($opParts['parameterOrder'])) {
5713
+ $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
5714
+ }
5715
+ $portType_xml .= '>';
5716
+ if (isset($opParts['documentation']) && $opParts['documentation'] != '') {
5717
+ $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
5718
+ }
5719
+ $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>';
5720
+ $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>';
5721
+ $portType_xml .= "\n" . ' </operation>';
5722
+ }
5723
+ $portType_xml .= "\n" . '</portType>';
5724
+ $binding_xml .= "\n" . '</binding>';
5725
+ }
5726
+ $xml .= $portType_xml . $binding_xml;
5727
+ }
5728
+ // services
5729
+ $xml .= "\n<service name=\"" . $this->serviceName . '">';
5730
+ if (count($this->ports) >= 1) {
5731
+ foreach ($this->ports as $pName => $attrs) {
5732
+ $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5733
+ $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
5734
+ $xml .= "\n" . ' </port>';
5735
+ }
5736
+ }
5737
+ $xml .= "\n" . '</service>';
5738
+ return $xml . "\n</definitions>";
5739
+ }
5740
+
5741
+ /**
5742
+ * determine whether a set of parameters are unwrapped
5743
+ * when they are expect to be wrapped, Microsoft-style.
5744
+ *
5745
+ * @param string $type the type (element name) of the wrapper
5746
+ * @param array $parameters the parameter values for the SOAP call
5747
+ * @return boolean whether they parameters are unwrapped (and should be wrapped)
5748
+ * @access private
5749
+ */
5750
+ function parametersMatchWrapped($type, &$parameters)
5751
+ {
5752
+ $this->debug("in parametersMatchWrapped type=$type, parameters=");
5753
+ $this->appendDebug($this->varDump($parameters));
5754
+
5755
+ // split type into namespace:unqualified-type
5756
+ if (strpos($type, ':')) {
5757
+ $uqType = substr($type, strrpos($type, ':') + 1);
5758
+ $ns = substr($type, 0, strrpos($type, ':'));
5759
+ $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
5760
+ if ($this->getNamespaceFromPrefix($ns)) {
5761
+ $ns = $this->getNamespaceFromPrefix($ns);
5762
+ $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
5763
+ }
5764
+ } else {
5765
+ // TODO: should the type be compared to types in XSD, and the namespace
5766
+ // set to XSD if the type matches?
5767
+ $this->debug("in parametersMatchWrapped: No namespace for type $type");
5768
+ $ns = '';
5769
+ $uqType = $type;
5770
+ }
5771
+
5772
+ // get the type information
5773
+ if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
5774
+ $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
5775
+ return false;
5776
+ }
5777
+ $this->debug("in parametersMatchWrapped: found typeDef=");
5778
+ $this->appendDebug($this->varDump($typeDef));
5779
+ if (substr($uqType, -1) == '^') {
5780
+ $uqType = substr($uqType, 0, -1);
5781
+ }
5782
+ $phpType = $typeDef['phpType'];
5783
+ $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
5784
+ $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
5785
+
5786
+ // we expect a complexType or element of complexType
5787
+ if ($phpType != 'struct') {
5788
+ $this->debug("in parametersMatchWrapped: not a struct");
5789
+ return false;
5790
+ }
5791
+
5792
+ // see whether the parameter names match the elements
5793
+ if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
5794
+ $elements = 0;
5795
+ $matches = 0;
5796
+ foreach ($typeDef['elements'] as $name => $attrs) {
5797
+ if (isset($parameters[$name])) {
5798
+ $this->debug("in parametersMatchWrapped: have parameter named $name");
5799
+ $matches++;
5800
+ } else {
5801
+ $this->debug("in parametersMatchWrapped: do not have parameter named $name");
5802
+ }
5803
+ $elements++;
5804
+ }
5805
+
5806
+ $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
5807
+ if ($matches == 0) {
5808
+ return false;
5809
+ }
5810
+ return true;
5811
+ }
5812
+
5813
+ // since there are no elements for the type, if the user passed no
5814
+ // parameters, the parameters match wrapped.
5815
+ $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
5816
+ return count($parameters) == 0;
5817
+ }
5818
+
5819
+ /**
5820
+ * serialize PHP values according to a WSDL message definition
5821
+ * contrary to the method name, this is not limited to RPC
5822
+ *
5823
+ * TODO
5824
+ * - multi-ref serialization
5825
+ * - validate PHP values against type definitions, return errors if invalid
5826
+ *
5827
+ * @param string $operation operation name
5828
+ * @param string $direction (input|output)
5829
+ * @param mixed $parameters parameter value(s)
5830
+ * @param string $bindingType (soap|soap12)
5831
+ * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
5832
+ * @access public
5833
+ */
5834
+ function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap')
5835
+ {
5836
+ $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
5837
+ $this->appendDebug('parameters=' . $this->varDump($parameters));
5838
+
5839
+ if ($direction != 'input' && $direction != 'output') {
5840
+ $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5841
+ $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5842
+ return false;
5843
+ }
5844
+ if (!$opData = $this->getOperationData($operation, $bindingType)) {
5845
+ $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5846
+ $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5847
+ return false;
5848
+ }
5849
+ $this->debug('in serializeRPCParameters: opData:');
5850
+ $this->appendDebug($this->varDump($opData));
5851
+
5852
+ // Get encoding style for output and set to current
5853
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5854
+ if (($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5855
+ $encodingStyle = $opData['output']['encodingStyle'];
5856
+ $enc_style = $encodingStyle;
5857
+ }
5858
+
5859
+ // set input params
5860
+ $xml = '';
5861
+ if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5862
+ $parts = &$opData[$direction]['parts'];
5863
+ $part_count = sizeof($parts);
5864
+ $style = $opData['style'];
5865
+ $use = $opData[$direction]['use'];
5866
+ $this->debug("have $part_count part(s) to serialize using $style/$use");
5867
+ if (is_array($parameters)) {
5868
+ $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5869
+ $parameter_count = count($parameters);
5870
+ $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
5871
+ // check for Microsoft-style wrapped parameters
5872
+ if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
5873
+ $this->debug('check whether the caller has wrapped the parameters');
5874
+ if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) {
5875
+ // TODO: consider checking here for double-wrapping, when
5876
+ // service function wraps, then NuSOAP wraps again
5877
+ $this->debug("change simple array to associative with 'parameters' element");
5878
+ $parameters['parameters'] = $parameters[0];
5879
+ unset($parameters[0]);
5880
+ }
5881
+ if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) {
5882
+ $this->debug('check whether caller\'s parameters match the wrapped ones');
5883
+ if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
5884
+ $this->debug('wrap the parameters for the caller');
5885
+ $parameters = array('parameters' => $parameters);
5886
+ $parameter_count = 1;
5887
+ }
5888
+ }
5889
+ }
5890
+ foreach ($parts as $name => $type) {
5891
+ $this->debug("serializing part $name of type $type");
5892
+ // Track encoding style
5893
+ if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5894
+ $encodingStyle = $opData[$direction]['encodingStyle'];
5895
+ $enc_style = $encodingStyle;
5896
+ } else {
5897
+ $enc_style = false;
5898
+ }
5899
+ // NOTE: add error handling here
5900
+ // if serializeType returns false, then catch global error and fault
5901
+ if ($parametersArrayType == 'arraySimple') {
5902
+ $p = array_shift($parameters);
5903
+ $this->debug('calling serializeType w/indexed param');
5904
+ $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5905
+ } elseif (isset($parameters[$name])) {
5906
+ $this->debug('calling serializeType w/named param');
5907
+ $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5908
+ } else {
5909
+ // TODO: only send nillable
5910
+ $this->debug('calling serializeType w/null param');
5911
+ $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5912
+ }
5913
+ }
5914
+ } else {
5915
+ $this->debug('no parameters passed.');
5916
+ }
5917
+ }
5918
+ $this->debug("serializeRPCParameters returning: $xml");
5919
+ return $xml;
5920
+ }
5921
+
5922
+ /**
5923
+ * serialize a PHP value according to a WSDL message definition
5924
+ *
5925
+ * TODO
5926
+ * - multi-ref serialization
5927
+ * - validate PHP values against type definitions, return errors if invalid
5928
+ *
5929
+ * @param string $operation operation name
5930
+ * @param string $direction (input|output)
5931
+ * @param mixed $parameters parameter value(s)
5932
+ * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
5933
+ * @access public
5934
+ * @deprecated
5935
+ */
5936
+ function serializeParameters($operation, $direction, $parameters)
5937
+ {
5938
+ $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
5939
+ $this->appendDebug('parameters=' . $this->varDump($parameters));
5940
+
5941
+ if ($direction != 'input' && $direction != 'output') {
5942
+ $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5943
+ $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5944
+ return false;
5945
+ }
5946
+ if (!$opData = $this->getOperationData($operation)) {
5947
+ $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
5948
+ $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
5949
+ return false;
5950
+ }
5951
+ $this->debug('opData:');
5952
+ $this->appendDebug($this->varDump($opData));
5953
+
5954
+ // Get encoding style for output and set to current
5955
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5956
+ if (($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5957
+ $encodingStyle = $opData['output']['encodingStyle'];
5958
+ $enc_style = $encodingStyle;
5959
+ }
5960
+
5961
+ // set input params
5962
+ $xml = '';
5963
+ if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5964
+
5965
+ $use = $opData[$direction]['use'];
5966
+ $this->debug("use=$use");
5967
+ $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
5968
+ if (is_array($parameters)) {
5969
+ $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5970
+ $this->debug('have ' . $parametersArrayType . ' parameters');
5971
+ foreach ($opData[$direction]['parts'] as $name => $type) {
5972
+ $this->debug('serializing part "' . $name . '" of type "' . $type . '"');
5973
+ // Track encoding style
5974
+ if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5975
+ $encodingStyle = $opData[$direction]['encodingStyle'];
5976
+ $enc_style = $encodingStyle;
5977
+ } else {
5978
+ $enc_style = false;
5979
+ }
5980
+ // NOTE: add error handling here
5981
+ // if serializeType returns false, then catch global error and fault
5982
+ if ($parametersArrayType == 'arraySimple') {
5983
+ $p = array_shift($parameters);
5984
+ $this->debug('calling serializeType w/indexed param');
5985
+ $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5986
+ } elseif (isset($parameters[$name])) {
5987
+ $this->debug('calling serializeType w/named param');
5988
+ $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5989
+ } else {
5990
+ // TODO: only send nillable
5991
+ $this->debug('calling serializeType w/null param');
5992
+ $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5993
+ }
5994
+ }
5995
+ } else {
5996
+ $this->debug('no parameters passed.');
5997
+ }
5998
+ }
5999
+ $this->debug("serializeParameters returning: $xml");
6000
+ return $xml;
6001
+ }
6002
+
6003
+ /**
6004
+ * serializes a PHP value according a given type definition
6005
+ *
6006
+ * @param string $name name of value (part or element)
6007
+ * @param string $type XML schema type of value (type or element)
6008
+ * @param mixed $value a native PHP value (parameter value)
6009
+ * @param string $use use for part (encoded|literal)
6010
+ * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
6011
+ * @param boolean $unqualified a kludge for what should be XML namespace form handling
6012
+ * @return string value serialized as an XML string
6013
+ * @access private
6014
+ */
6015
+ function serializeType($name, $type, $value, $use = 'encoded', $encodingStyle = false, $unqualified = false)
6016
+ {
6017
+ $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
6018
+ $this->appendDebug("value=" . $this->varDump($value));
6019
+ if ($use == 'encoded' && $encodingStyle) {
6020
+ $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
6021
+ }
6022
+
6023
+ // if a soapval has been supplied, let its type override the WSDL
6024
+ if (is_object($value) && get_class($value) == 'soapval') {
6025
+ if ($value->type_ns) {
6026
+ $type = $value->type_ns . ':' . $value->type;
6027
+ $forceType = true;
6028
+ $this->debug("in serializeType: soapval overrides type to $type");
6029
+ } elseif ($value->type) {
6030
+ $type = $value->type;
6031
+ $forceType = true;
6032
+ $this->debug("in serializeType: soapval overrides type to $type");
6033
+ } else {
6034
+ $forceType = false;
6035
+ $this->debug("in serializeType: soapval does not override type");
6036
+ }
6037
+ $attrs = $value->attributes;
6038
+ $value = $value->value;
6039
+ $this->debug("in serializeType: soapval overrides value to $value");
6040
+ if ($attrs) {
6041
+ if (!is_array($value)) {
6042
+ $value['!'] = $value;
6043
+ }
6044
+ foreach ($attrs as $n => $v) {
6045
+ $value['!' . $n] = $v;
6046
+ }
6047
+ $this->debug("in serializeType: soapval provides attributes");
6048
+ }
6049
+ } else {
6050
+ $forceType = false;
6051
+ }
6052
+
6053
+ $xml = '';
6054
+ if (strpos($type, ':')) {
6055
+ $uqType = substr($type, strrpos($type, ':') + 1);
6056
+ $ns = substr($type, 0, strrpos($type, ':'));
6057
+ $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
6058
+ if ($this->getNamespaceFromPrefix($ns)) {
6059
+ $ns = $this->getNamespaceFromPrefix($ns);
6060
+ $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
6061
+ }
6062
+
6063
+ if ($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/') {
6064
+ $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
6065
+ if ($unqualified && $use == 'literal') {
6066
+ $elementNS = " xmlns=\"\"";
6067
+ } else {
6068
+ $elementNS = '';
6069
+ }
6070
+ if (is_null($value)) {
6071
+ if ($use == 'literal') {
6072
+ // TODO: depends on minOccurs
6073
+ $xml = "<$name$elementNS/>";
6074
+ } else {
6075
+ // TODO: depends on nillable, which should be checked before calling this method
6076
+ $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
6077
+ }
6078
+ $this->debug("in serializeType: returning: $xml");
6079
+ return $xml;
6080
+ }
6081
+ if ($uqType == 'Array') {
6082
+ // JBoss/Axis does this sometimes
6083
+ return $this->serialize_val($value, $name, false, false, false, false, $use);
6084
+ }
6085
+ if ($uqType == 'boolean') {
6086
+ if ((is_string($value) && $value == 'false') || (!$value)) {
6087
+ $value = 'false';
6088
+ } else {
6089
+ $value = 'true';
6090
+ }
6091
+ }
6092
+ if ($uqType == 'string' && gettype($value) == 'string') {
6093
+ $value = $this->expandEntities($value);
6094
+ }
6095
+ if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
6096
+ $value = sprintf("%.0lf", $value);
6097
+ }
6098
+ // it's a scalar
6099
+ // TODO: what about null/nil values?
6100
+ // check type isn't a custom type extending xmlschema namespace
6101
+ if (!$this->getTypeDef($uqType, $ns)) {
6102
+ if ($use == 'literal') {
6103
+ if ($forceType) {
6104
+ $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6105
+ } else {
6106
+ $xml = "<$name$elementNS>$value</$name>";
6107
+ }
6108
+ } else {
6109
+ $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6110
+ }
6111
+ $this->debug("in serializeType: returning: $xml");
6112
+ return $xml;
6113
+ }
6114
+ $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
6115
+ } elseif ($ns == 'http://xml.apache.org/xml-soap') {
6116
+ $this->debug('in serializeType: appears to be Apache SOAP type');
6117
+ if ($uqType == 'Map') {
6118
+ $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
6119
+ if (!$tt_prefix) {
6120
+ $this->debug('in serializeType: Add namespace for Apache SOAP type');
6121
+ $tt_prefix = 'ns' . rand(1000, 9999);
6122
+ $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
6123
+ // force this to be added to usedNamespaces
6124
+ $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
6125
+ }
6126
+ $contents = '';
6127
+ foreach ($value as $k => $v) {
6128
+ $this->debug("serializing map element: key $k, value $v");
6129
+ $contents .= '<item>';
6130
+ $contents .= $this->serialize_val($k, 'key', false, false, false, false, $use);
6131
+ $contents .= $this->serialize_val($v, 'value', false, false, false, false, $use);
6132
+ $contents .= '</item>';
6133
+ }
6134
+ if ($use == 'literal') {
6135
+ if ($forceType) {
6136
+ $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
6137
+ } else {
6138
+ $xml = "<$name>$contents</$name>";
6139
+ }
6140
+ } else {
6141
+ $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
6142
+ }
6143
+ $this->debug("in serializeType: returning: $xml");
6144
+ return $xml;
6145
+ }
6146
+ $this->debug('in serializeType: Apache SOAP type, but only support Map');
6147
+ }
6148
+ } else {
6149
+ // TODO: should the type be compared to types in XSD, and the namespace
6150
+ // set to XSD if the type matches?
6151
+ $this->debug("in serializeType: No namespace for type $type");
6152
+ $ns = '';
6153
+ $uqType = $type;
6154
+ }
6155
+ if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
6156
+ $this->setError("$type ($uqType) is not a supported type.");
6157
+ $this->debug("in serializeType: $type ($uqType) is not a supported type.");
6158
+ return false;
6159
+ } else {
6160
+ $this->debug("in serializeType: found typeDef");
6161
+ $this->appendDebug('typeDef=' . $this->varDump($typeDef));
6162
+ if (substr($uqType, -1) == '^') {
6163
+ $uqType = substr($uqType, 0, -1);
6164
+ }
6165
+ }
6166
+ if (!isset($typeDef['phpType'])) {
6167
+ $this->setError("$type ($uqType) has no phpType.");
6168
+ $this->debug("in serializeType: $type ($uqType) has no phpType.");
6169
+ return false;
6170
+ }
6171
+ $phpType = $typeDef['phpType'];
6172
+ $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''));
6173
+ // if php type == struct, map value to the <all> element names
6174
+ if ($phpType == 'struct') {
6175
+ if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
6176
+ $elementName = $uqType;
6177
+ if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6178
+ $elementNS = " xmlns=\"$ns\"";
6179
+ } else {
6180
+ $elementNS = " xmlns=\"\"";
6181
+ }
6182
+ } else {
6183
+ $elementName = $name;
6184
+ if ($unqualified) {
6185
+ $elementNS = " xmlns=\"\"";
6186
+ } else {
6187
+ $elementNS = '';
6188
+ }
6189
+ }
6190
+ if (is_null($value)) {
6191
+ if ($use == 'literal') {
6192
+ // TODO: depends on minOccurs and nillable
6193
+ $xml = "<$elementName$elementNS/>";
6194
+ } else {
6195
+ $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
6196
+ }
6197
+ $this->debug("in serializeType: returning: $xml");
6198
+ return $xml;
6199
+ }
6200
+ if (is_object($value)) {
6201
+ $value = get_object_vars($value);
6202
+ }
6203
+ if (is_array($value)) {
6204
+ $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6205
+ if ($use == 'literal') {
6206
+ if ($forceType) {
6207
+ $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
6208
+ } else {
6209
+ $xml = "<$elementName$elementNS$elementAttrs>";
6210
+ }
6211
+ } else {
6212
+ $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
6213
+ }
6214
+
6215
+ if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') {
6216
+ if (isset($value['!'])) {
6217
+ $xml .= $value['!'];
6218
+ $this->debug("in serializeType: serialized simpleContent for type $type");
6219
+ } else {
6220
+ $this->debug("in serializeType: no simpleContent to serialize for type $type");
6221
+ }
6222
+ } else {
6223
+ // complexContent
6224
+ $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6225
+ }
6226
+ $xml .= "</$elementName>";
6227
+ } else {
6228
+ $this->debug("in serializeType: phpType is struct, but value is not an array");
6229
+ $this->setError("phpType is struct, but value is not an array: see debug output for details");
6230
+ $xml = '';
6231
+ }
6232
+ } elseif ($phpType == 'array') {
6233
+ if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6234
+ $elementNS = " xmlns=\"$ns\"";
6235
+ } else {
6236
+ if ($unqualified) {
6237
+ $elementNS = " xmlns=\"\"";
6238
+ } else {
6239
+ $elementNS = '';
6240
+ }
6241
+ }
6242
+ if (is_null($value)) {
6243
+ if ($use == 'literal') {
6244
+ // TODO: depends on minOccurs
6245
+ $xml = "<$name$elementNS/>";
6246
+ } else {
6247
+ $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
6248
+ $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
6249
+ ":Array\" " .
6250
+ $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
6251
+ ':arrayType="' .
6252
+ $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
6253
+ ':' .
6254
+ $this->getLocalPart($typeDef['arrayType']) . "[0]\"/>";
6255
+ }
6256
+ $this->debug("in serializeType: returning: $xml");
6257
+ return $xml;
6258
+ }
6259
+ if (isset($typeDef['multidimensional'])) {
6260
+ $nv = array();
6261
+ foreach ($value as $v) {
6262
+ $cols = ',' . sizeof($v);
6263
+ $nv = array_merge($nv, $v);
6264
+ }
6265
+ $value = $nv;
6266
+ } else {
6267
+ $cols = '';
6268
+ }
6269
+ if (is_array($value) && sizeof($value) >= 1) {
6270
+ $rows = sizeof($value);
6271
+ $contents = '';
6272
+ foreach ($value as $k => $v) {
6273
+ $this->debug("serializing array element: $k, " . (is_array($v) ? "array" : $v) . " of type: $typeDef[arrayType]");
6274
+ //if (strpos($typeDef['arrayType'], ':') ) {
6275
+ if (!in_array($typeDef['arrayType'], $this->typemap['http://www.w3.org/2001/XMLSchema'])) {
6276
+ $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
6277
+ } else {
6278
+ $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
6279
+ }
6280
+ }
6281
+ } else {
6282
+ $rows = 0;
6283
+ $contents = null;
6284
+ }
6285
+ // TODO: for now, an empty value will be serialized as a zero element
6286
+ // array. Revisit this when coding the handling of null/nil values.
6287
+ if ($use == 'literal') {
6288
+ $xml = "<$name$elementNS>"
6289
+ . $contents
6290
+ . "</$name>";
6291
+ } else {
6292
+ $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ':Array" ' .
6293
+ $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6294
+ . ':arrayType="'
6295
+ . $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
6296
+ . ":" . $this->getLocalPart($typeDef['arrayType']) . "[$rows$cols]\">"
6297
+ . $contents
6298
+ . "</$name>";
6299
+ }
6300
+ } elseif ($phpType == 'scalar') {
6301
+ if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6302
+ $elementNS = " xmlns=\"$ns\"";
6303
+ } else {
6304
+ if ($unqualified) {
6305
+ $elementNS = " xmlns=\"\"";
6306
+ } else {
6307
+ $elementNS = '';
6308
+ }
6309
+ }
6310
+ if ($use == 'literal') {
6311
+ if ($forceType) {
6312
+ $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6313
+ } else {
6314
+ $xml = "<$name$elementNS>$value</$name>";
6315
+ }
6316
+ } else {
6317
+ $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6318
+ }
6319
+ }
6320
+ $this->debug("in serializeType: returning: $xml");
6321
+ return $xml;
6322
+ }
6323
+
6324
+ /**
6325
+ * serializes the attributes for a complexType
6326
+ *
6327
+ * @param array $typeDef our internal representation of an XML schema type (or element)
6328
+ * @param mixed $value a native PHP value (parameter value)
6329
+ * @param string $ns the namespace of the type
6330
+ * @param string $uqType the local part of the type
6331
+ * @return string value serialized as an XML string
6332
+ * @access private
6333
+ */
6334
+ function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType)
6335
+ {
6336
+ $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType");
6337
+ $xml = '';
6338
+ if (isset($typeDef['extensionBase'])) {
6339
+ $nsx = $this->getPrefix($typeDef['extensionBase']);
6340
+ $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
6341
+ if ($this->getNamespaceFromPrefix($nsx)) {
6342
+ $nsx = $this->getNamespaceFromPrefix($nsx);
6343
+ }
6344
+ if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
6345
+ $this->debug("serialize attributes for extension base $nsx:$uqTypex");
6346
+ $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex);
6347
+ } else {
6348
+ $this->debug("extension base $nsx:$uqTypex is not a supported type");
6349
+ }
6350
+ }
6351
+ if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
6352
+ $this->debug("serialize attributes for XML Schema type $ns:$uqType");
6353
+ if (is_array($value)) {
6354
+ $xvalue = $value;
6355
+ } elseif (is_object($value)) {
6356
+ $xvalue = get_object_vars($value);
6357
+ } else {
6358
+ $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6359
+ $xvalue = array();
6360
+ }
6361
+ foreach ($typeDef['attrs'] as $aName => $attrs) {
6362
+ if (isset($xvalue['!' . $aName])) {
6363
+ $xname = '!' . $aName;
6364
+ $this->debug("value provided for attribute $aName with key $xname");
6365
+ } elseif (isset($xvalue[$aName])) {
6366
+ $xname = $aName;
6367
+ $this->debug("value provided for attribute $aName with key $xname");
6368
+ } elseif (isset($attrs['default'])) {
6369
+ $xname = '!' . $aName;
6370
+ $xvalue[$xname] = $attrs['default'];
6371
+ $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
6372
+ } else {
6373
+ $xname = '';
6374
+ $this->debug("no value provided for attribute $aName");
6375
+ }
6376
+ if ($xname) {
6377
+ $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
6378
+ }
6379
+ }
6380
+ } else {
6381
+ $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
6382
+ }
6383
+ return $xml;
6384
+ }
6385
+
6386
+ /**
6387
+ * serializes the elements for a complexType
6388
+ *
6389
+ * @param array $typeDef our internal representation of an XML schema type (or element)
6390
+ * @param mixed $value a native PHP value (parameter value)
6391
+ * @param string $ns the namespace of the type
6392
+ * @param string $uqType the local part of the type
6393
+ * @param string $use use for part (encoded|literal)
6394
+ * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
6395
+ * @return string value serialized as an XML string
6396
+ * @access private
6397
+ */
6398
+ function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use = 'encoded', $encodingStyle = false)
6399
+ {
6400
+ $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType");
6401
+ $xml = '';
6402
+ if (isset($typeDef['extensionBase'])) {
6403
+ $nsx = $this->getPrefix($typeDef['extensionBase']);
6404
+ $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
6405
+ if ($this->getNamespaceFromPrefix($nsx)) {
6406
+ $nsx = $this->getNamespaceFromPrefix($nsx);
6407
+ }
6408
+ if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
6409
+ $this->debug("serialize elements for extension base $nsx:$uqTypex");
6410
+ $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle);
6411
+ } else {
6412
+ $this->debug("extension base $nsx:$uqTypex is not a supported type");
6413
+ }
6414
+ }
6415
+ if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6416
+ $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
6417
+ if (is_array($value)) {
6418
+ $xvalue = $value;
6419
+ } elseif (is_object($value)) {
6420
+ $xvalue = get_object_vars($value);
6421
+ } else {
6422
+ $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6423
+ $xvalue = array();
6424
+ }
6425
+ // toggle whether all elements are present - ideally should validate against schema
6426
+ if (count($typeDef['elements']) != count($xvalue)) {
6427
+ $optionals = true;
6428
+ }
6429
+ foreach ($typeDef['elements'] as $eName => $attrs) {
6430
+ if (!isset($xvalue[$eName])) {
6431
+ if (isset($attrs['default'])) {
6432
+ $xvalue[$eName] = $attrs['default'];
6433
+ $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
6434
+ }
6435
+ }
6436
+ // if user took advantage of a minOccurs=0, then only serialize named parameters
6437
+ if (isset($optionals)
6438
+ && (!isset($xvalue[$eName]))
6439
+ && ((!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
6440
+ ) {
6441
+ if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
6442
+ $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
6443
+ }
6444
+ // do nothing
6445
+ $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
6446
+ } else {
6447
+ // get value
6448
+ if (isset($xvalue[$eName])) {
6449
+ $v = $xvalue[$eName];
6450
+ } else {
6451
+ $v = null;
6452
+ }
6453
+ if (isset($attrs['form'])) {
6454
+ $unqualified = ($attrs['form'] == 'unqualified');
6455
+ } else {
6456
+ $unqualified = false;
6457
+ }
6458
+ if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
6459
+ $vv = $v;
6460
+ foreach ($vv as $k => $v) {
6461
+ if (isset($attrs['type']) || isset($attrs['ref'])) {
6462
+ // serialize schema-defined type
6463
+ $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6464
+ } else {
6465
+ // serialize generic type (can this ever really happen?)
6466
+ $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6467
+ $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6468
+ }
6469
+ }
6470
+ } else {
6471
+ if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') {
6472
+ // do nothing
6473
+ } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') {
6474
+ // TODO: serialize a nil correctly, but for now serialize schema-defined type
6475
+ $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6476
+ } elseif (isset($attrs['type']) || isset($attrs['ref'])) {
6477
+ // serialize schema-defined type
6478
+ $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6479
+ } else {
6480
+ // serialize generic type (can this ever really happen?)
6481
+ $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6482
+ $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6483
+ }
6484
+ }
6485
+ }
6486
+ }
6487
+ } else {
6488
+ $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
6489
+ }
6490
+ return $xml;
6491
+ }
6492
+
6493
+ /**
6494
+ * adds an XML Schema complex type to the WSDL types
6495
+ *
6496
+ * @param string $name
6497
+ * @param string $typeClass (complexType|simpleType|attribute)
6498
+ * @param string $phpType currently supported are array and struct (php assoc array)
6499
+ * @param string $compositor (all|sequence|choice)
6500
+ * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
6501
+ * @param array $elements e.g. array ( name => array(name=>'',type=>'') )
6502
+ * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
6503
+ * @param string $arrayType as namespace:name (xsd:string)
6504
+ * @see nusoap_xmlschema
6505
+ * @access public
6506
+ */
6507
+ function addComplexType($name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '')
6508
+ {
6509
+ if (count($elements) > 0) {
6510
+ $eElements = array();
6511
+ foreach ($elements as $n => $e) {
6512
+ // expand each element
6513
+ $ee = array();
6514
+ foreach ($e as $k => $v) {
6515
+ $k = strpos($k, ':') ? $this->expandQname($k) : $k;
6516
+ $v = strpos($v, ':') ? $this->expandQname($v) : $v;
6517
+ $ee[$k] = $v;
6518
+ }
6519
+ $eElements[$n] = $ee;
6520
+ }
6521
+ $elements = $eElements;
6522
+ }
6523
+
6524
+ if (count($attrs) > 0) {
6525
+ foreach ($attrs as $n => $a) {
6526
+ // expand each attribute
6527
+ foreach ($a as $k => $v) {
6528
+ $k = strpos($k, ':') ? $this->expandQname($k) : $k;
6529
+ $v = strpos($v, ':') ? $this->expandQname($v) : $v;
6530
+ $aa[$k] = $v;
6531
+ }
6532
+ $eAttrs[$n] = $aa;
6533
+ }
6534
+ $attrs = $eAttrs;
6535
+ }
6536
+
6537
+ $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6538
+ $arrayType = strpos($arrayType, ':') ? $this->expandQname($arrayType) : $arrayType;
6539
+
6540
+ $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6541
+ $this->schemas[$typens][0]->addComplexType($name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType);
6542
+ }
6543
+
6544
+ /**
6545
+ * adds an XML Schema simple type to the WSDL types
6546
+ *
6547
+ * @param string $name
6548
+ * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
6549
+ * @param string $typeClass (should always be simpleType)
6550
+ * @param string $phpType (should always be scalar)
6551
+ * @param array $enumeration array of values
6552
+ * @see nusoap_xmlschema
6553
+ * @access public
6554
+ */
6555
+ function addSimpleType($name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array())
6556
+ {
6557
+ $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6558
+
6559
+ $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6560
+ $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
6561
+ }
6562
+
6563
+ /**
6564
+ * adds an element to the WSDL types
6565
+ *
6566
+ * @param array $attrs attributes that must include name and type
6567
+ * @see nusoap_xmlschema
6568
+ * @access public
6569
+ */
6570
+ function addElement($attrs)
6571
+ {
6572
+ $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6573
+ $this->schemas[$typens][0]->addElement($attrs);
6574
+ }
6575
+
6576
+ /**
6577
+ * register an operation with the server
6578
+ *
6579
+ * @param string $name operation (method) name
6580
+ * @param array $in assoc array of input values: key = param name, value = param type
6581
+ * @param array $out assoc array of output values: key = param name, value = param type
6582
+ * @param string $namespace optional The namespace for the operation
6583
+ * @param string $soapaction optional The soapaction for the operation
6584
+ * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically
6585
+ * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)
6586
+ * @param string $documentation optional The description to include in the WSDL
6587
+ * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
6588
+ * @access public
6589
+ */
6590
+ function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = '')
6591
+ {
6592
+ if ($use == 'encoded' && $encodingStyle == '') {
6593
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6594
+ }
6595
+
6596
+ if ($style == 'document') {
6597
+ $elements = array();
6598
+ foreach ($in as $n => $t) {
6599
+ $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
6600
+ }
6601
+ $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
6602
+ $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
6603
+ $in = array('parameters' => 'tns:' . $name . '^');
6604
+
6605
+ $elements = array();
6606
+ foreach ($out as $n => $t) {
6607
+ $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
6608
+ }
6609
+ $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
6610
+ $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
6611
+ $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
6612
+ }
6613
+
6614
+ // get binding
6615
+ $this->bindings[$this->serviceName . 'Binding']['operations'][$name] =
6616
+ array(
6617
+ 'name' => $name,
6618
+ 'binding' => $this->serviceName . 'Binding',
6619
+ 'endpoint' => $this->endpoint,
6620
+ 'soapAction' => $soapaction,
6621
+ 'style' => $style,
6622
+ 'input' => array(
6623
+ 'use' => $use,
6624
+ 'namespace' => $namespace,
6625
+ 'encodingStyle' => $encodingStyle,
6626
+ 'message' => $name . 'Request',
6627
+ 'parts' => $in),
6628
+ 'output' => array(
6629
+ 'use' => $use,
6630
+ 'namespace' => $namespace,
6631
+ 'encodingStyle' => $encodingStyle,
6632
+ 'message' => $name . 'Response',
6633
+ 'parts' => $out),
6634
+ 'namespace' => $namespace,
6635
+ 'transport' => 'http://schemas.xmlsoap.org/soap/http',
6636
+ 'documentation' => $documentation);
6637
+ // add portTypes
6638
+ // add messages
6639
+ if ($in) {
6640
+ foreach ($in as $pName => $pType) {
6641
+ if (strpos($pType, ':')) {
6642
+ $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ":" . $this->getLocalPart($pType);
6643
+ }
6644
+ $this->messages[$name . 'Request'][$pName] = $pType;
6645
+ }
6646
+ } else {
6647
+ $this->messages[$name . 'Request'] = '0';
6648
+ }
6649
+ if ($out) {
6650
+ foreach ($out as $pName => $pType) {
6651
+ if (strpos($pType, ':')) {
6652
+ $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ":" . $this->getLocalPart($pType);
6653
+ }
6654
+ $this->messages[$name . 'Response'][$pName] = $pType;
6655
+ }
6656
+ } else {
6657
+ $this->messages[$name . 'Response'] = '0';
6658
+ }
6659
+ return true;
6660
+ }
6661
+ }
6662
+
6663
+
6664
+ /**
6665
+ *
6666
+ * nusoap_parser class parses SOAP XML messages into native PHP values
6667
+ *
6668
+ * @author Dietrich Ayala <dietrich@ganx4.com>
6669
+ * @author Scott Nichol <snichol@users.sourceforge.net>
6670
+ * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
6671
+ * @access public
6672
+ */
6673
+ class nusoap_parser extends nusoap_base
6674
+ {
6675
+
6676
+ var $xml = '';
6677
+ var $xml_encoding = '';
6678
+ var $method = '';
6679
+ var $root_struct = '';
6680
+ var $root_struct_name = '';
6681
+ var $root_struct_namespace = '';
6682
+ var $root_header = '';
6683
+ var $document = ''; // incoming SOAP body (text)
6684
+ // determines where in the message we are (envelope,header,body,method)
6685
+ var $status = '';
6686
+ var $position = 0;
6687
+ var $depth = 0;
6688
+ var $default_namespace = '';
6689
+ var $namespaces = array();
6690
+ var $message = array();
6691
+ var $parent = '';
6692
+ var $fault = false;
6693
+ var $fault_code = '';
6694
+ var $fault_str = '';
6695
+ var $fault_detail = '';
6696
+ var $depth_array = array();
6697
+ var $debug_flag = true;
6698
+ var $soapresponse = null; // parsed SOAP Body
6699
+ var $soapheader = null; // parsed SOAP Header
6700
+ var $responseHeaders = ''; // incoming SOAP headers (text)
6701
+ var $body_position = 0;
6702
+ // for multiref parsing:
6703
+ // array of id => pos
6704
+ var $ids = array();
6705
+ // array of id => hrefs => pos
6706
+ var $multirefs = array();
6707
+ // toggle for auto-decoding element content
6708
+ var $decode_utf8 = true;
6709
+
6710
+ /**
6711
+ * constructor that actually does the parsing
6712
+ *
6713
+ * @param string $xml SOAP message
6714
+ * @param string $encoding character encoding scheme of message
6715
+ * @param string $method method for which XML is parsed (unused?)
6716
+ * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
6717
+ * @access public
6718
+ */
6719
+ function __construct($xml, $encoding = 'UTF-8', $method = '', $decode_utf8 = true)
6720
+ {
6721
+ parent::__construct();
6722
+ $this->xml = $xml;
6723
+ $this->xml_encoding = $encoding;
6724
+ $this->method = $method;
6725
+ $this->decode_utf8 = $decode_utf8;
6726
+
6727
+ // Check whether content has been read.
6728
+ if (!empty($xml)) {
6729
+ // Check XML encoding
6730
+ $pos_xml = strpos($xml, '<?xml');
6731
+ if ($pos_xml !== false) {
6732
+ $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
6733
+ if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
6734
+ $xml_encoding = $res[1];
6735
+ if (strtoupper($xml_encoding) != $encoding) {
6736
+ $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
6737
+ $this->debug($err);
6738
+ if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
6739
+ $this->setError($err);
6740
+ return;
6741
+ }
6742
+ // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
6743
+ } else {
6744
+ $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
6745
+ }
6746
+ } else {
6747
+ $this->debug('No encoding specified in XML declaration');
6748
+ }
6749
+ } else {
6750
+ $this->debug('No XML declaration');
6751
+ }
6752
+ $this->debug('Entering nusoap_parser(), length=' . strlen($xml) . ', encoding=' . $encoding);
6753
+ // Create an XML parser - why not xml_parser_create_ns?
6754
+ $this->parser = xml_parser_create($this->xml_encoding);
6755
+ // Set the options for parsing the XML data.
6756
+ //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
6757
+ xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
6758
+ xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
6759
+ // Set the object for the parser.
6760
+ xml_set_object($this->parser, $this);
6761
+ // Set the element handlers for the parser.
6762
+ xml_set_element_handler($this->parser, 'start_element', 'end_element');
6763
+ xml_set_character_data_handler($this->parser, 'character_data');
6764
+
6765
+ // Parse the XML file.
6766
+ if (!xml_parse($this->parser, $xml, true)) {
6767
+ // Display an error message.
6768
+ $err = sprintf('XML error parsing SOAP payload on line %d: %s',
6769
+ xml_get_current_line_number($this->parser),
6770
+ xml_error_string(xml_get_error_code($this->parser)));
6771
+ $this->debug($err);
6772
+ $this->debug("XML payload:\n" . $xml);
6773
+ $this->setError($err);
6774
+ } else {
6775
+ $this->debug('in nusoap_parser ctor, message:');
6776
+ $this->appendDebug($this->varDump($this->message));
6777
+ $this->debug('parsed successfully, found root struct: ' . $this->root_struct . ' of name ' . $this->root_struct_name);
6778
+ // get final value
6779
+ $this->soapresponse = $this->message[$this->root_struct]['result'];
6780
+ // get header value
6781
+ if ($this->root_header != '' && isset($this->message[$this->root_header]['result'])) {
6782
+ $this->soapheader = $this->message[$this->root_header]['result'];
6783
+ }
6784
+ // resolve hrefs/ids
6785
+ if (sizeof($this->multirefs) > 0) {
6786
+ foreach ($this->multirefs as $id => $hrefs) {
6787
+ $this->debug('resolving multirefs for id: ' . $id);
6788
+ $idVal = $this->buildVal($this->ids[$id]);
6789
+ if (is_array($idVal) && isset($idVal['!id'])) {
6790
+ unset($idVal['!id']);
6791
+ }
6792
+ foreach ($hrefs as $refPos => $ref) {
6793
+ $this->debug('resolving href at pos ' . $refPos);
6794
+ $this->multirefs[$id][$refPos] = $idVal;
6795
+ }
6796
+ }
6797
+ }
6798
+ }
6799
+ xml_parser_free($this->parser);
6800
+ unset($this->parser);
6801
+ } else {
6802
+ $this->debug('xml was empty, didn\'t parse!');
6803
+ $this->setError('xml was empty, didn\'t parse!');
6804
+ }
6805
+ }
6806
+
6807
+ /**
6808
+ * start-element handler
6809
+ *
6810
+ * @param resource $parser XML parser object
6811
+ * @param string $name element name
6812
+ * @param array $attrs associative array of attributes
6813
+ * @access private
6814
+ */
6815
+ function start_element($parser, $name, $attrs)
6816
+ {
6817
+ // position in a total number of elements, starting from 0
6818
+ // update class level pos
6819
+ $pos = $this->position++;
6820
+ // and set mine
6821
+ $this->message[$pos] = array('pos' => $pos, 'children' => '', 'cdata' => '');
6822
+ // depth = how many levels removed from root?
6823
+ // set mine as current global depth and increment global depth value
6824
+ $this->message[$pos]['depth'] = $this->depth++;
6825
+
6826
+ // else add self as child to whoever the current parent is
6827
+ if ($pos != 0) {
6828
+ $this->message[$this->parent]['children'] .= '|' . $pos;
6829
+ }
6830
+ // set my parent
6831
+ $this->message[$pos]['parent'] = $this->parent;
6832
+ // set self as current parent
6833
+ $this->parent = $pos;
6834
+ // set self as current value for this depth
6835
+ $this->depth_array[$this->depth] = $pos;
6836
+ // get element prefix
6837
+ if (strpos($name, ':')) {
6838
+ // get ns prefix
6839
+ $prefix = substr($name, 0, strpos($name, ':'));
6840
+ // get unqualified name
6841
+ $name = substr(strstr($name, ':'), 1);
6842
+ }
6843
+ // set status
6844
+ if ($name == 'Envelope' && $this->status == '') {
6845
+ $this->status = 'envelope';
6846
+ } elseif ($name == 'Header' && $this->status == 'envelope') {
6847
+ $this->root_header = $pos;
6848
+ $this->status = 'header';
6849
+ } elseif ($name == 'Body' && $this->status == 'envelope') {
6850
+ $this->status = 'body';
6851
+ $this->body_position = $pos;
6852
+ // set method
6853
+ } elseif ($this->status == 'body' && $pos == ($this->body_position + 1)) {
6854
+ $this->status = 'method';
6855
+ $this->root_struct_name = $name;
6856
+ $this->root_struct = $pos;
6857
+ $this->message[$pos]['type'] = 'struct';
6858
+ $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
6859
+ }
6860
+ // set my status
6861
+ $this->message[$pos]['status'] = $this->status;
6862
+ // set name
6863
+ $this->message[$pos]['name'] = htmlspecialchars($name);
6864
+ // set attrs
6865
+ $this->message[$pos]['attrs'] = $attrs;
6866
+
6867
+ // loop through atts, logging ns and type declarations
6868
+ $attstr = '';
6869
+ foreach ($attrs as $key => $value) {
6870
+ $key_prefix = $this->getPrefix($key);
6871
+ $key_localpart = $this->getLocalPart($key);
6872
+ // if ns declarations, add to class level array of valid namespaces
6873
+ if ($key_prefix == 'xmlns') {
6874
+ if (preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/', $value)) {
6875
+ $this->XMLSchemaVersion = $value;
6876
+ $this->namespaces['xsd'] = $this->XMLSchemaVersion;
6877
+ $this->namespaces['xsi'] = $this->XMLSchemaVersion . '-instance';
6878
+ }
6879
+ $this->namespaces[$key_localpart] = $value;
6880
+ // set method namespace
6881
+ if ($name == $this->root_struct_name) {
6882
+ $this->methodNamespace = $value;
6883
+ }
6884
+ // if it's a type declaration, set type
6885
+ } elseif ($key_localpart == 'type') {
6886
+ if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
6887
+ // do nothing: already processed arrayType
6888
+ } else {
6889
+ $value_prefix = $this->getPrefix($value);
6890
+ $value_localpart = $this->getLocalPart($value);
6891
+ $this->message[$pos]['type'] = $value_localpart;
6892
+ $this->message[$pos]['typePrefix'] = $value_prefix;
6893
+ if (isset($this->namespaces[$value_prefix])) {
6894
+ $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
6895
+ } elseif (isset($attrs['xmlns:' . $value_prefix])) {
6896
+ $this->message[$pos]['type_namespace'] = $attrs['xmlns:' . $value_prefix];
6897
+ }
6898
+ // should do something here with the namespace of specified type?
6899
+ }
6900
+ } elseif ($key_localpart == 'arrayType') {
6901
+ $this->message[$pos]['type'] = 'array';
6902
+ /* do arrayType ereg here
6903
+ [1] arrayTypeValue ::= atype asize
6904
+ [2] atype ::= QName rank*
6905
+ [3] rank ::= '[' (',')* ']'
6906
+ [4] asize ::= '[' length~ ']'
6907
+ [5] length ::= nextDimension* Digit+
6908
+ [6] nextDimension ::= Digit+ ','
6909
+ */
6910
+ $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
6911
+ if (preg_match($expr, $value, $regs)) {
6912
+ $this->message[$pos]['typePrefix'] = $regs[1];
6913
+ $this->message[$pos]['arrayTypePrefix'] = $regs[1];
6914
+ if (isset($this->namespaces[$regs[1]])) {
6915
+ $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
6916
+ } elseif (isset($attrs['xmlns:' . $regs[1]])) {
6917
+ $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:' . $regs[1]];
6918
+ }
6919
+ $this->message[$pos]['arrayType'] = $regs[2];
6920
+ $this->message[$pos]['arraySize'] = $regs[3];
6921
+ $this->message[$pos]['arrayCols'] = $regs[4];
6922
+ }
6923
+ // specifies nil value (or not)
6924
+ } elseif ($key_localpart == 'nil') {
6925
+ $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
6926
+ // some other attribute
6927
+ } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
6928
+ $this->message[$pos]['xattrs']['!' . $key] = $value;
6929
+ }
6930
+
6931
+ if ($key == 'xmlns') {
6932
+ $this->default_namespace = $value;
6933
+ }
6934
+ // log id
6935
+ if ($key == 'id') {
6936
+ $this->ids[$value] = $pos;
6937
+ }
6938
+ // root
6939
+ if ($key_localpart == 'root' && $value == 1) {
6940
+ $this->status = 'method';
6941
+ $this->root_struct_name = $name;
6942
+ $this->root_struct = $pos;
6943
+ $this->debug("found root struct $this->root_struct_name, pos $pos");
6944
+ }
6945
+ // for doclit
6946
+ $attstr .= " $key=\"$value\"";
6947
+ }
6948
+ // get namespace - must be done after namespace atts are processed
6949
+ if (isset($prefix)) {
6950
+ $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
6951
+ $this->default_namespace = $this->namespaces[$prefix];
6952
+ } else {
6953
+ $this->message[$pos]['namespace'] = $this->default_namespace;
6954
+ }
6955
+ if ($this->status == 'header') {
6956
+ if ($this->root_header != $pos) {
6957
+ $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6958
+ }
6959
+ } elseif ($this->root_struct_name != '') {
6960
+ $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6961
+ }
6962
+ }
6963
+
6964
+ /**
6965
+ * end-element handler
6966
+ *
6967
+ * @param resource $parser XML parser object
6968
+ * @param string $name element name
6969
+ * @access private
6970
+ */
6971
+ function end_element($parser, $name)
6972
+ {
6973
+ // position of current element is equal to the last value left in depth_array for my depth
6974
+ $pos = $this->depth_array[$this->depth--];
6975
+
6976
+ // get element prefix
6977
+ if (strpos($name, ':')) {
6978
+ // get ns prefix
6979
+ $prefix = substr($name, 0, strpos($name, ':'));
6980
+ // get unqualified name
6981
+ $name = substr(strstr($name, ':'), 1);
6982
+ }
6983
+
6984
+ // build to native type
6985
+ if (isset($this->body_position) && $pos > $this->body_position) {
6986
+ // deal w/ multirefs
6987
+ if (isset($this->message[$pos]['attrs']['href'])) {
6988
+ // get id
6989
+ $id = substr($this->message[$pos]['attrs']['href'], 1);
6990
+ // add placeholder to href array
6991
+ $this->multirefs[$id][$pos] = 'placeholder';
6992
+ // add set a reference to it as the result value
6993
+ $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
6994
+ // build complexType values
6995
+ } elseif ($this->message[$pos]['children'] != '') {
6996
+ // if result has already been generated (struct/array)
6997
+ if (!isset($this->message[$pos]['result'])) {
6998
+ $this->message[$pos]['result'] = $this->buildVal($pos);
6999
+ }
7000
+ // build complexType values of attributes and possibly simpleContent
7001
+ } elseif (isset($this->message[$pos]['xattrs'])) {
7002
+ if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
7003
+ $this->message[$pos]['xattrs']['!'] = null;
7004
+ } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
7005
+ if (isset($this->message[$pos]['type'])) {
7006
+ $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7007
+ } else {
7008
+ $parent = $this->message[$pos]['parent'];
7009
+ if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
7010
+ $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7011
+ } else {
7012
+ $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
7013
+ }
7014
+ }
7015
+ }
7016
+ $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
7017
+ // set value of simpleType (or nil complexType)
7018
+ } else {
7019
+ //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
7020
+ if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
7021
+ $this->message[$pos]['xattrs']['!'] = null;
7022
+ } elseif (isset($this->message[$pos]['type'])) {
7023
+ $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7024
+ } else {
7025
+ $parent = $this->message[$pos]['parent'];
7026
+ if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
7027
+ $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7028
+ } else {
7029
+ $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
7030
+ }
7031
+ }
7032
+
7033
+ /* add value to parent's result, if parent is struct/array
7034
+ $parent = $this->message[$pos]['parent'];
7035
+ if($this->message[$parent]['type'] != 'map'){
7036
+ if(strtolower($this->message[$parent]['type']) == 'array'){
7037
+ $this->message[$parent]['result'][] = $this->message[$pos]['result'];
7038
+ } else {
7039
+ $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
7040
+ }
7041
+ }
7042
+ */
7043
+ }
7044
+ }
7045
+
7046
+ // for doclit
7047
+ if ($this->status == 'header') {
7048
+ if ($this->root_header != $pos) {
7049
+ $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
7050
+ }
7051
+ } elseif ($pos >= $this->root_struct) {
7052
+ $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
7053
+ }
7054
+ // switch status
7055
+ if ($pos == $this->root_struct) {
7056
+ $this->status = 'body';
7057
+ $this->root_struct_namespace = $this->message[$pos]['namespace'];
7058
+ } elseif ($pos == $this->root_header) {
7059
+ $this->status = 'envelope';
7060
+ } elseif ($name == 'Body' && $this->status == 'body') {
7061
+ $this->status = 'envelope';
7062
+ } elseif ($name == 'Header' && $this->status == 'header') { // will never happen
7063
+ $this->status = 'envelope';
7064
+ } elseif ($name == 'Envelope' && $this->status == 'envelope') {
7065
+ $this->status = '';
7066
+ }
7067
+ // set parent back to my parent
7068
+ $this->parent = $this->message[$pos]['parent'];
7069
+ }
7070
+
7071
+ /**
7072
+ * element content handler
7073
+ *
7074
+ * @param resource $parser XML parser object
7075
+ * @param string $data element content
7076
+ * @access private
7077
+ */
7078
+ function character_data($parser, $data)
7079
+ {
7080
+ $pos = $this->depth_array[$this->depth];
7081
+ if ($this->xml_encoding == 'UTF-8') {
7082
+ // TODO: add an option to disable this for folks who want
7083
+ // raw UTF-8 that, e.g., might not map to iso-8859-1
7084
+ // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
7085
+ if ($this->decode_utf8) {
7086
+ $data = utf8_decode($data);
7087
+ }
7088
+ }
7089
+ $this->message[$pos]['cdata'] .= $data;
7090
+ // for doclit
7091
+ if ($this->status == 'header') {
7092
+ $this->responseHeaders .= $data;
7093
+ } else {
7094
+ $this->document .= $data;
7095
+ }
7096
+ }
7097
+
7098
+ /**
7099
+ * get the parsed message (SOAP Body)
7100
+ *
7101
+ * @return mixed
7102
+ * @access public
7103
+ * @deprecated use get_soapbody instead
7104
+ */
7105
+ function get_response()
7106
+ {
7107
+ return $this->soapresponse;
7108
+ }
7109
+
7110
+ /**
7111
+ * get the parsed SOAP Body (null if there was none)
7112
+ *
7113
+ * @return mixed
7114
+ * @access public
7115
+ */
7116
+ function get_soapbody()
7117
+ {
7118
+ return $this->soapresponse;
7119
+ }
7120
+
7121
+ /**
7122
+ * get the parsed SOAP Header (null if there was none)
7123
+ *
7124
+ * @return mixed
7125
+ * @access public
7126
+ */
7127
+ function get_soapheader()
7128
+ {
7129
+ return $this->soapheader;
7130
+ }
7131
+
7132
+ /**
7133
+ * get the unparsed SOAP Header
7134
+ *
7135
+ * @return string XML or empty if no Header
7136
+ * @access public
7137
+ */
7138
+ function getHeaders()
7139
+ {
7140
+ return $this->responseHeaders;
7141
+ }
7142
+
7143
+ /**
7144
+ * decodes simple types into PHP variables
7145
+ *
7146
+ * @param string $value value to decode
7147
+ * @param string $type XML type to decode
7148
+ * @param string $typens XML type namespace to decode
7149
+ * @return mixed PHP value
7150
+ * @access private
7151
+ */
7152
+ function decodeSimple($value, $type, $typens)
7153
+ {
7154
+ // TODO: use the namespace!
7155
+ if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
7156
+ return (string) $value;
7157
+ }
7158
+ if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
7159
+ return (int) $value;
7160
+ }
7161
+ if ($type == 'float' || $type == 'double' || $type == 'decimal') {
7162
+ return (double) $value;
7163
+ }
7164
+ if ($type == 'boolean') {
7165
+ if (strtolower($value) == 'false' || strtolower($value) == 'f') {
7166
+ return false;
7167
+ }
7168
+ return (boolean) $value;
7169
+ }
7170
+ if ($type == 'base64' || $type == 'base64Binary') {
7171
+ $this->debug('Decode base64 value');
7172
+ return base64_decode($value);
7173
+ }
7174
+ // obscure numeric types
7175
+ if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
7176
+ || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
7177
+ || $type == 'unsignedInt'
7178
+ || $type == 'unsignedShort' || $type == 'unsignedByte'
7179
+ ) {
7180
+ return (int) $value;
7181
+ }
7182
+ // bogus: parser treats array with no elements as a simple type
7183
+ if ($type == 'array') {
7184
+ return array();
7185
+ }
7186
+ // everything else
7187
+ return (string) $value;
7188
+ }
7189
+
7190
+ /**
7191
+ * builds response structures for compound values (arrays/structs)
7192
+ * and scalars
7193
+ *
7194
+ * @param integer $pos position in node tree
7195
+ * @return mixed PHP value
7196
+ * @access private
7197
+ */
7198
+ function buildVal($pos)
7199
+ {
7200
+ if (!isset($this->message[$pos]['type'])) {
7201
+ $this->message[$pos]['type'] = '';
7202
+ }
7203
+ $this->debug('in buildVal() for ' . $this->message[$pos]['name'] . "(pos $pos) of type " . $this->message[$pos]['type']);
7204
+ // if there are children...
7205
+ if ($this->message[$pos]['children'] != '') {
7206
+ $this->debug('in buildVal, there are children');
7207
+ $children = explode('|', $this->message[$pos]['children']);
7208
+ array_shift($children); // knoc