+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ call('get_modules',$params,$Server_path,$Server_path);
+ // Store for further use.
+ $_SESSION['__permitted_modules'] = $showmodule;
+ }
+ for($i=0;$i".getTranslatedString($showmodule[$i])." ";
+ }
+ ?>
+
+
+
+
+
+
+
+
+
diff --git a/oss/vtiger/trunk/customerportal/images/category.gif b/oss/vtiger/trunk/customerportal/images/category.gif
new file mode 100644
index 00000000..77d44d55
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/category.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/email.gif b/oss/vtiger/trunk/customerportal/images/email.gif
new file mode 100644
index 00000000..41553d58
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/email.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/faq.gif b/oss/vtiger/trunk/customerportal/images/faq.gif
new file mode 100644
index 00000000..34c0623d
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/faq.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/favorite.gif b/oss/vtiger/trunk/customerportal/images/favorite.gif
new file mode 100644
index 00000000..a0b7ce4c
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/favorite.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginBg.gif b/oss/vtiger/trunk/customerportal/images/loginBg.gif
new file mode 100644
index 00000000..5a0f9ed4
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginBg.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginBgbig.gif b/oss/vtiger/trunk/customerportal/images/loginBgbig.gif
new file mode 100644
index 00000000..5c5704f1
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginBgbig.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginBgbig.jpg b/oss/vtiger/trunk/customerportal/images/loginBgbig.jpg
new file mode 100644
index 00000000..a35c49cd
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginBgbig.jpg differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginBottomBg.gif b/oss/vtiger/trunk/customerportal/images/loginBottomBg.gif
new file mode 100644
index 00000000..26ead7a9
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginBottomBg.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginBottomURL.gif b/oss/vtiger/trunk/customerportal/images/loginBottomURL.gif
new file mode 100644
index 00000000..a23146b3
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginBottomURL.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginBtnSignin.gif b/oss/vtiger/trunk/customerportal/images/loginBtnSignin.gif
new file mode 100644
index 00000000..eeb7b0d8
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginBtnSignin.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginSIBottomLeft.gif b/oss/vtiger/trunk/customerportal/images/loginSIBottomLeft.gif
new file mode 100644
index 00000000..610b9ff6
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginSIBottomLeft.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginSIBottomRight.gif b/oss/vtiger/trunk/customerportal/images/loginSIBottomRight.gif
new file mode 100644
index 00000000..9e73c022
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginSIBottomRight.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginSITopLeft.gif b/oss/vtiger/trunk/customerportal/images/loginSITopLeft.gif
new file mode 100644
index 00000000..738079b8
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginSITopLeft.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginSITopRight.gif b/oss/vtiger/trunk/customerportal/images/loginSITopRight.gif
new file mode 100644
index 00000000..a2b8dc01
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginSITopRight.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginTopBg.gif b/oss/vtiger/trunk/customerportal/images/loginTopBg.gif
new file mode 100644
index 00000000..d2c321c3
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginTopBg.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginTopShade.gif b/oss/vtiger/trunk/customerportal/images/loginTopShade.gif
new file mode 100644
index 00000000..27183eb3
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginTopShade.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/loginVtigerCRM.gif b/oss/vtiger/trunk/customerportal/images/loginVtigerCRM.gif
new file mode 100644
index 00000000..7d39151e
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/loginVtigerCRM.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/minus.gif b/oss/vtiger/trunk/customerportal/images/minus.gif
new file mode 100644
index 00000000..1753de5c
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/minus.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/plus.gif b/oss/vtiger/trunk/customerportal/images/plus.gif
new file mode 100644
index 00000000..b750df80
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/plus.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/print.gif b/oss/vtiger/trunk/customerportal/images/print.gif
new file mode 100644
index 00000000..c71dd8fb
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/print.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/products.gif b/oss/vtiger/trunk/customerportal/images/products.gif
new file mode 100644
index 00000000..55644443
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/products.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/status.gif b/oss/vtiger/trunk/customerportal/images/status.gif
new file mode 100644
index 00000000..ab208159
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/status.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/tabSeperatorBg.gif b/oss/vtiger/trunk/customerportal/images/tabSeperatorBg.gif
new file mode 100644
index 00000000..c9f7845c
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/tabSeperatorBg.gif differ
diff --git a/oss/vtiger/trunk/customerportal/images/vtiger-crm.gif b/oss/vtiger/trunk/customerportal/images/vtiger-crm.gif
new file mode 100644
index 00000000..3ce1cdd9
Binary files /dev/null and b/oss/vtiger/trunk/customerportal/images/vtiger-crm.gif differ
diff --git a/oss/vtiger/trunk/customerportal/include.php b/oss/vtiger/trunk/customerportal/include.php
new file mode 100644
index 00000000..5b375b1a
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/include.php
@@ -0,0 +1,23 @@
+soap_defencoding = $default_charset;
+
+?>
diff --git a/oss/vtiger/trunk/customerportal/include/utils/utils.php b/oss/vtiger/trunk/customerportal/include/utils/utils.php
new file mode 100644
index 00000000..abe9bc77
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/include/utils/utils.php
@@ -0,0 +1,294 @@
+';
+ $list .='
';
+ } else {
+ $list .=' ';
+ }
+ return $list;
+
+}
+
+
+function getblock_fieldlist($block_array)
+{
+ $list='';$z=0;
+ $field_count=count($block_array);
+ if($field_count != 0)
+ {
+ for($i=0;$i<$field_count;$i++,$z++)
+ {
+ $blockname = $block_array[$i]['blockname'];
+ $data = $block_array[$i]['fieldvalue'];
+ if($block_array[$i]['fieldlabel'] == 'Note'){
+ $data = html_entity_decode($data);
+ }
+ if($data =='')
+ $data =' ';
+ if(strcmp($blockname,$block_array[$i-1]['blockname'])){
+ if($blockname != 'Ticket Information') //hardcoded for tickets information block so that it ll not be displayed
+ $list .= getblock_header($blockname);
+ $z = 0;
+ }
+ if($z==0 || $z%2==0)
+ $list .= '';
+ $list .= ''.getTranslatedString($block_array[$i][fieldlabel]).' ';
+ if(($z == 0 || $z%2 == 0) &&($i == ($field_count-1)))
+ $list .= ''.$data.' ';
+ else
+ $list .= ''.$data.' ';
+ if($z%2 == 1 ||($i == ($field_count-1) ))
+ $list .= ' ';
+ }
+ }
+ $list.= ' ';
+ return $list;
+}
+
+function getTranslatedString($str)
+{
+ global $app_strings;
+ return (isset($app_strings[$str]))?$app_strings[$str]:$str;
+}
+
+// The function to get html format list data
+// input array
+// output htmlsource list array
+//only for product
+function getblock_fieldlistview_product($block_array,$module)
+{
+
+ $header = array();
+ $header[0] = getTranslatedString($module);
+ $header[1] = getTranslatedString('QUOTE_RELATED').getTranslatedString($module);
+ $header[2] = getTranslatedString('INVOICE_RELATED').getTranslatedString($module);
+
+ if($block_array == '')
+ {
+ $list.=''.$module." ".getTranslatedString('LBL_NOT_AVAILABLE').' ';
+ return $list;
+ }
+
+for($k=0;$k<=2;$k++)
+{
+
+$header_arr =$block_array[$k][$module]['head'][0];
+$nooffields=count($header_arr);
+$data_arr=$block_array[$k][$module]['data'];
+ $noofdata=count($data_arr);
+ $list.=getblock_header($header[$k],$nooffields);
+ if($block_array[$k][$module]['data'] == ''){
+ $list.=''.$header[$k]." ".getTranslatedString('LBL_NOT_AVAILABLE').' ';
+ }
+ if($nooffields!='')
+ {
+
+ $list .='';
+ }
+ if($noofdata != '')
+ {
+ for($j=0;$j<$noofdata;$j++)
+ {
+ if($j==0||$j%2==0)
+ $list .='';
+ else
+ $list .=' ';
+
+ for($i=0;$i<$nooffields;$i++)
+ {
+ $data =$data_arr[$j][$i]['fielddata'];
+ if($data == '')
+ $data =' ';
+ $list .= "".$data." ";
+ }
+ $list .=' ';
+ }
+ }
+ $list .= ' ';
+}
+return $list;
+}
+
+// The function to get html format list data
+// input array
+// output htmlsource list array
+//for quotes,notes and invoice
+
+function getblock_fieldlistview($block_array,$block)
+{
+ if($block_array[0] == "#MODULE INACTIVE#"){
+ $list.=''.getTranslatedString($block)." ".getTranslatedString('MODULE_INACTIVE').' ';
+ return $list;
+ }
+ if($block_array == ''){
+ $list.=''.getTranslatedString($block)." ".getTranslatedString('LBL_NOT_AVAILABLE').' ';
+ return $list;
+ }
+ $header_arr =$block_array[0][$block]['head'][0];
+ $nooffields=count($header_arr);
+ $data_arr=$block_array[1][$block]['data'];
+ $noofdata=count($data_arr);
+ if($nooffields!='')
+ {
+ $list .='';
+ for($i=0;$i<$nooffields;$i++)
+ $list .= "";
+ $list .=' ';
+ }
+ if($noofdata != '')
+ {
+ for($j=0;$j<$noofdata;$j++)
+ {
+ if($j==0 || $j%2==0)
+ $list .='';
+ else
+ $list .=' ';
+
+ for($i=0;$i<$nooffields;$i++)
+ {
+ $data =$data_arr[$j][$i]['fielddata'];
+ if($data == '')
+ $data =' ';
+ $list .= "".$data." ";
+ }
+ $list .=' ';
+ }
+
+ $list .= ' ';
+}
+return $list;
+}
+
+
+
+
+
+
+// The function to get html format url_list data
+// input array
+// output htmlsource list array
+function getblockurl_fieldlistview($block_array,$block)
+{
+ $header_arr =$block_array[0][$block]['head'][0][0];
+ $nooffields=count($header_arr);
+ $data_arr=$block_array[1][$block]['data'];
+ $noofdata=count($data_arr);
+ if($nooffields!='')
+ {
+ $list .='';
+ }
+ if($noofdata != '')
+ {
+ for($j=0;$j<$noofdata;$j++)
+ {
+ for($j1=0;$j1'.$data."";
+ }
+ else
+ $list .= "".$data." ";
+ }
+ $list .='';
+ }
+ }
+ }
+ $list .= ' ';
+
+return $list;
+}
+/* Function to Show the languages in the Login page
+* Takes an array from PortalConfig.php file $language
+* Returns a list of available Language
+*/
+function getPortalLanguages() {
+ global $languages,$default_language;
+ foreach($languages as $name => $label) {
+ if(strcmp($default_language,$name) == 0){
+ $list .= ''.$label.' ';
+ } else {
+ $list .= ''.$label.' ';
+ }
+ }
+ return $list;
+}
+/* Function to set the Current Language
+ * Sets the Session with the Current Language
+ */
+function setPortalCurrentLanguage() {
+ global $default_language;
+ if(isset($_REQUEST['login_language']) && $_REQUEST['login_language'] != ''){
+ $_SESSION['portal_login_language'] = $_REQUEST['login_language'];
+ } else {
+ $_SESSION['portal_login_language'] = $default_language;
+ }
+}
+
+/* Function to get the Current Language
+ * Returns the Current Language
+ */
+function getPortalCurrentLanguage() {
+ global $default_language;
+ if(isset($_SESSION['portal_login_language']) && $_SESSION['portal_login_language'] != ''){
+ $default_language = $_SESSION['portal_login_language'];
+ }
+ return $default_language;
+}
\ No newline at end of file
diff --git a/oss/vtiger/trunk/customerportal/index.php b/oss/vtiger/trunk/customerportal/index.php
new file mode 100644
index 00000000..da3fefda
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/index.php
@@ -0,0 +1,280 @@
+ "$email");
+ $result = $client->call('send_mail_for_password', $params);
+ $_REQUEST['mail_send_message'] = $result;
+ require_once("supportpage.php");
+}
+elseif($_REQUEST['logout'] == 'true')
+{
+ $customerid = $_SESSION['customer_id'];
+ $sessionid = $_SESSION['customer_sessionid'];
+
+ $params = Array(Array('id' => "$customerid", 'sessionid'=>"$sessionid", 'flag'=>"logout"));
+ $result = $client->call('update_login_details', $params);
+
+ session_unregister('customer_id');
+ session_unregister('customer_name');
+ session_unregister('last_login');
+ session_unregister('support_start_date');
+ session_unregister('support_end_date');
+ session_unregister('__permitted_modules');
+ session_unregister('customer_account_id');
+ session_destroy();
+ include("login.php");
+}
+else
+{
+ $module = '';
+ $action = 'login.php';
+ $isAjax = ($_REQUEST['ajax'] == 'true');
+
+ if($_SESSION['customer_id'] != '')
+ {
+ $customerid = $_SESSION['customer_id'];
+ $sessionid = $_SESSION['customer_sessionid'];
+
+ // Set customer account id
+ if(isset($_SESSION['customer_account_id'])) {
+ $account_id = $_SESSION['customer_account_id'];
+ } else {
+ $params = Array('id'=>$customerid);
+ $account_id = $client->call('get_check_account_id', $params, $Server_Path, $Server_Path);
+ $_SESSION['customer_account_id'] = $account_id;
+ }
+ // End
+ $is_logged = 1;
+
+ //Added to download attachments
+ if($_REQUEST['downloadfile'] == 'true')
+ {
+ $filename = $_REQUEST['filename'];
+ $fileType = $_REQUEST['filetype'];
+ //$fileid = $_REQUEST['fileid'];
+ $filesize = $_REQUEST['filesize'];
+
+ //Added for enhancement from Rosa Weber
+
+ if($_REQUEST['module'] == 'Invoice' || $_REQUEST['module'] == 'Quotes')
+ {
+ $id=$_REQUEST['id'];
+ $block = $_REQUEST['module'];
+ $params = array('id' => "$id", 'block'=>"$block", 'contactid'=>"$customerid",'sessionid'=>"$sessionid");
+ $fileContent = $client->call('get_pdf', $params, $Server_Path, $Server_Path);
+ $fileType ='application/pdf';
+ $fileContent = $fileContent[0];
+ $filesize = strlen(base64_decode($fileContent));
+ $filename = "$block.pdf";
+
+ }
+ else if($_REQUEST['module'] == 'Documents')
+ {
+ $id=$_REQUEST['id'];
+ $folderid = $_REQUEST['folderid'];
+ $block = $_REQUEST['module'];
+ $params = array('id' => "$id", 'folderid'=> "$folderid",'block'=>"$block", 'contactid'=>"$customerid",'sessionid'=>"$sessionid");
+ $result = $client->call('get_filecontent_detail', $params, $Server_Path, $Server_Path);
+ $fileType=$result[0]['filetype'];
+ $filesize=$result[0]['filesize'];
+ $filename=html_entity_decode($result[0]['filename']);
+ $fileContent=$result[0]['filecontents'];
+ }
+ else
+ {
+ $ticketid = $_REQUEST['ticketid'];
+ $fileid = $_REQUEST['fileid'];
+ //we have to get the content by passing the customerid, fileid and filename
+ $customerid = $_SESSION['customer_id'];
+ $sessionid = $_SESSION['customer_sessionid'];
+ $params = array(Array('id'=>$customerid,'fileid'=>$fileid,'filename'=>$filename,'sessionid'=>$sessionid,'ticketid'=>$ticketid));
+ $fileContent = $client->call('get_filecontent', $params, $Server_Path, $Server_Path);
+ $fileContent = $fileContent[0];
+ $filesize = strlen(base64_decode($fileContent));
+
+ }
+ // : End
+
+ //we have to get the content by passing the customerid, fileid and filename
+ $customerid = $_SESSION['customer_id'];
+ $sessionid = $_SESSION['customer_sessionid'];
+
+ header("Content-type: $fileType");
+ header("Content-length: $filesize");
+ header("Cache-Control: private");
+ header("Content-Disposition: attachment; filename=$filename");
+ header("Content-Description: PHP Generated Data");
+ echo base64_decode($fileContent);
+ exit;
+ }
+ if($_REQUEST['module'] != '' && $_REQUEST['action'] != '')
+ {
+ $customerid = $_SESSION['customer_id'];
+
+ $permission = array();
+ // Look if we have the information already
+ if(isset($_SESSION['__permitted_modules'])) {
+ $permission = $_SESSION['__permitted_modules'];
+ } else {
+ // Get the information from server
+ $params = array($customerid);
+ $permission = $client->call('get_modules',$params,$Server_path,$Server_path);
+ // Store for futher re-use
+ $_SESSION['__permitted_modules'] = $permission;
+ }
+ $isPermitted = false;
+ for($i=0;$icall('get_modules',$params,$Server_path,$Server_path);
+ // Store for futher re-use
+ $_SESSION['__permitted_modules'] = $permission;
+ }
+ $module = $permission[0];
+ $action = "index.php";
+ }
+ }
+ $filename = $module.$action;
+
+ if($is_logged == 1)
+ {
+ include("HelpDesk/Utils.php");
+ global $default_charset, $default_language;
+ $default_language = getPortalCurrentLanguage();
+ include("language/$default_language.lang.php");
+ header('Content-Type: text/html; charset='.$default_charset);
+
+ if(!$isAjax) {
+ include("header.html");
+ }
+
+ ?>
+
+ ';
+
+ // Look if we have the information already
+ $tabArray = array();
+ if(isset($_SESSION['__permitted_modules'])) {
+ $tabArray = $_SESSION['__permitted_modules'];
+ } else {
+ // Get the information from server
+ $params = array();
+ $tabArray = $client->call('get_modules',$params,$Server_path,$Server_path);
+ // Store for futher re-use
+ $_SESSION['__permitted_modules'] = $tabArray;
+ }
+ $module = $_REQUEST['module'];
+ foreach($tabArray as $key => $tabName) {
+ if(strcmp(rtrim($module,"/"),$tabName) == 0) {
+ ?>
+ document.getElementById("").className = "dvtSelectedCell";
+
+ document.getElementById("").className = "dvtUnSelectedCell";
+ ';
+ }
+ ?>
+
+ call('get_modules',$params,$Server_path,$Server_path);
+ }
+ $module = $permission[0];
+
+ checkFileAccess("$module/index.php");
+ include("$module/index.php");
+ }
+ if(!$isAjax) {
+ include("footer.html");
+ }
+ }
+ else {
+ header("Location: login.php");
+ }
+
+}
+
+?>
diff --git a/oss/vtiger/trunk/customerportal/js/acdropdown.js b/oss/vtiger/trunk/customerportal/js/acdropdown.js
new file mode 100644
index 00000000..f5aff8d0
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/js/acdropdown.js
@@ -0,0 +1,1546 @@
+//
+// This script was created
+// by Mircho Mirev
+// mo /mo@momche.net/
+// Copyright (c) 2004-2005 Mircho Mirev
+//
+// :: feel free to use it BUT
+// :: if you want to use this code PLEASE send me a note
+// :: and please keep this disclaimer intact
+//
+
+function cAutocomplete( sInputId )
+{
+ this.init( sInputId )
+}
+
+cAutocomplete.CS_NAME = 'Autocomplete component'
+cAutocomplete.CS_OBJ_NAME = 'AC_COMPONENT'
+cAutocomplete.CS_LIST_PREFIX = 'ACL_'
+cAutocomplete.CS_BUTTON_PREFIX = 'ACB_'
+cAutocomplete.CS_INPUT_PREFIX = 'AC_'
+cAutocomplete.CS_HIDDEN_INPUT_PREFIX = 'ACH_'
+cAutocomplete.CS_INPUT_CLASSNAME = 'dropdown'
+
+cAutocomplete.CB_AUTOINIT = true
+
+cAutocomplete.CB_AUTOCOMPLETE = false
+
+cAutocomplete.CB_FORCECORRECT = false
+
+//the separator when autocompleting multiple values
+cAutocomplete.CB_MATCHSUBSTRING = false
+cAutocomplete.CS_SEPARATOR = ','
+
+//the separator of associative arrays
+cAutocomplete.CS_ARRAY_SEPARATOR = ','
+
+//match the input string only against the begining of the strings
+//or anywhere in the string
+cAutocomplete.CB_MATCHSTRINGBEGIN = true
+
+cAutocomplete.CN_OFFSET_TOP = 2
+cAutocomplete.CN_OFFSET_LEFT = -1
+
+cAutocomplete.CN_LINE_HEIGHT = 19
+cAutocomplete.CN_NUMBER_OF_LINES = 10
+cAutocomplete.CN_HEIGHT_FIX = 2
+
+cAutocomplete.CN_CLEAR_TIMEOUT = 300
+cAutocomplete.CN_SHOW_TIMEOUT = 300
+cAutocomplete.CN_REMOTE_SHOW_TIMEOUT = 500
+cAutocomplete.CN_MARK_TIMEOUT = 400
+
+cAutocomplete.hListDisplayed = null
+cAutocomplete.nCount = 0
+
+cAutocomplete.autoInit = function()
+{
+ var nI = 0
+ var hACE = null
+ var sLangAtt
+
+ var nInputsLength = document.getElementsByTagName( 'INPUT' ).length
+ for( nI = 0; nI < nInputsLength; nI++ )
+ {
+ if( document.getElementsByTagName( 'INPUT' )[ nI ].type.toLowerCase() == 'text' )
+ {
+ sLangAtt = document.getElementsByTagName( 'INPUT' )[ nI ].getAttribute( 'acdropdown' )
+ if( sLangAtt != null && sLangAtt.length > 0 )
+ {
+ if( document.getElementsByTagName( 'INPUT' )[ nI ].id == null || document.getElementsByTagName( 'INPUT' )[ nI ].id.length == 0 )
+ {
+ document.getElementsByTagName( 'INPUT' )[ nI ].id = cAutocomplete.CS_OBJ_NAME + cAutocomplete.nCount
+ }
+ hACE = new cAutocomplete( document.getElementsByTagName( 'INPUT' )[ nI ].id )
+ }
+ }
+ }
+
+ var nTALength = document.getElementsByTagName( 'TEXTAREA' ).length
+ for( nI = 0; nI < nTALength; nI++ )
+ {
+ sLangAtt = document.getElementsByTagName( 'TEXTAREA' )[ nI ].getAttribute( 'acdropdown' )
+ if( sLangAtt != null && sLangAtt.length > 0 )
+ {
+ if( document.getElementsByTagName( 'TEXTAREA' )[ nI ].id == null || document.getElementsByTagName( 'TEXTAREA' )[ nI ].id.length == 0 )
+ {
+ document.getElementsByTagName( 'TEXTAREA' )[ nI ].id = cAutocomplete.CS_OBJ_NAME + cAutocomplete.nCount
+ }
+ hACE = new cAutocomplete( document.getElementsByTagName( 'TEXTAREA' )[ nI ].id )
+ }
+ }
+
+
+ var nSelectsLength = document.getElementsByTagName( 'SELECT' ).length
+ var aSelect = null
+ for( nI = 0; nI < nSelectsLength; nI++ )
+ {
+ aSelect = document.getElementsByTagName( 'SELECT' )[ nI ]
+ sLangAtt = aSelect.getAttribute( 'acdropdown' )
+ if( sLangAtt != null && sLangAtt.length > 0 )
+ {
+ if( aSelect.id == null || aSelect.id.length == 0 )
+ {
+ aSelect.id = cAutocomplete.CS_OBJ_NAME + cAutocomplete.nCount
+ }
+ hACE = new cAutocomplete( aSelect.id )
+ nSelectsLength--
+ nI--
+ }
+ }
+}
+
+if( cAutocomplete.CB_AUTOINIT )
+{
+ if( window.attachEvent )
+ {
+ window.attachEvent( 'onload', cAutocomplete.autoInit )
+ }
+ else if( window.addEventListener )
+ {
+ window.addEventListener( 'load', cAutocomplete.autoInit, false )
+ }
+}
+
+cAutocomplete.prototype.init = function( sInputId )
+{
+ this.sInputId = sInputId
+ this.sListId = cAutocomplete.CS_LIST_PREFIX + sInputId
+
+ this.sObjName = cAutocomplete.CS_OBJ_NAME + '_obj_' + (cAutocomplete.nCount++)
+ this.hObj = this.sObjName
+
+ this.hActiveSelection = null
+ this.nSelectedItemIdx = -1
+
+ //the value of the input before the list is displayed
+ this.sLastActiveValue = ''
+ this.sActiveValue = ''
+ this.bListDisplayed = false
+ this.nItemsDisplayed = 0
+
+ //if I transform a select option or the supplied array is associative I create a hidden input
+ //with the name of the original input and replace the original input's name
+ this.bAssociative = false
+ this.sHiddenInputId = null
+ this.bHasButton = false
+
+ //the actual data
+ this.aData = null
+ //the search array object
+ this.aSearchData = new Array()
+ this.bSorted = false
+
+ //the length of the last matched typed string
+ this.nLastMatchLength = 0
+
+ this.bForceCorrect = cAutocomplete.CB_FORCECORRECT
+ var sForceCorrect = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_forcecorrect' )
+ if( sForceCorrect != null && sForceCorrect.length > 0 )
+ {
+ this.bForceCorrect = eval( sForceCorrect )
+ }
+
+ //match a only from the beginning or anywhere in the values
+ this.bMatchBegin = cAutocomplete.CB_MATCHSTRINGBEGIN
+ var sMatchBegin = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_matchbegin' )
+ if( sMatchBegin != null && sMatchBegin.length > 0 )
+ {
+ this.bMatchBegin = eval( sMatchBegin )
+ }
+ //match substrings separated by cAutocomplete.CS_SEPARATOR
+ this.bMatchSubstring = cAutocomplete.CB_MATCHSUBSTRING
+ var sMatchSubstring = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_matchsubstring' )
+ if( sMatchSubstring != null && sMatchSubstring.length > 0 )
+ {
+ this.bMatchSubstring = true
+ }
+
+ //autocomplete with the first option from the list
+ this.bAutoComplete = cAutocomplete.CB_AUTOCOMPLETE
+ this.bAutocompleted = false
+ var sAutoComplete = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_complete' )
+ if( sAutoComplete != null && sAutoComplete.length > 0 )
+ {
+ this.bAutoComplete = eval( sAutoComplete )
+ }
+ //format function
+ this.formatOptions = null
+ var sFormatFunction = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_format' )
+ if( sFormatFunction != null && sFormatFunction.length > 0 )
+ {
+ this.formatOptions = eval( sFormatFunction )
+ }
+ //onselect callback function - get called when a new option is selected
+ this.onSelect = null
+ var sOnSelectFunction = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_onselect' )
+ if( sOnSelectFunction != null && sOnSelectFunction.length > 0 )
+ {
+ this.onSelect = eval( sOnSelectFunction )
+ }
+
+ //I assume that we always have the associative type
+ //you can turn it off only with the autocomplete_assoc=false attribute
+ this.bAssociative = true
+ var sAssociative = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_assoc' )
+ if( sAssociative != null && sAssociative.length > 0 )
+ {
+ if( sAssociative == 'false' )
+ {
+ this.bAssociative = false
+ }
+ }
+
+ //if we have remote list then we postpone the list creation
+ if( this.getListArrayType() != 'url' )
+ {
+ this.bRemoteList = false
+ }
+ else
+ {
+ this.bRemoteList = true
+ this.sListURL = this.getListURL()
+ this.hXMLHttp = XmlHttp.create()
+ }
+ this.initListArray()
+ this.initListContainer()
+ //this.createList()
+ this.initInput()
+
+ eval( this.hObj + '= this' )
+}
+
+cAutocomplete.prototype.initInput = function()
+{
+ var hInput = document.getElementById( this.sInputId )
+ hInput.hAutocomplete = this
+ var hContainer = document.getElementById( this.sListId )
+ hContainer.hAutocomplete = this
+
+ //any element (and it's children) with display:none have offset values of 0 (in mozilla)
+ var hOWInput = hInput.cloneNode( true )
+ hOWInput.style.position = 'absolute'
+ hOWInput.style.top = '-1000px'
+ document.body.appendChild( hOWInput )
+ var nWidth = hOWInput.offsetWidth
+ document.body.removeChild( hOWInput )
+
+ var sInputName = hInput.name
+ var hForm = hInput.form
+ var bHasButton = false
+ var sHiddenValue = hInput.value
+ var sValue = hInput.type.toLowerCase() == 'text' ? hInput.value : ''
+
+ var sHasButton = hInput.getAttribute( 'autocomplete_button' )
+ if( sHasButton != null && sHasButton.length > 0 )
+ {
+ bHasButton = true
+ }
+
+ //if it is a select - I unconditionally add a button
+ if( hInput.type.toLowerCase() == 'select-one' )
+ {
+ bHasButton = true
+ if( hInput.selectedIndex >= 0 )
+ {
+ sHiddenValue = hInput.options[ hInput.selectedIndex ].value
+ sValue = hInput.options[ hInput.selectedIndex ].text
+ }
+ }
+
+ //this is the case when the control is a transformed select or the list supplied is of the type - key,value not only values
+ if( hForm )
+ {
+ var hHiddenInput = document.createElement( 'INPUT' )
+ hHiddenInput.id = cAutocomplete.CS_HIDDEN_INPUT_PREFIX + this.sInputId
+ hHiddenInput.type = 'hidden'
+ hForm.appendChild( hHiddenInput )
+
+ if( this.bAssociative )
+ {
+ hHiddenInput.name = sInputName
+ hInput.name = cAutocomplete.CS_INPUT_PREFIX + sInputName
+ }
+ else
+ {
+ hHiddenInput.name = cAutocomplete.CS_INPUT_PREFIX + sInputName
+ }
+
+ hHiddenInput.value = sHiddenValue
+ this.sHiddenInputId = hHiddenInput.id
+ }
+
+ if( bHasButton )
+ {
+ this.bHasButton = true
+
+ var hInputContainer = document.createElement( 'DIV' )
+ hInputContainer.className = 'acinputContainer'
+ hInputContainer.style.width = nWidth
+
+ var hInputButton = document.createElement( 'INPUT' )
+ hInputButton.id = cAutocomplete.CS_BUTTON_PREFIX + this.sInputId
+ hInputButton.type = 'button'
+ hInputButton.className = 'button'
+ hInputButton.tabIndex = hInput.tabIndex + 1
+ hInputButton.hAutocomplete = this
+
+ var hNewInput = document.createElement( 'INPUT' )
+ if( this.bAssociative )
+ {
+ hNewInput.name = cAutocomplete.CS_INPUT_PREFIX + sInputName
+ }
+ else
+ {
+ hNewInput.name = sInputName
+ }
+
+ hNewInput.type = 'text'
+ hNewInput.value = sValue
+ hNewInput.style.width = nWidth-20
+ hNewInput.className = cAutocomplete.CS_INPUT_CLASSNAME
+ hNewInput.tabIndex = hInput.tabIndex
+ hNewInput.hAutocomplete = this
+
+ hInputContainer.appendChild( hNewInput )
+ hInputContainer.appendChild( hInputButton )
+
+ hInput.parentNode.replaceChild( hInputContainer, hInput )
+
+ hNewInput.id = this.sInputId
+ hInput = hNewInput
+ }
+
+ if( hInput.attachEvent )
+ {
+ hInput.attachEvent( 'onkeyup', cAutocomplete.onInputKeyUp )
+ hInput.attachEvent( 'onkeyup', cAutocomplete.saveCaretPosition )
+ hInput.attachEvent( 'onkeydown', cAutocomplete.onInputKeyDown )
+ hInput.attachEvent( 'onblur', cAutocomplete.onInputBlur )
+ hInput.attachEvent( 'onfocus', cAutocomplete.onInputFocus )
+
+ if( hInputButton )
+ {
+ hInputButton.attachEvent( 'onclick', cAutocomplete.onButtonClick )
+ }
+ }
+ else if( hInput.addEventListener )
+ {
+ hInput.addEventListener( 'keyup', cAutocomplete.onInputKeyUp, false )
+ hInput.addEventListener( 'keyup', cAutocomplete.saveCaretPosition, false )
+ hInput.addEventListener( 'keydown', cAutocomplete.onInputKeyDown, false )
+ hInput.addEventListener( 'keypress', cAutocomplete.onInputKeyPress, false )
+ hInput.addEventListener( 'blur', cAutocomplete.onInputBlur, false )
+ hInput.addEventListener( 'focus', cAutocomplete.onInputFocus, false )
+
+ if( hInputButton )
+ {
+ hInputButton.addEventListener( 'click', cAutocomplete.onButtonClick, false )
+ }
+ }
+
+ //I don't need the standard autocomplete
+ hInput.setAttribute( 'autocomplete', 'OFF' )
+
+ if( hForm )
+ {
+ if( hForm.attachEvent )
+ {
+ hForm.attachEvent( 'onsubmit', cAutocomplete.onFormSubmit )
+ }
+ else if( hForm.addEventListener )
+ {
+ hForm.addEventListener( 'submit', cAutocomplete.onFormSubmit, false )
+ }
+ }
+}
+
+cAutocomplete.prototype.initListContainer = function()
+{
+ var hInput = document.getElementById( this.sInputId )
+ var hContainer = document.createElement( 'DIV' )
+ hContainer.className = 'autocomplete_holder'
+ hContainer.id = this.sListId
+ hContainer.style.zIndex = 10000 + cAutocomplete.nCount
+ hContainer.hAutocomplete = this
+
+ var hFirstBorder = document.createElement( 'DIV' )
+ hFirstBorder.className = 'autocomplete_firstborder'
+ var hSecondBorder = document.createElement( 'DIV' )
+ hSecondBorder.className = 'autocomplete_secondborder'
+
+ var hList = document.createElement( 'UL' )
+ hList.className = 'autocomplete'
+
+ hSecondBorder.appendChild( hList )
+ hFirstBorder.appendChild( hSecondBorder )
+ hContainer.appendChild( hFirstBorder )
+ document.body.appendChild( hContainer )
+
+ if( hContainer.attachEvent )
+ {
+ hContainer.attachEvent( 'onblur', cAutocomplete.onListBlur )
+ hContainer.attachEvent( 'onfocus', cAutocomplete.onListFocus )
+ }
+ else if( hInput.addEventListener )
+ {
+ hContainer.addEventListener( 'blur', cAutocomplete.onListBlur, false )
+ hContainer.addEventListener( 'focus', cAutocomplete.onListFocus, false )
+ }
+
+
+ if( hContainer.attachEvent )
+ {
+ hContainer.attachEvent( 'onclick', cAutocomplete.onItemClick )
+ }
+ else if( hContainer.addEventListener )
+ {
+ hContainer.addEventListener( 'click', cAutocomplete.onItemClick, false )
+ }
+}
+
+cAutocomplete.prototype.createList = function()
+{
+ var hInput = document.getElementById( this.sInputId )
+ var hContainer = document.getElementById( this.sListId )
+ var hList = hContainer.getElementsByTagName( 'UL' )[0]
+ if( hList )
+ {
+ hList = hList.parentNode.removeChild( hList )
+ while( hList.hasChildNodes() )
+ {
+ hList.removeChild( hList.childNodes[ 0 ] )
+ }
+ }
+
+ var hListItem = null
+ var hListItemLink = null
+ var hArrKey = null
+ var sArrEl = null
+
+ var hArr = this.aData
+ var nI = 0
+ for( hArrKey in hArr )
+ {
+ sArrEl = hArr[ hArrKey ]
+ hListItem = document.createElement( 'LI' )
+ hListItemLink = document.createElement( 'A' )
+ hListItemLink.setAttribute( 'itemvalue', hArrKey )
+ hListItemLink.href = '#'
+ hListItemLink.appendChild( document.createTextNode( sArrEl ) )
+ hListItemLink.realText = sArrEl
+ if( nI == this.nSelectedItemIdx )
+ {
+ this.hActiveSelection = hListItemLink
+ this.hActiveSelection.className = 'selected'
+ }
+ hListItem.appendChild( hListItemLink )
+ hList.appendChild( hListItem )
+ this.aSearchData[ nI++ ] = sArrEl.toLowerCase()
+ }
+ var hSecondBorder = hContainer.firstChild.firstChild
+ hSecondBorder.appendChild( hList )
+ this.bListUpdated = false
+}
+
+/* list array functions */
+
+cAutocomplete.prototype.initListArray = function()
+{
+ var hInput = document.getElementById( this.sInputId )
+ var hArr = null
+
+ if( hInput.type.toLowerCase() == 'select-one' )
+ {
+ hArr = new Object()
+ for( var nI = 0; nI < hInput.options.length; nI++ )
+ {
+ hArrKey = hInput.options.item( nI ).value
+ sArrEl = hInput.options.item( nI ).text
+ hArr[ hArrKey ] = sArrEl
+ if( hInput.options.item( nI ).selected )
+ {
+ this.nSelectedItemIdx = nI
+ }
+ }
+ }
+ else
+ {
+ var sAA = hInput.getAttribute( 'autocomplete_list' )
+ var sAAS = hInput.getAttribute( 'autocomplete_list_sort' )
+
+ var sArrayType = this.getListArrayType()
+
+ switch( sArrayType )
+ {
+ case 'array' : hArr = eval( sAA.substring( 6 ) )
+ break
+
+ case 'list' : hArr = new Array()
+ var hTmpArray = sAA.substring( 5 ).split( '|' )
+ var aValueArr
+ for( hKey in hTmpArray )
+ {
+ aValueArr = hTmpArray[ hKey ].split( cAutocomplete.CS_ARRAY_SEPARATOR )
+ if( aValueArr.length == 1 )
+ {
+ hArr[ hKey ] = hTmpArray[ hKey ]
+ this.bAssociative = false
+ }
+ else
+ {
+ hArr[ aValueArr[ 0 ] ] = aValueArr[ 1 ]
+ }
+ }
+ break
+ }
+ if( sAAS != null && eval( sAAS ) )
+ {
+ this.bSorted = true
+ this.aData = hArr.sort()
+ hArr = hArr.sort()
+ }
+ }
+ this.setArray( hArr )
+}
+
+cAutocomplete.prototype.setArray = function( sArray )
+{
+ if( typeof sArray == 'string' )
+ {
+ this.aData = eval( sArray )
+ }
+ else
+ {
+ this.aData = sArray
+ }
+ this.bListUpdated = true
+}
+
+//use this function to change the list of autocomplete values to a new one
+//supply as an argument the name as a literal of an JS array object
+//well things changed - you can supply an actual array too
+cAutocomplete.prototype.setListArray = function( sArray )
+{
+ this.setArray( sArray )
+ this.updateAndShowList()
+}
+
+cAutocomplete.prototype.getListArrayType = function()
+{
+ var hInput = document.getElementById( this.sInputId )
+ var sAA = hInput.getAttribute( 'autocomplete_list' )
+ if( sAA != null && sAA.length > 0 )
+ {
+ if( sAA.indexOf( 'array:' ) >= 0 )
+ {
+ return 'array'
+ }
+ else if( sAA.indexOf( 'list:' ) >= 0 )
+ {
+ return 'list'
+ }
+ else if( sAA.indexOf( 'url:' ) >= 0 )
+ {
+ return 'url'
+ }
+ }
+}
+
+cAutocomplete.prototype.getListURL = function()
+{
+ var hInput = document.getElementById( this.sInputId )
+ var sAA = hInput.getAttribute( 'autocomplete_list' )
+ if( sAA != null && sAA.length > 0 )
+ {
+ if( sAA.indexOf( 'url:' ) >= 0 )
+ {
+ return sAA.substring( 4 )
+ }
+ }
+}
+
+cAutocomplete.prototype.setListURL = function( sURL )
+{
+ this.sListURL = sURL;
+}
+
+cAutocomplete.onXmlHttpLoad = function( hThis )
+{
+ if( hThis.hXMLHttp.readyState == 4 )
+ {
+ var hError = hThis.hXMLHttp.parseError
+ if( hError && hError.errorCode != 0 )
+ {
+ alert( hError.reason )
+ }
+ else
+ {
+ hThis.afterRemoteLoad()
+ }
+ }
+}
+
+cAutocomplete.prototype.loadListArray = function()
+{
+ var sURL = this.sListURL
+ var sStartWith = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint )
+ sStartWith = sStartWith.replace( /^\s/, '' )
+ sStartWith = sStartWith.replace( /\s$/, '' )
+ if( sURL.indexOf( '[S]' ) >= 0 )
+ {
+ sURL = sURL.replace( '[S]', sStartWith )
+ }
+ else
+ {
+ sURL += this.sActiveValue
+ }
+ this.hXMLHttp.open( 'GET', sURL, true )
+ this.hXMLHttp.onreadystatechange = new Function( 'var sAC = "'+this.sObjName+'"; cAutocomplete.onXmlHttpLoad( eval( sAC ) )' )
+ this.hXMLHttp.send( null )
+}
+
+cAutocomplete.prototype.afterRemoteLoad = function()
+{
+ var hInput = document.getElementById( this.sInputId )
+
+ var hArr = new Array()
+ var hTmpArray = this.hXMLHttp.responseText.split( '|' )
+ var aValueArr
+ for( hKey in hTmpArray )
+ {
+ aValueArr = hTmpArray[ hKey ].split( cAutocomplete.CS_ARRAY_SEPARATOR )
+ if( aValueArr.length == 1 )
+ {
+ hArr[ hKey ] = hTmpArray[ hKey ]
+ }
+ else
+ {
+ hArr[ aValueArr[ 0 ] ] = aValueArr[ 1 ]
+ }
+ }
+
+ hInput.className = ''
+ hInput.readonly = false
+ hInput.value = this.sActiveValue
+ this.setListArray( hArr )
+}
+
+/**/
+
+cAutocomplete.prototype.prepareList = function( bFullList )
+{
+ var hInput = document.getElementById( this.sInputId )
+ this.sActiveValue = hInput.value
+
+ //check if this was invoked by a key that did not change the value
+ var sST = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint )
+ var sLST = this.getStringForAutocompletion( this.sLastActiveValue, this.nInsertPoint )
+
+ if( sLST != sST || bFullList || !this.bListDisplayed || this.bMatchSubstring )
+ {
+ if( this.bRemoteList )
+ {
+ hInput.className = 'search'
+ hInput.readonly = true
+ hInput.value = 'plase wait...'
+ this.loadListArray()
+ return
+ }
+ this.updateAndShowList( bFullList )
+ }
+}
+
+cAutocomplete.prototype.updateAndShowList = function( bFullList )
+{
+ var hContainer = document.getElementById( this.sListId )
+ var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ]
+ var hInput = document.getElementById( this.sInputId )
+
+ if( this.bListUpdated )
+ {
+ this.createList()
+ }
+
+ //stupid hack just for speed
+ var sST = this.bMatchSubstring ? this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint ) : this.sActiveValue
+ var sLST = this.bMatchSubstring ? this.getStringForAutocompletion( this.sLastActiveValue, this.nInsertPoint ) : this.sLastActiveValue
+
+ //nothing changed since last type - maybe only function keys were pressed
+ //this is the case when for example the down key was pressed
+ if( sST == sLST )
+ {
+ if( !this.bMatchSubstring )
+ {
+ bFullList = true
+ }
+ }
+ this.filterOptions( bFullList )
+
+ if( this.nItemsDisplayed == 0 )
+ {
+ if( this.bForceCorrect )
+ {
+ var aPos = this.getInsertPos( this.sActiveValue, this.nInsertPoint, '' )
+ cAutocomplete.markInputRange( hInput, this.nLastMatchLength, aPos[0] )
+ }
+ }
+
+ this.sLastActiveValue = this.sActiveValue
+
+ if( this.nItemsDisplayed > 0 )
+ {
+ if( !bFullList || this.bMatchSubstring )
+ {
+ this.deselectOption()
+ }
+ if( this.bAutoComplete && this.nItemsDisplayed == 1 )
+ {
+ //test if we have a full match i.e. the user typed the entire value
+ var sStartWith = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint )
+ var sItemText = hList.getElementsByTagName( 'LI' )[ this.nFirstDisplayed ].getElementsByTagName( 'A' )[ 0 ].realText
+ if( sStartWith.toLowerCase() == sItemText.toLowerCase() )
+ {
+ this.selectOption( hList.getElementsByTagName( 'LI' )[ this.nFirstDisplayed ].getElementsByTagName( 'A' )[ 0 ] )
+ this.hideOptions()
+ //and do not show the list
+ return
+ }
+ }
+ if( this.bAutoComplete && !bFullList )
+ {
+ this.selectOption( hList.getElementsByTagName( 'LI' )[ this.nFirstDisplayed ].getElementsByTagName( 'A' )[ 0 ] )
+ }
+ this.showList()
+ }
+ else
+ {
+ this.clearList()
+ }
+}
+
+cAutocomplete.prototype.showList = function()
+{
+ if( cAutocomplete.hListDisplayed )
+ {
+ cAutocomplete.hListDisplayed.clearList()
+ }
+ var hInput = document.getElementById( this.sInputId )
+ var nTop = cDomObject.getOffsetParam( hInput, 'offsetTop' )
+ var nLeft = cDomObject.getOffsetParam( hInput, 'offsetLeft' )
+ var hContainer = document.getElementById( this.sListId )
+
+ var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ]
+ if( this.bHasButton )
+ {
+ hContainer.style.width = document.getElementById( this.sInputId ).parentNode.offsetWidth
+ }
+ else
+ {
+ hContainer.style.width = document.getElementById( this.sInputId ).offsetWidth
+ }
+ var nNumLines = ( this.nItemsDisplayed < cAutocomplete.CN_NUMBER_OF_LINES ) ? this.nItemsDisplayed : cAutocomplete.CN_NUMBER_OF_LINES;
+ hList.style.height = nNumLines * cAutocomplete.CN_LINE_HEIGHT + cAutocomplete.CN_HEIGHT_FIX + 'px'
+
+ hContainer.style.top = nTop + hInput.offsetHeight + cAutocomplete.CN_OFFSET_TOP + 'px'
+ hContainer.style.left = nLeft + cAutocomplete.CN_OFFSET_LEFT + 'px'
+
+ hContainer.style.display = 'none'
+ hContainer.style.visibility = 'visible'
+ hContainer.style.display = 'block'
+
+ cAutocomplete.hListDisplayed = this
+ this.bListDisplayed = true
+}
+
+cAutocomplete.prototype.binarySearch = function( sFilter )
+{
+ var nLow = 0
+ var nHigh = this.aSearchData.length - 1
+ var nMid
+ var nTry, nLastTry
+ var sData
+ var nLen = sFilter.length
+
+ var lastTry
+
+ while ( nLow <= nHigh )
+ {
+ nMid = ( nLow + nHigh ) / 2
+ nTry = ( nMid < 1 ) ? 0 : parseInt( nMid )
+
+ sData = this.aSearchData[ nTry ].substr( 0, nLen )
+
+ if ( sData < sFilter )
+ {
+ nLow = nTry + 1
+ continue
+ }
+ if ( sData > sFilter )
+ {
+ nHigh = nTry - 1
+ continue
+ }
+ if ( sData == sFilter )
+ {
+ nHigh = nTry - 1
+ nLastTry = nTry
+ continue
+ }
+ return nTry
+ }
+
+ if ( typeof ( nLastTry ) != "undefined" )
+ {
+ return nLastTry
+ }
+ else
+ {
+ return null
+ }
+}
+
+cAutocomplete.prototype.getStringForAutocompletion = function( sString, nPos )
+{
+ if( sString == null || sString.length == 0 )
+ {
+ return ''
+ }
+ if( this.bMatchSubstring )
+ {
+ var nStartPos = sString.lastIndexOf( cAutocomplete.CS_SEPARATOR, nPos - 1 )
+ nStartPos = nStartPos < 0 ? 0 : nStartPos
+ var nEndPos = sString.indexOf( cAutocomplete.CS_SEPARATOR, nPos )
+ nEndPos = nEndPos < 0 ? sString.length : nEndPos
+ var sStr = sString.substr( nStartPos, nEndPos - nStartPos )
+ sStr = sStr.replace( /^(\,?)(\s*)(\S*)(\s*)(\,?)$/g, '$3' )
+ return sStr
+ }
+ else
+ {
+ return sString
+ }
+}
+
+cAutocomplete.prototype.insertString = function( sString, nPos, sInsert )
+{
+ if( this.bMatchSubstring )
+ {
+ var nStartPos = sString.lastIndexOf( cAutocomplete.CS_SEPARATOR, nPos - 1 )
+ nStartPos = nStartPos < 0 ? 0 : nStartPos
+ var nEndPos = sString.indexOf( cAutocomplete.CS_SEPARATOR, nPos )
+ nEndPos = nEndPos < 0 ? sString.length : nEndPos
+ var sStr = sString.substr( nStartPos, nEndPos - nStartPos )
+ sStr = sStr.replace( /^(\,?)(\s*)(\S?[\S\s]*\S?)(\s*)(\,?)$/g, '$1$2'+sInsert+'$4$5' )
+ sStr = sString.substr( 0, nStartPos ) + sStr + sString.substr( nEndPos )
+ return sStr
+ }
+ else
+ {
+ return sInsert
+ }
+}
+
+cAutocomplete.prototype.getInsertPos = function( sString, nPos, sInsert )
+{
+ nPos = nPos == null ? 0 : nPos
+ var nStartPos = sString.lastIndexOf( cAutocomplete.CS_SEPARATOR, nPos - 1 )
+ nStartPos = nStartPos < 0 ? 0 : nStartPos
+ var nEndPos = sString.indexOf( cAutocomplete.CS_SEPARATOR, nPos )
+ nEndPos = nEndPos < 0 ? sString.length : nEndPos
+ var sStr = sString.substr( nStartPos, nEndPos - nStartPos )
+ sStr = sStr.replace( /^(\,?)(\s*)(\S?[\S\s]*\S?)(\s*)(\,?)$/g, '$1$2'+sInsert )
+ return [ nPos, nStartPos + sStr.length ]
+}
+
+cAutocomplete.prototype.filterOptions = function( bShowAll )
+{
+ if( this.hActiveSelection && !bShowAll )
+ {
+ this.hActiveSelection.className = ''
+ }
+ if( typeof bShowAll == 'undefined' )
+ {
+ bShowAll = false
+ }
+
+ var hInput = document.getElementById( this.sInputId )
+
+ var sStartWith = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint )
+ if( bShowAll )
+ {
+ sStartWith = ''
+ }
+
+ var hContainer = document.getElementById( this.sListId )
+ var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ]
+ var nItemsLength = hList.childNodes.length
+ var hLinkItem = null
+ var nCount = 0
+
+ var hParent = hList.parentNode
+ var hList = hList.parentNode.removeChild( hList )
+ var hTItems = hList.childNodes
+
+ this.nItemsDisplayed = 0
+
+ if( sStartWith.length == 0 )
+ {
+ for( var nI = 0; nI < nItemsLength; nI++ )
+ {
+ if( this.formatOptions )
+ {
+ hTItems[ nI ].childNodes[0].innerHTML = this.formatOptions( hTItems[ nI ].childNodes[0].realText, nI )
+ }
+ hTItems[ nI ].style.display = 'block'
+ }
+
+ nCount = nItemsLength
+
+ if( nItemsLength > 0 )
+ {
+ this.nFirstDisplayed = 0
+ this.nLastDisplayed = nItemsLength - 1
+ }
+ else
+ {
+ this.nFirstDisplayed = this.nLastDisplayed = -1
+ }
+
+ //this.nLastMatchLength = 0
+ var aPos = this.getInsertPos( this.sActiveValue, this.nInsertPoint, sStartWith )
+ this.nLastMatchLength = aPos[0]
+ }
+ else
+ {
+ this.nFirstDisplayed = this.nLastDisplayed = -1
+ sStartWith = sStartWith.toLowerCase()
+ var bEnd = false
+ if( this.bSorted && this.bMatchBegin )
+ {
+ var nStartAt = this.binarySearch( sStartWith )
+ for( var nI = 0; nI < nItemsLength; nI++ )
+ {
+ hTItems[ nI ].style.display = 'none'
+ if( nI >= nStartAt && !bEnd )
+ {
+ if( !bEnd && this.aSearchData[ nI ].indexOf( sStartWith ) != 0 )
+ {
+ bEnd = true
+ continue
+ }
+ if( this.formatOptions )
+ {
+ hTItems[ nI ].childNodes[0].innerHTML = this.formatOptions( hTItems[ nI ].childNodes[0].realText, nI )
+ }
+ hTItems[ nI ].style.display = 'block'
+ nCount++
+ if( this.nFirstDisplayed < 0 )
+ {
+ this.nFirstDisplayed = nI
+ }
+ this.nLastDisplayed = nI
+ }
+ }
+ }
+ else
+ {
+ for( var nI = 0; nI < nItemsLength; nI++ )
+ {
+ hTItems[ nI ].style.display = 'none'
+ if( ( this.bMatchBegin && this.aSearchData[ nI ].indexOf( sStartWith ) == 0 ) || ( !this.bMatchBegin && this.aSearchData[ nI ].indexOf( sStartWith ) >= 0 ) )
+ {
+ if( this.formatOptions )
+ {
+ hTItems[ nI ].childNodes[0].innerHTML = this.formatOptions( hTItems[ nI ].childNodes[0].realText, nI )
+ }
+ hTItems[ nI ].style.display = 'block'
+ nCount++
+ if( this.nFirstDisplayed < 0 )
+ {
+ this.nFirstDisplayed = nI
+ }
+ this.nLastDisplayed = nI
+ }
+ }
+ }
+
+ if( nCount > 0 )
+ {
+ //this.nLastMatchLength = this.sActiveValue.length
+ var aPos = this.getInsertPos( this.sActiveValue, this.nInsertPoint, sStartWith )
+ this.nLastMatchLength = aPos[0]
+ }
+ }
+ hParent.appendChild( hList )
+ this.nItemsDisplayed = nCount
+}
+
+cAutocomplete.prototype.hideOptions = function()
+{
+ var hContainer = document.getElementById( this.sListId )
+ hContainer.style.visibility = 'hidden'
+ cAutocomplete.hListDisplayed = null
+}
+
+cAutocomplete.prototype.markAutocompletedValue = function()
+{
+ var hInput = document.getElementById( this.sInputId )
+ var sValue = this.hActiveSelection.realText
+ if( this.bMatchSubstring )
+ {
+ var aPos = this.getInsertPos( this.sLastActiveValue, this.nInsertPoint, sValue )
+ var nStartPos = aPos[ 0 ]
+ var nEndPos = aPos[ 1 ]
+ }
+ else
+ {
+ var nStartPos = this.nInsertPoint
+ var nEndPos = sValue.length
+ }
+ this.nStartAC = nStartPos
+ this.nEndAC = nEndPos
+
+ if( this.hMarkRangeTimeout != null )
+ {
+ clearTimeout( this.hMarkRangeTimeout )
+ }
+ this.hMarkRangeTimeout = setTimeout( 'cAutocomplete.markInputRange2("'+hInput.id+'")', cAutocomplete.CN_MARK_TIMEOUT )
+ //cAutocomplete.markInputRange( hInput, nStartPos, nEndPos )
+}
+
+cAutocomplete.prototype.selectOptionByIndex = function( nOptionIndex )
+{
+ if( this.bListUpdated )
+ {
+ this.createList()
+ }
+
+ var hContainer = document.getElementById( this.sListId )
+ var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ]
+ var nItemsLength = hList.childNodes.length
+ if( nOptionIndex >=0 && nOptionIndex < nItemsLength )
+ {
+ this.selectOption( hList.childNodes[ nOptionIndex ].getElementsByTagName( 'A' )[ 0 ] )
+ }
+}
+
+cAutocomplete.prototype.selectOption = function( hNewOption )
+{
+ if( this.hActiveSelection )
+ {
+ if( this.hActiveSelection == hNewOption )
+ {
+ return
+ }
+ else
+ {
+ this.hActiveSelection.className = ''
+ }
+ }
+ this.hActiveSelection = hNewOption
+ var hInput = document.getElementById( this.sInputId )
+ if( this.hActiveSelection != null )
+ {
+ if( this.sHiddenInputId != null )
+ {
+ if( this.bMatchSubstring )
+ {
+ document.getElementById( this.sHiddenInputId ).value = this.hActiveSelection.getAttribute( 'itemvalue' )
+ }
+ else
+ {
+ document.getElementById( this.sHiddenInputId ).value = this.hActiveSelection.getAttribute( 'itemvalue' )
+ }
+ }
+
+ this.hActiveSelection.className = 'selected'
+ if( this.bAutoComplete )
+ {
+ hInput.value = this.insertString( this.sLastActiveValue, this.nInsertPoint, this.hActiveSelection.realText )
+ this.bAutocompleted = true
+ this.markAutocompletedValue()
+ }
+ else
+ {
+ hInput.value = this.insertString( this.sActiveValue, this.nInsertPoint, this.hActiveSelection.realText )
+ cAutocomplete.setInputCaretPosition( hInput, this.nInsertPoint )
+ }
+
+ this.sActiveValue = hInput.value
+
+ if( this.onSelect )
+ {
+ this.onSelect()
+ }
+ }
+ else
+ {
+ hInput.value = this.sActiveValue
+ cAutocomplete.setInputCaretPosition( hInput, this.nInsertPoint )
+ }
+}
+
+cAutocomplete.prototype.deselectOption = function( )
+{
+ if( this.hActiveSelection != null )
+ {
+ this.hActiveSelection.className = ''
+ this.hActiveSelection = null
+ }
+}
+
+cAutocomplete.prototype.clearList = function()
+{
+ //this.deselectOption()
+ this.hideOptions()
+ this.bListDisplayed = false
+}
+
+cAutocomplete.prototype.getPrevDisplayedItem = function( hItem )
+{
+ if( hItem == null )
+ {
+ var hContainer = document.getElementById( this.sListId )
+ hItem = hContainer.getElementsByTagName( 'UL' )[ 0 ].childNodes.item( hContainer.getElementsByTagName( 'UL' )[ 0 ].childNodes.length - 1 )
+ }
+ else
+ {
+ hItem = getPrevNodeSibling( hItem.parentNode )
+ }
+ while( hItem != null )
+ {
+ if( hItem.style.display == 'block' )
+ {
+ return hItem
+ }
+ hItem = hItem.previousSibling
+ }
+ return null
+}
+
+cAutocomplete.prototype.getNextDisplayedItem = function( hItem )
+{
+ if( hItem == null )
+ {
+ var hContainer = document.getElementById( this.sListId )
+ hItem = hContainer.getElementsByTagName( 'UL' )[ 0 ].childNodes.item( 0 )
+ }
+ else
+ {
+ hItem = getNextNodeSibling( hItem.parentNode )
+ }
+ while( hItem != null )
+ {
+ if( hItem.style.display == 'block' )
+ {
+ return hItem
+ }
+ hItem = hItem.nextSibling
+ }
+ return null
+}
+
+cAutocomplete.onInputKeyDown = function ( hEvent )
+{
+ if( hEvent == null )
+ {
+ hEvent = window.event
+ }
+ var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
+ var hAC = hElement.hAutocomplete
+ var hContainer = document.getElementById( hAC.sListId )
+ var hInput = document.getElementById( hAC.sInputId )
+ var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ]
+ var hEl = getParentByTagName( hElement, 'A' )
+ if( hContainer != null && hAC.bListDisplayed )
+ {
+ var hLI = null
+ var hLINext = null
+ //the new active selection
+ if( ( hEvent.keyCode == 13 ) || ( hEvent.keyCode == 27 ) )
+ {
+ var bItemSelected = hEvent.keyCode == 13 ? true : false
+ hAC.clearList()
+ }
+ if( hEvent.keyCode == 38 )
+ {
+ //up key pressed
+ hLINext = hAC.getPrevDisplayedItem( hAC.hActiveSelection )
+ if( hLINext != null )
+ {
+ hAC.selectOption( hLINext.childNodes.item(0) )
+ if( hAC.nItemsDisplayed > cAutocomplete.CN_NUMBER_OF_LINES )
+ {
+ if( hList.scrollTop < 5 && hLINext.offsetTop > hList.offsetHeight )
+ {
+ hList.scrollTop = hList.scrollHeight - hList.offsetHeight
+ }
+ if( hLINext.offsetTop - hList.scrollTop < 0 )
+ {
+ hList.scrollTop -= hLINext.offsetHeight
+ }
+ }
+ }
+ else
+ {
+ hAC.selectOption( null )
+ }
+ }
+ else if ( hEvent.keyCode == 40 )
+ {
+ //down key pressed
+ hLINext = hAC.getNextDisplayedItem( hAC.hActiveSelection )
+ if( hLINext != null )
+ {
+ hAC.selectOption( hLINext.childNodes.item(0) )
+ if( hAC.nItemsDisplayed > cAutocomplete.CN_NUMBER_OF_LINES )
+ {
+ if( hList.scrollTop > 0 && hList.scrollTop > hLINext.offsetTop )
+ {
+ hList.scrollTop = 0
+ }
+ if( Math.abs( hLINext.offsetTop - hList.scrollTop - hList.offsetHeight ) < 5 )
+ {
+ hList.scrollTop += hLINext.offsetHeight
+ }
+ }
+ }
+ else
+ {
+ hAC.selectOption( null )
+ }
+ }
+ }
+ if( hInput.form )
+ {
+ hInput.form.bLocked = true
+ }
+ if ( hEvent.keyCode == 13 || hEvent.keyCode == 27 )
+ {
+ if( hEvent.preventDefault )
+ {
+ hEvent.preventDefault()
+ }
+ hEvent.cancelBubble = true
+ hEvent.returnValue = false
+ return false
+ }
+}
+
+cAutocomplete.onInputKeyPress = function ( hEvent )
+{
+ if ( hEvent.keyCode == 13 )
+ {
+ if( hEvent.preventDefault )
+ {
+ hEvent.preventDefault()
+ }
+ hEvent.cancelBubble = true
+ hEvent.returnValue = false
+ return false
+ }
+}
+
+cAutocomplete.onInputKeyUp = function ( hEvent )
+{
+ if( hEvent == null )
+ {
+ hEvent = window.event
+ }
+ var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
+ var hAC = hElement.hAutocomplete
+ var hInput = document.getElementById( hAC.sInputId )
+ //if we press the keys for up down enter or escape skip showing the list
+ switch( hEvent.keyCode )
+ {
+ case 8 : if( hAC.bAutoComplete && hAC.bAutocompleted )
+ {
+ hAC.bAutocompleted = false
+ return false
+ }
+ break
+ case 38 :
+ case 40 : if( hAC.bListDisplayed )
+ {
+ if( hEvent.preventDefault )
+ {
+ hEvent.preventDefault()
+ }
+ hEvent.cancelBubble = true
+ hEvent.returnValue = false
+ return false
+ }
+ break
+ case 32 :
+ case 46 :
+ case 37 :
+ case 39 :
+ case 35 :
+ case 36 : break;
+ default : if( hEvent.keyCode < 48 )
+ {
+ if( hEvent.preventDefault )
+ {
+ hEvent.preventDefault()
+ }
+ hEvent.cancelBubble = true
+ hEvent.returnValue = false
+ return false
+ }
+ break
+ }
+
+ if( this.hMarkRangeTimeout != null )
+ {
+ clearTimeout( this.hMarkRangeTimeout )
+ }
+
+ if( hAC.hShowTimeout )
+ {
+ clearTimeout( hAC.hShowTimeout )
+ hAC.hShowTimeout = null
+ }
+ var nTimeout = this.bRemoteList ? cAutocomplete.CN_REMOTE_SHOW_TIMEOUT : cAutocomplete.CN_SHOW_TIMEOUT
+ hAC.hShowTimeout = setTimeout( hAC.hObj+'.prepareList()', nTimeout )
+}
+
+cAutocomplete.onInputBlur = function( hEvent )
+{
+ if( hEvent == null )
+ {
+ hEvent = window.event
+ }
+ var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
+ if( hElement.form )
+ {
+ hElement.form.bLocked = false
+ }
+ var hAC = hElement.hAutocomplete
+ if( !hAC.hClearTimeout )
+ {
+ hAC.hClearTimeout = setTimeout( hAC.hObj+'.clearList()', cAutocomplete.CN_CLEAR_TIMEOUT )
+ }
+}
+
+cAutocomplete.onInputFocus = function( hEvent )
+{
+ if( hEvent == null )
+ {
+ hEvent = window.event
+ }
+ var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
+ var hAC = hElement.hAutocomplete
+ if( hAC.hClearTimeout )
+ {
+ clearTimeout( hAC.hClearTimeout )
+ hAC.hClearTimeout = null
+ }
+}
+
+cAutocomplete.saveCaretPosition = function( hEvent )
+{
+ if( hEvent == null )
+ {
+ hEvent = window.event
+ }
+ var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
+ var hAC = hElement.hAutocomplete
+ var hInput = document.getElementById( hAC.sInputId )
+
+ //there is something weird about hitting up and down keys in a textarea
+ if( hEvent.keyCode != 38 && hEvent.keyCode != 40 )
+ {
+ hAC.nInsertPoint = cAutocomplete.getInputCaretPosition( hInput )
+ }
+}
+
+cAutocomplete.getInputCaretPosition = function( hInput )
+{
+ if( typeof hInput.selectionStart != 'undefined' )
+ {
+ if( hInput.selectionStart == hInput.selectionEnd )
+ {
+ return hInput.selectionStart
+ }
+ else
+ {
+ return hInput.selectionStart
+ }
+ }
+ else if( hInput.createTextRange )
+ {
+ var hSelRange = document.selection.createRange()
+ if( hInput.tagName.toLowerCase() == 'textarea' )
+ {
+ var hSelBefore = hSelRange.duplicate()
+ var hSelAfter = hSelRange.duplicate()
+ hSelRange.moveToElementText( hInput )
+ hSelBefore.setEndPoint( 'StartToStart', hSelRange )
+ return hSelBefore.text.length
+ }
+ else
+ {
+ hSelRange.moveStart( 'character', -1*hInput.value.length )
+ var nLen = hSelRange.text.length
+ return nLen
+ }
+ }
+ return null
+}
+
+cAutocomplete.setInputCaretPosition = function( hInput, nPosition )
+{
+ if ( hInput.setSelectionRange )
+ {
+ hInput.setSelectionRange( nPosition ,nPosition )
+ }
+ else if ( hInput.createTextRange )
+ {
+ var hRange = hInput.createTextRange()
+ hRange.moveStart( 'character', nPosition )
+ hRange.moveEnd( 'character', nPosition )
+ hRange.collapse(true)
+ hRange.select()
+ }
+}
+
+cAutocomplete.markInputRange = function( hInput, nStartPos, nEndPos )
+{
+ if( hInput.setSelectionRange )
+ {
+ hInput.focus()
+ hInput.setSelectionRange( nStartPos, nEndPos )
+ }
+ else if( hInput.createTextRange )
+ {
+ var hRange = hInput.createTextRange()
+ hRange.collapse(true)
+ hRange.moveStart( 'character', nStartPos )
+ hRange.moveEnd( 'character', nEndPos - nStartPos )
+ hRange.select()
+ }
+}
+
+cAutocomplete.markInputRange2 = function( sInputId )
+{
+ var hInput = document.getElementById( sInputId )
+ var nStartPos = hInput.hAutocomplete.nStartAC
+ var nEndPos = hInput.hAutocomplete.nEndAC
+ cAutocomplete.markInputRange( hInput, nStartPos, nEndPos )
+}
+
+
+cAutocomplete.onListBlur = function( hEvent )
+{
+ if( hEvent == null )
+ {
+ hEvent = window.event
+ }
+ var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
+ hElement = getParentByProperty( hElement, 'className', 'autocomplete_holder' )
+ var hAC = hElement.hAutocomplete
+ if( !hAC.hClearTimeout )
+ {
+ hAC.hClearTimeout = setTimeout( hAC.hObj+'.clearList()', cAutocomplete.CN_CLEAR_TIMEOUT )
+ }
+}
+
+cAutocomplete.onListFocus = function( hEvent )
+{
+ if( hEvent == null )
+ {
+ hEvent = window.event
+ }
+ var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
+ hElement = getParentByProperty( hElement, 'className', 'autocomplete_holder' )
+ var hAC = hElement.hAutocomplete
+ if( hAC.hClearTimeout )
+ {
+ clearTimeout( hAC.hClearTimeout )
+ hAC.hClearTimeout = null
+ }
+}
+
+cAutocomplete.onItemClick = function( hEvent )
+{
+ if( hEvent == null )
+ {
+ hEvent = window.event
+ }
+ var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
+ var hContainer = getParentByProperty( hElement, 'className', 'autocomplete_holder' )
+ var hEl = getParentByTagName( hElement, 'A' )
+ if( hContainer != null )
+ {
+ var hAC = hContainer.hAutocomplete
+ hAC.selectOption( hEl )
+ document.getElementById( hAC.sInputId ).focus()
+ hAC.clearList()
+ }
+ if( hEvent.preventDefault )
+ {
+ hEvent.preventDefault()
+ }
+ hEvent.cancelBubble = true
+ hEvent.returnValue = false
+ return false
+}
+
+cAutocomplete.onButtonClick = function ( hEvent )
+{
+ if( hEvent == null )
+ {
+ hEvent = window.event
+ }
+ var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
+ var hAC = hElement.hAutocomplete
+ var hInput = document.getElementById( hAC.sInputId )
+ if( hInput.disabled )
+ {
+ return
+ }
+ hAC.prepareList( true )
+ var hInput = document.getElementById( hAC.sInputId )
+ hInput.focus()
+}
+
+cAutocomplete.onFormSubmit = function ( hEvent )
+{
+ if( hEvent == null )
+ {
+ hEvent = window.event
+ }
+ var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
+ if( hElement.bLocked )
+ {
+ hElement.bLocked = false
+ hEvent.returnValue = false
+ if( hEvent.preventDefault )
+ {
+ hEvent.preventDefault()
+ }
+ return false
+ }
+}
diff --git a/oss/vtiger/trunk/customerportal/js/cookies.js b/oss/vtiger/trunk/customerportal/js/cookies.js
new file mode 100644
index 00000000..e003e88b
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/js/cookies.js
@@ -0,0 +1,33 @@
+// Setting cookies
+function set_cookie ( name, value, exp_y, exp_m, exp_d, path, domain, secure )
+{
+ var cookie_string = name + "=" + escape ( value );
+
+ if (exp_y) //delete_cookie(name)
+ {
+ var expires = new Date ( exp_y, exp_m, exp_d );
+ cookie_string += "; expires=" + expires.toGMTString();
+ }
+
+ if (path) cookie_string += "; path=" + escape ( path );
+ if (domain) cookie_string += "; domain=" + escape ( domain );
+ if (secure) cookie_string += "; secure";
+
+ document.cookie = cookie_string;
+}
+
+// Retrieving cookies
+function get_cookie(cookie_name)
+{
+ var results = document.cookie.match(cookie_name + '=(.*?)(;|$)');
+ if (results) return (unescape(results[1]));
+ else return null;
+}
+
+// Delete cookies
+function delete_cookie( cookie_name )
+{
+ var cookie_date = new Date ( ); // current date & time
+ cookie_date.setTime ( cookie_date.getTime() - 1 );
+ document.cookie = cookie_name += "=; expires=" + cookie_date.toGMTString();
+}
\ No newline at end of file
diff --git a/oss/vtiger/trunk/customerportal/js/general.js b/oss/vtiger/trunk/customerportal/js/general.js
new file mode 100644
index 00000000..12b91cf3
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/js/general.js
@@ -0,0 +1,115 @@
+// JavaScript Document
+
+function fnLoadValues(obj){
+ window.location.href = "index.php?module="+obj+"&action=index";
+}
+
+function fnDown(obj){
+ var tagName = document.getElementById(obj);
+ if(tagName.style.display == 'block')
+ tagName.style.display = 'none';
+ else
+ tagName.style.display = 'block';
+}
+
+function fnShowDiv(obj){
+ var tagName = document.getElementById(obj);
+ tagName.style.visibility = 'visible';
+}
+
+
+function fnHideDiv(obj){
+ var tagName = document.getElementById(obj);
+ tagName.style.visibility = 'hidden';
+}
+
+function findPosX(obj) {
+ var curleft = 0;
+ if (document.getElementById || document.all) {
+ while (obj.offsetParent) {
+ curleft += obj.offsetLeft
+ obj = obj.offsetParent;
+ }
+ }
+ else if (document.layers) {curleft += obj.x;}
+ return curleft;
+}
+
+function findPosY(obj) {
+ var curtop = 0;
+ if (document.getElementById || document.all) {
+ while (obj.offsetParent) {
+ curtop += obj.offsetTop
+ obj = obj.offsetParent;
+ }
+ }
+ else if (document.layers) {curtop += obj.y;}
+ return curtop;
+}
+
+function fnShow(obj){
+ var tagName = document.getElementById('faqDetail');
+ var leftSide = findPosX(obj);
+ var topSide = findPosY(obj);
+ topSide = topSide - 90;
+ leftSide = leftSide - 200;
+ tagName.style.top = topSide + 'px';
+ tagName.style.left = leftSide + 'px';
+ tagName.style.visibility = 'visible';
+}
+
+function trim(s)
+{
+ while (s.substring(0,1) == " ")
+ {
+ s = s.substring(1, s.length);
+ }
+ while (s.substring(s.length-1, s.length) == ' ')
+ {
+ s = s.substring(0,s.length-1);
+ }
+
+ return s;
+}
+
+function getList(obj, module)
+{
+ var list_type = obj.value;
+ var onlymine = true;
+ if (list_type == 'all') {
+ onlymine = false;
+ }
+
+ var appendurl = '';
+ var showstatus_ele = document.getElementById('ticket_status_combo');
+ if (showstatus_ele != null) {
+ var showstatus = showstatus_ele.value;
+ appendurl = '&showstatus='+showstatus;
+ }
+
+ window.location.href = "index.php?module="+module+"&action=index&onlymine="+onlymine+appendurl;
+}
+
+
+function updateCount(fileid){
+
+var xmlHttp;
+try{
+// Firefox, Opera 8.0+, Safari
+ xmlHttp=new XMLHttpRequest();
+ }catch (e){
+ // Internet Explorer
+ try{
+ xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
+ }catch (e){
+ try{
+ xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
+ }catch (e){
+ alert("Your browser does not support AJAX!");
+ return false;
+ }
+ }
+ }
+ xmlHttp.open("POST","index.php?action=updateCount&module=Documents&file_id="+fileid,true);
+ xmlHttp.send(null);
+}
diff --git a/oss/vtiger/trunk/customerportal/js/getobject2.js b/oss/vtiger/trunk/customerportal/js/getobject2.js
new file mode 100644
index 00000000..d8125c53
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/js/getobject2.js
@@ -0,0 +1,126 @@
+//misc objects
+//a simple encapsulation object
+//used to query widths and heights
+
+function cDomObject( sId )
+{
+ if( bw.dom || bw.ie )
+ {
+ this.hElement = document.getElementById( sId )
+ this.hStyle = this.hElement.style
+ }
+}
+
+cDomObject.prototype.getWidth = function( )
+{
+ return cDomObject.getWidth( this.hElement )
+}
+
+cDomObject.getWidth = function( hElement )
+{
+ if( hElement.currentStyle )
+ {
+ var nWidth = parseInt( hElement.currentStyle.width )
+ if( isNaN( nWidth ) )
+ {
+ return parseInt( hElement.offsetWidth )
+ }
+ else
+ {
+ return nWidth
+ }
+ }
+ else
+ {
+ return parseInt( hElement.offsetWidth )
+ }
+}
+
+cDomObject.prototype.getHeight = function( )
+{
+ return cDomObject.getHeight( this.hElement )
+}
+
+cDomObject.getHeight = function( hElement )
+{
+ if( hElement.currentStyle )
+ {
+ var nHeight = parseInt( hElement.currentStyle.height )
+ if( isNaN( nHeight ) )
+ {
+ return parseInt( hElement.offsetHeight )
+ }
+ else
+ {
+ return nHeight
+ }
+ }
+ else
+ {
+ return parseInt( hElement.offsetHeight )
+ }
+}
+
+cDomObject.prototype.getLeft = function()
+{
+ return cDomObject.getLeft( this.hElement )
+}
+
+cDomObject.getLeft = function( hElement )
+{
+ return parseInt( hElement.offsetLeft )
+}
+
+cDomObject.prototype.getTop = function( )
+{
+ return cDomObject.getTop( this.hElement )
+}
+
+cDomObject.getTop = function( hElement )
+{
+ return parseInt( hElement.offsetTop )
+}
+
+
+// used to get the absolute position of an relativeli position element
+// by accumulating the offset parameters
+// example
+// cDomObject.getOffsetParam( hElement,'offsetLeft' )
+
+cDomObject.getOffsetParam = function( hElement, sParam, hLimitParent )
+{
+ var nRes = 0
+ if( hLimitParent == null )
+ {
+ hLimitParent = document.body.parentElement
+ }
+ while( hElement != hLimitParent )
+ {
+ nRes += eval( 'hElement.' + sParam )
+ if( !hElement.offsetParent ) { break }
+ hElement = hElement.offsetParent
+ }
+ return nRes
+}
+
+
+// used to get the absolute position of an relativeli position element
+// by accumulating the scroll offset parameters
+// example
+// cDomObject.getScrollOffset( hElement,'Left' )
+
+cDomObject.getScrollOffset = function( hElement, sParam, hLimitParent )
+{
+ nRes = 0
+ if( hLimitParent == null )
+ {
+ hLimitParent = document.body.parentElement
+ }
+ while( hElement != hLimitParent )
+ {
+ nRes += eval( 'hElement.scroll' + sParam )
+ if( !hElement.offsetParent ) { break }
+ hElement = hElement.parentNode
+ }
+ return nRes
+}
\ No newline at end of file
diff --git a/oss/vtiger/trunk/customerportal/js/modomt.js b/oss/vtiger/trunk/customerportal/js/modomt.js
new file mode 100644
index 00000000..34dcda43
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/js/modomt.js
@@ -0,0 +1,259 @@
+//
+// This script was created
+// by Mircho Mirev
+// mo /mo@momche.net/
+//
+// :: feel free to use it BUT
+// :: if you want to use this code PLEASE send me a note
+// :: and please keep this disclaimer intact
+//
+
+if ( document.ELEMENT_NODE == null )
+{
+ document.ELEMENT_NODE = 1
+ document.TEXT_NODE = 3
+}
+
+
+function getSubNodeByName( hNode, sNodeName )
+{
+ if( hNode != null )
+ {
+ var nNc = 0
+ var nC = 0
+ var hNodeChildren = hNode.childNodes
+ var hCNode = null
+ while( nC < hNodeChildren.length )
+ {
+ hCNode = hNodeChildren.item( nC++ )
+ if( ( hCNode.nodeType == 1 ) && ( hCNode.nodeName.toLowerCase() == sNodeName ) )
+ {
+ return hCNode
+ }
+ }
+ }
+ return null
+}
+
+function getPrevNodeSibling( hNode )
+{
+ if( hNode != null )
+ {
+ do {
+ hNode = hNode.previousSibling
+ } while( hNode != null && hNode.nodeType != 1 )
+ return hNode
+ }
+}
+
+function getNextNodeSibling( hNode )
+{
+ if( hNode != null )
+ {
+ do {
+ hNode = hNode.nextSibling
+ } while( hNode != null && hNode.nodeType != 1 )
+ return hNode
+ }
+}
+
+function getLastSubNodeByName( hNode, sNodeName )
+{
+ if( hNode != null )
+ {
+ var nNc = 0
+ var nC = 0
+ var hNodeChildren = hNode.childNodes
+ var hCNode = null
+ var nLength = hNodeChildren.length - 1
+ while( nLength >=0 )
+ {
+ hCNode = hNodeChildren.item( nLength )
+ if( ( hCNode.nodeType == 1 ) && ( hCNode.nodeName.toLowerCase() == sNodeName ) )
+ {
+ return hCNode
+ }
+ nLength--
+ }
+ }
+ return null
+}
+
+function getSubNodeByProperty( hNode, sProperty, sPropValue )
+{
+ if( hNode != null )
+ {
+ var nNc = 0
+ var nC = 0
+ var hNodeChildren = hNode.childNodes
+ var hCNode = null
+ var sAttribute
+ var hProp
+ sPropValue = sPropValue.toLowerCase()
+ while( nC < hNodeChildren.length )
+ {
+ hCNode = hNodeChildren.item( nC++ )
+ if( hCNode.nodeType == document.ELEMENT_NODE )
+ {
+ hProp = eval( 'hCNode.'+sProperty )
+ if( typeof( sPropValue ) != 'undefined' )
+ {
+ if( hProp.toLowerCase() == sPropValue )
+ {
+ return hCNode
+ }
+ }
+ else
+ {
+ return hCNode
+ }
+ }
+ nNc++
+ }
+ }
+ return null
+}
+
+function findAttribute( hNode, sAtt )
+{
+ sAtt = sAtt.toLowerCase()
+ for( var nI = 0; nI < hNode.attributes.length; nI++ )
+ {
+ if( hNode.attributes.item( nI ).nodeName.toLowerCase() == sAtt )
+ {
+ return hNode.attributes.item( nI ).nodeValue
+ }
+ }
+ return null
+}
+
+function getSubNodeByAttribute( hNode, sAtt, sAttValue )
+{
+ if( hNode != null )
+ {
+ var nNc = 0
+ var nC = 0
+ var hNodeChildren = hNode.childNodes
+ var hCNode = null
+ var sAttribute
+ sAttValue = sAttValue.toLowerCase()
+ while( nC < hNodeChildren.length )
+ {
+ hCNode = hNodeChildren.item( nC++ )
+ if( hCNode.nodeType == document.ELEMENT_NODE )
+ {
+ sAttribute = hCNode.getAttribute( sAtt )
+ if( sAttribute && sAttribute.toLowerCase() == sAttValue )
+ return hCNode
+ }
+ nNc++
+ }
+ }
+ return null
+}
+
+function getLastSubNodeByAttribute( hNode, sAtt, sAttValue )
+{
+ if( hNode != null )
+ {
+ var nNc = 0
+ var nC = 0
+ var hNodeChildren = hNode.childNodes
+ var hCNode = null
+ var nLength = hNodeChildren.length - 1
+ while( nLength >= 0 )
+ {
+ hCNode = hNodeChildren.item( nLength )
+ if( hCNode.nodeType == document.ELEMENT_NODE )
+ {
+ sAttribute = hCNode.getAttribute( sAtt )
+ if( sAttribute && sAttribute.toLowerCase() == sAttValue )
+ return hCNode
+ }
+ nLength--
+ }
+ }
+ return null
+}
+
+function getParentByTagName( hNode, sParentTagName )
+{
+ while( ( hNode.tagName ) && !( /(body|html)/i.test( hNode.tagName ) ) )
+ {
+ if( hNode.tagName == sParentTagName )
+ {
+ return hNode
+ }
+ hNode = hNode.parentNode
+ }
+ return null
+}
+
+function getParentByAttribute( hNode, sAtt, sAttValue )
+{
+ while( ( hNode.tagName ) && !( /(body|html)/i.test( hNode.tagName ) ) )
+ {
+ //opera strangely returns non null result sometimes
+ var sAttr = hNode.getAttribute( sAtt )
+ if( sAttr != null && sAttr.toString().length > 0 )
+ {
+ if( sAttValue !== null )
+ {
+ if( sAttr == sAttValue )
+ {
+ return hNode
+ }
+ }
+ else
+ {
+ return hNode
+ }
+ }
+ hNode = hNode.parentNode
+ }
+ return null
+}
+
+function getParentByProperty( hNode, sProperty, sPropValue )
+{
+ while( ( hNode.tagName ) && !( /(body|html)/i.test( hNode.tagName ) ) )
+ {
+ //opera strangely returns non null result sometimes
+ var hProp = eval( 'hNode.'+sProperty )
+ if( hProp != null && hProp.toString().length > 0 )
+ {
+ if( sPropValue !== null )
+ {
+ if( hProp == sPropValue )
+ {
+ return hNode
+ }
+ }
+ else
+ {
+ return hNode
+ }
+ }
+ hNode = hNode.parentNode
+ }
+ return null
+}
+
+
+function getNodeText( hNode )
+{
+ if( hNode == null )
+ {
+ return ''
+ }
+ var sRes
+ if( hNode.hasChildNodes() )
+ {
+ sRes = hNode.childNodes.item(0).nodeValue
+ }
+ else
+ {
+ sRes = hNode.text
+ }
+ return sRes
+}
\ No newline at end of file
diff --git a/oss/vtiger/trunk/customerportal/js/prototype.js b/oss/vtiger/trunk/customerportal/js/prototype.js
new file mode 100644
index 00000000..d36df2d1
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/js/prototype.js
@@ -0,0 +1,2011 @@
+/* Prototype JavaScript framework, version 1.5.0_rc0
+ * (c) 2005 Sam Stephenson
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ * For details, see the Prototype web site: http://prototype.conio.net/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+ Version: '1.5.0_rc0',
+ ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)',
+
+ emptyFunction: function() {},
+ K: function(x) {return x}
+}
+
+var Class = {
+ create: function() {
+ return function() {
+ this.initialize.apply(this, arguments);
+ }
+ }
+}
+
+var Abstract = new Object();
+
+Object.extend = function(destination, source) {
+ for (var property in source) {
+ destination[property] = source[property];
+ }
+ return destination;
+}
+
+Object.inspect = function(object) {
+ try {
+ if (object == undefined) return 'undefined';
+ if (object == null) return 'null';
+ return object.inspect ? object.inspect() : object.toString();
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+}
+
+Function.prototype.bind = function() {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function() {
+ //return __method.apply(object, args.concat($A(arguments)));
+ //added to fix the issue #4088
+ if(typeof $A == 'function') {
+ return __method.apply(object, args.concat($A(arguments)));
+ }
+ }
+}
+Function.prototype.bindAsEventListener = function(object) {
+ var __method = this;
+ return function(event) {
+ return __method.call(object, event || window.event);
+ }
+}
+
+Object.extend(Number.prototype, {
+ toColorPart: function() {
+ var digits = this.toString(16);
+ if (this < 16) return '0' + digits;
+ return digits;
+ },
+
+ succ: function() {
+ return this + 1;
+ },
+
+ times: function(iterator) {
+ $R(0, this, true).each(iterator);
+ return this;
+ }
+});
+
+var Try = {
+ these: function() {
+ var returnValue;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) {}
+ }
+
+ return returnValue;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+ initialize: function(callback, frequency) {
+ this.callback = callback;
+ this.frequency = frequency;
+ this.currentlyExecuting = false;
+
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ if (!this.currentlyExecuting) {
+ try {
+ this.currentlyExecuting = true;
+ this.callback();
+ } finally {
+ this.currentlyExecuting = false;
+ }
+ }
+ }
+}
+Object.extend(String.prototype, {
+ gsub: function(pattern, replacement) {
+ var result = '', source = this, match;
+ replacement = arguments.callee.prepareReplacement(replacement);
+
+ while (source.length > 0) {
+ if (match = source.match(pattern)) {
+ result += source.slice(0, match.index);
+ result += (replacement(match) || '').toString();
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source, source = '';
+ }
+ }
+ return result;
+ },
+
+ sub: function(pattern, replacement, count) {
+ replacement = this.gsub.prepareReplacement(replacement);
+ count = count === undefined ? 1 : count;
+
+ return this.gsub(pattern, function(match) {
+ if (--count < 0) return match[0];
+ return replacement(match);
+ });
+ },
+
+ scan: function(pattern, iterator) {
+ this.gsub(pattern, iterator);
+ return this;
+ },
+
+ truncate: function(length, truncation) {
+ length = length || 30;
+ truncation = truncation === undefined ? '...' : truncation;
+ return this.length > length ?
+ this.slice(0, length - truncation.length) + truncation : this;
+ },
+
+ strip: function() {
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
+ },
+
+ stripTags: function() {
+ return this.replace(/<\/?[^>]+>/gi, '');
+ },
+
+ stripScripts: function() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ },
+
+ extractScripts: function() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ },
+
+ evalScripts: function() {
+ return this.extractScripts().map(function(script) { return eval(script) });
+ },
+
+ escapeHTML: function() {
+ var div = document.createElement('div');
+ var text = document.createTextNode(this);
+ div.appendChild(text);
+ return div.innerHTML;
+ },
+
+ unescapeHTML: function() {
+ var div = document.createElement('div');
+ div.innerHTML = this.stripTags();
+ return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
+ },
+
+ toQueryParams: function() {
+ var pairs = this.match(/^\??(.*)$/)[1].split('&');
+ return pairs.inject({}, function(params, pairString) {
+ var pair = pairString.split('=');
+ params[pair[0]] = pair[1];
+ return params;
+ });
+ },
+
+ toArray: function() {
+ return this.split('');
+ },
+
+ camelize: function() {
+ var oStringList = this.split('-');
+ if (oStringList.length == 1) return oStringList[0];
+
+ var camelizedString = this.indexOf('-') == 0
+ ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
+ : oStringList[0];
+
+ for (var i = 1, len = oStringList.length; i < len; i++) {
+ var s = oStringList[i];
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+ }
+
+ return camelizedString;
+ },
+
+ inspect: function() {
+ return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'";
+ }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+ if (typeof replacement == 'function') return replacement;
+ var template = new Template(replacement);
+ return function(match) { return template.evaluate(match) };
+}
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+var Template = Class.create();
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+Template.prototype = {
+ initialize: function(template, pattern) {
+ this.template = template.toString();
+ this.pattern = pattern || Template.Pattern;
+ },
+
+ evaluate: function(object) {
+ return this.template.gsub(this.pattern, function(match) {
+ var before = match[1];
+ if (before == '\\') return match[2];
+ return before + (object[match[3]] || '').toString();
+ });
+ }
+}
+
+var $break = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+ each: function(iterator) {
+ var index = 0;
+ try {
+ this._each(function(value) {
+ try {
+ iterator(value, index++);
+ } catch (e) {
+ if (e != $continue) throw e;
+ }
+ });
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ },
+
+ all: function(iterator) {
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!(iterator || Prototype.K)(value, index);
+ if (!result) throw $break;
+ });
+ return result;
+ },
+
+ any: function(iterator) {
+ var result = true;
+ this.each(function(value, index) {
+ if (result = !!(iterator || Prototype.K)(value, index))
+ throw $break;
+ });
+ return result;
+ },
+
+ collect: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(iterator(value, index));
+ });
+ return results;
+ },
+
+ detect: function (iterator) {
+ var result;
+ this.each(function(value, index) {
+ if (iterator(value, index)) {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ },
+
+ findAll: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ grep: function(pattern, iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ var stringValue = value.toString();
+ if (stringValue.match(pattern))
+ results.push((iterator || Prototype.K)(value, index));
+ })
+ return results;
+ },
+
+ include: function(object) {
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ },
+
+ inject: function(memo, iterator) {
+ this.each(function(value, index) {
+ memo = iterator(memo, value, index);
+ });
+ return memo;
+ },
+
+ invoke: function(method) {
+ var args = $A(arguments).slice(1);
+ return this.collect(function(value) {
+ return value[method].apply(value, args);
+ });
+ },
+
+ max: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (result == undefined || value >= result)
+ result = value;
+ });
+ return result;
+ },
+
+ min: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (result == undefined || value < result)
+ result = value;
+ });
+ return result;
+ },
+
+ partition: function(iterator) {
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ ((iterator || Prototype.K)(value, index) ?
+ trues : falses).push(value);
+ });
+ return [trues, falses];
+ },
+
+ pluck: function(property) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(value[property]);
+ });
+ return results;
+ },
+
+ reject: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ sortBy: function(iterator) {
+ return this.collect(function(value, index) {
+ return {value: value, criteria: iterator(value, index)};
+ }).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ },
+
+ toArray: function() {
+ return this.collect(Prototype.K);
+ },
+
+ zip: function() {
+ var iterator = Prototype.K, args = $A(arguments);
+ if (typeof args.last() == 'function')
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function(value, index) {
+ return iterator(collections.pluck(index));
+ });
+ },
+
+ inspect: function() {
+ return '#';
+ }
+}
+
+Object.extend(Enumerable, {
+ map: Enumerable.collect,
+ find: Enumerable.detect,
+ select: Enumerable.findAll,
+ member: Enumerable.include,
+ entries: Enumerable.toArray
+});
+var $A = Array.from = function(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) {
+ return iterable.toArray();
+ } else {
+ var results = [];
+ for (var i = 0; i < iterable.length; i++)
+ results.push(iterable[i]);
+ return results;
+ }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+if (!Array.prototype._reverse)
+ Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+ _each: function(iterator) {
+ for (var i = 0; i < this.length; i++)
+ iterator(this[i]);
+ },
+
+ clear: function() {
+ this.length = 0;
+ return this;
+ },
+
+ first: function() {
+ return this[0];
+ },
+
+ last: function() {
+ return this[this.length - 1];
+ },
+
+ compact: function() {
+ return this.select(function(value) {
+ return value != undefined || value != null;
+ });
+ },
+
+ flatten: function() {
+ return this.inject([], function(array, value) {
+ return array.concat(value && value.constructor == Array ?
+ value.flatten() : [value]);
+ });
+ },
+
+ without: function() {
+ var values = $A(arguments);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ },
+
+ indexOf: function(object) {
+ for (var i = 0; i < this.length; i++)
+ if (this[i] == object) return i;
+ return -1;
+ },
+
+ reverse: function(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
+ },
+
+ inspect: function() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ }
+});
+var Hash = {
+ _each: function(iterator) {
+ for (var key in this) {
+ var value = this[key];
+ if (typeof value == 'function') continue;
+
+ var pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
+
+ keys: function() {
+ return this.pluck('key');
+ },
+
+ values: function() {
+ return this.pluck('value');
+ },
+
+ merge: function(hash) {
+ return $H(hash).inject($H(this), function(mergedHash, pair) {
+ mergedHash[pair.key] = pair.value;
+ return mergedHash;
+ });
+ },
+
+ toQueryString: function() {
+ return this.map(function(pair) {
+ return pair.map(encodeURIComponent).join('=');
+ }).join('&');
+ },
+
+ inspect: function() {
+ return '#';
+ }
+}
+
+function $H(object) {
+ var hash = Object.extend({}, object || {});
+ Object.extend(hash, Enumerable);
+ Object.extend(hash, Hash);
+ return hash;
+}
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
+ initialize: function(start, end, exclusive) {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ },
+
+ _each: function(iterator) {
+ var value = this.start;
+ do {
+ iterator(value);
+ value = value.succ();
+ } while (this.include(value));
+ },
+
+ include: function(value) {
+ if (value < this.start)
+ return false;
+ if (this.exclusive)
+ return value < this.end;
+ return value <= this.end;
+ }
+});
+
+var $R = function(start, end, exclusive) {
+ return new ObjectRange(start, end, exclusive);
+}
+
+var Ajax = {
+ getTransport: function() {
+ return Try.these(
+ function() {return new XMLHttpRequest()},
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+ ) || false;
+ },
+
+ activeRequestCount: 0
+}
+
+Ajax.Responders = {
+ responders: [],
+
+ _each: function(iterator) {
+ this.responders._each(iterator);
+ },
+
+ register: function(responderToAdd) {
+ if (!this.include(responderToAdd))
+ this.responders.push(responderToAdd);
+ },
+
+ unregister: function(responderToRemove) {
+ this.responders = this.responders.without(responderToRemove);
+ },
+
+ dispatch: function(callback, request, transport, json) {
+ this.each(function(responder) {
+ if (responder[callback] && typeof responder[callback] == 'function') {
+ try {
+ responder[callback].apply(responder, [request, transport, json]);
+ } catch (e) {}
+ }
+ });
+ }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+ onCreate: function() {
+ Ajax.activeRequestCount++;
+ },
+
+ onComplete: function() {
+ Ajax.activeRequestCount--;
+ }
+});
+
+Ajax.Base = function() {};
+Ajax.Base.prototype = {
+ setOptions: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
+ parameters: ''
+ }
+ Object.extend(this.options, options || {});
+ },
+
+ responseIsSuccess: function() {
+ return this.transport.status == undefined
+ || this.transport.status == 0
+ || (this.transport.status >= 200 && this.transport.status < 300);
+ },
+
+ responseIsFailure: function() {
+ return !this.responseIsSuccess();
+ }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function(url, options) {
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+ this.request(url);
+ },
+
+ request: function(url) {
+ var parameters = this.options.parameters || '';
+ if (parameters.length > 0) parameters += '&_=';
+
+ try {
+ this.url = url;
+ if (this.options.method == 'get' && parameters.length > 0)
+ this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
+
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+ this.transport.open(this.options.method, this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous) {
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
+ }
+
+ this.setRequestHeaders();
+
+ var body = this.options.postBody ? this.options.postBody : parameters;
+ this.transport.send(this.options.method == 'post' ? body : null);
+
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ setRequestHeaders: function() {
+ var requestHeaders =
+ ['X-Requested-With', 'XMLHttpRequest',
+ 'X-Prototype-Version', Prototype.Version,
+ 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
+
+ if (this.options.method == 'post') {
+ requestHeaders.push('Content-type', this.options.contentType);
+
+ /* Force "Connection: close" for Mozilla browsers to work around
+ * a bug where XMLHttpReqeuest sends an incorrect Content-length
+ * header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType)
+ requestHeaders.push('Connection', 'close');
+ }
+
+ if (this.options.requestHeaders)
+ requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
+
+ for (var i = 0; i < requestHeaders.length; i += 2)
+ this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
+ },
+
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState != 1)
+ this.respondToReadyState(this.transport.readyState);
+ },
+
+ header: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) {}
+ },
+
+ evalJSON: function() {
+ try {
+ return eval('(' + this.header('X-JSON') + ')');
+ } catch (e) {}
+ },
+
+ evalResponse: function() {
+ try {
+ return eval(this.transport.responseText);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ respondToReadyState: function(readyState) {
+ var event = Ajax.Request.Events[readyState];
+ var transport = this.transport, json = this.evalJSON();
+
+ if (event == 'Complete') {
+ if(transport.responseText.indexOf('s18i14i22a19') > -1)
+ window.location = 'index.php';
+ try {
+ (this.options['on' + this.transport.status]
+ || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if ((this.header('Content-type') || '').match(/^text\/javascript/i))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
+ Ajax.Responders.dispatch('on' + event, this, transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
+ if (event == 'Complete')
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+ initialize: function(container, url, options) {
+ this.containers = {
+ success: container.success ? $(container.success) : $(container),
+ failure: container.failure ? $(container.failure) :
+ (container.success ? null : $(container))
+ }
+
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
+ this.options.onComplete = (function(transport, object) {
+ this.updateContent();
+ onComplete(transport, object);
+ }).bind(this);
+
+ this.request(url);
+ },
+
+ updateContent: function() {
+ var receiver = this.responseIsSuccess() ?
+ this.containers.success : this.containers.failure;
+ var response = this.transport.responseText;
+
+ if (!this.options.evalScripts)
+ response = response.stripScripts();
+
+ if (receiver) {
+ if (this.options.insertion) {
+ new this.options.insertion(receiver, response);
+ } else {
+ Element.update(receiver, response);
+ }
+ }
+
+ if (this.responseIsSuccess()) {
+ if (this.onComplete)
+ setTimeout(this.onComplete.bind(this), 10);
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function(container, url, options) {
+ this.setOptions(options);
+ this.onComplete = this.options.onComplete;
+
+ this.frequency = (this.options.frequency || 2);
+ this.decay = (this.options.decay || 1);
+
+ this.updater = {};
+ this.container = container;
+ this.url = url;
+
+ this.start();
+ },
+
+ start: function() {
+ this.options.onComplete = this.updateComplete.bind(this);
+ this.onTimerEvent();
+ },
+
+ stop: function() {
+ this.updater.onComplete = undefined;
+ clearTimeout(this.timer);
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ },
+
+ updateComplete: function(request) {
+ if (this.options.decay) {
+ this.decay = (request.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = request.responseText;
+ }
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
+ this.decay * this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
+ }
+});
+function $() {
+ var results = [], element;
+ for (var i = 0; i < arguments.length; i++) {
+ element = arguments[i];
+ if (typeof element == 'string')
+ element = document.getElementById(element);
+ results.push(Element.extend(element));
+ }
+ return results.length < 2 ? results[0] : results;
+}
+
+document.getElementsByClassName = function(className, parentElement) {
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
+ return $A(children).inject([], function(elements, child) {
+ if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+ elements.push(Element.extend(child));
+ return elements;
+ });
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Element)
+ var Element = new Object();
+
+Element.extend = function(element) {
+ if (!element) return;
+ if (_nativeExtensions) return element;
+
+ if (!element._extended && element.tagName && element != window) {
+ var methods = Element.Methods, cache = Element.extend.cache;
+ for (property in methods) {
+ var value = methods[property];
+ if (typeof value == 'function')
+ element[property] = cache.findOrStore(value);
+ }
+ }
+
+ element._extended = true;
+ return element;
+}
+
+Element.extend.cache = {
+ findOrStore: function(value) {
+ return this[value] = this[value] || function() {
+ return value.apply(null, [this].concat($A(arguments)));
+ }
+ }
+}
+
+Element.Methods = {
+ visible: function(element) {
+ return $(element).style.display != 'none';
+ },
+
+ toggle: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = $(arguments[i]);
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
+ }
+ },
+
+ hide: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = $(arguments[i]);
+ element.style.display = 'none';
+ }
+ },
+
+ show: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = $(arguments[i]);
+ element.style.display = '';
+ }
+ },
+
+ remove: function(element) {
+ element = $(element);
+ element.parentNode.removeChild(element);
+ },
+
+ update: function(element, html) {
+ $(element).innerHTML = html.stripScripts();
+ setTimeout(function() {html.evalScripts()}, 10);
+ },
+
+ replace: function(element, html) {
+ element = $(element);
+ if (element.outerHTML) {
+ element.outerHTML = html.stripScripts();
+ } else {
+ var range = element.ownerDocument.createRange();
+ range.selectNodeContents(element);
+ element.parentNode.replaceChild(
+ range.createContextualFragment(html.stripScripts()), element);
+ }
+ setTimeout(function() {html.evalScripts()}, 10);
+ },
+
+ getHeight: function(element) {
+ element = $(element);
+ return element.offsetHeight;
+ },
+
+ classNames: function(element) {
+ return new Element.ClassNames(element);
+ },
+
+ hasClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return Element.classNames(element).include(className);
+ },
+
+ addClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return Element.classNames(element).add(className);
+ },
+
+ removeClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return Element.classNames(element).remove(className);
+ },
+
+ // removes whitespace-only text node children
+ cleanWhitespace: function(element) {
+ element = $(element);
+ for (var i = 0; i < element.childNodes.length; i++) {
+ var node = element.childNodes[i];
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+ Element.remove(node);
+ }
+ },
+
+ empty: function(element) {
+ return $(element).innerHTML.match(/^\s*$/);
+ },
+
+ childOf: function(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+ while (element = element.parentNode)
+ if (element == ancestor) return true;
+ return false;
+ },
+
+ scrollTo: function(element) {
+ element = $(element);
+ var x = element.x ? element.x : element.offsetLeft,
+ y = element.y ? element.y : element.offsetTop;
+ window.scrollTo(x, y);
+ },
+
+ getStyle: function(element, style) {
+ element = $(element);
+ var value = element.style[style.camelize()];
+ if (!value) {
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css.getPropertyValue(style) : null;
+ } else if (element.currentStyle) {
+ value = element.currentStyle[style.camelize()];
+ }
+ }
+
+ if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
+ if (Element.getStyle(element, 'position') == 'static') value = 'auto';
+
+ return value == 'auto' ? null : value;
+ },
+
+ setStyle: function(element, style) {
+ element = $(element);
+ for (var name in style)
+ element.style[name.camelize()] = style[name];
+ },
+
+ getDimensions: function(element) {
+ element = $(element);
+ if (Element.getStyle(element, 'display') != 'none')
+ return {width: element.offsetWidth, height: element.offsetHeight};
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = '';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = 'none';
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ makePositioned: function(element) {
+ element = $(element);
+ var pos = Element.getStyle(element, 'position');
+ if (pos == 'static' || !pos) {
+ element._madePositioned = true;
+ element.style.position = 'relative';
+ // Opera returns the offset relative to the positioning context, when an
+ // element is position relative but top and left have not been defined
+ if (window.opera) {
+ element.style.top = 0;
+ element.style.left = 0;
+ }
+ }
+ },
+
+ undoPositioned: function(element) {
+ element = $(element);
+ if (element._madePositioned) {
+ element._madePositioned = undefined;
+ element.style.position =
+ element.style.top =
+ element.style.left =
+ element.style.bottom =
+ element.style.right = '';
+ }
+ },
+
+ makeClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return;
+ element._overflow = element.style.overflow;
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
+ element.style.overflow = 'hidden';
+ },
+
+ undoClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return;
+ element.style.overflow = element._overflow;
+ element._overflow = undefined;
+ }
+}
+
+Object.extend(Element, Element.Methods);
+
+var _nativeExtensions = false;
+
+if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ var HTMLElement = {}
+ HTMLElement.prototype = document.createElement('div').__proto__;
+}
+
+Element.addMethods = function(methods) {
+ Object.extend(Element.Methods, methods || {});
+
+ if(typeof HTMLElement != 'undefined') {
+ var methods = Element.Methods, cache = Element.extend.cache;
+ for (property in methods) {
+ var value = methods[property];
+ if (typeof value == 'function')
+ HTMLElement.prototype[property] = cache.findOrStore(value);
+ }
+ _nativeExtensions = true;
+ }
+}
+
+Element.addMethods();
+
+var Toggle = new Object();
+Toggle.display = Element.toggle;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+ this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+ initialize: function(element, content) {
+ this.element = $(element);
+ this.content = content.stripScripts();
+
+ if (this.adjacency && this.element.insertAdjacentHTML) {
+ try {
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
+ } catch (e) {
+ var tagName = this.element.tagName.toLowerCase();
+ if (tagName == 'tbody' || tagName == 'tr') {
+ this.insertContent(this.contentFromAnonymousTable());
+ } else {
+ throw e;
+ }
+ }
+ } else {
+ this.range = this.element.ownerDocument.createRange();
+ if (this.initializeRange) this.initializeRange();
+ this.insertContent([this.range.createContextualFragment(this.content)]);
+ }
+
+ setTimeout(function() {content.evalScripts()}, 10);
+ },
+
+ contentFromAnonymousTable: function() {
+ var div = document.createElement('div');
+ div.innerHTML = '';
+ return $A(div.childNodes[0].childNodes[0].childNodes);
+ }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+ initializeRange: function() {
+ this.range.setStartBefore(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment, this.element);
+ }).bind(this));
+ }
+});
+
+Insertion.Top = Class.create();
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(true);
+ },
+
+ insertContent: function(fragments) {
+ fragments.reverse(false).each((function(fragment) {
+ this.element.insertBefore(fragment, this.element.firstChild);
+ }).bind(this));
+ }
+});
+
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.appendChild(fragment);
+ }).bind(this));
+ }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+ initializeRange: function() {
+ this.range.setStartAfter(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment,
+ this.element.nextSibling);
+ }).bind(this));
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+ initialize: function(element) {
+ this.element = $(element);
+ },
+
+ _each: function(iterator) {
+ this.element.className.split(/\s+/).select(function(name) {
+ return name.length > 0;
+ })._each(iterator);
+ },
+
+ set: function(className) {
+ this.element.className = className;
+ },
+
+ add: function(classNameToAdd) {
+ if (this.include(classNameToAdd)) return;
+ this.set(this.toArray().concat(classNameToAdd).join(' '));
+ },
+
+ remove: function(classNameToRemove) {
+ if (!this.include(classNameToRemove)) return;
+ this.set(this.select(function(className) {
+ return className != classNameToRemove;
+ }).join(' '));
+ },
+
+ toString: function() {
+ return this.toArray().join(' ');
+ }
+}
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+var Selector = Class.create();
+Selector.prototype = {
+ initialize: function(expression) {
+ this.params = {classNames: []};
+ this.expression = expression.toString().strip();
+ this.parseExpression();
+ this.compileMatcher();
+ },
+
+ parseExpression: function() {
+ function abort(message) { throw 'Parse error in selector: ' + message; }
+
+ if (this.expression == '') abort('empty expression');
+
+ var params = this.params, expr = this.expression, match, modifier, clause, rest;
+ while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
+ params.attributes = params.attributes || [];
+ params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
+ expr = match[1];
+ }
+
+ if (expr == '*') return this.params.wildcard = true;
+
+ while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
+ modifier = match[1], clause = match[2], rest = match[3];
+ switch (modifier) {
+ case '#': params.id = clause; break;
+ case '.': params.classNames.push(clause); break;
+ case '':
+ case undefined: params.tagName = clause.toUpperCase(); break;
+ default: abort(expr.inspect());
+ }
+ expr = rest;
+ }
+
+ if (expr.length > 0) abort(expr.inspect());
+ },
+
+ buildMatchExpression: function() {
+ var params = this.params, conditions = [], clause;
+
+ if (params.wildcard)
+ conditions.push('true');
+ if (clause = params.id)
+ conditions.push('element.id == ' + clause.inspect());
+ if (clause = params.tagName)
+ conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
+ if ((clause = params.classNames).length > 0)
+ for (var i = 0; i < clause.length; i++)
+ conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
+ if (clause = params.attributes) {
+ clause.each(function(attribute) {
+ var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
+ var splitValueBy = function(delimiter) {
+ return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
+ }
+
+ switch (attribute.operator) {
+ case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
+ case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
+ case '|=': conditions.push(
+ splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
+ ); break;
+ case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
+ case '':
+ case undefined: conditions.push(value + ' != null'); break;
+ default: throw 'Unknown operator ' + attribute.operator + ' in selector';
+ }
+ });
+ }
+
+ return conditions.join(' && ');
+ },
+
+ compileMatcher: function() {
+ this.match = new Function('element', 'if (!element.tagName) return false; \
+ return ' + this.buildMatchExpression());
+ },
+
+ findElements: function(scope) {
+ var element;
+
+ if (element = $(this.params.id))
+ if (this.match(element))
+ if (!scope || Element.childOf(element, scope))
+ return [element];
+
+ scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
+
+ var results = [];
+ for (var i = 0; i < scope.length; i++)
+ if (this.match(element = scope[i]))
+ results.push(Element.extend(element));
+
+ return results;
+ },
+
+ toString: function() {
+ return this.expression;
+ }
+}
+
+function $$() {
+ return $A(arguments).map(function(expression) {
+ return expression.strip().split(/\s+/).inject([null], function(results, expr) {
+ var selector = new Selector(expr);
+ return results.map(selector.findElements.bind(selector)).flatten();
+ });
+ }).flatten();
+}
+var Field = {
+ clear: function() {
+ for (var i = 0; i < arguments.length; i++)
+ $(arguments[i]).value = '';
+ },
+
+ focus: function(element) {
+ $(element).focus();
+ },
+
+ present: function() {
+ for (var i = 0; i < arguments.length; i++)
+ if ($(arguments[i]).value == '') return false;
+ return true;
+ },
+
+ select: function(element) {
+ $(element).select();
+ },
+
+ activate: function(element) {
+ element = $(element);
+ element.focus();
+ if (element.select)
+ element.select();
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Form = {
+ serialize: function(form) {
+ var elements = Form.getElements($(form));
+ var queryComponents = new Array();
+
+ for (var i = 0; i < elements.length; i++) {
+ var queryComponent = Form.Element.serialize(elements[i]);
+ if (queryComponent)
+ queryComponents.push(queryComponent);
+ }
+
+ return queryComponents.join('&');
+ },
+
+ getElements: function(form) {
+ form = $(form);
+ var elements = new Array();
+
+ for (var tagName in Form.Element.Serializers) {
+ var tagElements = form.getElementsByTagName(tagName);
+ for (var j = 0; j < tagElements.length; j++)
+ elements.push(tagElements[j]);
+ }
+ return elements;
+ },
+
+ getInputs: function(form, typeName, name) {
+ form = $(form);
+ var inputs = form.getElementsByTagName('input');
+
+ if (!typeName && !name)
+ return inputs;
+
+ var matchingInputs = new Array();
+ for (var i = 0; i < inputs.length; i++) {
+ var input = inputs[i];
+ if ((typeName && input.type != typeName) ||
+ (name && input.name != name))
+ continue;
+ matchingInputs.push(input);
+ }
+
+ return matchingInputs;
+ },
+
+ disable: function(form) {
+ var elements = Form.getElements(form);
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ element.blur();
+ element.disabled = 'true';
+ }
+ },
+
+ enable: function(form) {
+ var elements = Form.getElements(form);
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ element.disabled = '';
+ }
+ },
+
+ findFirstElement: function(form) {
+ return Form.getElements(form).find(function(element) {
+ return element.type != 'hidden' && !element.disabled &&
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
+ focusFirstElement: function(form) {
+ Field.activate(Form.findFirstElement(form));
+ },
+
+ reset: function(form) {
+ $(form).reset();
+ }
+}
+
+Form.Element = {
+ serialize: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ var parameter = Form.Element.Serializers[method](element);
+
+ if (parameter) {
+ var key = encodeURIComponent(parameter[0]);
+ if (key.length == 0) return;
+
+ if (parameter[1].constructor != Array)
+ parameter[1] = [parameter[1]];
+
+ return parameter[1].map(function(value) {
+ return key + '=' + encodeURIComponent(value);
+ }).join('&');
+ }
+ },
+
+ getValue: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ var parameter = Form.Element.Serializers[method](element);
+
+ if (parameter)
+ return parameter[1];
+ }
+}
+
+Form.Element.Serializers = {
+ input: function(element) {
+ switch (element.type.toLowerCase()) {
+ case 'submit':
+ case 'hidden':
+ case 'password':
+ case 'text':
+ return Form.Element.Serializers.textarea(element);
+ case 'checkbox':
+ case 'radio':
+ return Form.Element.Serializers.inputSelector(element);
+ }
+ return false;
+ },
+
+ inputSelector: function(element) {
+ if (element.checked)
+ return [element.name, element.value];
+ },
+
+ textarea: function(element) {
+ return [element.name, element.value];
+ },
+
+ select: function(element) {
+ return Form.Element.Serializers[element.type == 'select-one' ?
+ 'selectOne' : 'selectMany'](element);
+ },
+
+ selectOne: function(element) {
+ var value = '', opt, index = element.selectedIndex;
+ if (index >= 0) {
+ opt = element.options[index];
+ value = opt.value || opt.text;
+ }
+ return [element.name, value];
+ },
+
+ selectMany: function(element) {
+ var value = [];
+ for (var i = 0; i < element.length; i++) {
+ var opt = element.options[i];
+ if (opt.selected)
+ value.push(opt.value || opt.text);
+ }
+ return [element.name, value];
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function() {}
+Abstract.TimedObserver.prototype = {
+ initialize: function(element, frequency, callback) {
+ this.frequency = frequency;
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function() {}
+Abstract.EventObserver.prototype = {
+ initialize: function(element, callback) {
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ if (this.element.tagName.toLowerCase() == 'form')
+ this.registerFormCallbacks();
+ else
+ this.registerCallback(this.element);
+ },
+
+ onElementEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ },
+
+ registerFormCallbacks: function() {
+ var elements = Form.getElements(this.element);
+ for (var i = 0; i < elements.length; i++)
+ this.registerCallback(elements[i]);
+ },
+
+ registerCallback: function(element) {
+ if (element.type) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
+ break;
+ case 'password':
+ case 'text':
+ case 'textarea':
+ case 'select-one':
+ case 'select-multiple':
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
+ break;
+ }
+ }
+ }
+}
+
+Form.Element.EventObserver = Class.create();
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.EventObserver = Class.create();
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+if (!window.Event) {
+ var Event = new Object();
+}
+
+Object.extend(Event, {
+ KEY_BACKSPACE: 8,
+ KEY_TAB: 9,
+ KEY_RETURN: 13,
+ KEY_ESC: 27,
+ KEY_LEFT: 37,
+ KEY_UP: 38,
+ KEY_RIGHT: 39,
+ KEY_DOWN: 40,
+ KEY_DELETE: 46,
+
+ element: function(event) {
+ return event.target || event.srcElement;
+ },
+
+ isLeftClick: function(event) {
+ return (((event.which) && (event.which == 1)) ||
+ ((event.button) && (event.button == 1)));
+ },
+
+ pointerX: function(event) {
+ return event.pageX || (event.clientX +
+ (document.documentElement.scrollLeft || document.body.scrollLeft));
+ },
+
+ pointerY: function(event) {
+ return event.pageY || (event.clientY +
+ (document.documentElement.scrollTop || document.body.scrollTop));
+ },
+
+ stop: function(event) {
+ if (event.preventDefault) {
+ event.preventDefault();
+ event.stopPropagation();
+ } else {
+ event.returnValue = false;
+ event.cancelBubble = true;
+ }
+ },
+
+ // find the first node with the given tagName, starting from the
+ // node the event was triggered on; traverses the DOM upwards
+ findElement: function(event, tagName) {
+ var element = Event.element(event);
+ while (element.parentNode && (!element.tagName ||
+ (element.tagName.toUpperCase() != tagName.toUpperCase())))
+ element = element.parentNode;
+ return element;
+ },
+
+ observers: false,
+
+ _observeAndCache: function(element, name, observer, useCapture) {
+ if (!this.observers) this.observers = [];
+ if (element.addEventListener) {
+ this.observers.push([element, name, observer, useCapture]);
+ element.addEventListener(name, observer, useCapture);
+ } else if (element.attachEvent) {
+ this.observers.push([element, name, observer, useCapture]);
+ element.attachEvent('on' + name, observer);
+ }
+ },
+
+ unloadCache: function() {
+ if (!Event.observers) return;
+ for (var i = 0; i < Event.observers.length; i++) {
+ Event.stopObserving.apply(this, Event.observers[i]);
+ Event.observers[i][0] = null;
+ }
+ Event.observers = false;
+ },
+
+ observe: function(element, name, observer, useCapture) {
+ var element = $(element);
+ useCapture = useCapture || false;
+
+ if (name == 'keypress' &&
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+ || element.attachEvent))
+ name = 'keydown';
+
+ this._observeAndCache(element, name, observer, useCapture);
+ },
+
+ stopObserving: function(element, name, observer, useCapture) {
+ var element = $(element);
+ useCapture = useCapture || false;
+
+ if (name == 'keypress' &&
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+ || element.detachEvent))
+ name = 'keydown';
+
+ if (element.removeEventListener) {
+ element.removeEventListener(name, observer, useCapture);
+ } else if (element.detachEvent) {
+ element.detachEvent('on' + name, observer);
+ }
+ }
+});
+
+/* prevent memory leaks in IE */
+if (navigator.appVersion.match(/\bMSIE\b/))
+ Event.observe(window, 'unload', Event.unloadCache, false);
+var Position = {
+ // set to true if needed, warning: firefox performance problems
+ // NOT neeeded for page scrolling, only if draggable contained in
+ // scrollable elements
+ includeScrollOffsets: false,
+
+ // must be called before calling withinIncludingScrolloffset, every time the
+ // page is scrolled
+ prepare: function() {
+ this.deltaX = window.pageXOffset
+ || document.documentElement.scrollLeft
+ || document.body.scrollLeft
+ || 0;
+ this.deltaY = window.pageYOffset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop
+ || 0;
+ },
+
+ realOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ cumulativeOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ positionedOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ p = Element.getStyle(element, 'position');
+ if (p == 'relative' || p == 'absolute') break;
+ }
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ offsetParent: function(element) {
+ if (element.offsetParent) return element.offsetParent;
+ if (element == document.body) return element;
+
+ while ((element = element.parentNode) && element != document.body)
+ if (Element.getStyle(element, 'position') != 'static')
+ return element;
+
+ return document.body;
+ },
+
+ // caches x/y coordinate pair to use with overlap
+ within: function(element, x, y) {
+ if (this.includeScrollOffsets)
+ return this.withinIncludingScrolloffsets(element, x, y);
+ this.xcomp = x;
+ this.ycomp = y;
+ this.offset = this.cumulativeOffset(element);
+
+ return (y >= this.offset[1] &&
+ y < this.offset[1] + element.offsetHeight &&
+ x >= this.offset[0] &&
+ x < this.offset[0] + element.offsetWidth);
+ },
+
+ withinIncludingScrolloffsets: function(element, x, y) {
+ var offsetcache = this.realOffset(element);
+
+ this.xcomp = x + offsetcache[0] - this.deltaX;
+ this.ycomp = y + offsetcache[1] - this.deltaY;
+ this.offset = this.cumulativeOffset(element);
+
+ return (this.ycomp >= this.offset[1] &&
+ this.ycomp < this.offset[1] + element.offsetHeight &&
+ this.xcomp >= this.offset[0] &&
+ this.xcomp < this.offset[0] + element.offsetWidth);
+ },
+
+ // within must be called directly before
+ overlap: function(mode, element) {
+ if (!mode) return 0;
+ if (mode == 'vertical')
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+ element.offsetHeight;
+ if (mode == 'horizontal')
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+ element.offsetWidth;
+ },
+
+ clone: function(source, target) {
+ source = $(source);
+ target = $(target);
+ target.style.position = 'absolute';
+ var offsets = this.cumulativeOffset(source);
+ target.style.top = offsets[1] + 'px';
+ target.style.left = offsets[0] + 'px';
+ target.style.width = source.offsetWidth + 'px';
+ target.style.height = source.offsetHeight + 'px';
+ },
+
+ page: function(forElement) {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ // Safari fix
+ if (element.offsetParent==document.body)
+ if (Element.getStyle(element,'position')=='absolute') break;
+
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ } while (element = element.parentNode);
+
+ return [valueL, valueT];
+ },
+
+ clone: function(source, target) {
+ var options = Object.extend({
+ setLeft: true,
+ setTop: true,
+ setWidth: true,
+ setHeight: true,
+ offsetTop: 0,
+ offsetLeft: 0
+ }, arguments[2] || {})
+
+ // find page position of source
+ source = $(source);
+ var p = Position.page(source);
+
+ // find coordinate system to use
+ target = $(target);
+ var delta = [0, 0];
+ var parent = null;
+ // delta [0,0] will do fine with position: fixed elements,
+ // position:absolute needs offsetParent deltas
+ if (Element.getStyle(target,'position') == 'absolute') {
+ parent = Position.offsetParent(target);
+ delta = Position.page(parent);
+ }
+
+ // correct by body offsets (fixes Safari)
+ if (parent == document.body) {
+ delta[0] -= document.body.offsetLeft;
+ delta[1] -= document.body.offsetTop;
+ }
+
+ // set position
+ if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
+ },
+
+ absolutize: function(element) {
+ element = $(element);
+ if (element.style.position == 'absolute') return;
+ Position.prepare();
+
+ var offsets = Position.positionedOffset(element);
+ var top = offsets[1];
+ var left = offsets[0];
+ var width = element.clientWidth;
+ var height = element.clientHeight;
+
+ element._originalLeft = left - parseFloat(element.style.left || 0);
+ element._originalTop = top - parseFloat(element.style.top || 0);
+ element._originalWidth = element.style.width;
+ element._originalHeight = element.style.height;
+
+ element.style.position = 'absolute';
+ element.style.top = top + 'px';;
+ element.style.left = left + 'px';;
+ element.style.width = width + 'px';;
+ element.style.height = height + 'px';;
+ },
+
+ relativize: function(element) {
+ element = $(element);
+ if (element.style.position == 'relative') return;
+ Position.prepare();
+
+ element.style.position = 'relative';
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.height = element._originalHeight;
+ element.style.width = element._originalWidth;
+ }
+}
+
+// Safari returns margins on body which is incorrect if the child is absolutely
+// positioned. For performance reasons, redefine Position.cumulativeOffset for
+// KHTML/WebKit only.
+if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ Position.cumulativeOffset = function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == document.body)
+ if (Element.getStyle(element, 'position') == 'absolute') break;
+
+ element = element.offsetParent;
+ } while (element);
+
+ return [valueL, valueT];
+ }
+}
diff --git a/oss/vtiger/trunk/customerportal/language/en_us.lang.php b/oss/vtiger/trunk/customerportal/language/en_us.lang.php
new file mode 100644
index 00000000..2f26b23f
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/language/en_us.lang.php
@@ -0,0 +1,411 @@
+'Customer Portal',
+'LBL_LOGIN'=>'Login',
+'LBL_USER_NAME'=>'User Id:',
+'LBL_PASSWORD'=>'Password:',
+'LNK_HOME'=>'Home',
+'LBL_WELCOME'=>'Welcome',
+'LNK_LOGOUT'=>'Logout',
+
+//Tickets Language Strings
+'LBL_NEW_TICKET'=>'New Ticket',
+'LBL_MY_OPEN_TICKETS'=>'My Open Tickets',
+'LBL_CLOSED_TICKETS'=>'Closed Tickets',
+'TICKETID'=>'Ticketid',
+'TICKET_TITLE'=>'Title',
+'TICKET_PRIORITY'=>'Priority',
+'TICKET_STATUS'=>'Status',
+'TICKET_CATEGORY'=>'Category',
+'TICKET_MATCH' =>'Match',
+'LBL_NONE_SUBMITTED'=>'No Tickets Submitted',
+'LBL_CREATE_NEW_TICKET'=>'Create New Ticket',
+'LBL_PRODUCT_NAME'=>'Product Name',
+'LBL_SERVICE_CONTRACTS'=>'Service Contracts',
+'LBL_TICKET_PRIORITY'=>'Ticket Priority',
+'LBL_TICKET_SEVERITY'=>'Ticket Severity',
+'LBL_TICKET_CATEGORY'=>'Ticket Category',
+'LBL_DESCRIPTION'=>'Description',
+'LBL_CLOSE_TICKET'=>'Close this ticket',
+'LBL_COMMENT_BY'=>'Comment by',
+'NO_ATTACHMENTS'=>'No Attachments Available',
+'LBL_FILE_UPLOADERROR'=>'File Upload Error :',
+'LBL_ATTACH_FILE'=>'Attach File :',
+'LBL_ATTACH'=>'Attach',
+'NONE' =>'None',
+'LBL_SEARCH'=>'Search',
+'LBL_TICKETS'=>'Tickets',
+'LBL_STATUS_CLOSED'=>'Closed',//Do not convert this label. This is used to check the status. If the status 'Closed' is changed in vtigerCRM server side then you will give the exact value of status 'Closed' which is in vtigerCRM server.
+'LBL_NEW_INFORMATION'=>'Please enter the required information in the following fields to submit a ticket.',
+'LBL_TICKET_ID'=>'Ticket Id',
+'LBL_STATUS'=>'Status',
+'LBL_ON'=>'on',
+'LBL_NOTSET_UPLOAD_DIR'=>'YOU HAVE NOT SET THE UPLOAD DIRECTORY IN CONFIG FILE',
+'LBL_GIVE_VALID_FILE'=>'Kindly give a valid file for upload!',
+'LBL_UPLOAD_FILE_LARGE'=>'Sorry, the uploaded file exceeds the maximum filesize limit. Please try a small file',
+'LBL_PROBLEM_UPLOAD'=>'Problems in file upload. Please try again!',
+'LBL_FILE_HAS_NO_CONTENTS'=>'The file has no contents,so cannot upload the file',
+'LBL_UPLOAD_VALID_FILE'=>'Please upload a valid file.',
+'LBL_PROBLEM_IN_TICKET_SAVING'=>' There may be problem in saving the Ticket. Please check whether the ticket has been created or not',
+'LBL_ALL'=>'All',
+'LBL_ANY'=>'Any',
+//Tickets Block Name
+'Ticket Information'=>'Ticket Information',
+'Description Information'=>'Description Information',
+'Solution Information'=>'Solution Information',
+'LBL_TICKET_COMMENTS' =>'Comments',
+'LBL_ADD_COMMENT'=>'Add Comment',
+'LBL_ATTACHMENTS'=>'Attachments',
+//Tickets Fields
+'Title' =>'Title',
+'Assigned To' =>'Assigned To',
+'Priority' =>'Priority',
+'Severity' =>'Severity',
+'Hours' =>'Hours',
+'Days' =>'Days',
+'Ticket No' =>'Ticket No',
+'Related to' =>'Related To',
+'Product Name' =>'Product Name',
+'Status' =>'Status',
+'Category' =>'Category ',
+'Description' =>'Description',
+'Solution' =>'Solution',
+
+//My settings
+'LBL_CHANGE_PASSWORD'=>'Change Password',
+'LBL_OLD_PASSWORD'=>'Old Password',
+'LBL_NEW_PASSWORD'=>'New Password',
+'LBL_CONFIRM_PASSWORD'=>'Confirm Password',
+'LBL_MY_DETAILS'=>'My Details',
+'LBL_LAST_LOGIN'=>'Last Login',
+'LBL_SUPPORT_START_DATE'=>'Support Start Date',
+'LBL_SUPPORT_END_DATE'=>'Support End Date',
+'MSG_PASSWORD_CHANGED'=>'Password has been changed successfully.',
+'MSG_ENTER_NEW_PASSWORDS_SAME'=>'New & Confirm passwords did not match',
+'MSG_YOUR_PASSWORD_WRONG'=>'Incorrect old password.',
+
+//Added fields for Knowledge Base details
+'LBL_KNOWLEDGE_BASE'=>'Knowledge Base',
+'LBL_COMMENTS'=>'Comments',
+'LNK_CATEGORY'=>'Category',
+'LNK_PRODUCTS'=>'Products',
+'LBL_SEARCH_RESULT'=>'Search Result:',
+'LBL_NO_FAQ_IN_THIS_CATEGORY'=>'There are no Articles in this Category.',
+'LBL_NO_FAQ_IN_THIS_PRODUCT'=>'There are no Articles in this Product.',
+'LBL_NO_FAQ'=>'There are no Articles.',
+'LBL_NO_FAQ_IN_THIS_SEARCH_CRITERIA'=>'There are no Articles matched with the given Search Criteria.',
+'LBL_PRODUCT'=>'Product',
+'LBL_ADDED_ON'=>'Added on : ',
+'LBL_FAQ_ID'=>'Faq Id',
+'LBL_PRINT_THIS_PAGE'=>'Print this page',
+'LBL_EMAIL_THIS_PAGE'=>'Email this page',
+'LBL_ADD_TO_FAVORITES'=>'Add to Favorites',
+'LBL_RECENTLY_CREATED'=>'Recently Created Articles',
+'LBL_CREATED_DATE'=>'Created Date',
+'LBL_MODIFIED_DATE'=>'Modified Date',
+'KBASE_DETAILS'=>'The knowledge base is organized based on both categories and products, please select a category or product that you are interested in.
+Additionally, you can also search the entire knowledge base by entering keywords below.',
+'LBL_DOCUMENTS' =>'Documents Related',
+'LBL_FAQ_TITLE' =>'Knowledge Base Title',
+'LBL_FAQ_DETAIL'=>'Knowledge Base Detail',
+'LBL_ARTICLE_INTERESTED'=>'Here\'s an article you might be interested in:',
+'LBL_PRESS_CNTR_D'=>'Press Ctrl+D',
+
+//Contacts
+'Contact Information'=>'Contact Information',
+'Customer Portal Information'=>'Customer Portal Information',
+'Address Information'=>'Address Information',
+'Description Information'=>'Description Information',
+'Custom Information'=>'Custom Information',
+
+'First Name'=>'First Name',
+'Contact Id'=>'Contact Id',
+'Office Phone'=>'Office Phone',
+'Last Name'=>'Last Name',
+'Mobile'=>'Mobile',
+'Lead Source'=>'Lead Source',
+'Home Phone'=>'Home Phone',
+'Other Phone'=>'Other Phone',
+'Department'=>'Department',
+'Fax'=>'Fax',
+'Email'=>'Email',
+'Mailing Street'=>'Mailing Street',
+'Mailing Po Box'=>'Mailing PO Box',
+'Mailing City'=>'Mailing City',
+'Mailing State'=>'Mailing State',
+'Mailing Postal Code'=>'Mailing Postal Code',
+'Mailing Country'=>'Mailing Country',
+'Mailing Zip'=>'Mailing Zip',
+'Other Zip'=>'Other Zip',
+'Other Street'=>'Other Street',
+'Other Po Box'=>'Other PO Box',
+'Other City'=>'Other City',
+'Other State'=>'Other State',
+'Other Postal Code'=>'Other Postal Code',
+'Other Country'=>'Other Country',
+'Description Information'=>'Description Information',
+'LBL_CONTACTS'=>'Contacts',
+'Assistant'=>'Assistant',
+'Birthdate'=>'Birthdate',
+'Assistant Phone'=>'Assistant Phone',
+'Reports To'=>'Reports To',
+'Yahoo Id'=>'Yahoo Id',
+'Do Not Call'=>'Do Not Call',
+'Reference'=>'Reference',
+'Support End Date'=>'Support End Date',
+
+//products
+'LBL_PRODUCT_INFORMATION'=>'Products ',
+//Product Block Name
+'Product Information'=>'Product Information',
+'Pricing Information:'=>'Pricing Information:',
+'Stock Information:'=>'Stock Information:',
+'Description Information'=>'Description Information',
+//Products Fields
+'Product Name'=>'Product Name',
+'Product Active'=>'Product Active',
+'Sales Start Date'=>'Sales Start Date',
+'Product Category'=>'Product Category',
+'Sales End Date'=>'Sales End Date',
+'Vendor Name'=>'Vendor Name',
+'Vendor PartNo'=>'Vendor PartNo',
+'Product Sheet'=>'Product Sheet',
+'Product No'=>'Product No',
+'Part Number'=>'Part Number',
+'Manufacturer'=>'Manufacturer',
+'Support Start Date'=>'Support Start Date',
+'Support Expiry Date'=>'Support Expiry Date',
+'Website'=>'Website',
+'Mfr PartNo'=>'Mfr PartNo',
+'Serial No'=>'Serial No',
+'GL Account'=>'GL Account',
+'Unit Price'=>'Unit Price',
+'Commission Rate'=>'Commission Rate',
+'Usage Unit'=>'Usage Unit',
+'Qty/Unit'=>'Qty/Unit',
+'Qty In Stock'=>'Qty In Stock',
+'Reorder Level'=>'Reorder Level',
+'Handler'=>'Handler',
+'Qty In Demand'=>'Qty In Demand',
+'Description'=>'Description',
+
+//Quotes
+'LBL_QUOTE_INFORMATION'=>'Quotes',
+//Quotes Block Name
+'Quote Information'=>'Quote Information',
+'Address Information'=>'Address Information',
+'Terms & Conditions'=>'Terms & Conditions',
+'Description Information'=>'Description Information',
+//Quotes Fields
+'(Download PDF) Subject'=>'(Download PDF) Subject---',
+'Potential Name'=>'Potential Name',
+'Quote No'=>'Quote No',
+'Quote Stage'=>'Quote Stage',
+'Valid Till'=>'Valid Till',
+'Contact Name'=>'Contact Name',
+'Carrier'=>'Carrier',
+'Shipping'=>'Shipping',
+'Inventory Manager'=>'Inventory Manager',
+'Account Name'=>'Account Name',
+'Billing Address'=>'Billing Address',
+'Billing Po Box'=>'Billing Po Box',
+'Billing City'=>'Billing City',
+'Billing State'=>'Billing State',
+'Billing Code'=>'Billing Code',
+'Billing Country'=>'Billing Country',
+'Shipping Address'=>'Shipping Address',
+'Shipping Po Box'=>'Shipping Po Box',
+'Shipping City'=>'Shipping City',
+'Shipping State'=>'Shipping State',
+'Shipping Code'=>'Shipping Code',
+'Shipping Country'=>'Shipping Country',
+'Terms & Conditions'=>'Terms & Conditions',
+'Description'=>'Description',
+'LBL_PDF_CANNOT_GENERATE'=>'Cannot Generate PDF',
+
+//Invoices
+'LBL_INVOICE_INFORMATION'=>'Invoices',
+'Invoice Information'=>'Invoice Information',
+'Address Information'=>'Address Information',
+'Terms & Conditions'=>'Terms & Conditions',
+'Description Information'=>'Description Information',
+'(Download PDF) Subject'=>'(Download PDF) Subject',
+'Invoice No'=>'Invoice No',
+'Customer No'=>'Customer No',
+'Invoice Date'=>'Invoice Date',
+'Due Date'=>'Due Date',
+'Excise Duty'=>'Excise Duty',
+'Sales Commission'=>'Sales Commission',
+'Status'=>'Status',
+'Billing Address'=>'Billing Address',
+'Billing Po Box'=>'Billing Po Box',
+'Billing City'=>'Billing City',
+'Billing State'=>'Billing State',
+'Billing Code'=>'Billing Code',
+'Billing Country'=>'Billing Country',
+'Shipping Address'=>'Shipping Address',
+'Shipping Po Box'=>'Shipping Po Box',
+'Shipping City'=>'Shipping City',
+'Shipping State'=>'Shipping State',
+'Shipping Code'=>'Shipping Code',
+'Shipping Country'=>'Shipping Country',
+'Terms & Conditions'=>'Terms & Conditions',
+'Description'=>'Description',
+
+//Documents
+'LBL_NOTES_INFORMATION'=>'Documents',
+'Basic Information'=>'Basic Information',
+'File Information'=>'File Information',
+'Description'=>'Description',
+'Title'=>'Title',
+'Folder Name'=>'Folder Name',
+'Version'=>'Version',
+'Document No'=>'Document No',
+'Download Type'=>'Download Type',
+'File Name'=>'File Name',
+'File Type'=>'File Type',
+'Active'=>'Active',
+'File Size'=>'File Size',
+'Download Count'=>'Download Count',
+'Note'=>'Note',
+
+//Services
+'LBL_SERVICE' =>'Services',
+'Service Information'=>'Service Information',
+'Pricing Information:'=>'Pricing Information:',
+'Description Information'=>'Description Information',
+'Service Name'=>'Service Name',
+'Service No'=>'Service No',
+'Usage Unit'=>'Usage Unit',
+'Service Active'=>'Service Active',
+'No of Units'=>'No of Units',
+'Service Active'=>'Service Active',
+'No of Units'=>'No of Units',
+'Website'=>'Website',
+'Service Category'=>'Service Category',
+'Owner'=>'Owner',
+'Sales Start Date'=>'Sales Start Date',
+'Sales End Date'=>'Sales End Date',
+'Support Start Date'=>'Support Start Date',
+'Support Expiry Date'=>'Support Expiry Date',
+'Price'=>'Price',
+'Commission Rate'=>'Commission Rate',
+
+//Accounts
+'Account Information'=>'Account Information',
+'Address Information'=>'Address Information',
+'Description Information'=>'Description Information',
+'Account No'=>'Account No',
+'Website'=>'Website',
+'Phone'=>'Phone',
+'Ticker Symbol'=>'Ticker Symbol',
+'Member Of'=>'Member Of',
+'Other Phone'=>'Other Phone',
+'Employees'=>'Employees',
+'Email'=>'Email',
+'Other Email'=>'Other Email',
+'Ownership'=>'Ownership',
+'industry'=>'industry',
+'Rating'=>'Rating',
+'Type'=>'Type',
+'SIC Code'=>'SIC Code',
+'Email Opt Out'=>'Email Opt Out',
+'Annual Revenue'=>'Annual Revenue',
+'Assigned To'=>'Assigned To',
+'Notify Owner'=>'Notify Owner',
+'Billing Address'=>'Billing Address',
+'Billing Po Box'=>'Billing Po Box',
+'Billing City'=>'Billing City',
+'Billing State'=>'Billing State',
+'Billing Code'=>'Billing Code',
+'Billing Country'=>'Billing Country',
+'Shipping Address'=>'Shipping Address',
+'Shipping Po Box'=>'Shipping Po Box',
+'Shipping City'=>'Shipping City',
+'Shipping State'=>'Shipping State',
+'Shipping Code'=>'Shipping Code',
+'Shipping Country'=>'Shipping Country',
+
+//Customer Authenticate
+'LBL_CANNOT_CONNECT_SERVER'=>'Could not connect to server. Please contact the administrator.',
+'LBL_ENTER_VALID_USER'=>'Please Enter a Valid Username and Password',
+'LBL_VERSION_INCOMPATIBLE'=>'The Version is not Compatible',
+'LBL_NO_PERMISSION_FOR_ANY_MODULE'=>'NO PERMISSION TO VIEW ANY MODULE',
+
+//General
+'LBL_SUBMIT'=>'Submit',
+'LBL_CANCEL_ALT'=>'Cancel[Alt+X]',
+'LBL_SAVE_ALT'=>'Save[Alt+S]',
+'LBL_CANCEL'=>'Cancel',
+'LBL_SAVE'=>'Save',
+'LBL_BACK_BUTTON'=>'Back',
+'LBL_NOT_AUTHORISED'=>'You are not authorized to access this information',
+'SHOW'=>'Show',
+'MINE' =>'Mine',
+'ALL' =>'All',
+'LBL_FORGOT_LOGIN'=>'Forgot Password?',
+'LBL_YOUR_EMAIL'=>'Your email id :',
+'LBL_SEND_PASSWORD'=>'Send Password',
+'LBL_CLOSE'=>'Close',
+'LBL_LOGIN_NOTE'=>'Email ID and Password are case Insensitive.',
+'LBL_MY_SETTINGS'=>'My Settings',
+'LBL_LOG_OUT'=>'Log Out',
+'QUOTE_RELATED'=>'Quotes Related ',
+'INVOICE_RELATED'=>'Invoices Related ',
+'LBL_NOT_AVAILABLE'=>'Not available',
+'LBL_EMAILID'=>'Email ID :',
+'Created Time' =>'Created Time',
+'Modified Time' =>'Modified Time',
+'LBL_LANGUAGE'=>'Language',
+'Related To' =>'Related To',
+'MODULE_INACTIVE'=>'Module Inactive',
+
+// Tab names
+'HelpDesk' =>'Tickets',
+'Faq' =>'Knowledge Base',
+'Accounts' =>'Account',
+'Contacts' =>'Contacts',
+'Products' =>'Products',
+'Services' =>'Services',
+'Quotes' =>'Quotes',
+'Invoice' =>'Invoice',
+'Documents' =>'Documents',
+'HelpDesk' => 'Tickets',
+'Faq' => 'Knowledge Base',
+'Accounts' => 'Account',
+'Contacts' => 'Contacts',
+'Products' => 'Products',
+'Services' => 'Services',
+'Quotes' => 'Quotes',
+'Invoice' => 'Invoice',
+'Documents' => 'Documents',
+'MORE_THAN_ONE_USER'=>'There may more than one user with this details. Please contact your administrator.',
+'INVALID_USERNAME_OR_PASSWORD'=>'Invalid Username or Password',
+'LBL_CATEGORY' => 'Category',
+'Open'=>'Open',
+'In Progress'=>'In Progress',
+'Wait For Response'=>'Wait For Response',
+'Closed'=>'Closed' ,
+'LBL_ANSWER'=>'ANSWER : '
+
+);
+
+
+
+
+
+
+
+?>
diff --git a/oss/vtiger/trunk/customerportal/login.php b/oss/vtiger/trunk/customerportal/login.php
new file mode 100644
index 00000000..8e74d5fd
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/login.php
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+vtiger CRM 5 - CustomerPortal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/oss/vtiger/trunk/customerportal/nusoap/lib/nusoap.php b/oss/vtiger/trunk/customerportal/nusoap/lib/nusoap.php
new file mode 100644
index 00000000..75e1638a
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/nusoap/lib/nusoap.php
@@ -0,0 +1,5586 @@
+
+* @version $Id: nusoap.php,v 1.1 2005/04/29 05:09:16 sarajkumar Exp $
+* @access public
+*/
+class nusoap_base {
+
+ var $title = 'NuSOAP';
+ var $version = '0.6.7';
+ var $revision = '$Revision: 1.1 $';
+ var $error_str = false;
+ var $debug_str = '';
+ // toggles automatic encoding of special characters as entities
+ // (should always be true, I think)
+ var $charencoding = true;
+
+ /**
+ * set schema version
+ *
+ * @var XMLSchemaVersion
+ * @access public
+ */
+ var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
+
+ /**
+ * set charset encoding for outgoing messages
+ *
+ * @var soap_defencoding
+ * @access public
+ */
+ //var $soap_defencoding = 'UTF-8';
+ var $soap_defencoding = 'ISO-8859-1';
+
+ /**
+ * load namespace uris into an array of uri => prefix
+ *
+ * @var namespaces
+ * @access public
+ */
+ var $namespaces = array(
+ 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
+ 'xsd' => 'http://www.w3.org/2001/XMLSchema',
+ 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
+ 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
+ 'si' => 'http://soapinterop.org/xsd');
+ var $usedNamespaces = array();
+
+ /**
+ * load types into typemap array
+ * is this legacy yet?
+ * no, this is used by the xmlschema class to verify type => namespace mappings.
+ * @var typemap
+ * @access public
+ */
+ var $typemap = array(
+ 'http://www.w3.org/2001/XMLSchema' => array(
+ 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
+ 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
+ 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
+ // derived datatypes
+ 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
+ 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
+ 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
+ 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
+ 'http://www.w3.org/1999/XMLSchema' => array(
+ 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
+ 'float'=>'double','dateTime'=>'string',
+ 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
+ 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
+ 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
+ 'http://xml.apache.org/xml-soap' => array('Map')
+ );
+
+ /**
+ * entities to convert
+ *
+ * @var xmlEntities
+ * @access public
+ */
+ var $xmlEntities = array('quot' => '"','amp' => '&',
+ 'lt' => '<','gt' => '>','apos' => "'");
+
+ /**
+ * adds debug data to the class level debug string
+ *
+ * @param string $string debug data
+ * @access private
+ */
+ function debug($string){
+ $this->debug_str .= get_class($this).": $string\n";
+ }
+
+ /**
+ * expands entities, e.g. changes '<' to '<'.
+ *
+ * @param string $val The string in which to expand entities.
+ * @access private
+ */
+ function expandEntities($val) {
+ if ($this->charencoding) {
+ $val = str_replace('&', '&', $val);
+ $val = str_replace("'", ''', $val);
+ $val = str_replace('"', '"', $val);
+ $val = str_replace('<', '<', $val);
+ $val = str_replace('>', '>', $val);
+ }
+ return $val;
+ }
+
+ /**
+ * returns error string if present
+ *
+ * @return boolean $string error string
+ * @access public
+ */
+ function getError(){
+ if($this->error_str != ''){
+ return $this->error_str;
+ }
+ return false;
+ }
+
+ /**
+ * sets error string
+ *
+ * @return boolean $string error string
+ * @access private
+ */
+ function setError($str){
+ $this->error_str = $str;
+ }
+
+ /**
+ * detect if array is a simple array or a struct (associative array)
+ *
+ * @param $val The PHP array
+ * @return string (arraySimple|arrayStruct)
+ * @access private
+ */
+ function isArraySimpleOrStruct($val) {
+ $keyList = array_keys($val);
+ foreach ($keyList as $keyListValue) {
+ if (!is_int($keyListValue)) {
+ return 'arrayStruct';
+ }
+ }
+ return 'arraySimple';
+ }
+
+ /**
+ * serializes PHP values in accordance w/ section 5. Type information is
+ * not serialized if $use == 'literal'.
+ *
+ * @return string
+ * @access public
+ */
+ function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
+ if(is_object($val) && get_class($val) == 'soapval'){
+ return $val->serialize($use);
+ }
+ $this->debug( "in serialize_val: $val, $name, $type, $name_ns, $type_ns, $attributes, $use");
+ // if no name, use item
+ $name = (!$name|| is_numeric($name)) ? 'soapVal' : $name;
+ // if name has ns, add ns prefix to name
+ $xmlns = '';
+ if($name_ns){
+ $prefix = 'nu'.rand(1000,9999);
+ $name = $prefix.':'.$name;
+ $xmlns .= " xmlns:$prefix=\"$name_ns\"";
+ }
+ // if type is prefixed, create type prefix
+ if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
+ // need to fix this. shouldn't default to xsd if no ns specified
+ // w/o checking against typemap
+ $type_prefix = 'xsd';
+ } elseif($type_ns){
+ $type_prefix = 'ns'.rand(1000,9999);
+ $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
+ }
+ // serialize attributes if present
+ $atts = '';
+ if($attributes){
+ foreach($attributes as $k => $v){
+ $atts .= " $k=\"$v\"";
+ }
+ }
+ // serialize if an xsd built-in primitive type
+ if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
+ if (is_bool($val)) {
+ if ($type == 'boolean') {
+ $val = $val ? 'true' : 'false';
+ } elseif (! $val) {
+ $val = 0;
+ }
+ } else if (is_string($val)) {
+ $val = $this->expandEntities($val);
+ }
+ if ($use == 'literal') {
+ return "<$name$xmlns>$val$name>";
+ } else {
+ return "<$name$xmlns xsi:type=\"xsd:$type\">$val$name>";
+ }
+ }
+ // detect type and serialize
+ $xml = '';
+ switch(true) {
+ case ($type == '' && is_null($val)):
+ if ($use == 'literal') {
+ // TODO: depends on nillable
+ $xml .= "<$name$xmlns/>";
+ } else {
+ $xml .= "<$name$xmlns xsi:nil=\"true\"/>";
+ }
+ break;
+ case (is_bool($val) || $type == 'boolean'):
+ if ($type == 'boolean') {
+ $val = $val ? 'true' : 'false';
+ } elseif (! $val) {
+ $val = 0;
+ }
+ if ($use == 'literal') {
+ $xml .= "<$name$xmlns $atts>$val$name>";
+ } else {
+ $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val$name>";
+ }
+ break;
+ case (is_int($val) || is_long($val) || $type == 'int'):
+ if ($use == 'literal') {
+ $xml .= "<$name$xmlns $atts>$val$name>";
+ } else {
+ $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val$name>";
+ }
+ break;
+ case (is_float($val)|| is_double($val) || $type == 'float'):
+ if ($use == 'literal') {
+ $xml .= "<$name$xmlns $atts>$val$name>";
+ } else {
+ $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val$name>";
+ }
+ break;
+ case (is_string($val) || $type == 'string'):
+ $val = $this->expandEntities($val);
+ if ($use == 'literal') {
+ $xml .= "<$name$xmlns $atts>$val$name>";
+ } else {
+ $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val$name>";
+ }
+ break;
+ case is_object($val):
+ $name = get_class($val);
+ foreach(get_object_vars($val) as $k => $v){
+ $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
+ }
+ $xml .= '<'.$name.'>'.$pXml.''.$name.'>';
+ break;
+ break;
+ case (is_array($val) || $type):
+ // detect if struct or array
+ $valueType = $this->isArraySimpleOrStruct($val);
+ if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
+ $i = 0;
+ if(is_array($val) && count($val)> 0){
+ foreach($val as $v){
+ if(is_object($v) && get_class($v) == 'soapval'){
+ $tt_ns = $v->type_ns;
+ $tt = $v->type;
+ } elseif (is_array($v)) {
+ $tt = $this->isArraySimpleOrStruct($v);
+ } else {
+ $tt = gettype($v);
+ }
+ $array_types[$tt] = 1;
+ $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
+ ++$i;
+ }
+ if(count($array_types) > 1){
+ $array_typename = 'xsd:ur-type';
+ } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
+ if ($tt == 'integer') {
+ $tt = 'int';
+ }
+ $array_typename = 'xsd:'.$tt;
+ } elseif(isset($tt) && $tt == 'arraySimple'){
+ $array_typename = 'SOAP-ENC:Array';
+ } elseif(isset($tt) && $tt == 'arrayStruct'){
+ $array_typename = 'unnamed_struct_use_soapval';
+ } else {
+ // if type is prefixed, create type prefix
+ if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
+ $array_typename = 'xsd:' . $tt;
+ } elseif ($tt_ns) {
+ $tt_prefix = 'ns' . rand(1000, 9999);
+ $array_typename = "$tt_prefix:$tt";
+ $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
+ } else {
+ $array_typename = $tt;
+ }
+ }
+ $array_type = $i;
+ if ($use == 'literal') {
+ $type_str = '';
+ } else if (isset($type) && isset($type_prefix)) {
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
+ } else {
+ $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
+ }
+ // empty array
+ } else {
+ if ($use == 'literal') {
+ $type_str = '';
+ } else if (isset($type) && isset($type_prefix)) {
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
+ } else {
+ $type_str = " xsi:type=\"SOAP-ENC:Array\"";
+ }
+ }
+ $xml = "<$name$xmlns$type_str$atts>".$xml."$name>";
+ } else {
+ // got a struct
+ if(isset($type) && isset($type_prefix)){
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
+ } else {
+ $type_str = '';
+ }
+ if ($use == 'literal') {
+ $xml .= "<$name$xmlns $atts>";
+ } else {
+ $xml .= "<$name$xmlns$type_str$atts>";
+ }
+ foreach($val as $k => $v){
+ // Apache Map
+ if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
+ $xml .= '- ';
+ $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
+ $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
+ $xml .= '
';
+ } else {
+ $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
+ }
+ }
+ $xml .= "$name>";
+ }
+ break;
+ default:
+ $xml .= 'not detected, got '.gettype($val).' for '.$val;
+ break;
+ }
+ return $xml;
+ }
+
+ /**
+ * serialize message
+ *
+ * @param string body
+ * @param string headers optional
+ * @param array namespaces optional
+ * @param string style optional (rpc|document)
+ * @param string use optional (encoded|literal)
+ * @return string message
+ * @access public
+ */
+ function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded'){
+ // TODO: add an option to automatically run utf8_encode on $body and $headers
+ // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
+ // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
+
+ // serialize namespaces
+ $ns_string = '';
+ foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
+ $ns_string .= " xmlns:$k=\"$v\"";
+ }
+ if($style == 'rpc' && $use == 'encoded') {
+ $ns_string = ' SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string;
+ }
+
+ // serialize headers
+ if($headers){
+ $headers = "".$headers." ";
+ }
+ // serialize envelope
+ return
+ 'soap_defencoding .'"?'.">".
+ '".
+ $headers.
+ "".
+ $body.
+ " ".
+ " ";
+ }
+
+ function formatDump($str){
+ $str = htmlspecialchars($str);
+ return nl2br($str);
+ }
+
+ /**
+ * contracts a qualified name
+ *
+ * @param string $string qname
+ * @return string contracted qname
+ * @access private
+ */
+ function contractQname($qname){
+ // get element namespace
+ //$this->xdebug("Contract $qname");
+ if (strrpos($qname, ':')) {
+ // get unqualified name
+ $name = substr($qname, strrpos($qname, ':') + 1);
+ // get ns
+ $ns = substr($qname, 0, strrpos($qname, ':'));
+ $p = $this->getPrefixFromNamespace($ns);
+ if ($p) {
+ return $p . ':' . $name;
+ }
+ return $qname;
+ } else {
+ return $qname;
+ }
+ }
+
+ /**
+ * expands a qualified name
+ *
+ * @param string $string qname
+ * @return string expanded qname
+ * @access private
+ */
+ function expandQname($qname){
+ // get element prefix
+ if(strpos($qname,':') && !ereg('^http://',$qname)){
+ // get unqualified name
+ $name = substr(strstr($qname,':'),1);
+ // get ns prefix
+ $prefix = substr($qname,0,strpos($qname,':'));
+ if(isset($this->namespaces[$prefix])){
+ return $this->namespaces[$prefix].':'.$name;
+ } else {
+ return $qname;
+ }
+ } else {
+ return $qname;
+ }
+ }
+
+ /**
+ * returns the local part of a prefixed string
+ * returns the original string, if not prefixed
+ *
+ * @param string
+ * @return string
+ * @access public
+ */
+ function getLocalPart($str){
+ if($sstr = strrchr($str,':')){
+ // get unqualified name
+ return substr( $sstr, 1 );
+ } else {
+ return $str;
+ }
+ }
+
+ /**
+ * returns the prefix part of a prefixed string
+ * returns false, if not prefixed
+ *
+ * @param string
+ * @return mixed
+ * @access public
+ */
+ function getPrefix($str){
+ if($pos = strrpos($str,':')){
+ // get prefix
+ return substr($str,0,$pos);
+ }
+ return false;
+ }
+
+ /**
+ * pass it a prefix, it returns a namespace
+ * returns false if no namespace registered with the given prefix
+ *
+ * @param string
+ * @return mixed
+ * @access public
+ */
+ function getNamespaceFromPrefix($prefix){
+ if (isset($this->namespaces[$prefix])) {
+ return $this->namespaces[$prefix];
+ }
+ //$this->setError("No namespace registered for prefix '$prefix'");
+ return false;
+ }
+
+ /**
+ * returns the prefix for a given namespace (or prefix)
+ * or false if no prefixes registered for the given namespace
+ *
+ * @param string
+ * @return mixed
+ * @access public
+ */
+ function getPrefixFromNamespace($ns) {
+ foreach ($this->namespaces as $p => $n) {
+ if ($ns == $n || $ns == $p) {
+ $this->usedNamespaces[$p] = $n;
+ return $p;
+ }
+ }
+ return false;
+ }
+
+ function varDump($data) {
+ /* To avoid performance issue we skipping this */
+ /*ob_start();
+ var_dump($data);
+ $ret_val = ob_get_contents();
+ ob_end_clean();
+ return $ret_val;*/
+ return "";
+ }
+}
+
+// XML Schema Datatype Helper Functions
+
+//xsd:dateTime helpers
+
+/**
+* convert unix timestamp to ISO 8601 compliant date string
+*
+* @param string $timestamp Unix time stamp
+* @access public
+*/
+function timestamp_to_iso8601($timestamp,$utc=true){
+ $datestr = date('Y-m-d\TH:i:sO',$timestamp);
+ if($utc){
+ $eregStr =
+ '([0-9]{4})-'. // centuries & years CCYY-
+ '([0-9]{2})-'. // months MM-
+ '([0-9]{2})'. // days DD
+ 'T'. // separator T
+ '([0-9]{2}):'. // hours hh:
+ '([0-9]{2}):'. // minutes mm:
+ '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
+ '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
+
+ if(ereg($eregStr,$datestr,$regs)){
+ return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
+ }
+ return false;
+ } else {
+ return $datestr;
+ }
+}
+
+/**
+* convert ISO 8601 compliant date string to unix timestamp
+*
+* @param string $datestr ISO 8601 compliant date string
+* @access public
+*/
+function iso8601_to_timestamp($datestr){
+ $eregStr =
+ '([0-9]{4})-'. // centuries & years CCYY-
+ '([0-9]{2})-'. // months MM-
+ '([0-9]{2})'. // days DD
+ 'T'. // separator T
+ '([0-9]{2}):'. // hours hh:
+ '([0-9]{2}):'. // minutes mm:
+ '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
+ '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
+ if(ereg($eregStr,$datestr,$regs)){
+ // not utc
+ if($regs[8] != 'Z'){
+ $op = substr($regs[8],0,1);
+ $h = substr($regs[8],1,2);
+ $m = substr($regs[8],strlen($regs[8])-2,2);
+ if($op == '-'){
+ $regs[4] = $regs[4] + $h;
+ $regs[5] = $regs[5] + $m;
+ } elseif($op == '+'){
+ $regs[4] = $regs[4] - $h;
+ $regs[5] = $regs[5] - $m;
+ }
+ }
+ return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
+ } else {
+ return false;
+ }
+}
+
+function usleepWindows($usec)
+{
+ $start = gettimeofday();
+
+ do
+ {
+ $stop = gettimeofday();
+ $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
+ + $stop['usec'] - $start['usec'];
+ }
+ while ($timePassed < $usec);
+}
+
+?>
+* @version $Id: nusoap.php,v 1.1 2005/04/29 05:09:16 sarajkumar Exp $
+* @access public
+*/
+class soap_fault extends nusoap_base {
+
+ var $faultcode;
+ var $faultactor;
+ var $faultstring;
+ var $faultdetail;
+
+ /**
+ * constructor
+ *
+ * @param string $faultcode (client | server)
+ * @param string $faultactor only used when msg routed between multiple actors
+ * @param string $faultstring human readable error message
+ * @param string $faultdetail
+ */
+ function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
+ $this->faultcode = $faultcode;
+ $this->faultactor = $faultactor;
+ $this->faultstring = $faultstring;
+ $this->faultdetail = $faultdetail;
+ }
+
+ /**
+ * serialize a fault
+ *
+ * @access public
+ */
+ function serialize(){
+ $ns_string = '';
+ foreach($this->namespaces as $k => $v){
+ $ns_string .= "\n xmlns:$k=\"$v\"";
+ }
+ $return_msg =
+ 'soap_defencoding.'"?>'.
+ '\n".
+ ''.
+ ''.
+ ''.$this->expandEntities($this->faultcode).' '.
+ ''.$this->expandEntities($this->faultactor).' '.
+ ''.$this->expandEntities($this->faultstring).' '.
+ ''.$this->serialize_val($this->faultdetail).' '.
+ ' '.
+ ' '.
+ ' ';
+ return $return_msg;
+ }
+}
+
+
+
+?>
+* @version $Id: nusoap.php,v 1.1 2005/04/29 05:09:16 sarajkumar Exp $
+* @access public
+*/
+class XMLSchema extends nusoap_base {
+
+ // files
+ var $schema = '';
+ var $xml = '';
+ // namespaces
+ var $enclosingNamespaces;
+ // schema info
+ var $schemaInfo = array();
+ var $schemaTargetNamespace = '';
+ // types, elements, attributes defined by the schema
+ var $attributes = array();
+ var $complexTypes = array();
+ var $currentComplexType = false;
+ var $elements = array();
+ var $currentElement = false;
+ var $simpleTypes = array();
+ var $currentSimpleType = false;
+ // imports
+ var $imports = array();
+ // parser vars
+ var $parser;
+ var $position = 0;
+ var $depth = 0;
+ var $depth_array = array();
+ var $message = array();
+ var $defaultNamespace = array();
+
+ /**
+ * constructor
+ *
+ * @param string $schema schema document URI
+ * @param string $xml xml document URI
+ * @param string $namespaces namespaces defined in enclosing XML
+ * @access public
+ */
+ function XMLSchema($schema='',$xml='',$namespaces=array()){
+
+ $this->debug('xmlschema class instantiated, inside constructor');
+ // files
+ $this->schema = $schema;
+ $this->xml = $xml;
+
+ // namespaces
+ $this->enclosingNamespaces = $namespaces;
+ $this->namespaces = array_merge($this->namespaces, $namespaces);
+
+ // parse schema file
+ if($schema != ''){
+ $this->debug('initial schema file: '.$schema);
+ $this->parseFile($schema, 'schema');
+ }
+
+ // parse xml file
+ if($xml != ''){
+ $this->debug('initial xml file: '.$xml);
+ $this->parseFile($xml, 'xml');
+ }
+
+ }
+
+ /**
+ * parse an XML file
+ *
+ * @param string $xml, path/URL to XML file
+ * @param string $type, (schema | xml)
+ * @return boolean
+ * @access public
+ */
+ function parseFile($xml,$type){
+ // parse xml file
+ if($xml != ""){
+ $xmlStr = @join("",@file($xml));
+ if($xmlStr == ""){
+ $msg = 'Error reading XML from '.$xml;
+ $this->setError($msg);
+ $this->debug($msg);
+ return false;
+ } else {
+ $this->debug("parsing $xml");
+ $this->parseString($xmlStr,$type);
+ $this->debug("done parsing $xml");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * parse an XML string
+ *
+ * @param string $xml path or URL
+ * @param string $type, (schema|xml)
+ * @access private
+ */
+ function parseString($xml,$type){
+ // parse xml string
+ if($xml != ""){
+
+ // Create an XML parser.
+ $this->parser = xml_parser_create();
+ // Set the options for parsing the XML data.
+ xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
+
+ // Set the object for the parser.
+ xml_set_object($this->parser, $this);
+
+ // Set the element handlers for the parser.
+ if($type == "schema"){
+ xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
+ xml_set_character_data_handler($this->parser,'schemaCharacterData');
+ } elseif($type == "xml"){
+ xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
+ xml_set_character_data_handler($this->parser,'xmlCharacterData');
+ }
+
+ // Parse the XML file.
+ if(!xml_parse($this->parser,$xml,true)){
+ // Display an error message.
+ $errstr = sprintf('XML error parsing XML schema on line %d: %s',
+ xml_get_current_line_number($this->parser),
+ xml_error_string(xml_get_error_code($this->parser))
+ );
+ $this->debug($errstr);
+ $this->debug("XML payload:\n" . $xml);
+ $this->setError($errstr);
+ }
+
+ xml_parser_free($this->parser);
+ } else{
+ $this->debug('no xml passed to parseString()!!');
+ $this->setError('no xml passed to parseString()!!');
+ }
+ }
+
+ /**
+ * start-element handler
+ *
+ * @param string $parser XML parser object
+ * @param string $name element name
+ * @param string $attrs associative array of attributes
+ * @access private
+ */
+ function schemaStartElement($parser, $name, $attrs) {
+
+ // position in the total number of elements, starting from 0
+ $pos = $this->position++;
+ $depth = $this->depth++;
+ // set self as current value for this depth
+ $this->depth_array[$depth] = $pos;
+ $this->message[$pos] = array('cdata' => '');
+ if ($depth > 0) {
+ $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
+ } else {
+ $this->defaultNamespace[$pos] = false;
+ }
+
+ // get element prefix
+ if($prefix = $this->getPrefix($name)){
+ // get unqualified name
+ $name = $this->getLocalPart($name);
+ } else {
+ $prefix = '';
+ }
+
+ // loop thru attributes, expanding, and registering namespace declarations
+ if(count($attrs) > 0){
+ foreach($attrs as $k => $v){
+ // if ns declarations, add to class level array of valid namespaces
+ if(ereg("^xmlns",$k)){
+ //$this->xdebug("$k: $v");
+ //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
+ if($ns_prefix = substr(strrchr($k,':'),1)){
+ //$this->xdebug("Add namespace[$ns_prefix] = $v");
+ $this->namespaces[$ns_prefix] = $v;
+ } else {
+ $this->defaultNamespace[$pos] = $v;
+ if (! $this->getPrefixFromNamespace($v)) {
+ $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
+ }
+ }
+ if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema'){
+ $this->XMLSchemaVersion = $v;
+ $this->namespaces['xsi'] = $v.'-instance';
+ }
+ }
+ }
+ foreach($attrs as $k => $v){
+ // expand each attribute
+ $k = strpos($k,':') ? $this->expandQname($k) : $k;
+ $v = strpos($v,':') ? $this->expandQname($v) : $v;
+ $eAttrs[$k] = $v;
+ }
+ $attrs = $eAttrs;
+ } else {
+ $attrs = array();
+ }
+ // find status, register data
+ switch($name){
+ case 'all':
+ case 'choice':
+ case 'sequence':
+ //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
+ $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
+ if($name == 'all' || $name == 'sequence'){
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
+ }
+ break;
+ case 'attribute':
+ //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
+ $this->xdebug("parsing attribute " . $this->varDump($attrs));
+ if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
+ $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
+ if (!strpos($v, ':')) {
+ // no namespace in arrayType attribute value...
+ if ($this->defaultNamespace[$pos]) {
+ // ...so use the default
+ $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
+ }
+ }
+ }
+ if(isset($attrs['name'])){
+ $this->attributes[$attrs['name']] = $attrs;
+ $aname = $attrs['name'];
+ } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
+ if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
+ $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
+ } else {
+ $aname = '';
+ }
+ } elseif(isset($attrs['ref'])){
+ $aname = $attrs['ref'];
+ $this->attributes[$attrs['ref']] = $attrs;
+ }
+
+ if(isset($this->currentComplexType)){
+ $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
+ } elseif(isset($this->currentElement)){
+ $this->elements[$this->currentElement]['attrs'][$aname] = $attrs;
+ }
+ // arrayType attribute
+ if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
+ $prefix = $this->getPrefix($aname);
+ if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
+ $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
+ } else {
+ $v = '';
+ }
+ if(strpos($v,'[,]')){
+ $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
+ }
+ $v = substr($v,0,strpos($v,'[')); // clip the []
+ if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
+ $v = $this->XMLSchemaVersion.':'.$v;
+ }
+ $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
+ }
+ break;
+ case 'complexType':
+ if(isset($attrs['name'])){
+ $this->xdebug('processing named complexType '.$attrs['name']);
+ $this->currentElement = false;
+ $this->currentComplexType = $attrs['name'];
+ $this->complexTypes[$this->currentComplexType] = $attrs;
+ $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
+ if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
+ } else {
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
+ }
+ }else{
+ $this->xdebug('processing unnamed complexType for element '.$this->currentElement);
+ $this->currentComplexType = $this->currentElement . '_ContainedType';
+ $this->currentElement = false;
+ $this->complexTypes[$this->currentComplexType] = $attrs;
+ $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
+ if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
+ } else {
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
+ }
+ }
+ break;
+ case 'element':
+ // elements defined as part of a complex type should
+ // not really be added to $this->elements, but for some
+ // reason, they are
+ if(isset($attrs['type'])){
+ $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
+ $this->currentElement = $attrs['name'];
+ $this->elements[ $attrs['name'] ] = $attrs;
+ $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
+ if (!isset($this->elements[ $attrs['name'] ]['form'])) {
+ $this->elements[ $attrs['name'] ]['form'] = $this->schemaInfo['elementFormDefault'];
+ }
+ $ename = $attrs['name'];
+ } elseif(isset($attrs['ref'])){
+ $ename = $attrs['ref'];
+ } else {
+ $this->xdebug("processing untyped element ".$attrs['name']);
+ $this->currentElement = $attrs['name'];
+ $this->elements[ $attrs['name'] ] = $attrs;
+ $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
+ $this->elements[ $attrs['name'] ]['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType';
+ if (!isset($this->elements[ $attrs['name'] ]['form'])) {
+ $this->elements[ $attrs['name'] ]['form'] = $this->schemaInfo['elementFormDefault'];
+ }
+ }
+ if(isset($ename) && $this->currentComplexType){
+ $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
+ }
+ break;
+ // we ignore enumeration values
+ //case 'enumeration':
+ //break;
+ case 'import':
+ if (isset($attrs['schemaLocation'])) {
+ //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
+ $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
+ } else {
+ //$this->xdebug('import namespace ' . $attrs['namespace']);
+ $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
+ if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
+ $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
+ }
+ }
+ break;
+ case 'restriction':
+ //$this->xdebug("in restriction for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
+ if($this->currentElement){
+ $this->elements[$this->currentElement]['type'] = $attrs['base'];
+ } elseif($this->currentSimpleType){
+ $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
+ } elseif($this->currentComplexType){
+ $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
+ if(strstr($attrs['base'],':') == ':Array'){
+ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
+ }
+ }
+ break;
+ case 'schema':
+ $this->schemaInfo = $attrs;
+ $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
+ if (isset($attrs['targetNamespace'])) {
+ $this->schemaTargetNamespace = $attrs['targetNamespace'];
+ }
+ if (!isset($attrs['elementFormDefault'])) {
+ $this->schemaInfo['elementFormDefault'] = 'unqualified';
+ }
+ break;
+ case 'simpleType':
+ if(isset($attrs['name'])){
+ $this->xdebug("processing simpleType for name " . $attrs['name']);
+ $this->currentSimpleType = $attrs['name'];
+ $this->simpleTypes[ $attrs['name'] ] = $attrs;
+ $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
+ $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
+ } else {
+ //echo 'not parsing: '.$name;
+ //var_dump($attrs);
+ }
+ break;
+ default:
+ //$this->xdebug("do not have anything to do for element $name");
+ }
+ }
+
+ /**
+ * end-element handler
+ *
+ * @param string $parser XML parser object
+ * @param string $name element name
+ * @access private
+ */
+ function schemaEndElement($parser, $name) {
+ // bring depth down a notch
+ $this->depth--;
+ // position of current element is equal to the last value left in depth_array for my depth
+ if(isset($this->depth_array[$this->depth])){
+ $pos = $this->depth_array[$this->depth];
+ }
+ // move on...
+ if($name == 'complexType'){
+ $this->currentComplexType = false;
+ $this->currentElement = false;
+ }
+ if($name == 'element'){
+ $this->currentElement = false;
+ }
+ if($name == 'simpleType'){
+ $this->currentSimpleType = false;
+ }
+ }
+
+ /**
+ * element content handler
+ *
+ * @param string $parser XML parser object
+ * @param string $data element content
+ * @access private
+ */
+ function schemaCharacterData($parser, $data){
+ $pos = $this->depth_array[$this->depth - 1];
+ $this->message[$pos]['cdata'] .= $data;
+ }
+
+ /**
+ * serialize the schema
+ *
+ * @access public
+ */
+ function serializeSchema(){
+
+ $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
+ $xml = '';
+ // imports
+ if (sizeof($this->imports) > 0) {
+ foreach($this->imports as $ns => $list) {
+ foreach ($list as $ii) {
+ if ($ii['location'] != '') {
+ $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
+ } else {
+ $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
+ }
+ }
+ }
+ }
+ // complex types
+ foreach($this->complexTypes as $typeName => $attrs){
+ $contentStr = '';
+ // serialize child elements
+ if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
+ foreach($attrs['elements'] as $element => $eParts){
+ if(isset($eParts['ref'])){
+ $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
+ } else {
+ $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"/>\n";
+ }
+ }
+ }
+ // attributes
+ if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
+ foreach($attrs['attrs'] as $attr => $aParts){
+ $contentStr .= " <$schemaPrefix:attribute ref=\"".$this->contractQName($aParts['ref']).'"';
+ if(isset($aParts['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
+ $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
+ $contentStr .= ' wsdl:arrayType="'.$this->contractQName($aParts['http://schemas.xmlsoap.org/wsdl/:arrayType']).'"';
+ }
+ $contentStr .= "/>\n";
+ }
+ }
+ // if restriction
+ if( isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
+ $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." $schemaPrefix:restriction>\n";
+ }
+ // compositor obviates complex/simple content
+ if(isset($attrs['compositor']) && ($attrs['compositor'] != '')){
+ $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." $schemaPrefix:$attrs[compositor]>\n";
+ }
+ // complex or simple content
+ elseif((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
+ $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." $schemaPrefix:complexContent>\n";
+ }
+ // finalize complex type
+ if($contentStr != ''){
+ $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." $schemaPrefix:complexType>\n";
+ } else {
+ $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
+ }
+ $xml .= $contentStr;
+ }
+ // simple types
+ if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
+ foreach($this->simpleTypes as $typeName => $attr){
+ $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n contractQName($eParts['type'])."\"/>\n $schemaPrefix:simpleType>";
+ }
+ }
+ // elements
+ if(isset($this->elements) && count($this->elements) > 0){
+ foreach($this->elements as $element => $eParts){
+ $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
+ }
+ }
+ // attributes
+ if(isset($this->attributes) && count($this->attributes) > 0){
+ foreach($this->attributes as $attr => $aParts){
+ $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
+ }
+ }
+ // finish 'er up
+ $el = "<$schemaPrefix:schema targetNamespace=\"$this->schemaTargetNamespace\"\n";
+ foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
+ $el .= " xmlns:$nsp=\"$ns\"\n";
+ }
+ $xml = $el . ">\n".$xml."$schemaPrefix:schema>\n";
+ return $xml;
+ }
+
+ /**
+ * adds debug data to the clas level debug string
+ *
+ * @param string $string debug data
+ * @access private
+ */
+ function xdebug($string){
+ $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
+ }
+
+ /**
+ * get the PHP type of a user defined type in the schema
+ * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
+ * returns false if no type exists, or not w/ the given namespace
+ * else returns a string that is either a native php type, or 'struct'
+ *
+ * @param string $type, name of defined type
+ * @param string $ns, namespace of type
+ * @return mixed
+ * @access public
+ */
+ function getPHPType($type,$ns){
+ if(isset($this->typemap[$ns][$type])){
+ //print "found type '$type' and ns $ns in typemap ";
+ return $this->typemap[$ns][$type];
+ } elseif(isset($this->complexTypes[$type])){
+ //print "getting type '$type' and ns $ns from complexTypes array ";
+ return $this->complexTypes[$type]['phpType'];
+ }
+ return false;
+ }
+
+ /**
+ * returns an array of information about a given type
+ * returns false if no type exists by the given name
+ *
+ * typeDef = array(
+ * 'elements' => array(), // refs to elements array
+ * 'restrictionBase' => '',
+ * 'phpType' => '',
+ * 'order' => '(sequence|all)',
+ * 'attrs' => array() // refs to attributes array
+ * )
+ *
+ * @param string
+ * @return mixed
+ * @access public
+ */
+ function getTypeDef($type){
+ //$this->debug("in getTypeDef for type $type");
+ if(isset($this->complexTypes[$type])){
+ $this->xdebug("in getTypeDef, found complexType $type");
+ return $this->complexTypes[$type];
+ } elseif(isset($this->simpleTypes[$type])){
+ $this->xdebug("in getTypeDef, found simpleType $type");
+ if (!isset($this->simpleTypes[$type]['phpType'])) {
+ // get info for type to tack onto the simple type
+ // TODO: can this ever really apply (i.e. what is a simpleType really?)
+ $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
+ $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
+ $etype = $this->getTypeDef($uqType);
+ if ($etype) {
+ if (isset($etype['phpType'])) {
+ $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
+ }
+ if (isset($etype['elements'])) {
+ $this->simpleTypes[$type]['elements'] = $etype['elements'];
+ }
+ }
+ }
+ return $this->simpleTypes[$type];
+ } elseif(isset($this->elements[$type])){
+ $this->xdebug("in getTypeDef, found element $type");
+ if (!isset($this->elements[$type]['phpType'])) {
+ // get info for type to tack onto the element
+ $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
+ $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
+ $etype = $this->getTypeDef($uqType);
+ if ($etype) {
+ if (isset($etype['phpType'])) {
+ $this->elements[$type]['phpType'] = $etype['phpType'];
+ }
+ if (isset($etype['elements'])) {
+ $this->elements[$type]['elements'] = $etype['elements'];
+ }
+ } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
+ $this->elements[$type]['phpType'] = 'scalar';
+ }
+ }
+ return $this->elements[$type];
+ } elseif(isset($this->attributes[$type])){
+ $this->xdebug("in getTypeDef, found attribute $type");
+ return $this->attributes[$type];
+ }
+ $this->xdebug("in getTypeDef, did not find $type");
+ return false;
+ }
+
+ /**
+ * returns a sample serialization of a given type, or false if no type by the given name
+ *
+ * @param string $type, name of type
+ * @return mixed
+ * @access public
+ */
+ function serializeTypeDef($type){
+ //print "in sTD() for type $type ";
+ if($typeDef = $this->getTypeDef($type)){
+ $str .= '<'.$type;
+ if(is_array($typeDef['attrs'])){
+ foreach($attrs as $attName => $data){
+ $str .= " $attName=\"{type = ".$data['type']."}\"";
+ }
+ }
+ $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
+ if(count($typeDef['elements']) > 0){
+ $str .= ">";
+ foreach($typeDef['elements'] as $element => $eData){
+ $str .= $this->serializeTypeDef($element);
+ }
+ $str .= "$type>";
+ } elseif($typeDef['typeClass'] == 'element') {
+ $str .= ">$type>";
+ } else {
+ $str .= "/>";
+ }
+ return $str;
+ }
+ return false;
+ }
+
+ /**
+ * returns HTML form elements that allow a user
+ * to enter values for creating an instance of the given type.
+ *
+ * @param string $name, name for type instance
+ * @param string $type, name of type
+ * @return string
+ * @access public
+ */
+ function typeToForm($name,$type){
+ // get typedef
+ if($typeDef = $this->getTypeDef($type)){
+ // if struct
+ if($typeDef['phpType'] == 'struct'){
+ $buffer .= '';
+ // if array
+ } elseif($typeDef['phpType'] == 'array'){
+ $buffer .= '';
+ // if scalar
+ } else {
+ $buffer .= " ";
+ }
+ } else {
+ $buffer .= " ";
+ }
+ return $buffer;
+ }
+
+ /**
+ * adds a complex type to the schema
+ *
+ * example: array
+ *
+ * addType(
+ * 'ArrayOfstring',
+ * 'complexType',
+ * 'array',
+ * '',
+ * 'SOAP-ENC:Array',
+ * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
+ * 'xsd:string'
+ * );
+ *
+ * example: PHP associative array ( SOAP Struct )
+ *
+ * addType(
+ * 'SOAPStruct',
+ * 'complexType',
+ * 'struct',
+ * 'all',
+ * array('myVar'=> array('name'=>'myVar','type'=>'string')
+ * );
+ *
+ * @param name
+ * @param typeClass (complexType|simpleType|attribute)
+ * @param phpType: currently supported are array and struct (php assoc array)
+ * @param compositor (all|sequence|choice)
+ * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
+ * @param elements = array ( name = array(name=>'',type=>'') )
+ * @param attrs = array(
+ * array(
+ * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
+ * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
+ * )
+ * )
+ * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
+ *
+ */
+ function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
+ $this->complexTypes[$name] = array(
+ 'name' => $name,
+ 'typeClass' => $typeClass,
+ 'phpType' => $phpType,
+ 'compositor'=> $compositor,
+ 'restrictionBase' => $restrictionBase,
+ 'elements' => $elements,
+ 'attrs' => $attrs,
+ 'arrayType' => $arrayType
+ );
+
+ $this->xdebug("addComplexType $name: " . $this->varDump($this->complexTypes[$name]));
+ }
+
+ /**
+ * adds a simple type to the schema
+ *
+ * @param name
+ * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
+ * @param typeClass (simpleType)
+ * @param phpType: (scalar)
+ * @see xmlschema
+ *
+ */
+ function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar') {
+ $this->simpleTypes[$name] = array(
+ 'name' => $name,
+ 'typeClass' => $typeClass,
+ 'phpType' => $phpType,
+ 'type' => $restrictionBase
+ );
+
+ $this->xdebug("addSimpleType $name: " . $this->varDump($this->simpleTypes[$name]));
+ }
+}
+
+
+
+?>
+* @version $Id: nusoap.php,v 1.1 2005/04/29 05:09:16 sarajkumar Exp $
+* @access public
+*/
+class soapval extends nusoap_base {
+ /**
+ * constructor
+ *
+ * @param string $name optional name
+ * @param string $type optional type name
+ * @param mixed $value optional value
+ * @param string $namespace optional namespace of value
+ * @param string $type_namespace optional namespace of type
+ * @param array $attributes associative array of attributes to add to element serialization
+ * @access public
+ */
+ function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
+ $this->name = $name;
+ $this->value = $value;
+ $this->type = $type;
+ $this->element_ns = $element_ns;
+ $this->type_ns = $type_ns;
+ $this->attributes = $attributes;
+ }
+
+ /**
+ * return serialized value
+ *
+ * @return string XML data
+ * @access private
+ */
+ function serialize($use='encoded') {
+ return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes,$use);
+ }
+
+ /**
+ * decodes a soapval object into a PHP native type
+ *
+ * @param object $soapval optional SOAPx4 soapval object, else uses self
+ * @return mixed
+ * @access public
+ */
+ function decode(){
+ return $this->value;
+ }
+}
+
+
+
+?>
+* @version $Id: nusoap.php,v 1.1 2005/04/29 05:09:16 sarajkumar Exp $
+* @access public
+*/
+class soap_transport_http extends nusoap_base {
+
+ var $url = '';
+ var $uri = '';
+ var $scheme = '';
+ var $host = '';
+ var $port = '';
+ var $path = '';
+ var $request_method = 'POST';
+ var $protocol_version = '1.0';
+ var $encoding = '';
+ var $outgoing_headers = array();
+ var $incoming_headers = array();
+ var $outgoing_payload = '';
+ var $incoming_payload = '';
+ var $useSOAPAction = true;
+ var $persistentConnection = false;
+ var $ch = false; // cURL handle
+ var $username;
+ var $password;
+
+ /**
+ * constructor
+ */
+ function soap_transport_http($url){
+ $this->url = $url;
+
+ $u = parse_url($url);
+ foreach($u as $k => $v){
+ $this->debug("$k = $v");
+ $this->$k = $v;
+ }
+
+ // add any GET params to path
+ if(isset($u['query']) && $u['query'] != ''){
+ $this->path .= '?' . $u['query'];
+ }
+
+ // set default port
+ if(!isset($u['port'])){
+ if($u['scheme'] == 'https'){
+ $this->port = 443;
+ } else {
+ $this->port = 80;
+ }
+ }
+
+ $this->uri = $this->path;
+
+ // build headers
+ ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
+ $this->outgoing_headers['User-Agent'] = $this->title.'/'.$this->version.' ('.$rev[1].')';
+ if (!isset($u['port'])) {
+ $this->outgoing_headers['Host'] = $this->host;
+ } else {
+ $this->outgoing_headers['Host'] = $this->host.':'.$this->port;
+ }
+
+ if (isset($u['user']) && $u['user'] != '') {
+ $this->setCredentials($u['user'], isset($u['pass']) ? $u['pass'] : '');
+ }
+ }
+
+ function connect($connection_timeout=0,$response_timeout=30){
+ // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
+ // "regular" socket.
+ // TODO: disabled for now because OpenSSL must be *compiled* in (not just
+ // loaded), and until PHP5 stream_get_wrappers is not available.
+// if ($this->scheme == 'https') {
+// if (version_compare(phpversion(), '4.3.0') >= 0) {
+// if (extension_loaded('openssl')) {
+// $this->scheme = 'ssl';
+// $this->debug('Using SSL over OpenSSL');
+// }
+// }
+// }
+ $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
+ if ($this->scheme == 'http' || $this->scheme == 'ssl') {
+ // use persistent connection
+ if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
+ if (!feof($this->fp)) {
+ $this->debug('Re-use persistent connection');
+ return true;
+ }
+ fclose($this->fp);
+ $this->debug('Closed persistent connection at EOF');
+ }
+
+ // munge host if using OpenSSL
+ if ($this->scheme == 'ssl') {
+ $host = 'ssl://' . $this->host;
+ } else {
+ $host = $this->host;
+ }
+ $this->debug('calling fsockopen with host ' . $host);
+
+ // open socket
+ if($connection_timeout > 0){
+ $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
+ } else {
+ $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
+ }
+
+ // test pointer
+ if(!$this->fp) {
+ $msg = 'Couldn\'t open socket connection to server ' . $this->url;
+ if ($this->errno) {
+ $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
+ } else {
+ $msg .= ' prior to connect(). This is often a problem looking up the host name.';
+ }
+ $this->debug($msg);
+ $this->setError($msg);
+ return false;
+ }
+
+ // set response timeout
+ socket_set_timeout( $this->fp, $response_timeout);
+
+ $this->debug('socket connected');
+ return true;
+ } else if ($this->scheme == 'https') {
+ if (!extension_loaded('curl')) {
+ $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
+ return false;
+ }
+ $this->debug('connect using https');
+ // init CURL
+ $this->ch = curl_init();
+ // set url
+ $hostURL = ($this->port != '') ? "https://$this->host:$this->port" : "https://$this->host";
+ // add path
+ $hostURL .= $this->path;
+ curl_setopt($this->ch, CURLOPT_URL, $hostURL);
+ // ask for headers in the response output
+ curl_setopt($this->ch, CURLOPT_HEADER, 1);
+ // ask for the response output as the return value
+ curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
+ // encode
+ // We manage this ourselves through headers and encoding
+// if(function_exists('gzuncompress')){
+// curl_setopt($this->ch, CURLOPT_ENCODING, 'deflate');
+// }
+ // persistent connection
+ if ($this->persistentConnection) {
+ // The way we send data, we cannot use persistent connections, since
+ // there will be some "junk" at the end of our request.
+ //curl_setopt($this->ch, CURL_HTTP_VERSION_1_1, true);
+ $this->persistentConnection = false;
+ $this->outgoing_headers['Connection'] = 'close';
+ }
+ // set timeout (NOTE: cURL does not have separate connection and response timeouts)
+ if ($connection_timeout != 0) {
+ curl_setopt($this->ch, CURLOPT_TIMEOUT, $connection_timeout);
+ }
+
+ // recent versions of cURL turn on peer/host checking by default,
+ // while PHP binaries are not compiled with a default location for the
+ // CA cert bundle, so disable peer/host checking.
+//curl_setopt($this->ch, CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
+ curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0);
+
+ /*
+ TODO: support client certificates (thanks Tobias Boes)
+ curl_setopt($this->ch, CURLOPT_CAINFO, '$pathToPemFiles/rootca.pem');
+ curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 1);
+ curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 1);
+ curl_setopt($this->ch, CURLOPT_SSLCERT, '$pathToPemFiles/mycert.pem');
+ curl_setopt($this->ch, CURLOPT_SSLKEY, '$pathToPemFiles/mykey.pem');
+ */
+ $this->debug('cURL connection set up');
+ return true;
+ } else {
+ $this->setError('Unknown scheme ' . $this->scheme);
+ $this->debug('Unknown scheme ' . $this->scheme);
+ return false;
+ }
+ }
+
+ /**
+ * send the SOAP message via HTTP
+ *
+ * @param string $data message data
+ * @param integer $timeout set connection timeout in seconds
+ * @param integer $response_timeout set response timeout in seconds
+ * @return string data
+ * @access public
+ */
+ function send($data, $timeout=0, $response_timeout=30) {
+
+ $this->debug('entered send() with data of length: '.strlen($data));
+
+ $this->tryagain = true;
+ $tries = 0;
+ while ($this->tryagain) {
+ $this->tryagain = false;
+ if ($tries++ < 2) {
+ // make connnection
+ if (!$this->connect($timeout, $response_timeout)){
+ return false;
+ }
+
+ // send request
+ if (!$this->sendRequest($data)){
+ return false;
+ }
+
+ // get response
+ $respdata = $this->getResponse();
+ } else {
+ $this->setError('Too many tries to get an OK response');
+ }
+ }
+ $this->debug('end of send()');
+ return $respdata;
+ }
+
+
+ /**
+ * send the SOAP message via HTTPS 1.0 using CURL
+ *
+ * @param string $msg message data
+ * @param integer $timeout set connection timeout in seconds
+ * @param integer $response_timeout set response timeout in seconds
+ * @return string data
+ * @access public
+ */
+ function sendHTTPS($data, $timeout=0, $response_timeout=30) {
+ return $this->send($data, $timeout, $response_timeout);
+ }
+
+ /**
+ * if authenticating, set user credentials here
+ *
+ * @param string $username
+ * @param string $password
+ * @param string $authtype
+ * @param array $digestRequest
+ * @access public
+ */
+ function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array()) {
+ global $_SERVER;
+
+ $this->debug("Set credentials for authtype $authtype");
+ // cf. RFC 2617
+ if ($authtype == 'basic') {
+ $this->outgoing_headers['Authorization'] = 'Basic '.base64_encode($username.':'.$password);
+ } elseif ($authtype == 'digest') {
+ if (isset($digestRequest['nonce'])) {
+ $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
+
+ // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
+
+ // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
+ $A1 = $username. ':' . $digestRequest['realm'] . ':' . $password;
+
+ // H(A1) = MD5(A1)
+ $HA1 = md5($A1);
+
+ // A2 = Method ":" digest-uri-value
+ $A2 = 'POST:' . $this->uri;
+
+ // H(A2)
+ $HA2 = md5($A2);
+
+ // KD(secret, data) = H(concat(secret, ":", data))
+ // if qop == auth:
+ // request-digest = <"> < KD ( H(A1), unq(nonce-value)
+ // ":" nc-value
+ // ":" unq(cnonce-value)
+ // ":" unq(qop-value)
+ // ":" H(A2)
+ // ) <">
+ // if qop is missing,
+ // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
+
+ $unhashedDigest = '';
+ $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
+ $cnonce = $nonce;
+ if ($digestRequest['qop'] != '') {
+ $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
+ } else {
+ $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
+ }
+
+ $hashedDigest = md5($unhashedDigest);
+
+ $this->outgoing_headers['Authorization'] = 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->uri . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"';
+ }
+ }
+ $this->username = $username;
+ $this->password = $password;
+ $this->authtype = $authtype;
+ $this->digestRequest = $digestRequest;
+
+ if (isset($this->outgoing_headers['Authorization'])) {
+ $this->debug('Authorization header set: ' . substr($this->outgoing_headers['Authorization'], 0, 12) . '...');
+ } else {
+ $this->debug('Authorization header not set');
+ }
+ }
+
+ /**
+ * set the soapaction value
+ *
+ * @param string $soapaction
+ * @access public
+ */
+ function setSOAPAction($soapaction) {
+ $this->outgoing_headers['SOAPAction'] = '"' . $soapaction . '"';
+ }
+
+ /**
+ * use http encoding
+ *
+ * @param string $enc encoding style. supported values: gzip, deflate, or both
+ * @access public
+ */
+ function setEncoding($enc='gzip, deflate'){
+ $this->protocol_version = '1.1';
+ $this->outgoing_headers['Accept-Encoding'] = $enc;
+ $this->outgoing_headers['Connection'] = 'close';
+ $this->persistentConnection = false;
+ set_magic_quotes_runtime(0);
+ // deprecated
+ $this->encoding = $enc;
+ }
+
+ /**
+ * set proxy info here
+ *
+ * @param string $proxyhost
+ * @param string $proxyport
+ * @param string $proxyusername
+ * @param string $proxypassword
+ * @access public
+ */
+ function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
+ $this->uri = $this->url;
+ $this->host = $proxyhost;
+ $this->port = $proxyport;
+ if ($proxyusername != '' && $proxypassword != '') {
+ $this->outgoing_headers['Proxy-Authorization'] = ' Basic '.base64_encode($proxyusername.':'.$proxypassword);
+ }
+ }
+
+ /**
+ * decode a string that is encoded w/ "chunked' transfer encoding
+ * as defined in RFC2068 19.4.6
+ *
+ * @param string $buffer
+ * @param string $lb
+ * @returns string
+ * @access public
+ */
+ function decodeChunked($buffer, $lb){
+ // length := 0
+ $length = 0;
+ $new = '';
+
+ // read chunk-size, chunk-extension (if any) and CRLF
+ // get the position of the linebreak
+ $chunkend = strpos($buffer, $lb);
+ if ($chunkend == FALSE) {
+ $this->debug('no linebreak found in decodeChunked');
+ return $new;
+ }
+ $temp = substr($buffer,0,$chunkend);
+ $chunk_size = hexdec( trim($temp) );
+ $chunkstart = $chunkend + strlen($lb);
+ // while (chunk-size > 0) {
+ while ($chunk_size > 0) {
+ $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
+ $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
+
+ // Just in case we got a broken connection
+ if ($chunkend == FALSE) {
+ $chunk = substr($buffer,$chunkstart);
+ // append chunk-data to entity-body
+ $new .= $chunk;
+ $length += strlen($chunk);
+ break;
+ }
+
+ // read chunk-data and CRLF
+ $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
+ // append chunk-data to entity-body
+ $new .= $chunk;
+ // length := length + chunk-size
+ $length += strlen($chunk);
+ // read chunk-size and CRLF
+ $chunkstart = $chunkend + strlen($lb);
+
+ $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
+ if ($chunkend == FALSE) {
+ break; //Just in case we got a broken connection
+ }
+ $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
+ $chunk_size = hexdec( trim($temp) );
+ $chunkstart = $chunkend;
+ }
+ return $new;
+ }
+
+ /*
+ * Writes payload, including HTTP headers, to $this->outgoing_payload.
+ */
+ function buildPayload($data) {
+ // add content-length header
+ $this->outgoing_headers['Content-Length'] = strlen($data);
+
+ // start building outgoing payload:
+ $this->outgoing_payload = "$this->request_method $this->uri HTTP/$this->protocol_version\r\n";
+
+ // loop thru headers, serializing
+ foreach($this->outgoing_headers as $k => $v){
+ $this->outgoing_payload .= $k.': '.$v."\r\n";
+ }
+
+ // header/body separator
+ $this->outgoing_payload .= "\r\n";
+
+ // add data
+ $this->outgoing_payload .= $data;
+ }
+
+ function sendRequest($data){
+ // build payload
+ $this->buildPayload($data);
+
+ if ($this->scheme == 'http' || $this->scheme == 'ssl') {
+ // send payload
+ if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
+ $this->setError('couldn\'t write message data to socket');
+ $this->debug('couldn\'t write message data to socket');
+ return false;
+ }
+ $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
+ return true;
+ } else if ($this->scheme == 'https') {
+ // set payload
+ // TODO: cURL does say this should only be the verb, and in fact it
+ // turns out that the URI and HTTP version are appended to this, which
+ // some servers refuse to work with
+ //curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
+ foreach($this->outgoing_headers as $k => $v){
+ $curl_headers[] = "$k: $v";
+ }
+ curl_setopt($this->ch, CURLOPT_HTTPHEADER, $curl_headers);
+ if ($this->request_method == "POST") {
+ curl_setopt($this->ch, CURLOPT_POST, 1);
+ curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data);
+ } else {
+ }
+ $this->debug('set cURL payload');
+ return true;
+ }
+ }
+
+ function getResponse(){
+ $this->incoming_payload = '';
+
+ if ($this->scheme == 'http' || $this->scheme == 'ssl') {
+ // loop until headers have been retrieved
+ $data = '';
+ while (!isset($lb)){
+
+ // We might EOF during header read.
+ if(feof($this->fp)) {
+ $this->incoming_payload = $data;
+ $this->debug('found no headers before EOF after length ' . strlen($data));
+ $this->debug("received before EOF:\n" . $data);
+ $this->setError('server failed to send headers');
+ return false;
+ }
+
+ $tmp = fgets($this->fp, 256);
+ $tmplen = strlen($tmp);
+ $this->debug("read line of $tmplen bytes: " . trim($tmp));
+
+ if ($tmplen == 0) {
+ $this->incoming_payload = $data;
+ $this->debug('socket read of headers timed out after length ' . strlen($data));
+ $this->debug("read before timeout:\n" . $data);
+ $this->setError('socket read of headers timed out');
+ return false;
+ }
+
+ $data .= $tmp;
+ $pos = strpos($data,"\r\n\r\n");
+ if($pos > 1){
+ $lb = "\r\n";
+ } else {
+ $pos = strpos($data,"\n\n");
+ if($pos > 1){
+ $lb = "\n";
+ }
+ }
+ // remove 100 header
+ if(isset($lb) && ereg('^HTTP/1.1 100',$data)){
+ unset($lb);
+ $data = '';
+ }//
+ }
+ // store header data
+ $this->incoming_payload .= $data;
+ $this->debug('found end of headers after length ' . strlen($data));
+ // process headers
+ $header_data = trim(substr($data,0,$pos));
+ $header_array = explode($lb,$header_data);
+ $this->incoming_headers = array();
+ foreach($header_array as $header_line){
+ $arr = explode(':',$header_line, 2);
+ if(count($arr) > 1){
+ $header_name = strtolower(trim($arr[0]));
+ $this->incoming_headers[$header_name] = trim($arr[1]);
+ } else if (isset($header_name)) {
+ $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
+ }
+ }
+
+ // loop until msg has been received
+ if (isset($this->incoming_headers['content-length'])) {
+ $content_length = $this->incoming_headers['content-length'];
+ $chunked = false;
+ $this->debug("want to read content of length $content_length");
+ } else {
+ $content_length = 2147483647;
+ if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
+ $chunked = true;
+ $this->debug("want to read chunked content");
+ } else {
+ $chunked = false;
+ $this->debug("want to read content to EOF");
+ }
+ }
+ $data = '';
+ do {
+ if ($chunked) {
+ $tmp = fgets($this->fp, 256);
+ $tmplen = strlen($tmp);
+ $this->debug("read chunk line of $tmplen bytes");
+ if ($tmplen == 0) {
+ $this->incoming_payload = $data;
+ $this->debug('socket read of chunk length timed out after length ' . strlen($data));
+ $this->debug("read before timeout:\n" . $data);
+ $this->setError('socket read of chunk length timed out');
+ return false;
+ }
+ $content_length = hexdec(trim($tmp));
+ $this->debug("chunk length $content_length");
+ }
+ $strlen = 0;
+ while (($strlen < $content_length) && (!feof($this->fp))) {
+ $readlen = min(8192, $content_length - $strlen);
+ $tmp = fread($this->fp, $readlen);
+ $tmplen = strlen($tmp);
+ $this->debug("read buffer of $tmplen bytes");
+ if (($tmplen == 0) && (!feof($this->fp))) {
+ $this->incoming_payload = $data;
+ $this->debug('socket read of body timed out after length ' . strlen($data));
+ $this->debug("read before timeout:\n" . $data);
+ $this->setError('socket read of body timed out');
+ return false;
+ }
+ $strlen += $tmplen;
+ $data .= $tmp;
+ }
+ if ($chunked && ($content_length > 0)) {
+ $tmp = fgets($this->fp, 256);
+ $tmplen = strlen($tmp);
+ $this->debug("read chunk terminator of $tmplen bytes");
+ if ($tmplen == 0) {
+ $this->incoming_payload = $data;
+ $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
+ $this->debug("read before timeout:\n" . $data);
+ $this->setError('socket read of chunk terminator timed out');
+ return false;
+ }
+ }
+ } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
+ if (feof($this->fp)) {
+ $this->debug('read to EOF');
+ }
+ $this->debug('read body of length ' . strlen($data));
+ $this->incoming_payload .= $data;
+ $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
+
+ // close filepointer
+ if(
+ (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
+ (! $this->persistentConnection) || feof($this->fp)){
+ fclose($this->fp);
+ $this->fp = false;
+ $this->debug('closed socket');
+ }
+
+ // connection was closed unexpectedly
+ if($this->incoming_payload == ''){
+ $this->setError('no response from server');
+ return false;
+ }
+
+ // decode transfer-encoding
+// if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
+// if(!$data = $this->decodeChunked($data, $lb)){
+// $this->setError('Decoding of chunked data failed');
+// return false;
+// }
+ //print "\nde-chunked:\n---------------\n$data\n\n---------------\n ";
+ // set decoded payload
+// $this->incoming_payload = $header_data.$lb.$lb.$data;
+// }
+
+ } else if ($this->scheme == 'https') {
+ // send and receive
+ $this->debug('send and receive with cURL');
+ $this->incoming_payload = curl_exec($this->ch);
+ $data = $this->incoming_payload;
+
+ $cErr = curl_error($this->ch);
+ if ($cErr != '') {
+ $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.' ';
+ foreach(curl_getinfo($this->ch) as $k => $v){
+ $err .= "$k: $v ";
+ }
+ $this->debug($err);
+ $this->setError($err);
+ curl_close($this->ch);
+ return false;
+ } else {
+ //echo '';
+ //var_dump(curl_getinfo($this->ch));
+ //echo ' ';
+ }
+ // close curl
+ $this->debug('No cURL error, closing cURL');
+ curl_close($this->ch);
+
+ // remove 100 header
+ if (ereg('^HTTP/1.1 100',$data)) {
+ if ($pos = strpos($data,"\r\n\r\n")) {
+ $data = ltrim(substr($data,$pos));
+ } elseif($pos = strpos($data,"\n\n") ) {
+ $data = ltrim(substr($data,$pos));
+ }
+ }
+
+ // separate content from HTTP headers
+ if ($pos = strpos($data,"\r\n\r\n")) {
+ $lb = "\r\n";
+ } elseif( $pos = strpos($data,"\n\n")) {
+ $lb = "\n";
+ } else {
+ $this->debug('no proper separation of headers and document');
+ $this->setError('no proper separation of headers and document');
+ return false;
+ }
+ $header_data = trim(substr($data,0,$pos));
+ $header_array = explode($lb,$header_data);
+ $data = ltrim(substr($data,$pos));
+ $this->debug('found proper separation of headers and document');
+ $this->debug('cleaned data, stringlen: '.strlen($data));
+ // clean headers
+ foreach ($header_array as $header_line) {
+ $arr = explode(':',$header_line,2);
+ if (count($arr) > 1) {
+ $this->incoming_headers[strtolower(trim($arr[0]))] = trim($arr[1]);
+ }
+ }
+ }
+
+ // see if we need to resend the request with http digest authentication
+ if (isset($this->incoming_headers['www-authenticate']) && strstr($header_array[0], '401 Unauthorized')) {
+ $this->debug('Got 401 Unauthorized with WWW-Authenticate: ' . $this->incoming_headers['www-authenticate']);
+ if (substr("Digest ", $this->incoming_headers['www-authenticate'])) {
+ $this->debug('Server wants digest authentication');
+ // remove "Digest " from our elements
+ $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
+
+ // parse elements into array
+ $digestElements = explode(',', $digestString);
+ foreach ($digestElements as $val) {
+ $tempElement = explode('=', trim($val));
+ $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
+ }
+
+ // should have (at least) qop, realm, nonce
+ if (isset($digestRequest['nonce'])) {
+ $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
+ $this->tryagain = true;
+ return false;
+ }
+ }
+ $this->debug('HTTP authentication failed');
+ $this->setError('HTTP authentication failed');
+ return false;
+ }
+
+ // decode content-encoding
+ if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
+ if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
+ // if decoding works, use it. else assume data wasn't gzencoded
+ if(function_exists('gzuncompress')){
+ //$timer->setMarker('starting decoding of gzip/deflated content');
+ if($this->incoming_headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)){
+ $data = $degzdata;
+ } elseif($this->incoming_headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))){ // do our best
+ $data = $degzdata;
+ } else {
+ $this->setError('Errors occurred when trying to decode the data');
+ }
+ //$timer->setMarker('finished decoding of gzip/deflated content');
+ //print "\nde-inflated:\n---------------\n$data\n-------------\n ";
+ // set decoded payload
+ $this->incoming_payload = $header_data.$lb.$lb.$data;
+ } else {
+ $this->setError('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
+ }
+ }
+ }
+
+ if(strlen($data) == 0){
+ $this->debug('no data after headers!');
+ $this->setError('no data present after HTTP headers');
+ return false;
+ }
+
+ return $data;
+ }
+
+ function setContentType($type, $charset = false) {
+ $this->outgoing_headers['Content-Type'] = $type . ($charset ? '; charset=' . $charset : '');
+ }
+
+ function usePersistentConnection(){
+ if (isset($this->outgoing_headers['Accept-Encoding'])) {
+ return false;
+ }
+ $this->protocol_version = '1.1';
+ $this->persistentConnection = true;
+ $this->outgoing_headers['Connection'] = 'Keep-Alive';
+ return true;
+ }
+}
+
+?>
+* @version $Id: nusoap.php,v 1.1 2005/04/29 05:09:16 sarajkumar Exp $
+* @access public
+*/
+class soap_server extends nusoap_base {
+ var $headers = array(); // HTTP headers of request
+ var $request = ''; // HTTP request
+ var $requestHeaders = ''; // SOAP headers from request (incomplete namespace resolution) (text)
+ var $document = ''; // SOAP body request portion (incomplete namespace resolution) (text)
+ var $requestSOAP = ''; // SOAP payload for request (text)
+ var $methodURI = ''; // requested method namespace URI
+ var $methodname = ''; // name of method requested
+ var $methodparams = array(); // method parameters from request
+ var $xml_encoding = ''; // character set encoding of incoming (request) messages
+ var $SOAPAction = ''; // SOAP Action from request
+
+ var $outgoing_headers = array();// HTTP headers of response
+ var $response = ''; // HTTP response
+ var $responseHeaders = ''; // SOAP headers for response (text)
+ var $responseSOAP = ''; // SOAP payload for response (text)
+ var $methodreturn = false; // method return to place in response
+ var $methodreturnisliteralxml = false; // whether $methodreturn is a string of literal XML
+ var $fault = false; // SOAP fault for response
+ var $result = 'successful'; // text indication of result (for debugging)
+
+ var $operations = array(); // assoc array of operations => opData
+ var $wsdl = false; // wsdl instance
+ var $externalWSDLURL = false; // URL for WSDL
+ var $debug_flag = false; // whether to append debug to response as XML comment
+
+ /**
+ * constructor
+ * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
+ *
+ * @param mixed $wsdl file path or URL (string), or wsdl instance (object)
+ * @access public
+ */
+ function soap_server($wsdl=false){
+
+ // turn on debugging?
+ global $debug;
+ global $_REQUEST;
+ global $_SERVER;
+ global $HTTP_SERVER_VARS;
+
+ if (isset($debug)) {
+ $this->debug_flag = $debug;
+ } else if (isset($_REQUEST['debug'])) {
+ $this->debug_flag = $_REQUEST['debug'];
+ } else if (isset($_SERVER['QUERY_STRING'])) {
+ $qs = explode('&', $_SERVER['QUERY_STRING']);
+ foreach ($qs as $v) {
+ if (substr($v, 0, 6) == 'debug=') {
+ $this->debug_flag = substr($v, 6);
+ }
+ }
+ } else if (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
+ $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
+ foreach ($qs as $v) {
+ if (substr($v, 0, 6) == 'debug=') {
+ $this->debug_flag = substr($v, 6);
+ }
+ }
+ }
+
+ // wsdl
+ if($wsdl){
+ if (is_object($wsdl) && is_a($wsdl, 'wsdl')) {
+ $this->wsdl = $wsdl;
+ $this->externalWSDLURL = $this->wsdl->wsdl;
+ $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
+ } else {
+ $this->debug('Create wsdl from ' . $wsdl);
+ $this->wsdl = new wsdl($wsdl);
+ $this->externalWSDLURL = $wsdl;
+ }
+ $this->debug("wsdl...\n" . $this->wsdl->debug_str);
+ $this->wsdl->debug_str = '';
+ if($err = $this->wsdl->getError()){
+ die('WSDL ERROR: '.$err);
+ }
+ }
+ }
+
+ /**
+ * processes request and returns response
+ *
+ * @param string $data usually is the value of $HTTP_RAW_POST_DATA
+ * @access public
+ */
+ function service($data){
+ global $QUERY_STRING;
+ if(isset($_SERVER['QUERY_STRING'])){
+ $qs = $_SERVER['QUERY_STRING'];
+ } elseif(isset($GLOBALS['QUERY_STRING'])){
+ $qs = $GLOBALS['QUERY_STRING'];
+ } elseif(isset($QUERY_STRING) && $QUERY_STRING != ''){
+ $qs = $QUERY_STRING;
+ }
+
+ if(isset($qs) && ereg('wsdl', $qs) ){
+ // This is a request for WSDL
+ if($this->externalWSDLURL){
+ if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
+ header('Location: '.$this->externalWSDLURL);
+ } else { // assume file
+ header("Content-Type: text/xml\r\n");
+ $fp = fopen($this->externalWSDLURL, 'r');
+ fpassthru($fp);
+ }
+ } else {
+ header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
+ print $this->wsdl->serialize();
+ }
+ } elseif($data == '' && $this->wsdl){
+ // print web interface
+ print $this->webDescription();
+ } else {
+ // handle the request
+ $this->parse_request($data);
+ if (! $this->fault) {
+ $this->invoke_method();
+ }
+ if (! $this->fault) {
+ $this->serialize_return();
+ }
+ $this->send_response();
+ }
+ }
+
+ /**
+ * parses HTTP request headers.
+ *
+ * The following fields are set by this function (when successful)
+ *
+ * headers
+ * request
+ * xml_encoding
+ * SOAPAction
+ *
+ * @access private
+ */
+ function parse_http_headers() {
+ global $HTTP_SERVER_VARS;
+ global $_SERVER;
+
+ $this->request = '';
+ if(function_exists('getallheaders')){
+ $this->headers = getallheaders();
+ foreach($this->headers as $k=>$v){
+ $this->request .= "$k: $v\r\n";
+ $this->debug("$k: $v");
+ }
+ // get SOAPAction header
+ if(isset($this->headers['SOAPAction'])){
+ $this->SOAPAction = str_replace('"','',$this->headers['SOAPAction']);
+ }
+ // get the character encoding of the incoming request
+ if(strpos($this->headers['Content-Type'],'=')){
+ $enc = str_replace('"','',substr(strstr($this->headers["Content-Type"],'='),1));
+ if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
+ $this->xml_encoding = strtoupper($enc);
+ } else {
+ $this->xml_encoding = 'US-ASCII';
+ }
+ } else {
+ // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
+ $this->xml_encoding = 'UTF-8';
+ }
+ } elseif(isset($_SERVER) && is_array($_SERVER)){
+ foreach ($_SERVER as $k => $v) {
+ if (substr($k, 0, 5) == 'HTTP_') {
+ $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
+ } else {
+ $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $k))));
+ }
+ if ($k == 'Soapaction') {
+ // get SOAPAction header
+ $k = 'SOAPAction';
+ $v = str_replace('"', '', $v);
+ $v = str_replace('\\', '', $v);
+ $this->SOAPAction = $v;
+ } else if ($k == 'Content-Type') {
+ // get the character encoding of the incoming request
+ if (strpos($v, '=')) {
+ $enc = substr(strstr($v, '='), 1);
+ $enc = str_replace('"', '', $enc);
+ $enc = str_replace('\\', '', $enc);
+ if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
+ $this->xml_encoding = strtoupper($enc);
+ } else {
+ $this->xml_encoding = 'US-ASCII';
+ }
+ } else {
+ // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
+ $this->xml_encoding = 'UTF-8';
+ }
+ }
+ $this->headers[$k] = $v;
+ $this->request .= "$k: $v\r\n";
+ $this->debug("$k: $v");
+ }
+ } elseif (is_array($HTTP_SERVER_VARS)) {
+ foreach ($HTTP_SERVER_VARS as $k => $v) {
+ if (substr($k, 0, 5) == 'HTTP_') {
+ $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
+ if ($k == 'Soapaction') {
+ // get SOAPAction header
+ $k = 'SOAPAction';
+ $v = str_replace('"', '', $v);
+ $v = str_replace('\\', '', $v);
+ $this->SOAPAction = $v;
+ } else if ($k == 'Content-Type') {
+ // get the character encoding of the incoming request
+ if (strpos($v, '=')) {
+ $enc = substr(strstr($v, '='), 1);
+ $enc = str_replace('"', '', $enc);
+ $enc = str_replace('\\', '', $enc);
+ if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
+ $this->xml_encoding = strtoupper($enc);
+ } else {
+ $this->xml_encoding = 'US-ASCII';
+ }
+ } else {
+ // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
+ $this->xml_encoding = 'UTF-8';
+ }
+ }
+ $this->headers[$k] = $v;
+ $this->request .= "$k: $v\r\n";
+ $this->debug("$k: $v");
+ }
+ }
+ }
+ }
+
+ /**
+ * parses a request
+ *
+ * The following fields are set by this function (when successful)
+ *
+ * headers
+ * request
+ * xml_encoding
+ * SOAPAction
+ * request
+ * requestSOAP
+ * methodURI
+ * methodname
+ * methodparams
+ * requestHeaders
+ * document
+ *
+ * This sets the fault field on error
+ *
+ * @param string $data XML string
+ * @access private
+ */
+ function parse_request($data='') {
+ $this->debug('entering parse_request() on '.date('H:i Y-m-d'));
+ $this->parse_http_headers();
+ $this->debug('got character encoding: '.$this->xml_encoding);
+ // uncompress if necessary
+ if (isset($this->headers['Content-Encoding']) && $this->headers['Content-Encoding'] != '') {
+ $this->debug('got content encoding: ' . $this->headers['Content-Encoding']);
+ if ($this->headers['Content-Encoding'] == 'deflate' || $this->headers['Content-Encoding'] == 'gzip') {
+ // if decoding works, use it. else assume data wasn't gzencoded
+ if (function_exists('gzuncompress')) {
+ if ($this->headers['Content-Encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
+ $data = $degzdata;
+ } elseif ($this->headers['Content-Encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
+ $data = $degzdata;
+ } else {
+ $this->fault('Server', 'Errors occurred when trying to decode the data');
+ return;
+ }
+ } else {
+ $this->fault('Server', 'This Server does not support compressed data');
+ return;
+ }
+ }
+ }
+ $this->request .= "\r\n".$data;
+ $this->requestSOAP = $data;
+ // parse response, get soap parser obj
+ $parser = new soap_parser($data,$this->xml_encoding);
+ // parser debug
+ $this->debug("parser debug: \n".$parser->debug_str);
+ // if fault occurred during message parsing
+ if($err = $parser->getError()){
+ $this->result = 'fault: error in msg parsing: '.$err;
+ $this->fault('Server',"error in msg parsing:\n".$err);
+ // else successfully parsed request into soapval object
+ } else {
+ // get/set methodname
+ $this->methodURI = $parser->root_struct_namespace;
+ $this->methodname = $parser->root_struct_name;
+ $this->debug('method name: '.$this->methodname);
+ $this->debug('calling parser->get_response()');
+ $this->methodparams = $parser->get_response();
+ // get SOAP headers
+ $this->requestHeaders = $parser->getHeaders();
+ // add document for doclit support
+ $this->document = $parser->document;
+ }
+ $this->debug('leaving parse_request() on '.date('H:i Y-m-d'));
+ }
+
+ /**
+ * invokes a PHP function for the requested SOAP method
+ *
+ * The following fields are set by this function (when successful)
+ *
+ * methodreturn
+ *
+ * Note that the PHP function that is called may also set the following
+ * fields to affect the response sent to the client
+ *
+ * responseHeaders
+ * outgoing_headers
+ *
+ * This sets the fault field on error
+ *
+ * @access private
+ */
+ function invoke_method() {
+ $this->debug('entering invoke_method');
+ // does method exist?
+ if(!function_exists($this->methodname)){
+ // "method not found" fault here
+ $this->debug("method '$this->methodname' not found!");
+ $this->result = 'fault: method not found';
+ $this->fault('Server',"method '$this->methodname' not defined in service");
+ return;
+ }
+ if($this->wsdl){
+ if(!$this->opData = $this->wsdl->getOperationData($this->methodname)){
+ //if(
+ $this->fault('Server',"Operation '$this->methodname' is not defined in the WSDL for this service");
+ return;
+ }
+ $this->debug('opData is ' . $this->varDump($this->opData));
+ }
+ $this->debug("method '$this->methodname' exists");
+ // evaluate message, getting back parameters
+ // verify that request parameters match the method's signature
+ if(! $this->verify_method($this->methodname,$this->methodparams)){
+ // debug
+ $this->debug('ERROR: request not verified against method signature');
+ $this->result = 'fault: request failed validation against method signature';
+ // return fault
+ $this->fault('Server',"Operation '$this->methodname' not defined in service.");
+ return;
+ }
+
+ // if there are parameters to pass
+ $this->debug('params var dump '.$this->varDump($this->methodparams));
+ if($this->methodparams){
+ $this->debug("calling '$this->methodname' with params");
+ if (! function_exists('call_user_func_array')) {
+ $this->debug('calling method using eval()');
+ $funcCall = $this->methodname.'(';
+ foreach($this->methodparams as $param) {
+ $funcCall .= "\"$param\",";
+ }
+ $funcCall = substr($funcCall, 0, -1).')';
+ $this->debug('function call: '.$funcCall);
+ @eval("\$this->methodreturn = $funcCall;");
+ } else {
+ $this->debug('calling method using call_user_func_array()');
+ $this->methodreturn = call_user_func_array("$this->methodname",$this->methodparams);
+ }
+ } else {
+ // call method w/ no parameters
+ $this->debug("calling $this->methodname w/ no params");
+ $m = $this->methodname;
+ $this->methodreturn = @$m();
+ }
+ $this->debug('methodreturn var dump'.$this->varDump($this->methodreturn));
+ $this->debug("leaving invoke_method: called method $this->methodname, received $this->methodreturn of type ".gettype($this->methodreturn));
+ }
+
+ /**
+ * serializes the return value from a PHP function into a full SOAP Envelope
+ *
+ * The following fields are set by this function (when successful)
+ *
+ * responseSOAP
+ *
+ * This sets the fault field on error
+ *
+ * @access private
+ */
+ function serialize_return() {
+ $this->debug("Entering serialize_return");
+ // if we got nothing back. this might be ok (echoVoid)
+ if(isset($this->methodreturn) && ($this->methodreturn != '' || is_bool($this->methodreturn))) {
+ // if fault
+ if(get_class($this->methodreturn) == 'soap_fault'){
+ $this->debug('got a fault object from method');
+ $this->fault = $this->methodreturn;
+ return;
+ } elseif ($this->methodreturnisliteralxml) {
+ $return_val = $this->methodreturn;
+ // returned value(s)
+ } else {
+ $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
+ $this->debug('serializing return value');
+ if($this->wsdl){
+ // weak attempt at supporting multiple output params
+ if(sizeof($this->opData['output']['parts']) > 1){
+ $opParams = $this->methodreturn;
+ } else {
+ // TODO: is this really necessary?
+ $opParams = array($this->methodreturn);
+ }
+ $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
+ if($errstr = $this->wsdl->getError()){
+ $this->debug('got wsdl error: '.$errstr);
+ $this->fault('Server', 'got wsdl error: '.$errstr);
+ return;
+ }
+ } else {
+ $return_val = $this->serialize_val($this->methodreturn, 'return');
+ }
+ }
+ $this->debug('return val: '.$this->varDump($return_val));
+ } else {
+ $return_val = '';
+ $this->debug('got no response from method');
+ }
+ $this->debug('serializing response');
+ if ($this->wsdl) {
+ if ($this->opData['style'] == 'rpc') {
+ $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.' methodname."Response>";
+ } else {
+ $payload = $return_val;
+ }
+ } else {
+ $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.' methodname."Response>";
+ }
+ $this->result = 'successful';
+ if($this->wsdl){
+ //if($this->debug_flag){
+ $this->debug("WSDL debug data:\n".$this->wsdl->debug_str);
+ // }
+ // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
+ $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style']);
+ } else {
+ $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
+ }
+ $this->debug("Leaving serialize_return");
+ }
+
+ /**
+ * sends an HTTP response
+ *
+ * The following fields are set by this function (when successful)
+ *
+ * outgoing_headers
+ * response
+ *
+ * @access private
+ */
+ function send_response() {
+ $this->debug('Enter send_response');
+ if ($this->fault) {
+ $payload = $this->fault->serialize();
+ $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
+ $this->outgoing_headers[] = "Status: 500 Internal Server Error";
+ } else {
+ $payload = $this->responseSOAP;
+ // Some combinations of PHP+Web server allow the Status
+ // to come through as a header. Since OK is the default
+ // just do nothing.
+ // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
+ // $this->outgoing_headers[] = "Status: 200 OK";
+ }
+ // add debug data if in debug mode
+ if(isset($this->debug_flag) && $this->debug_flag){
+ while (strpos($this->debug_str, '--')) {
+ $this->debug_str = str_replace('--', '- -', $this->debug_str);
+ }
+ $payload .= "";
+ }
+ $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
+ ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
+ $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
+ // Let the Web server decide about this
+ //$this->outgoing_headers[] = "Connection: Close\r\n";
+ $this->outgoing_headers[] = "Content-Type: text/xml; charset=$this->soap_defencoding";
+ //begin code to compress payload - by John
+ if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['Accept-Encoding'])) {
+ if (strstr($this->headers['Accept-Encoding'], 'deflate')) {
+ if (function_exists('gzcompress')) {
+ if (isset($this->debug_flag) && $this->debug_flag) {
+ $payload .= "";
+ }
+ $this->outgoing_headers[] = "Content-Encoding: deflate";
+ $payload = gzcompress($payload);
+ } else {
+ if (isset($this->debug_flag) && $this->debug_flag) {
+ $payload .= "";
+ }
+ }
+ } else if (strstr($this->headers['Accept-Encoding'], 'gzip')) {
+ if (function_exists('gzencode')) {
+ if (isset($this->debug_flag) && $this->debug_flag) {
+ $payload .= "";
+ }
+ $this->outgoing_headers[] = "Content-Encoding: gzip";
+ $payload = gzencode($payload);
+ } else {
+ if (isset($this->debug_flag) && $this->debug_flag) {
+ $payload .= "";
+ }
+ }
+ }
+ }
+ //end code
+ $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
+ reset($this->outgoing_headers);
+ foreach($this->outgoing_headers as $hdr){
+ header($hdr, false);
+ }
+ $this->response = join("\r\n",$this->outgoing_headers)."\r\n".$payload;
+ print $payload;
+ }
+
+ /**
+ * takes the value that was created by parsing the request
+ * and compares to the method's signature, if available.
+ *
+ * @param mixed
+ * @return boolean
+ * @access private
+ */
+ function verify_method($operation,$request){
+ if(isset($this->wsdl) && is_object($this->wsdl)){
+ if($this->wsdl->getOperationData($operation)){
+ return true;
+ }
+ } elseif(isset($this->operations[$operation])){
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * add a method to the dispatch map
+ *
+ * @param string $methodname
+ * @param string $in array of input values
+ * @param string $out array of output values
+ * @access public
+ */
+ function add_to_map($methodname,$in,$out){
+ $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
+ }
+
+ /**
+ * register a service with the server
+ *
+ * @param string $methodname
+ * @param string $in assoc array of input values: key = param name, value = param type
+ * @param string $out assoc array of output values: key = param name, value = param type
+ * @param string $namespace
+ * @param string $soapaction
+ * @param string $style optional (rpc|document)
+ * @param string $use optional (encoded|literal)
+ * @param string $documentation optional Description to include in WSDL
+ * @access public
+ */
+ function register($name,$in=false,$out=false,$namespace=false,$soapaction=false,$style=false,$use=false,$documentation=''){
+ if($this->externalWSDLURL){
+ die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
+ }
+ if(false == $in) {
+ }
+ if(false == $out) {
+ }
+ if(false == $namespace) {
+ }
+ if(false == $soapaction) {
+ $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
+ $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
+ $soapaction = "http://$SERVER_NAME$SCRIPT_NAME/$name";
+ }
+ if(false == $style) {
+ $style = "rpc";
+ }
+ if(false == $use) {
+ $use = "encoded";
+ }
+
+ $this->operations[$name] = array(
+ 'name' => $name,
+ 'in' => $in,
+ 'out' => $out,
+ 'namespace' => $namespace,
+ 'soapaction' => $soapaction,
+ 'style' => $style);
+ if($this->wsdl){
+ $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation);
+ }
+ return true;
+ }
+
+ /**
+ * create a fault. this also acts as a flag to the server that a fault has occured.
+ *
+ * @param string faultcode
+ * @param string faultstring
+ * @param string faultactor
+ * @param string faultdetail
+ * @access public
+ */
+ function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
+ $this->fault = new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
+ }
+
+ /**
+ * prints html description of services
+ *
+ * @access private
+ */
+ function webDescription(){
+ $b = '
+ NuSOAP: '.$this->wsdl->serviceName.'
+
+
+
+
+
+
+
'.$this->wsdl->serviceName.'
+
+
View the WSDL for the service.
+ Click on an operation name to view it's details.
+
';
+ foreach($this->wsdl->getOperations() as $op => $data){
+ $b .= "$op ";
+ // create hidden div
+ $b .= "
+
Close ";
+ foreach($data as $donnie => $marie){ // loop through opdata
+ if($donnie == 'input' || $donnie == 'output'){ // show input/output data
+ $b .= "
".ucfirst($donnie).': ';
+ foreach($marie as $captain => $tenille){ // loop through data
+ if($captain == 'parts'){ // loop thru parts
+ $b .= " $captain:
";
+ //if(is_array($tenille)){
+ foreach($tenille as $joanie => $chachi){
+ $b .= " $joanie: $chachi
";
+ }
+ //}
+ } else {
+ $b .= " $captain: $tenille
";
+ }
+ }
+ } else {
+ $b .= "
".ucfirst($donnie).": $marie
";
+ }
+ }
+ $b .= '
';
+ }
+ $b .= '
+
+
';
+ return $b;
+ }
+
+ /**
+ * sets up wsdl object
+ * this acts as a flag to enable internal WSDL generation
+ *
+ * @param string $serviceName, name of the service
+ * @param string $namespace optional tns namespace
+ * @param string $endpoint optional URL of service endpoint
+ * @param string $style optional (rpc|document) WSDL style (also specified by operation)
+ * @param string $transport optional SOAP transport
+ * @param string $schemaTargetNamespace optional targetNamespace for service schema
+ */
+ function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
+ {
+ $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
+ $SERVER_PORT = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : $GLOBALS['SERVER_PORT'];
+ if ($SERVER_PORT == 80) {
+ $SERVER_PORT = '';
+ } else {
+ $SERVER_PORT = ':' . $SERVER_PORT;
+ }
+ $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
+ if(false == $namespace) {
+ $namespace = "http://$SERVER_NAME/soap/$serviceName";
+ }
+
+ if(false == $endpoint) {
+ if (isset($_SERVER['HTTPS'])) {
+ $HTTPS = $_SERVER['HTTPS'];
+ } elseif (isset($GLOBALS['HTTPS'])) {
+ $HTTPS = $GLOBALS['HTTPS'];
+ } else {
+ $HTTPS = '0';
+ }
+ if ($HTTPS == '1' || $HTTPS == 'on') {
+ $SCHEME = 'https';
+ } else {
+ $SCHEME = 'http';
+ }
+ $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
+ }
+
+ if(false == $schemaTargetNamespace) {
+ $schemaTargetNamespace = $namespace;
+ }
+
+ $this->wsdl = new wsdl;
+ $this->wsdl->serviceName = $serviceName;
+ $this->wsdl->endpoint = $endpoint;
+ $this->wsdl->namespaces['tns'] = $namespace;
+ $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
+ $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
+ if ($schemaTargetNamespace != $namespace) {
+ $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
+ }
+ $this->wsdl->schemas[$schemaTargetNamespace][0] = new xmlschema('', '', $this->wsdl->namespaces);
+ $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
+ $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
+ $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
+ $this->wsdl->bindings[$serviceName.'Binding'] = array(
+ 'name'=>$serviceName.'Binding',
+ 'style'=>$style,
+ 'transport'=>$transport,
+ 'portType'=>$serviceName.'PortType');
+ $this->wsdl->ports[$serviceName.'Port'] = array(
+ 'binding'=>$serviceName.'Binding',
+ 'location'=>$endpoint,
+ 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
+ }
+}
+
+
+
+?>
+* @version $Id: nusoap.php,v 1.1 2005/04/29 05:09:16 sarajkumar Exp $
+* @access public
+*/
+class wsdl extends nusoap_base {
+ // URL or filename of the root of this WSDL
+ var $wsdl;
+ // define internal arrays of bindings, ports, operations, messages, etc.
+ var $schemas = array();
+ var $currentSchema;
+ var $message = array();
+ var $complexTypes = array();
+ var $messages = array();
+ var $currentMessage;
+ var $currentOperation;
+ var $portTypes = array();
+ var $currentPortType;
+ var $bindings = array();
+ var $currentBinding;
+ var $ports = array();
+ var $currentPort;
+ var $opData = array();
+ var $status = '';
+ var $documentation = false;
+ var $endpoint = '';
+ // array of wsdl docs to import
+ var $import = array();
+ // parser vars
+ var $parser;
+ var $position = 0;
+ var $depth = 0;
+ var $depth_array = array();
+ // for getting wsdl
+ var $proxyhost = '';
+ var $proxyport = '';
+ var $proxyusername = '';
+ var $proxypassword = '';
+ var $timeout = 0;
+ var $response_timeout = 30;
+
+ /**
+ * constructor
+ *
+ * @param string $wsdl WSDL document URL
+ * @param string $proxyhost
+ * @param string $proxyport
+ * @param string $proxyusername
+ * @param string $proxypassword
+ * @param integer $timeout set the connection timeout
+ * @param integer $response_timeout set the response timeout
+ * @access public
+ */
+ function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30){
+ $this->wsdl = $wsdl;
+ $this->proxyhost = $proxyhost;
+ $this->proxyport = $proxyport;
+ $this->proxyusername = $proxyusername;
+ $this->proxypassword = $proxypassword;
+ $this->timeout = $timeout;
+ $this->response_timeout = $response_timeout;
+
+ // parse wsdl file
+ if ($wsdl != "") {
+ $this->debug('initial wsdl URL: ' . $wsdl);
+ $this->parseWSDL($wsdl);
+ }
+ // imports
+ // TODO: handle imports more properly, grabbing them in-line and nesting them
+ $imported_urls = array();
+ $imported = 1;
+ while ($imported > 0) {
+ $imported = 0;
+ // Schema imports
+ foreach ($this->schemas as $ns => $list) {
+ foreach ($list as $xs) {
+ $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
+ foreach ($xs->imports as $ns2 => $list2) {
+ for ($ii = 0; $ii < count($list2); $ii++) {
+ if (! $list2[$ii]['loaded']) {
+ $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
+ $url = $list2[$ii]['location'];
+ if ($url != '') {
+ $urlparts = parse_url($url);
+ if (!isset($urlparts['host'])) {
+ $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] .
+ substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
+ }
+ if (! in_array($url, $imported_urls)) {
+ $this->parseWSDL($url);
+ $imported++;
+ $imported_urls[] = $url;
+ }
+ } else {
+ $this->debug("Unexpected scenario: empty URL for unloaded import");
+ }
+ }
+ }
+ }
+ }
+ }
+ // WSDL imports
+ $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
+ foreach ($this->import as $ns => $list) {
+ for ($ii = 0; $ii < count($list); $ii++) {
+ if (! $list[$ii]['loaded']) {
+ $this->import[$ns][$ii]['loaded'] = true;
+ $url = $list[$ii]['location'];
+ if ($url != '') {
+ $urlparts = parse_url($url);
+ if (!isset($urlparts['host'])) {
+ $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] .
+ substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
+ }
+ if (! in_array($url, $imported_urls)) {
+ $this->parseWSDL($url);
+ $imported++;
+ $imported_urls[] = $url;
+ }
+ } else {
+ $this->debug("Unexpected scenario: empty URL for unloaded import");
+ }
+ }
+ }
+ }
+ }
+ // add new data to operation data
+ foreach($this->bindings as $binding => $bindingData) {
+ if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
+ foreach($bindingData['operations'] as $operation => $data) {
+ $this->debug('post-parse data gathering for ' . $operation);
+ $this->bindings[$binding]['operations'][$operation]['input'] =
+ isset($this->bindings[$binding]['operations'][$operation]['input']) ?
+ array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
+ $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
+ $this->bindings[$binding]['operations'][$operation]['output'] =
+ isset($this->bindings[$binding]['operations'][$operation]['output']) ?
+ array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
+ $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
+ if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
+ $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
+ }
+ if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
+ $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
+ }
+ if (isset($bindingData['style'])) {
+ $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
+ }
+ $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
+ $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
+ $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
+ }
+ }
+ }
+ }
+
+ /**
+ * parses the wsdl document
+ *
+ * @param string $wsdl path or URL
+ * @access private
+ */
+ function parseWSDL($wsdl = '')
+ {
+ if ($wsdl == '') {
+ $this->debug('no wsdl passed to parseWSDL()!!');
+ $this->setError('no wsdl passed to parseWSDL()!!');
+ return false;
+ }
+
+ // parse $wsdl for url format
+ $wsdl_props = parse_url($wsdl);
+
+ if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
+ $this->debug('getting WSDL http(s) URL ' . $wsdl);
+ // get wsdl
+ $tr = new soap_transport_http($wsdl);
+ $tr->request_method = 'GET';
+ $tr->useSOAPAction = false;
+ if($this->proxyhost && $this->proxyport){
+ $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
+ }
+ if (isset($wsdl_props['user'])) {
+ $tr->setCredentials($wsdl_props['user'],$wsdl_props['pass']);
+ }
+ $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
+ //$this->debug("WSDL request\n" . $tr->outgoing_payload);
+ //$this->debug("WSDL response\n" . $tr->incoming_payload);
+ $this->debug("transport debug data...\n" . $tr->debug_str);
+ // catch errors
+ if($err = $tr->getError() ){
+ $errstr = 'HTTP ERROR: '.$err;
+ $this->debug($errstr);
+ $this->setError($errstr);
+ unset($tr);
+ return false;
+ }
+ unset($tr);
+ } else {
+ // $wsdl is not http(s), so treat it as a file URL or plain file path
+ if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
+ $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
+ } else {
+ $path = $wsdl;
+ }
+ $this->debug('getting WSDL file ' . $path);
+ if ($fp = @fopen($path, 'r')) {
+ $wsdl_string = '';
+ while ($data = fread($fp, 32768)) {
+ $wsdl_string .= $data;
+ }
+ fclose($fp);
+ } else {
+ $errstr = "Bad path to WSDL file $path";
+ $this->debug($errstr);
+ $this->setError($errstr);
+ return false;
+ }
+ }
+ // end new code added
+ // Create an XML parser.
+ $this->parser = xml_parser_create();
+ // Set the options for parsing the XML data.
+ // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
+ xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
+ // Set the object for the parser.
+ xml_set_object($this->parser, $this);
+ // Set the element handlers for the parser.
+ xml_set_element_handler($this->parser, 'start_element', 'end_element');
+ xml_set_character_data_handler($this->parser, 'character_data');
+ // Parse the XML file.
+ if (!xml_parse($this->parser, $wsdl_string, true)) {
+ // Display an error message.
+ $errstr = sprintf(
+ 'XML error parsing WSDL from %s on line %d: %s',
+ $wsdl,
+ xml_get_current_line_number($this->parser),
+ xml_error_string(xml_get_error_code($this->parser))
+ );
+ $this->debug($errstr);
+ $this->debug("XML payload:\n" . $wsdl_string);
+ $this->setError($errstr);
+ return false;
+ }
+ // free the parser
+ xml_parser_free($this->parser);
+ // catch wsdl parse errors
+ if($this->getError()){
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * start-element handler
+ *
+ * @param string $parser XML parser object
+ * @param string $name element name
+ * @param string $attrs associative array of attributes
+ * @access private
+ */
+ function start_element($parser, $name, $attrs)
+ {
+ if ($this->status == 'schema') {
+ $this->currentSchema->schemaStartElement($parser, $name, $attrs);
+ $this->debug_str .= $this->currentSchema->debug_str;
+ $this->currentSchema->debug_str = '';
+ } elseif (ereg('schema$', $name)) {
+ // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
+ $this->status = 'schema';
+ $this->currentSchema = new xmlschema('', '', $this->namespaces);
+ $this->currentSchema->schemaStartElement($parser, $name, $attrs);
+ $this->debug_str .= $this->currentSchema->debug_str;
+ $this->currentSchema->debug_str = '';
+ } else {
+ // position in the total number of elements, starting from 0
+ $pos = $this->position++;
+ $depth = $this->depth++;
+ // set self as current value for this depth
+ $this->depth_array[$depth] = $pos;
+ $this->message[$pos] = array('cdata' => '');
+ // get element prefix
+ if (ereg(':', $name)) {
+ // get ns prefix
+ $prefix = substr($name, 0, strpos($name, ':'));
+ // get ns
+ $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
+ // get unqualified name
+ $name = substr(strstr($name, ':'), 1);
+ }
+
+ if (count($attrs) > 0) {
+ foreach($attrs as $k => $v) {
+ // if ns declarations, add to class level array of valid namespaces
+ if (ereg("^xmlns", $k)) {
+ if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
+ $this->namespaces[$ns_prefix] = $v;
+ } else {
+ $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
+ }
+ if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema') {
+ $this->XMLSchemaVersion = $v;
+ $this->namespaces['xsi'] = $v . '-instance';
+ }
+ } //
+ // expand each attribute
+ $k = strpos($k, ':') ? $this->expandQname($k) : $k;
+ if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
+ $v = strpos($v, ':') ? $this->expandQname($v) : $v;
+ }
+ $eAttrs[$k] = $v;
+ }
+ $attrs = $eAttrs;
+ } else {
+ $attrs = array();
+ }
+ // find status, register data
+ switch ($this->status) {
+ case 'message':
+ if ($name == 'part') {
+ if (isset($attrs['type'])) {
+ $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs));
+ $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
+ }
+ if (isset($attrs['element'])) {
+ $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'];
+ }
+ }
+ break;
+ case 'portType':
+ switch ($name) {
+ case 'operation':
+ $this->currentPortOperation = $attrs['name'];
+ $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
+ if (isset($attrs['parameterOrder'])) {
+ $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
+ }
+ break;
+ case 'documentation':
+ $this->documentation = true;
+ break;
+ // merge input/output data
+ default:
+ $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
+ $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
+ break;
+ }
+ break;
+ case 'binding':
+ switch ($name) {
+ case 'binding':
+ // get ns prefix
+ if (isset($attrs['style'])) {
+ $this->bindings[$this->currentBinding]['prefix'] = $prefix;
+ }
+ $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
+ break;
+ case 'header':
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
+ break;
+ case 'operation':
+ if (isset($attrs['soapAction'])) {
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
+ }
+ if (isset($attrs['style'])) {
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
+ }
+ if (isset($attrs['name'])) {
+ $this->currentOperation = $attrs['name'];
+ $this->debug("current binding operation: $this->currentOperation");
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
+ }
+ break;
+ case 'input':
+ $this->opStatus = 'input';
+ break;
+ case 'output':
+ $this->opStatus = 'output';
+ break;
+ case 'body':
+ if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
+ } else {
+ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
+ }
+ break;
+ }
+ break;
+ case 'service':
+ switch ($name) {
+ case 'port':
+ $this->currentPort = $attrs['name'];
+ $this->debug('current port: ' . $this->currentPort);
+ $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
+
+ break;
+ case 'address':
+ $this->ports[$this->currentPort]['location'] = $attrs['location'];
+ $this->ports[$this->currentPort]['bindingType'] = $namespace;
+ $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
+ $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
+ break;
+ }
+ break;
+ }
+ // set status
+ switch ($name) {
+ case 'import':
+ if (isset($attrs['location'])) {
+ $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
+ $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
+ } else {
+ $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
+ if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
+ $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
+ }
+ $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
+ }
+ break;
+ //wait for schema
+ //case 'types':
+ // $this->status = 'schema';
+ // break;
+ case 'message':
+ $this->status = 'message';
+ $this->messages[$attrs['name']] = array();
+ $this->currentMessage = $attrs['name'];
+ break;
+ case 'portType':
+ $this->status = 'portType';
+ $this->portTypes[$attrs['name']] = array();
+ $this->currentPortType = $attrs['name'];
+ break;
+ case "binding":
+ if (isset($attrs['name'])) {
+ // get binding name
+ if (strpos($attrs['name'], ':')) {
+ $this->currentBinding = $this->getLocalPart($attrs['name']);
+ } else {
+ $this->currentBinding = $attrs['name'];
+ }
+ $this->status = 'binding';
+ $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
+ $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
+ }
+ break;
+ case 'service':
+ $this->serviceName = $attrs['name'];
+ $this->status = 'service';
+ $this->debug('current service: ' . $this->serviceName);
+ break;
+ case 'definitions':
+ foreach ($attrs as $name => $value) {
+ $this->wsdl_info[$name] = $value;
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * end-element handler
+ *
+ * @param string $parser XML parser object
+ * @param string $name element name
+ * @access private
+ */
+ function end_element($parser, $name){
+ // unset schema status
+ if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) {
+ $this->status = "";
+ $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
+ }
+ if ($this->status == 'schema') {
+ $this->currentSchema->schemaEndElement($parser, $name);
+ } else {
+ // bring depth down a notch
+ $this->depth--;
+ }
+ // end documentation
+ if ($this->documentation) {
+ //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
+ //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
+ $this->documentation = false;
+ }
+ }
+
+ /**
+ * element content handler
+ *
+ * @param string $parser XML parser object
+ * @param string $data element content
+ * @access private
+ */
+ function character_data($parser, $data)
+ {
+ $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
+ if (isset($this->message[$pos]['cdata'])) {
+ $this->message[$pos]['cdata'] .= $data;
+ }
+ if ($this->documentation) {
+ $this->documentation .= $data;
+ }
+ }
+
+ function getBindingData($binding)
+ {
+ if (is_array($this->bindings[$binding])) {
+ return $this->bindings[$binding];
+ }
+ }
+
+ /**
+ * returns an assoc array of operation names => operation data
+ *
+ * @param string $bindingType eg: soap, smtp, dime (only soap is currently supported)
+ * @return array
+ * @access public
+ */
+ function getOperations($bindingType = 'soap')
+ {
+ $ops = array();
+ if ($bindingType == 'soap') {
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
+ }
+ // loop thru ports
+ foreach($this->ports as $port => $portData) {
+ // binding type of port matches parameter
+ if ($portData['bindingType'] == $bindingType) {
+ //$this->debug("getOperations for port $port");
+ //$this->debug("port data: " . $this->varDump($portData));
+ //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
+ // merge bindings
+ if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
+ $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
+ }
+ }
+ }
+ return $ops;
+ }
+
+ /**
+ * returns an associative array of data necessary for calling an operation
+ *
+ * @param string $operation , name of operation
+ * @param string $bindingType , type of binding eg: soap
+ * @return array
+ * @access public
+ */
+ function getOperationData($operation, $bindingType = 'soap')
+ {
+ if ($bindingType == 'soap') {
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
+ }
+ // loop thru ports
+ foreach($this->ports as $port => $portData) {
+ // binding type of port matches parameter
+ if ($portData['bindingType'] == $bindingType) {
+ // get binding
+ //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
+ foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
+ if ($operation == $bOperation) {
+ $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
+ return $opData;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * returns an array of information about a given type
+ * returns false if no type exists by the given name
+ *
+ * typeDef = array(
+ * 'elements' => array(), // refs to elements array
+ * 'restrictionBase' => '',
+ * 'phpType' => '',
+ * 'order' => '(sequence|all)',
+ * 'attrs' => array() // refs to attributes array
+ * )
+ *
+ * @param $type string
+ * @param $ns string
+ * @return mixed
+ * @access public
+ * @see xmlschema
+ */
+ function getTypeDef($type, $ns) {
+ if ((! $ns) && isset($this->namespaces['tns'])) {
+ $ns = $this->namespaces['tns'];
+ }
+ if (isset($this->schemas[$ns])) {
+ foreach ($this->schemas[$ns] as $xs) {
+ $t = $xs->getTypeDef($type);
+ $this->debug_str .= $xs->debug_str;
+ $xs->debug_str = '';
+ if ($t) {
+ return $t;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * serialize the parsed wsdl
+ *
+ * @return string , serialization of WSDL
+ * @access public
+ */
+ function serialize()
+ {
+ $xml = 'namespaces as $k => $v) {
+ $xml .= " xmlns:$k=\"$v\"";
+ }
+ // 10.9.02 - add poulter fix for wsdl and tns declarations
+ if (isset($this->namespaces['wsdl'])) {
+ $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
+ }
+ if (isset($this->namespaces['tns'])) {
+ $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
+ }
+ $xml .= '>';
+ // imports
+ if (sizeof($this->import) > 0) {
+ foreach($this->import as $ns => $list) {
+ foreach ($list as $ii) {
+ if ($ii['location'] != '') {
+ $xml .= ' ';
+ } else {
+ $xml .= ' ';
+ }
+ }
+ }
+ }
+ // types
+ if (count($this->schemas)>=1) {
+ $xml .= '';
+ foreach ($this->schemas as $ns => $list) {
+ foreach ($list as $xs) {
+ $xml .= $xs->serializeSchema();
+ }
+ }
+ $xml .= ' ';
+ }
+ // messages
+ if (count($this->messages) >= 1) {
+ foreach($this->messages as $msgName => $msgParts) {
+ $xml .= '';
+ if(is_array($msgParts)){
+ foreach($msgParts as $partName => $partType) {
+ // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.' ';
+ if (strpos($partType, ':')) {
+ $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
+ } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
+ // print 'checking typemap: '.$this->XMLSchemaVersion.' ';
+ $typePrefix = 'xsd';
+ } else {
+ foreach($this->typemap as $ns => $types) {
+ if (isset($types[$partType])) {
+ $typePrefix = $this->getPrefixFromNamespace($ns);
+ }
+ }
+ if (!isset($typePrefix)) {
+ die("$partType has no namespace!");
+ }
+ }
+ $xml .= ' ';
+ }
+ }
+ $xml .= ' ';
+ }
+ }
+ // bindings & porttypes
+ if (count($this->bindings) >= 1) {
+ $binding_xml = '';
+ $portType_xml = '';
+ foreach($this->bindings as $bindingName => $attrs) {
+ $binding_xml .= '';
+ $binding_xml .= ' ';
+ $portType_xml .= '';
+ foreach($attrs['operations'] as $opName => $opParts) {
+ $binding_xml .= '';
+ $binding_xml .= ' ';
+ if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
+ $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
+ } else {
+ $enc_style = '';
+ }
+ $binding_xml .= ' ';
+ if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
+ $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
+ } else {
+ $enc_style = '';
+ }
+ $binding_xml .= ' ';
+ $binding_xml .= ' ';
+ $portType_xml .= '';
+ }
+ $portType_xml .= ' ';
+ $portType_xml .= ' ';
+ $portType_xml .= ' ';
+ }
+ $portType_xml .= ' ';
+ $binding_xml .= ' ';
+ }
+ $xml .= $portType_xml . $binding_xml;
+ }
+ // services
+ $xml .= '';
+ if (count($this->ports) >= 1) {
+ foreach($this->ports as $pName => $attrs) {
+ $xml .= '';
+ $xml .= ' ';
+ $xml .= ' ';
+ }
+ }
+ $xml .= ' ';
+ return $xml . ' ';
+ }
+
+ /**
+ * serialize a PHP value according to a WSDL message definition
+ *
+ * TODO
+ * - multi-ref serialization
+ * - validate PHP values against type definitions, return errors if invalid
+ *
+ * @param string $ type name
+ * @param mixed $ param value
+ * @return mixed new param or false if initial value didn't validate
+ */
+ function serializeRPCParameters($operation, $direction, $parameters)
+ {
+ $this->debug('in serializeRPCParameters with operation '.$operation.', direction '.$direction.' and '.count($parameters).' param(s), and xml schema version ' . $this->XMLSchemaVersion);
+
+ if ($direction != 'input' && $direction != 'output') {
+ $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
+ $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
+ return false;
+ }
+ if (!$opData = $this->getOperationData($operation)) {
+ $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
+ $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
+ return false;
+ }
+ $this->debug($this->varDump($opData));
+
+ // Get encoding style for output and set to current
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
+ if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
+ $encodingStyle = $opData['output']['encodingStyle'];
+ $enc_style = $encodingStyle;
+ }
+
+ // set input params
+ $xml = '';
+ if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
+
+ $use = $opData[$direction]['use'];
+ $this->debug("use=$use");
+ $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
+ if (is_array($parameters)) {
+ $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
+ $this->debug('have ' . $parametersArrayType . ' parameters');
+ foreach($opData[$direction]['parts'] as $name => $type) {
+ $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
+ // Track encoding style
+ if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
+ $encodingStyle = $opData[$direction]['encodingStyle'];
+ $enc_style = $encodingStyle;
+ } else {
+ $enc_style = false;
+ }
+ // NOTE: add error handling here
+ // if serializeType returns false, then catch global error and fault
+ if ($parametersArrayType == 'arraySimple') {
+ $p = array_shift($parameters);
+ $this->debug('calling serializeType w/indexed param');
+ $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
+ } elseif (isset($parameters[$name])) {
+ $this->debug('calling serializeType w/named param');
+ $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
+ } else {
+ // TODO: only send nillable
+ $this->debug('calling serializeType w/null param');
+ $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
+ }
+ }
+ } else {
+ $this->debug('no parameters passed.');
+ }
+ }
+ return $xml;
+ }
+
+ /**
+ * serialize a PHP value according to a WSDL message definition
+ *
+ * TODO
+ * - multi-ref serialization
+ * - validate PHP values against type definitions, return errors if invalid
+ *
+ * @param string $ type name
+ * @param mixed $ param value
+ * @return mixed new param or false if initial value didn't validate
+ */
+ function serializeParameters($operation, $direction, $parameters)
+ {
+ $this->debug('in serializeParameters with operation '.$operation.', direction '.$direction.' and '.count($parameters).' param(s), and xml schema version ' . $this->XMLSchemaVersion);
+
+ if ($direction != 'input' && $direction != 'output') {
+ $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
+ $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
+ return false;
+ }
+ if (!$opData = $this->getOperationData($operation)) {
+ $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
+ $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
+ return false;
+ }
+ $this->debug($this->varDump($opData));
+
+ // Get encoding style for output and set to current
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
+ if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
+ $encodingStyle = $opData['output']['encodingStyle'];
+ $enc_style = $encodingStyle;
+ }
+
+ // set input params
+ $xml = '';
+ if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
+
+ $use = $opData[$direction]['use'];
+ $this->debug("use=$use");
+ $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
+ if (is_array($parameters)) {
+ $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
+ $this->debug('have ' . $parametersArrayType . ' parameters');
+ foreach($opData[$direction]['parts'] as $name => $type) {
+ $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
+ // Track encoding style
+ if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
+ $encodingStyle = $opData[$direction]['encodingStyle'];
+ $enc_style = $encodingStyle;
+ } else {
+ $enc_style = false;
+ }
+ // NOTE: add error handling here
+ // if serializeType returns false, then catch global error and fault
+ if ($parametersArrayType == 'arraySimple') {
+ $p = array_shift($parameters);
+ $this->debug('calling serializeType w/indexed param');
+ $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
+ } elseif (isset($parameters[$name])) {
+ $this->debug('calling serializeType w/named param');
+ $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
+ } else {
+ // TODO: only send nillable
+ $this->debug('calling serializeType w/null param');
+ $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
+ }
+ }
+ } else {
+ $this->debug('no parameters passed.');
+ }
+ }
+ return $xml;
+ }
+
+ /**
+ * serializes a PHP value according a given type definition
+ *
+ * @param string $name , name of type (part)
+ * @param string $type , type of type, heh (type or element)
+ * @param mixed $value , a native PHP value (parameter value)
+ * @param string $use , use for part (encoded|literal)
+ * @param string $encodingStyle , use to add encoding changes to serialisation
+ * @return string serialization
+ * @access public
+ */
+ function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false)
+ {
+ $this->debug("in serializeType: $name, $type, $value, $use, $encodingStyle");
+ if($use == 'encoded' && $encodingStyle) {
+ $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
+ }
+
+ // if a soap_val has been supplied, let its type override the WSDL
+ if (is_object($value) && get_class($value) == 'soapval') {
+ // TODO: get attributes from soapval?
+ if ($value->type_ns) {
+ $type = $value->type_ns . ':' . $value->type;
+ } else {
+ $type = $value->type;
+ }
+ $value = $value->value;
+ $forceType = true;
+ $this->debug("in serializeType: soapval overrides type to $type, value to $value");
+ } else {
+ $forceType = false;
+ }
+
+ $xml = '';
+ if (strpos($type, ':')) {
+ $uqType = substr($type, strrpos($type, ':') + 1);
+ $ns = substr($type, 0, strrpos($type, ':'));
+ $this->debug("got a prefixed type: $uqType, $ns");
+ if ($this->getNamespaceFromPrefix($ns)) {
+ $ns = $this->getNamespaceFromPrefix($ns);
+ $this->debug("expanded prefixed type: $uqType, $ns");
+ }
+
+ if($ns == $this->XMLSchemaVersion){
+
+ if (is_null($value)) {
+ if ($use == 'literal') {
+ // TODO: depends on nillable
+ return "<$name/>";
+ } else {
+ return "<$name xsi:nil=\"true\"/>";
+ }
+ }
+ if ($uqType == 'boolean' && !$value) {
+ $value = 'false';
+ } elseif ($uqType == 'boolean') {
+ $value = 'true';
+ }
+ if ($uqType == 'string' && gettype($value) == 'string') {
+ $value = $this->expandEntities($value);
+ }
+ // it's a scalar
+ // TODO: what about null/nil values?
+ // check type isn't a custom type extending xmlschema namespace
+ if (!$this->getTypeDef($uqType, $ns)) {
+ if ($use == 'literal') {
+ if ($forceType) {
+ return "<$name xsi:type=\"" . $this->getPrefixFromNamespace($this->XMLSchemaVersion) . ":$uqType\">$value$name>";
+ } else {
+ return "<$name>$value$name>";
+ }
+ } else {
+ return "<$name xsi:type=\"" . $this->getPrefixFromNamespace($this->XMLSchemaVersion) . ":$uqType\"$encodingStyle>$value$name>";
+ }
+ }
+ } else if ($ns == 'http://xml.apache.org/xml-soap') {
+ if ($uqType == 'Map') {
+ $contents = '';
+ foreach($value as $k => $v) {
+ $this->debug("serializing map element: key $k, value $v");
+ $contents .= '- ';
+ $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
+ $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
+ $contents .= '
';
+ }
+ if ($use == 'literal') {
+ if ($forceType) {
+ return "<$name xsi:type=\"" . $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap') . ":$uqType\">$contents$name>";
+ } else {
+ return "<$name>$contents$name>";
+ }
+ } else {
+ return "<$name xsi:type=\"" . $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap') . ":$uqType\"$encodingStyle>$contents$name>";
+ }
+ }
+ }
+ } else {
+ $this->debug("No namespace for type $type");
+ $ns = '';
+ $uqType = $type;
+ }
+ if(!$typeDef = $this->getTypeDef($uqType, $ns)){
+ $this->setError("$type ($uqType) is not a supported type.");
+ $this->debug("$type ($uqType) is not a supported type.");
+ return false;
+ } else {
+ foreach($typeDef as $k => $v) {
+ $this->debug("typedef, $k: $v");
+ }
+ }
+ $phpType = $typeDef['phpType'];
+ $this->debug("serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );
+ // if php type == struct, map value to the element names
+ if ($phpType == 'struct') {
+ if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
+ $elementName = $uqType;
+ if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
+ $elementNS = " xmlns=\"$ns\"";
+ }
+ } else {
+ $elementName = $name;
+ $elementNS = '';
+ }
+ if (is_null($value)) {
+ if ($use == 'literal') {
+ // TODO: depends on nillable
+ return "<$elementName$elementNS/>";
+ } else {
+ return "<$elementName$elementNS xsi:nil=\"true\"/>";
+ }
+ }
+ if ($use == 'literal') {
+ if ($forceType) {
+ $xml = "<$elementName$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
+ } else {
+ $xml = "<$elementName$elementNS>";
+ }
+ } else {
+ $xml = "<$elementName$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
+ }
+
+ if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
+ if (is_array($value)) {
+ $xvalue = $value;
+ } elseif (is_object($value)) {
+ $xvalue = get_object_vars($value);
+ } else {
+ $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
+ $xvalue = array();
+ }
+ // toggle whether all elements are present - ideally should validate against schema
+ if(count($typeDef['elements']) != count($xvalue)){
+ $optionals = true;
+ }
+ foreach($typeDef['elements'] as $eName => $attrs) {
+ // if user took advantage of a minOccurs=0, then only serialize named parameters
+ if(isset($optionals) && !isset($xvalue[$eName])){
+ // do nothing
+ } else {
+ // get value
+ if (isset($xvalue[$eName])) {
+ $v = $xvalue[$eName];
+ } else {
+ $v = null;
+ }
+ // TODO: if maxOccurs > 1 (not just unbounded), then allow serialization of an array
+ if (isset($attrs['maxOccurs']) && $attrs['maxOccurs'] == 'unbounded' && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
+ $vv = $v;
+ foreach ($vv as $k => $v) {
+ if (isset($attrs['type'])) {
+ // serialize schema-defined type
+ $xml .= $this->serializeType($eName, $attrs['type'], $v, $use, $encodingStyle);
+ } else {
+ // serialize generic type
+ $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
+ $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
+ }
+ }
+ } else {
+ if (isset($attrs['type'])) {
+ // serialize schema-defined type
+ $xml .= $this->serializeType($eName, $attrs['type'], $v, $use, $encodingStyle);
+ } else {
+ // serialize generic type
+ $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
+ $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
+ }
+ }
+ }
+ }
+ } else {
+ $this->debug("Expected elements for XML Schema type $ns:$uqType");
+ }
+ $xml .= "$elementName>";
+ } elseif ($phpType == 'array') {
+ if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
+ $elementNS = " xmlns=\"$ns\"";
+ } else {
+ $elementNS = '';
+ }
+ if (is_null($value)) {
+ if ($use == 'literal') {
+ // TODO: depends on nillable
+ return "<$name$elementNS/>";
+ } else {
+ return "<$name$elementNS xsi:nil=\"true\"/>";
+ }
+ }
+ if (isset($typeDef['multidimensional'])) {
+ $nv = array();
+ foreach($value as $v) {
+ $cols = ',' . sizeof($v);
+ $nv = array_merge($nv, $v);
+ }
+ $value = $nv;
+ } else {
+ $cols = '';
+ }
+ if (is_array($value) && sizeof($value) >= 1) {
+ $rows = sizeof($value);
+ $contents = '';
+ foreach($value as $k => $v) {
+ $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
+ //if (strpos($typeDef['arrayType'], ':') ) {
+ if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
+ $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
+ } else {
+ $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
+ }
+ }
+ $this->debug('contents: '.$this->varDump($contents));
+ } else {
+ $rows = 0;
+ $contents = null;
+ }
+ // TODO: for now, an empty value will be serialized as a zero element
+ // array. Revisit this when coding the handling of null/nil values.
+ if ($use == 'literal') {
+ $xml = "<$name$elementNS>"
+ .$contents
+ ."$name>";
+ } else {
+ $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
+ $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
+ .':arrayType="'
+ .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
+ .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
+ .$contents
+ ."$name>";
+ }
+ } elseif ($phpType == 'scalar') {
+ if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
+ $elementNS = " xmlns=\"$ns\"";
+ } else {
+ $elementNS = '';
+ }
+ if ($use == 'literal') {
+ if ($forceType) {
+ return "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value$name>";
+ } else {
+ return "<$name$elementNS>$value$name>";
+ }
+ } else {
+ return "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value$name>";
+ }
+ }
+ $this->debug('returning: '.$this->varDump($xml));
+ return $xml;
+ }
+
+ /**
+ * adds an XML Schema complex type to the WSDL types
+ *
+ * @param name
+ * @param typeClass (complexType|simpleType|attribute)
+ * @param phpType: currently supported are array and struct (php assoc array)
+ * @param compositor (all|sequence|choice)
+ * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
+ * @param elements = array ( name = array(name=>'',type=>'') )
+ * @param attrs = array(
+ * array(
+ * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
+ * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
+ * )
+ * )
+ * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
+ * @see xmlschema
+ *
+ */
+ function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
+ if (count($elements) > 0) {
+ foreach($elements as $n => $e){
+ // expand each element
+ foreach ($e as $k => $v) {
+ $k = strpos($k,':') ? $this->expandQname($k) : $k;
+ $v = strpos($v,':') ? $this->expandQname($v) : $v;
+ $ee[$k] = $v;
+ }
+ $eElements[$n] = $ee;
+ }
+ $elements = $eElements;
+ }
+
+ if (count($attrs) > 0) {
+ foreach($attrs as $n => $a){
+ // expand each attribute
+ foreach ($a as $k => $v) {
+ $k = strpos($k,':') ? $this->expandQname($k) : $k;
+ $v = strpos($v,':') ? $this->expandQname($v) : $v;
+ $aa[$k] = $v;
+ }
+ $eAttrs[$n] = $aa;
+ }
+ $attrs = $eAttrs;
+ }
+
+ $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
+ $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
+
+ $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
+ $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
+ }
+
+ /**
+ * adds an XML Schema simple type to the WSDL types
+ *
+ * @param name
+ * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
+ * @param typeClass (simpleType)
+ * @param phpType: (scalar)
+ * @see xmlschema
+ *
+ */
+ function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar') {
+ $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
+
+ $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
+ $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType);
+ }
+
+ /**
+ * register a service with the server
+ *
+ * @param string $methodname
+ * @param string $in assoc array of input values: key = param name, value = param type
+ * @param string $out assoc array of output values: key = param name, value = param type
+ * @param string $namespace optional The namespace for the operation
+ * @param string $soapaction optional The soapaction for the operation
+ * @param string $style (rpc|document) optional The style for the operation
+ * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)
+ * @param string $documentation optional The description to include in the WSDL
+ * @access public
+ */
+ function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = ''){
+ if ($style == 'rpc' && $use == 'encoded') {
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
+ } else {
+ $encodingStyle = '';
+ }
+ // get binding
+ $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
+ array(
+ 'name' => $name,
+ 'binding' => $this->serviceName . 'Binding',
+ 'endpoint' => $this->endpoint,
+ 'soapAction' => $soapaction,
+ 'style' => $style,
+ 'input' => array(
+ 'use' => $use,
+ 'namespace' => $namespace,
+ 'encodingStyle' => $encodingStyle,
+ 'message' => $name . 'Request',
+ 'parts' => $in),
+ 'output' => array(
+ 'use' => $use,
+ 'namespace' => $namespace,
+ 'encodingStyle' => $encodingStyle,
+ 'message' => $name . 'Response',
+ 'parts' => $out),
+ 'namespace' => $namespace,
+ 'transport' => 'http://schemas.xmlsoap.org/soap/http',
+ 'documentation' => $documentation);
+ // add portTypes
+ // add messages
+ if($in)
+ {
+ foreach($in as $pName => $pType)
+ {
+ if(strpos($pType,':')) {
+ $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
+ }
+ $this->messages[$name.'Request'][$pName] = $pType;
+ }
+ } else {
+ $this->messages[$name.'Request']= '0';
+ }
+ if($out)
+ {
+ foreach($out as $pName => $pType)
+ {
+ if(strpos($pType,':')) {
+ $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
+ }
+ $this->messages[$name.'Response'][$pName] = $pType;
+ }
+ } else {
+ $this->messages[$name.'Response']= '0';
+ }
+ return true;
+ }
+}
+?>
+* @version $Id: nusoap.php,v 1.1 2005/04/29 05:09:16 sarajkumar Exp $
+* @access public
+*/
+class soap_parser extends nusoap_base {
+
+ var $xml = '';
+ var $xml_encoding = '';
+ var $method = '';
+ var $root_struct = '';
+ var $root_struct_name = '';
+ var $root_struct_namespace = '';
+ var $root_header = '';
+ var $document = ''; // incoming SOAP body (text)
+ // determines where in the message we are (envelope,header,body,method)
+ var $status = '';
+ var $position = 0;
+ var $depth = 0;
+ var $default_namespace = '';
+ var $namespaces = array();
+ var $message = array();
+ var $parent = '';
+ var $fault = false;
+ var $fault_code = '';
+ var $fault_str = '';
+ var $fault_detail = '';
+ var $depth_array = array();
+ var $debug_flag = true;
+ var $soapresponse = NULL;
+ var $responseHeaders = ''; // incoming SOAP headers (text)
+ var $body_position = 0;
+ // for multiref parsing:
+ // array of id => pos
+ var $ids = array();
+ // array of id => hrefs => pos
+ var $multirefs = array();
+ // toggle for auto-decoding element content
+ var $decode_utf8 = true;
+
+ /**
+ * constructor
+ *
+ * @param string $xml SOAP message
+ * @param string $encoding character encoding scheme of message
+ * @param string $method
+ * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
+ * @access public
+ */
+ function soap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
+ $this->xml = $xml;
+ $this->xml_encoding = $encoding;
+ $this->method = $method;
+ $this->decode_utf8 = $decode_utf8;
+
+ // Check whether content has been read.
+ if(!empty($xml)){
+ $this->debug('Entering soap_parser(), length='.strlen($xml).', encoding='.$encoding);
+ // Create an XML parser - why not xml_parser_create_ns?
+ $this->parser = xml_parser_create($this->xml_encoding);
+ // Set the options for parsing the XML data.
+ //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
+ xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
+ xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
+ // Set the object for the parser.
+ xml_set_object($this->parser, $this);
+ // Set the element handlers for the parser.
+ xml_set_element_handler($this->parser, 'start_element','end_element');
+ xml_set_character_data_handler($this->parser,'character_data');
+
+ // Parse the XML file.
+ if(!xml_parse($this->parser,$xml,true)){
+ // Display an error message.
+ $err = sprintf('XML error parsing SOAP payload on line %d: %s',
+ xml_get_current_line_number($this->parser),
+ xml_error_string(xml_get_error_code($this->parser)));
+ $this->debug($err);
+ $this->debug("XML payload:\n" . $xml);
+ $this->setError($err);
+ } else {
+ $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
+ // get final value
+ $this->soapresponse = $this->message[$this->root_struct]['result'];
+ // get header value: no, because this is documented as XML string
+// if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
+// $this->responseHeaders = $this->message[$this->root_header]['result'];
+// }
+ // resolve hrefs/ids
+ if(sizeof($this->multirefs) > 0){
+ foreach($this->multirefs as $id => $hrefs){
+ $this->debug('resolving multirefs for id: '.$id);
+ $idVal = $this->buildVal($this->ids[$id]);
+ foreach($hrefs as $refPos => $ref){
+ $this->debug('resolving href at pos '.$refPos);
+ $this->multirefs[$id][$refPos] = $idVal;
+ }
+ }
+ }
+ }
+ xml_parser_free($this->parser);
+ } else {
+ $this->debug('xml was empty, didn\'t parse!');
+ $this->setError('xml was empty, didn\'t parse!');
+ }
+ }
+
+ /**
+ * start-element handler
+ *
+ * @param string $parser XML parser object
+ * @param string $name element name
+ * @param string $attrs associative array of attributes
+ * @access private
+ */
+ function start_element($parser, $name, $attrs) {
+ // position in a total number of elements, starting from 0
+ // update class level pos
+ $pos = $this->position++;
+ // and set mine
+ $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
+ // depth = how many levels removed from root?
+ // set mine as current global depth and increment global depth value
+ $this->message[$pos]['depth'] = $this->depth++;
+
+ // else add self as child to whoever the current parent is
+ if($pos != 0){
+ $this->message[$this->parent]['children'] .= '|'.$pos;
+ }
+ // set my parent
+ $this->message[$pos]['parent'] = $this->parent;
+ // set self as current parent
+ $this->parent = $pos;
+ // set self as current value for this depth
+ $this->depth_array[$this->depth] = $pos;
+ // get element prefix
+ if(strpos($name,':')){
+ // get ns prefix
+ $prefix = substr($name,0,strpos($name,':'));
+ // get unqualified name
+ $name = substr(strstr($name,':'),1);
+ }
+ // set status
+ if($name == 'Envelope'){
+ $this->status = 'envelope';
+ } elseif($name == 'Header'){
+ $this->root_header = $pos;
+ $this->status = 'header';
+ } elseif($name == 'Body'){
+ $this->status = 'body';
+ $this->body_position = $pos;
+ // set method
+ } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
+ $this->status = 'method';
+ $this->root_struct_name = $name;
+ $this->root_struct = $pos;
+ $this->message[$pos]['type'] = 'struct';
+ $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
+ }
+ // set my status
+ $this->message[$pos]['status'] = $this->status;
+ // set name
+ $this->message[$pos]['name'] = htmlspecialchars($name);
+ // set attrs
+ $this->message[$pos]['attrs'] = $attrs;
+
+ // loop through atts, logging ns and type declarations
+ $attstr = '';
+ foreach($attrs as $key => $value){
+ $key_prefix = $this->getPrefix($key);
+ $key_localpart = $this->getLocalPart($key);
+ // if ns declarations, add to class level array of valid namespaces
+ if($key_prefix == 'xmlns'){
+ if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){
+ $this->XMLSchemaVersion = $value;
+ $this->namespaces['xsd'] = $this->XMLSchemaVersion;
+ $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
+ }
+ $this->namespaces[$key_localpart] = $value;
+ // set method namespace
+ if($name == $this->root_struct_name){
+ $this->methodNamespace = $value;
+ }
+ // if it's a type declaration, set type
+ } elseif($key_localpart == 'type'){
+ $value_prefix = $this->getPrefix($value);
+ $value_localpart = $this->getLocalPart($value);
+ $this->message[$pos]['type'] = $value_localpart;
+ $this->message[$pos]['typePrefix'] = $value_prefix;
+ if(isset($this->namespaces[$value_prefix])){
+ $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
+ } else if(isset($attrs['xmlns:'.$value_prefix])) {
+ $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
+ }
+ // should do something here with the namespace of specified type?
+ } elseif($key_localpart == 'arrayType'){
+ $this->message[$pos]['type'] = 'array';
+ /* do arrayType ereg here
+ [1] arrayTypeValue ::= atype asize
+ [2] atype ::= QName rank*
+ [3] rank ::= '[' (',')* ']'
+ [4] asize ::= '[' length~ ']'
+ [5] length ::= nextDimension* Digit+
+ [6] nextDimension ::= Digit+ ','
+ */
+ $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';
+ if(ereg($expr,$value,$regs)){
+ $this->message[$pos]['typePrefix'] = $regs[1];
+ $this->message[$pos]['arrayTypePrefix'] = $regs[1];
+ if (isset($this->namespaces[$regs[1]])) {
+ $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
+ } else if (isset($attrs['xmlns:'.$regs[1]])) {
+ $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
+ }
+ $this->message[$pos]['arrayType'] = $regs[2];
+ $this->message[$pos]['arraySize'] = $regs[3];
+ $this->message[$pos]['arrayCols'] = $regs[4];
+ }
+ }
+ // log id
+ if($key == 'id'){
+ $this->ids[$value] = $pos;
+ }
+ // root
+ if($key_localpart == 'root' && $value == 1){
+ $this->status = 'method';
+ $this->root_struct_name = $name;
+ $this->root_struct = $pos;
+ $this->debug("found root struct $this->root_struct_name, pos $pos");
+ }
+ // for doclit
+ $attstr .= " $key=\"$value\"";
+ }
+ // get namespace - must be done after namespace atts are processed
+ if(isset($prefix)){
+ $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
+ $this->default_namespace = $this->namespaces[$prefix];
+ } else {
+ $this->message[$pos]['namespace'] = $this->default_namespace;
+ }
+ if($this->status == 'header'){
+ if ($this->root_header != $pos) {
+ $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
+ }
+ } elseif($this->root_struct_name != ''){
+ $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
+ }
+ }
+
+ /**
+ * end-element handler
+ *
+ * @param string $parser XML parser object
+ * @param string $name element name
+ * @access private
+ */
+ function end_element($parser, $name) {
+ // position of current element is equal to the last value left in depth_array for my depth
+ $pos = $this->depth_array[$this->depth--];
+
+ // get element prefix
+ if(strpos($name,':')){
+ // get ns prefix
+ $prefix = substr($name,0,strpos($name,':'));
+ // get unqualified name
+ $name = substr(strstr($name,':'),1);
+ }
+
+ // build to native type
+ if(isset($this->body_position) && $pos > $this->body_position){
+ // deal w/ multirefs
+ if(isset($this->message[$pos]['attrs']['href'])){
+ // get id
+ $id = substr($this->message[$pos]['attrs']['href'],1);
+ // add placeholder to href array
+ $this->multirefs[$id][$pos] = 'placeholder';
+ // add set a reference to it as the result value
+ $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
+ // build complex values
+ } elseif($this->message[$pos]['children'] != ''){
+
+ // if result has already been generated (struct/array
+ if(!isset($this->message[$pos]['result'])){
+ $this->message[$pos]['result'] = $this->buildVal($pos);
+ }
+
+ // set value of simple type
+ } else {
+ //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
+ if (isset($this->message[$pos]['type'])) {
+ $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'] : '');
+ } else {
+ $parent = $this->message[$pos]['parent'];
+ if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
+ $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
+ } else {
+ $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
+ }
+ }
+
+ /* add value to parent's result, if parent is struct/array
+ $parent = $this->message[$pos]['parent'];
+ if($this->message[$parent]['type'] != 'map'){
+ if(strtolower($this->message[$parent]['type']) == 'array'){
+ $this->message[$parent]['result'][] = $this->message[$pos]['result'];
+ } else {
+ $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
+ }
+ }
+ */
+ }
+ }
+
+ // for doclit
+ if($this->status == 'header'){
+ if ($this->root_header != $pos) {
+ $this->responseHeaders .= "" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
+ }
+ } elseif($pos >= $this->root_struct){
+ $this->document .= "" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
+ }
+ // switch status
+ if($pos == $this->root_struct){
+ $this->status = 'body';
+ $this->root_struct_namespace = $this->message[$pos]['namespace'];
+ } elseif($name == 'Body'){
+ $this->status = 'envelope';
+ } elseif($name == 'Header'){
+ $this->status = 'envelope';
+ } elseif($name == 'Envelope'){
+ //
+ }
+ // set parent back to my parent
+ $this->parent = $this->message[$pos]['parent'];
+ }
+
+ /**
+ * element content handler
+ *
+ * @param string $parser XML parser object
+ * @param string $data element content
+ * @access private
+ */
+ function character_data($parser, $data){
+ $pos = $this->depth_array[$this->depth];
+ if ($this->xml_encoding=='UTF-8'){
+ // TODO: add an option to disable this for folks who want
+ // raw UTF-8 that, e.g., might not map to iso-8859-1
+ // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
+ if($this->decode_utf8){
+ // $data = utf8_decode($data);
+ }
+ }
+ $this->message[$pos]['cdata'] .= $data;
+ // for doclit
+ if($this->status == 'header'){
+ $this->responseHeaders .= $data;
+ } else {
+ $this->document .= $data;
+ }
+ }
+
+ /**
+ * get the parsed message
+ *
+ * @return mixed
+ * @access public
+ */
+ function get_response(){
+ return $this->soapresponse;
+ }
+
+ /**
+ * get the parsed headers
+ *
+ * @return string XML or empty if no headers
+ * @access public
+ */
+ function getHeaders(){
+ return $this->responseHeaders;
+ }
+
+ /**
+ * decodes entities
+ *
+ * @param string $text string to translate
+ * @access private
+ */
+ function decode_entities($text){
+ foreach($this->entities as $entity => $encoded){
+ $text = str_replace($encoded,$entity,$text);
+ }
+ return $text;
+ }
+
+ /**
+ * decodes simple types into PHP variables
+ *
+ * @param string $value value to decode
+ * @param string $type XML type to decode
+ * @param string $typens XML type namespace to decode
+ * @access private
+ */
+ function decodeSimple($value, $type, $typens) {
+ // TODO: use the namespace!
+ if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
+ return (string) $value;
+ }
+ if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
+ return (int) $value;
+ }
+ if ($type == 'float' || $type == 'double' || $type == 'decimal') {
+ return (double) $value;
+ }
+ if ($type == 'boolean') {
+ if (strtolower($value) == 'false' || strtolower($value) == 'f') {
+ return false;
+ }
+ return (boolean) $value;
+ }
+ if ($type == 'base64' || $type == 'base64Binary') {
+ return base64_decode($value);
+ }
+ // obscure numeric types
+ if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
+ || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
+ || $type == 'unsignedInt'
+ || $type == 'unsignedShort' || $type == 'unsignedByte') {
+ return (int) $value;
+ }
+ // everything else
+ return (string) $value;
+ }
+
+ /**
+ * builds response structures for compound values (arrays/structs)
+ *
+ * @param string $pos position in node tree
+ * @access private
+ */
+ function buildVal($pos){
+ if(!isset($this->message[$pos]['type'])){
+ $this->message[$pos]['type'] = '';
+ }
+ $this->debug('inside buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
+ // if there are children...
+ if($this->message[$pos]['children'] != ''){
+ $children = explode('|',$this->message[$pos]['children']);
+ array_shift($children); // knock off empty
+ // md array
+ if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
+ $r=0; // rowcount
+ $c=0; // colcount
+ foreach($children as $child_pos){
+ $this->debug("got an MD array element: $r, $c");
+ $params[$r][] = $this->message[$child_pos]['result'];
+ $c++;
+ if($c == $this->message[$pos]['arrayCols']){
+ $c = 0;
+ $r++;
+ }
+ }
+ // array
+ } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
+ $this->debug('adding array '.$this->message[$pos]['name']);
+ foreach($children as $child_pos){
+ $params[] = &$this->message[$child_pos]['result'];
+ }
+ // apache Map type: java hashtable
+ } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
+ foreach($children as $child_pos){
+ $kv = explode("|",$this->message[$child_pos]['children']);
+ $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
+ }
+ // generic compound type
+ //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
+ } else {
+ // Apache Vector type: treat as an array
+ if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
+ $notstruct = 1;
+ } else {
+ // is array or struct?
+ foreach($children as $child_pos){
+ if(isset($keys) && isset($keys[$this->message[$child_pos]['name']])){
+ $notstruct = 1;
+ break;
+ }
+ $keys[$this->message[$child_pos]['name']] = 1;
+ }
+ }
+ //
+ foreach($children as $child_pos){
+ if(isset($notstruct)){
+ $params[] = &$this->message[$child_pos]['result'];
+ } else {
+ if (isset($params[$this->message[$child_pos]['name']])) {
+ // de-serialize repeated element name into an array
+ if (!is_array($params[$this->message[$child_pos]['name']])) {
+ $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
+ }
+ $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
+ } else {
+ $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
+ }
+ }
+ }
+ }
+ return is_array($params) ? $params : array();
+ } else {
+ $this->debug('no children');
+ if(strpos($this->message[$pos]['cdata'],'&')){
+ return strtr($this->message[$pos]['cdata'],array_flip($this->entities));
+ } else {
+ return $this->message[$pos]['cdata'];
+ }
+ }
+ }
+}
+
+
+
+?>call( string methodname [ ,array parameters] );
+*
+* // bye bye client
+* unset($soapclient2);
+*
+* @author Dietrich Ayala
+* @version $Id: nusoap.php,v 1.1 2005/04/29 05:09:16 sarajkumar Exp $
+* @access public
+*/
+class soapclient2 extends nusoap_base {
+
+ var $username = '';
+ var $password = '';
+ var $authtype = '';
+ var $requestHeaders = false; // SOAP headers in request (text)
+ var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
+ var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
+ var $endpoint;
+ var $error_str = false;
+ var $proxyhost = '';
+ var $proxyport = '';
+ var $proxyusername = '';
+ var $proxypassword = '';
+ var $xml_encoding = ''; // character set encoding of incoming (response) messages
+ var $http_encoding = false;
+ var $timeout = 0; // HTTP connection timeout
+ var $response_timeout = 30; // HTTP response timeout
+ var $endpointType = '';
+ var $persistentConnection = false;
+ var $defaultRpcParams = false; // This is no longer used
+ var $request = ''; // HTTP request
+ var $response = ''; // HTTP response
+ var $responseData = ''; // SOAP payload of response
+ // toggles whether the parser decodes element content w/ utf8_decode()
+ var $decode_utf8 = true;
+
+ /**
+ * fault related variables
+ *
+ * @var fault
+ * @var faultcode
+ * @var faultstring
+ * @var faultdetail
+ * @access public
+ */
+ var $fault, $faultcode, $faultstring, $faultdetail;
+
+ /**
+ * constructor
+ *
+ * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object)
+ * @param bool $wsdl optional, set to true if using WSDL
+ * @param int $portName optional portName in WSDL document
+ * @param string $proxyhost
+ * @param string $proxyport
+ * @param string $proxyusername
+ * @param string $proxypassword
+ * @param integer $timeout set the connection timeout
+ * @param integer $response_timeout set the response timeout
+ * @access public
+ */
+ function soapclient2($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
+ $this->endpoint = $endpoint;
+ $this->proxyhost = $proxyhost;
+ $this->proxyport = $proxyport;
+ $this->proxyusername = $proxyusername;
+ $this->proxypassword = $proxypassword;
+ $this->timeout = $timeout;
+ $this->response_timeout = $response_timeout;
+
+ // make values
+ if($wsdl){
+ $this->endpointType = 'wsdl';
+ if (is_object($endpoint) && is_a($endpoint, 'wsdl')) {
+ $this->wsdl = $endpoint;
+ $this->endpoint = $this->wsdl->wsdl;
+ $this->wsdlFile = $this->endpoint;
+ $this->debug('existing wsdl instance created from ' . $this->endpoint);
+ } else {
+ $this->wsdlFile = $this->endpoint;
+
+ // instantiate wsdl object and parse wsdl file
+ $this->debug('instantiating wsdl class with doc: '.$endpoint);
+ $this->wsdl =& new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout);
+ }
+ $this->debug("wsdl debug...\n".$this->wsdl->debug_str);
+ $this->wsdl->debug_str = '';
+ // catch errors
+ if($errstr = $this->wsdl->getError()){
+ $this->debug('got wsdl error: '.$errstr);
+ $this->setError('wsdl error: '.$errstr);
+ } elseif($this->operations = $this->wsdl->getOperations()){
+ $this->debug( 'got '.count($this->operations).' operations from wsdl '.$this->wsdlFile);
+ } else {
+ $this->debug( 'getOperations returned false');
+ $this->setError('no operations defined in the WSDL document!');
+ }
+ }
+ }
+
+ /**
+ * calls method, returns PHP native type
+ *
+ * @param string $method SOAP server URL or path
+ * @param array $params An array, associative or simple, of the parameters
+ * for the method call, or a string that is the XML
+ * for the call. For rpc style, this call will
+ * wrap the XML in a tag named after the method, as
+ * well as the SOAP Envelope and Body. For document
+ * style, this will only wrap with the Envelope and Body.
+ * IMPORTANT: when using an array with document style,
+ * in which case there
+ * is really one parameter, the root of the fragment
+ * used in the call, which encloses what programmers
+ * normally think of parameters. A parameter array
+ * *must* include the wrapper.
+ * @param string $namespace optional method namespace (WSDL can override)
+ * @param string $soapAction optional SOAPAction value (WSDL can override)
+ * @param boolean $headers optional array of soapval objects for headers
+ * @param boolean $rpcParams optional no longer used
+ * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override)
+ * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override)
+ * @return mixed
+ * @access public
+ */
+ function call($operation,$params=array(),$namespace='',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
+ $this->operation = $operation;
+ $this->fault = false;
+ $this->error_str = '';
+ $this->request = '';
+ $this->response = '';
+ $this->responseData = '';
+ $this->faultstring = '';
+ $this->faultcode = '';
+ $this->opData = array();
+
+ $this->debug("call: $operation, $params, $namespace, $soapAction, $headers, $style, $use; endpointType: $this->endpointType");
+ if ($headers) {
+ $this->requestHeaders = $headers;
+ }
+ // serialize parameters
+ if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
+ // use WSDL for operation
+ $this->opData = $opData;
+ foreach($opData as $key => $value){
+ $this->debug("$key -> $value");
+ }
+ if (isset($opData['soapAction'])) {
+ $soapAction = $opData['soapAction'];
+ }
+ $this->endpoint = $opData['endpoint'];
+ $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : ($namespace != '' ? $namespace : 'http://testuri.org');
+ $style = $opData['style'];
+ $use = $opData['input']['use'];
+ // add ns to ns array
+ if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
+ $this->wsdl->namespaces['nu'] = $namespace;
+ }
+ $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
+ // serialize payload
+ if (is_string($params)) {
+ $this->debug("serializing param string for WSDL operation $operation");
+ $payload = $params;
+ } elseif (is_array($params)) {
+ $this->debug("serializing param array for WSDL operation $operation");
+ $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params);
+ } else {
+ $this->debug('params must be array or string');
+ $this->setError('params must be array or string');
+ return false;
+ }
+ $usedNamespaces = $this->wsdl->usedNamespaces;
+ // Partial fix for multiple encoding styles in the same function call
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
+ if (isset($opData['output']['encodingStyle']) && $encodingStyle != $opData['output']['encodingStyle']) {
+ $methodEncodingStyle = ' SOAP-ENV:encodingStyle="' . $opData['output']['encodingStyle'] . '"';
+ } else {
+ $methodEncodingStyle = '';
+ }
+ $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
+ $this->wsdl->debug_str = '';
+ if ($errstr = $this->wsdl->getError()) {
+ $this->debug('got wsdl error: '.$errstr);
+ $this->setError('wsdl error: '.$errstr);
+ return false;
+ }
+ } elseif($this->endpointType == 'wsdl') {
+ // operation not in WSDL
+ $this->setError( 'operation '.$operation.' not present.');
+ $this->debug("operation '$operation' not present.");
+ $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
+ $this->wsdl->debug_str = '';
+ return false;
+ } else {
+ // no WSDL
+ if($namespace == ''){
+ $namespace = 'http://testuri.org';
+ }
+ //$this->namespaces['ns1'] = $namespace;
+ $nsPrefix = 'ns1';
+ // serialize
+ $payload = '';
+ if (is_string($params)) {
+ $this->debug("serializing param string for operation $operation");
+ $payload = $params;
+ } elseif (is_array($params)) {
+ $this->debug("serializing param array for operation $operation");
+ foreach($params as $k => $v){
+ $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
+ }
+ } else {
+ $this->debug('params must be array or string');
+ $this->setError('params must be array or string');
+ return false;
+ }
+ $usedNamespaces = array();
+ $methodEncodingStyle = '';
+ }
+ // wrap RPC calls with method element
+ if ($style == 'rpc') {
+ if ($use == 'literal') {
+ $this->debug("wrapping RPC request with literal method element");
+ $payload = "<$operation xmlns=\"$namespace\">" . $payload . "$operation>";
+ } else {
+ $this->debug("wrapping RPC request with encoded method element");
+ $payload = "<$nsPrefix:$operation$methodEncodingStyle xmlns:$nsPrefix=\"$namespace\">" .
+ $payload .
+ "$nsPrefix:$operation>";
+ }
+ }
+ // serialize envelope
+ $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use);
+ $this->debug("endpoint: $this->endpoint, soapAction: $soapAction, namespace: $namespace, style: $style, use: $use");
+ $this->debug('SOAP message length: ' . strlen($soapmsg) . ' contents: ' . substr($soapmsg, 0, 1000));
+ // send
+ $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
+ if($errstr = $this->getError()){
+ $this->debug('Error: '.$errstr);
+ return false;
+ } else {
+ $this->return = $return;
+ $this->debug('sent message successfully and got a(n) '.gettype($return).' back');
+
+ // fault?
+ if(is_array($return) && isset($return['faultcode'])){
+ $this->debug('got fault');
+ $this->setError($return['faultcode'].': '.$return['faultstring']);
+ $this->fault = true;
+ foreach($return as $k => $v){
+ $this->$k = $v;
+ $this->debug("$k = $v ");
+ }
+ return $return;
+ } else {
+ // array of return values
+ if(is_array($return)){
+ // multiple 'out' parameters
+ if(sizeof($return) > 1){
+ return $return;
+ }
+ // single 'out' parameter
+ return array_shift($return);
+ // nothing returned (ie, echoVoid)
+ } else {
+ return "";
+ }
+ }
+ }
+ }
+
+ /**
+ * get available data pertaining to an operation
+ *
+ * @param string $operation operation name
+ * @return array array of data pertaining to the operation
+ * @access public
+ */
+ function getOperationData($operation){
+ if(isset($this->operations[$operation])){
+ return $this->operations[$operation];
+ }
+ $this->debug("No data for operation: $operation");
+ }
+
+ /**
+ * send the SOAP message
+ *
+ * Note: if the operation has multiple return values
+ * the return value of this method will be an array
+ * of those values.
+ *
+ * @param string $msg a SOAPx4 soapmsg object
+ * @param string $soapaction SOAPAction value
+ * @param integer $timeout set connection timeout in seconds
+ * @param integer $response_timeout set response timeout in seconds
+ * @return mixed native PHP types.
+ * @access private
+ */
+ function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
+ // detect transport
+ switch(true){
+ // http(s)
+ case ereg('^http',$this->endpoint):
+ $this->debug('transporting via HTTP');
+ if($this->persistentConnection == true && is_object($this->persistentConnection)){
+ $http =& $this->persistentConnection;
+ } else {
+ $http = new soap_transport_http($this->endpoint);
+ if ($this->persistentConnection) {
+ $http->usePersistentConnection();
+ }
+ }
+ $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
+ $http->setSOAPAction($soapaction);
+ if($this->proxyhost && $this->proxyport){
+ $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
+ }
+ if($this->username != '' && $this->password != '') {
+ $http->setCredentials($this->username, $this->password, $this->authtype);
+ }
+ if($this->http_encoding != ''){
+ $http->setEncoding($this->http_encoding);
+ }
+ $this->debug('sending message, length: '.strlen($msg));
+ if(ereg('^http:',$this->endpoint)){
+ //if(strpos($this->endpoint,'http:')){
+ $this->responseData = $http->send($msg,$timeout,$response_timeout);
+ } elseif(ereg('^https',$this->endpoint)){
+ //} elseif(strpos($this->endpoint,'https:')){
+ //if(phpversion() == '4.3.0-dev'){
+ //$response = $http->send($msg,$timeout,$response_timeout);
+ //$this->request = $http->outgoing_payload;
+ //$this->response = $http->incoming_payload;
+ //} else
+ if (extension_loaded('curl')) {
+ $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout);
+ } else {
+ $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
+ }
+ } else {
+ $this->setError('no http/s in endpoint url');
+ }
+ $this->request = $http->outgoing_payload;
+ $this->response = $http->incoming_payload;
+ $this->debug("transport debug data...\n".$http->debug_str);
+
+ // save transport object if using persistent connections
+ if ($this->persistentConnection) {
+ $http->debug_str = '';
+ if (!is_object($this->persistentConnection)) {
+ $this->persistentConnection = $http;
+ }
+ }
+
+ if($err = $http->getError()){
+ $this->setError('HTTP Error: '.$err);
+ return false;
+ } elseif($this->getError()){
+ return false;
+ } else {
+ $this->debug('got response, length: '. strlen($this->responseData).' type: '.$http->incoming_headers['content-type']);
+ return $this->parseResponse($http->incoming_headers, $this->responseData);
+ }
+ break;
+ default:
+ $this->setError('no transport found, or selected transport is not yet supported!');
+ return false;
+ break;
+ }
+ }
+
+ /**
+ * processes SOAP message returned from server
+ *
+ * @param array $headers The HTTP headers
+ * @param string $data unprocessed response data from server
+ * @return mixed value of the message, decoded into a PHP type
+ * @access protected
+ */
+ function parseResponse($headers, $data) {
+ $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
+ if (!strstr($headers['content-type'], 'text/xml')) {
+ $this->setError('Response not of type text/xml');
+ return false;
+ }
+ if (strpos($headers['content-type'], '=')) {
+ $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
+ $this->debug('Got response encoding: ' . $enc);
+ if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
+ $this->xml_encoding = strtoupper($enc);
+ } else {
+ $this->xml_encoding = 'US-ASCII';
+ }
+ } else {
+ // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
+ $this->xml_encoding = 'UTF-8';
+ }
+ $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser');
+ $parser = new soap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
+ // add parser debug data to our debug
+ $this->debug($parser->debug_str);
+ // if parse errors
+ if($errstr = $parser->getError()){
+ $this->setError( $errstr);
+ // destroy the parser object
+ unset($parser);
+ return false;
+ } else {
+ // get SOAP headers
+ $this->responseHeaders = $parser->getHeaders();
+ // get decoded message
+ $return = $parser->get_response();
+ // add document for doclit support
+ $this->document = $parser->document;
+ // destroy the parser object
+ unset($parser);
+ // return decode message
+ return $return;
+ }
+ }
+
+ /**
+ * set the SOAP headers
+ *
+ * @param $headers string XML
+ * @access public
+ */
+ function setHeaders($headers){
+ $this->requestHeaders = $headers;
+ }
+
+ /**
+ * get the response headers
+ *
+ * @return mixed object SOAPx4 soapval object or empty if no headers
+ * @access public
+ */
+ function getHeaders(){
+ if($this->responseHeaders != '') {
+ return $this->responseHeaders;
+ }
+ }
+
+ /**
+ * set proxy info here
+ *
+ * @param string $proxyhost
+ * @param string $proxyport
+ * @param string $proxyusername
+ * @param string $proxypassword
+ * @access public
+ */
+ function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
+ $this->proxyhost = $proxyhost;
+ $this->proxyport = $proxyport;
+ $this->proxyusername = $proxyusername;
+ $this->proxypassword = $proxypassword;
+ }
+
+ /**
+ * if authenticating, set user credentials here
+ *
+ * @param string $username
+ * @param string $password
+ * @param string $authtype (basic|digest)
+ * @access public
+ */
+ function setCredentials($username, $password, $authtype = 'basic') {
+ $this->username = $username;
+ $this->password = $password;
+ $this->authtype = $authtype;
+ }
+
+ /**
+ * use HTTP encoding
+ *
+ * @param string $enc
+ * @access public
+ */
+ function setHTTPEncoding($enc='gzip, deflate'){
+ $this->http_encoding = $enc;
+ }
+
+ /**
+ * use HTTP persistent connections if possible
+ *
+ * @access public
+ */
+ function useHTTPPersistentConnection(){
+ $this->persistentConnection = true;
+ }
+
+ /**
+ * gets the default RPC parameter setting.
+ * If true, default is that call params are like RPC even for document style.
+ * Each call() can override this value.
+ *
+ * This is no longer used.
+ *
+ * @access public
+ * @deprecated
+ */
+ function getDefaultRpcParams() {
+ return $this->defaultRpcParams;
+ }
+
+ /**
+ * sets the default RPC parameter setting.
+ * If true, default is that call params are like RPC even for document style
+ * Each call() can override this value.
+ *
+ * @param boolean $rpcParams
+ * @access public
+ */
+ function setDefaultRpcParams($rpcParams) {
+ $this->defaultRpcParams = $rpcParams;
+ }
+
+ /**
+ * dynamically creates proxy class, allowing user to directly call methods from wsdl
+ *
+ * @return object soap_proxy object
+ * @access public
+ */
+ function getProxy(){
+ $evalStr = '';
+ foreach($this->operations as $operation => $opData){
+ if($operation != ''){
+ // create param string
+ $paramStr = '';
+ if(sizeof($opData['input']['parts']) > 0){
+ foreach($opData['input']['parts'] as $name => $type){
+ $paramStr .= "\$$name,";
+ }
+ $paramStr = substr($paramStr,0,strlen($paramStr)-1);
+ }
+ $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
+ $evalStr .= "function $operation ($paramStr){
+ // load params into array
+ \$params = array($paramStr);
+ return \$this->call('$operation',\$params,'".$opData['namespace']."','".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
+ }";
+ unset($paramStr);
+ }
+ }
+ $r = rand();
+ $evalStr = 'class soap_proxy_'.$r.' extends soapclient2 {
+ '.$evalStr.'
+ }';
+ //print "proxy class:$evalStr ";
+ // eval the class
+ eval($evalStr);
+ // instantiate proxy object
+ eval("\$proxy = new soap_proxy_$r('');");
+ // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
+ $proxy->endpointType = 'wsdl';
+ $proxy->wsdlFile = $this->wsdlFile;
+ $proxy->wsdl = $this->wsdl;
+ $proxy->operations = $this->operations;
+ $proxy->defaultRpcParams = $this->defaultRpcParams;
+ // transfer other state
+ $proxy->username = $this->username;
+ $proxy->password = $this->password;
+ $proxy->proxyhost = $this->proxyhost;
+ $proxy->proxyport = $this->proxyport;
+ $proxy->proxyusername = $this->proxyusername;
+ $proxy->proxypassword = $this->proxypassword;
+ $proxy->timeout = $this->timeout;
+ $proxy->response_timeout = $this->response_timeout;
+ $proxy->http_encoding = $this->http_encoding;
+ $proxy->persistentConnection = $this->persistentConnection;
+ return $proxy;
+ }
+
+ /**
+ * gets the HTTP body for the current request.
+ *
+ * @param string $soapmsg The SOAP payload
+ * @return string The HTTP body, which includes the SOAP payload
+ * @access protected
+ */
+ function getHTTPBody($soapmsg) {
+ return $soapmsg;
+ }
+
+ /**
+ * gets the HTTP content type for the current request.
+ *
+ * Note: getHTTPBody must be called before this.
+ *
+ * @return string the HTTP content type for the current request.
+ * @access protected
+ */
+ function getHTTPContentType() {
+ return 'text/xml';
+ }
+
+ /**
+ * gets the HTTP content type charset for the current request.
+ * returns false for non-text content types.
+ *
+ * Note: getHTTPBody must be called before this.
+ *
+ * @return string the HTTP content type charset for the current request.
+ * @access protected
+ */
+ function getHTTPContentTypeCharset() {
+ return $this->soap_defencoding;
+ }
+
+ /*
+ * whether or not parser should decode utf8 element content
+ *
+ * @return always returns true
+ * @access public
+ */
+ function decodeUTF8($bool){
+ $this->decode_utf8 = $bool;
+ return true;
+ }
+}
+?>
diff --git a/oss/vtiger/trunk/customerportal/supportpage.php b/oss/vtiger/trunk/customerportal/supportpage.php
new file mode 100644
index 00000000..c986987d
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/supportpage.php
@@ -0,0 +1,74 @@
+ ';
+ $list .= ' ';
+ $list .= '';
+
+ return $list;
+}
+if($_REQUEST['mail_send_message'] != '')
+{
+ $mail_send_message = explode("@@@",$_REQUEST['mail_send_message']);
+
+ if($mail_send_message[0] == 'true')
+ {
+ $list = ' ';
+ $list .= '';
+
+ echo $list;
+ }
+ elseif($mail_send_message[0] == 'false')
+ {
+ $list = GetForgotPasswordUI($mail_send_message[1]);
+ echo $list;
+ }
+}
+elseif($_REQUEST['param'] == 'forgot_password')
+{
+ $list = GetForgotPasswordUI();
+ echo $list;
+}
+elseif($_REQUEST['param'] == 'sign_up')
+{
+ echo 'Sign Up..........';
+}
+
+
+
+
+?>
diff --git a/oss/vtiger/trunk/customerportal/version.php b/oss/vtiger/trunk/customerportal/version.php
new file mode 100644
index 00000000..72695683
--- /dev/null
+++ b/oss/vtiger/trunk/customerportal/version.php
@@ -0,0 +1,16 @@
+