From b33bb4f614657f590110db566288f32188e187ea Mon Sep 17 00:00:00 2001 From: whb <whb@yoho.cn> Date: Wed, 20 Apr 2016 18:07:04 +0800 Subject: [PATCH] temp 逛和支付 --- library/LibModels/Web/Guang/InfoData.php | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/LibModels/Web/Guang/ListData.php | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- library/LibModels/Web/Guang/PlusstarData.php | 2 +- library/LibModels/Web/Product/PayData.php | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Helpers.php | 17 +++++++++++------ library/WebPlugin/Pay/AliExpressgateway/Config.php | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/AliExpressgateway/Service.php | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Alibank/Config.php | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Alibank/Service.php | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Alibarcode/Config.php | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Alibarcode/Service.php | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Alipay/Config.php | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Alipay/Service.php | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Allinpay/Config.php | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Allinpay/Service.php | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Banks.php | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Ccb/Config.php | 1 + library/WebPlugin/Pay/Ccb/Service.php | 1 + library/WebPlugin/Pay/Chinabank/Config.php | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Chinabank/Service.php | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Cmb/Config.php | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Cmb/Service.php | 28 ++++++++++++++++++++++++++++ library/WebPlugin/Pay/Ips/Config.php | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Ips/Service.php | 41 +++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Kqshenzhou/Config.php | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Kqshenzhou/Service.php | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Kuaiqian/Config.php | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Kuaiqian/Service.php | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/Service.php | 39 +++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/SofeeXmlParser.php | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.CreateXML.php | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.MotoClient.php | 422 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.XmlParser.php | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/class.nusoap_base.php | 905 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/class.soap_fault.php | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/class.soap_parser.php | 599 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/class.soap_server.php | 1038 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/class.soap_transport_http.php | 1038 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/class.soap_val.php | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/class.soapclient.php | 859 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/class.wsdl.php | 1727 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/class.wsdlcache.php | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/class.xmlschema.php | 906 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/nusoap.php | 7241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Motopay/lib/nusoapmime.php | 478 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/PayAbstract.php | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/PayFactory.php | 19 +++++++++++++++++++ library/WebPlugin/Pay/PayInterface.php | 21 +++++++++++++++++++++ library/WebPlugin/Pay/Reqparams.php | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Rspparams.php | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Shengpay/Config.php | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Shengpay/Service.php | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Signature.php | 46 ++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Tenpay/Config.php | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Tenpay/Service.php | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/Func/PhpLog.php | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/Func/PinBlock.php | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/Func/PublicEncrypte.php | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/Func/common.php | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/Func/httpClient.php | 47 +++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/Func/secureUtil.php | 252 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/Service.php | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/conf/release/SDKConfig.php | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/conf/release/certs/RSA2048_PROD_index_22.cer | 24 ++++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/conf/release/certs/UpopRsaCert.cer | 20 ++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/conf/release/certs/mobile.pfx | Bin 0 -> 2850 bytes library/WebPlugin/Pay/Unionpayweb/conf/release/certs/pc_nocard_payment.pfx | Bin 0 -> 2850 bytes library/WebPlugin/Pay/Unionpayweb/conf/release/certs/pc_online_banking.pfx | Bin 0 -> 2850 bytes library/WebPlugin/Pay/Unionpayweb/conf/test/SDKConfig.php | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/conf/test/certs/PM_700000000000001_acp.pfx | Bin 0 -> 2170 bytes library/WebPlugin/Pay/Unionpayweb/conf/test/certs/encrypt.cer | 22 ++++++++++++++++++++++ library/WebPlugin/Pay/Unionpayweb/conf/test/certs/verify_sign_acp.cer | 25 +++++++++++++++++++++++++ library/WebPlugin/Pay/Wechatqrcode/Config.php | 18 ++++++++++++++++++ library/WebPlugin/Pay/Wechatqrcode/Service.php | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/weixin/lib/WxPayConfig.php | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------ library/WebPlugin/Pay/weixin/lib/WxPayNativePay.php | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ library/WebPlugin/Pay/weixin/lib/WxPayUnifiedOrder.php | 1013 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- template/www.yohobuy.com/actions/guang/index/editor.phtml | 32 ++++++++++++++++++++++++++++++++ template/www.yohobuy.com/actions/guang/index/index.phtml | 44 ++++++++++++++++++++++++++++++++++++++++++++ template/www.yohobuy.com/actions/guang/info/comment.phtml | 1 + template/www.yohobuy.com/actions/guang/info/info.phtml | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ template/www.yohobuy.com/actions/guang/tags/list.phtml | 24 ++++++++++++++++++++++++ template/www.yohobuy.com/actions/pay/index/index.phtml | 18 ++++++++++++++++++ template/www.yohobuy.com/actions/pay/notice/index.phtml | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ template/www.yohobuy.com/actions/pay/notice/wechatqrcodereturn.phtml | 38 ++++++++++++++++++++++++++++++++++++++ template/www.yohobuy.com/actions/pay/wechatqrcode/index.phtml | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ template/www.yohobuy.com/actions/shopping/pay/cashondelivery.phtml | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ template/www.yohobuy.com/actions/shopping/pay/index.phtml | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ template/www.yohobuy.com/actions/shopping/pay/notneedpay.phtml | 28 ++++++++++++++++++++++++++++ template/www.yohobuy.com/partials/guang/comment.phtml | 23 +++++++++++++++++++++++ template/www.yohobuy.com/partials/guang/msg.phtml | 96 ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------ template/www.yohobuy.com/partials/guang/right-side.phtml | 66 +++++++++++++++++++++++++++++++++--------------------------------- template/www.yohobuy.com/partials/shopping/box-analysis.phtml | 10 ++++++++++ template/www.yohobuy.com/partials/shopping/box-buy-analysis.phtml | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ web-static/js/pay/wechatqrcode.js | 12 ++---------- web-static/js/shopping/pay.js | 4 ++-- web-static/package.json | 2 +- web-static/sass/pay/_notice.css | 4 ++-- web-static/sass/shopping/_cashondelivery.css | 76 ++++++++++++++++++++++++++++++++++++++++++---------------------------------- yohobuy/www.yohobuy.com/application/controllers/Guang.php | 486 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ yohobuy/www.yohobuy.com/application/models/Guang/Index.php | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yohobuy/www.yohobuy.com/application/models/Guang/Info.php | 343 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yohobuy/www.yohobuy.com/application/models/Guang/Plusstar.php | 1 - yohobuy/www.yohobuy.com/application/models/Index/Brands.php | 47 ++++++++++++++++------------------------------- yohobuy/www.yohobuy.com/application/models/Shopping/Pay.php | 552 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Index.php | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Info.php | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Tags.php | 44 ++++++++++++++++++++++++++++++++++++++++++++ yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Index.php | 35 +++++++++++++++++++++++++++++++++++ yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Notice.php | 352 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Wechatqrcode.php | 38 ++++++++++++++++++++++++++++++++++++++ yohobuy/www.yohobuy.com/application/modules/Shopping/controllers/Pay.php | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yohobuy/www.yohobuy.com/configs/application.developer.ini | 6 +++--- yohobuy/www.yohobuy.com/configs/application.preview.ini | 6 +++--- yohobuy/www.yohobuy.com/configs/application.production.ini | 6 +++--- yohobuy/www.yohobuy.com/configs/application.testing.ini | 6 +++--- yohobuy/www.yohobuy.com/configs/routes.guang.ini | 6 ++++++ 117 files changed, 24744 insertions(+), 1246 deletions(-) create mode 100644 library/LibModels/Web/Guang/InfoData.php create mode 100644 library/LibModels/Web/Product/PayData.php create mode 100644 library/WebPlugin/Pay/AliExpressgateway/Config.php create mode 100644 library/WebPlugin/Pay/AliExpressgateway/Service.php create mode 100644 library/WebPlugin/Pay/Alibank/Config.php create mode 100644 library/WebPlugin/Pay/Alibank/Service.php create mode 100644 library/WebPlugin/Pay/Alibarcode/Config.php create mode 100644 library/WebPlugin/Pay/Alibarcode/Service.php create mode 100644 library/WebPlugin/Pay/Alipay/Config.php create mode 100644 library/WebPlugin/Pay/Alipay/Service.php create mode 100644 library/WebPlugin/Pay/Allinpay/Config.php create mode 100644 library/WebPlugin/Pay/Allinpay/Service.php create mode 100644 library/WebPlugin/Pay/Banks.php create mode 100644 library/WebPlugin/Pay/Ccb/Config.php create mode 100644 library/WebPlugin/Pay/Ccb/Service.php create mode 100644 library/WebPlugin/Pay/Chinabank/Config.php create mode 100644 library/WebPlugin/Pay/Chinabank/Service.php create mode 100644 library/WebPlugin/Pay/Cmb/Config.php create mode 100644 library/WebPlugin/Pay/Cmb/Service.php create mode 100644 library/WebPlugin/Pay/Ips/Config.php create mode 100644 library/WebPlugin/Pay/Ips/Service.php create mode 100644 library/WebPlugin/Pay/Kqshenzhou/Config.php create mode 100644 library/WebPlugin/Pay/Kqshenzhou/Service.php create mode 100644 library/WebPlugin/Pay/Kuaiqian/Config.php create mode 100644 library/WebPlugin/Pay/Kuaiqian/Service.php create mode 100644 library/WebPlugin/Pay/Motopay/Service.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/SofeeXmlParser.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.CreateXML.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.MotoClient.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.XmlParser.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/class.nusoap_base.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/class.soap_fault.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/class.soap_parser.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/class.soap_server.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/class.soap_transport_http.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/class.soap_val.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/class.soapclient.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/class.wsdl.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/class.wsdlcache.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/class.xmlschema.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/nusoap.php create mode 100644 library/WebPlugin/Pay/Motopay/lib/nusoapmime.php create mode 100644 library/WebPlugin/Pay/PayAbstract.php create mode 100644 library/WebPlugin/Pay/PayFactory.php create mode 100644 library/WebPlugin/Pay/PayInterface.php create mode 100644 library/WebPlugin/Pay/Reqparams.php create mode 100644 library/WebPlugin/Pay/Rspparams.php create mode 100644 library/WebPlugin/Pay/Shengpay/Config.php create mode 100644 library/WebPlugin/Pay/Shengpay/Service.php create mode 100644 library/WebPlugin/Pay/Signature.php create mode 100644 library/WebPlugin/Pay/Tenpay/Config.php create mode 100644 library/WebPlugin/Pay/Tenpay/Service.php create mode 100644 library/WebPlugin/Pay/Unionpayweb/Func/PhpLog.php create mode 100644 library/WebPlugin/Pay/Unionpayweb/Func/PinBlock.php create mode 100644 library/WebPlugin/Pay/Unionpayweb/Func/PublicEncrypte.php create mode 100644 library/WebPlugin/Pay/Unionpayweb/Func/common.php create mode 100644 library/WebPlugin/Pay/Unionpayweb/Func/httpClient.php create mode 100644 library/WebPlugin/Pay/Unionpayweb/Func/secureUtil.php create mode 100644 library/WebPlugin/Pay/Unionpayweb/Service.php create mode 100644 library/WebPlugin/Pay/Unionpayweb/conf/release/SDKConfig.php create mode 100644 library/WebPlugin/Pay/Unionpayweb/conf/release/certs/RSA2048_PROD_index_22.cer create mode 100644 library/WebPlugin/Pay/Unionpayweb/conf/release/certs/UpopRsaCert.cer create mode 100644 library/WebPlugin/Pay/Unionpayweb/conf/release/certs/mobile.pfx create mode 100644 library/WebPlugin/Pay/Unionpayweb/conf/release/certs/pc_nocard_payment.pfx create mode 100644 library/WebPlugin/Pay/Unionpayweb/conf/release/certs/pc_online_banking.pfx create mode 100644 library/WebPlugin/Pay/Unionpayweb/conf/test/SDKConfig.php create mode 100644 library/WebPlugin/Pay/Unionpayweb/conf/test/certs/PM_700000000000001_acp.pfx create mode 100644 library/WebPlugin/Pay/Unionpayweb/conf/test/certs/encrypt.cer create mode 100644 library/WebPlugin/Pay/Unionpayweb/conf/test/certs/verify_sign_acp.cer create mode 100644 library/WebPlugin/Pay/Wechatqrcode/Config.php create mode 100644 library/WebPlugin/Pay/Wechatqrcode/Service.php create mode 100644 library/WebPlugin/Pay/weixin/lib/WxPayNativePay.php create mode 100644 template/www.yohobuy.com/actions/guang/index/editor.phtml create mode 100644 template/www.yohobuy.com/actions/guang/index/index.phtml create mode 100644 template/www.yohobuy.com/actions/guang/info/comment.phtml create mode 100644 template/www.yohobuy.com/actions/guang/info/info.phtml create mode 100644 template/www.yohobuy.com/actions/guang/tags/list.phtml create mode 100644 template/www.yohobuy.com/actions/pay/index/index.phtml create mode 100644 template/www.yohobuy.com/actions/pay/notice/index.phtml create mode 100644 template/www.yohobuy.com/actions/pay/notice/wechatqrcodereturn.phtml create mode 100644 template/www.yohobuy.com/actions/pay/wechatqrcode/index.phtml create mode 100644 template/www.yohobuy.com/actions/shopping/pay/cashondelivery.phtml create mode 100644 template/www.yohobuy.com/actions/shopping/pay/index.phtml create mode 100644 template/www.yohobuy.com/actions/shopping/pay/notneedpay.phtml create mode 100644 template/www.yohobuy.com/partials/guang/comment.phtml create mode 100644 template/www.yohobuy.com/partials/shopping/box-analysis.phtml create mode 100644 template/www.yohobuy.com/partials/shopping/box-buy-analysis.phtml delete mode 100644 yohobuy/www.yohobuy.com/application/controllers/Guang.php create mode 100644 yohobuy/www.yohobuy.com/application/models/Guang/Index.php create mode 100644 yohobuy/www.yohobuy.com/application/models/Guang/Info.php create mode 100644 yohobuy/www.yohobuy.com/application/models/Shopping/Pay.php create mode 100644 yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Info.php create mode 100644 yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Tags.php create mode 100644 yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Index.php create mode 100644 yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Notice.php create mode 100644 yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Wechatqrcode.php create mode 100644 yohobuy/www.yohobuy.com/application/modules/Shopping/controllers/Pay.php diff --git a/library/LibModels/Web/Guang/InfoData.php b/library/LibModels/Web/Guang/InfoData.php new file mode 100644 index 0000000..cb6a956 --- /dev/null +++ b/library/LibModels/Web/Guang/InfoData.php @@ -0,0 +1,284 @@ +<?php +namespace LibModels\Web\Guang; + +use Api\Yohobuy; +use Api\Sign; +class InfoData +{ + /** + * 获取接口地址 + * @return string + */ + public static function getUrl($type) + { + //作者信息 + if ($type == 'author') { + return Yohobuy::SERVICE_URL.'guang/service/v1/author/getAuthor'; + } + //文章评论列表 + elseif($type == 'commentList') { + return Yohobuy::SERVICE_URL.'guang/api/v1/comments/getList'; + } + //热门标签 + elseif ($type == 'getTagTop') { + return Yohobuy::SERVICE_URL.'guang/api/v2/article/getTagTop'; + } + //精彩推荐 + elseif ($type == 'getArticleByViewsNum') { + return Yohobuy::SERVICE_URL.'guang/api/v2/article/getArticleByViewsNum'; + } + elseif ($type == 'getBrand'){ + return Yohobuy::SERVICE_URL.'guang/service/v2/article/getBrand'; + } + //相关文章 + elseif ($type == 'getOtherArticle') { + return Yohobuy::SERVICE_URL.'guang/service/v2/article/getOtherArticle'; + } + //文章标题等相关信息 + elseif ($type == 'getArticle') { + return Yohobuy::SERVICE_URL.'guang/service/v2/article/getArticle'; + } + //文章详情 + elseif ($type == 'getArticleContent') { + return Yohobuy::SERVICE_URL.'guang/service/v2/article/getArticleContent'; + } + //基本信息 + elseif ($type == 'getArticleBaseInfo') { + return Yohobuy::SERVICE_URL.'guang/api/v1/article/getArticleBaseInfo'; + } + //添加评论 + elseif ($type == 'addComment') { + return Yohobuy::SERVICE_URL.'guang/api/v1/comments/add'; + } + //点赞 + elseif ($type == 'setPraise') { + return Yohobuy::SERVICE_URL.'guang/api/v2/praise/setPraise'; + } + //取消赞 + elseif ($type == 'cancelPraise') { + return Yohobuy::SERVICE_URL.'guang/api/v2/praise/cancel'; + } + //收藏 + elseif ($type == 'setFavorite') { + return Yohobuy::SERVICE_URL.'guang/api/v1/favorite/setFavorite'; + } + //取消收藏 + elseif ($type == 'cancelFavorite') { + return Yohobuy::SERVICE_URL.'guang/api/v1/favorite/cancelFavorite'; + } + } + + /** + * 调用接口 + * @param string $url + * @param array $param + * @param bool $onlyUrl true:返回请求地址; false:返回接口数据 + * @return mixed + */ + public static function webApi($url, $param, $onlyUrl = false) + { + $param += Yohobuy::param(); + $param['client_type'] = 'web'; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['client_secret'] = Sign::getSign($param); + if ($onlyUrl) { + return Yohobuy::httpBuildQuery($url, $param); + } + return Yohobuy::get($url, $param); + } + + /** + * 根据文章id获取文章信息 + * @param $id + * @param $onlyUrl + * @return mixed + */ + public static function getArticleInfo($id, $onlyUrl = false) + { + $param['article_id'] = $id; + return self::webApi(self::getUrl('getArticle'), $param, $onlyUrl); + } + + /** + * 组建根据文章id查询作者信息的url + * @param $authorId + * @param bool $onlyUrl + * @return mixed + */ + public static function author($authorId, $onlyUrl = false) + { + $param['author_id'] = $authorId; + return self::webApi(self::getUrl('author'), $param, $onlyUrl); + } + + /** + * 热门标签 + * @param int $page + * @param int $limit + * @param bool $onlyUrl + * @return string + */ + + public static function tagTop($page = 1,$limit = 10, $onlyUrl = false) + { + $param['page'] = $page; + $param['limit'] = $limit; + return self::webApi(self::getUrl('getTagTop'), $param, $onlyUrl); + } + + /** + * 组建根据文章id查询评论列表 + * @param $articleId + * @param $page + * @param $limit + * @param $onlyUrl + * @return string + */ + public static function comment($articleId, $page = 1, $limit = 10, $onlyUrl = false) + { + $param['article_id'] = $articleId; + $param['page'] = $page; + $param['limit'] = $limit; + return self::webApi(self::getUrl('commentList'), $param, $onlyUrl); + } + + /** + * 文章详细内容 + * @param $articleId + * @param bool $onlyUrl + * @return mixed + */ + public static function articleContent($articleId, $onlyUrl = false) + { + $param['article_id'] = $articleId; + return self::webApi(self::getUrl('getArticleContent'), $param, $onlyUrl); + } + + /** + * 判断用户是否收藏文章地址 + * @param $articleId + * @param $uid + * @param $udid + * @param bool $onlyUrl + * @return mixed + */ + public static function baseInfo($articleId, $uid, $udid, $onlyUrl = false) + { + $param['id'] = $articleId; + $param['uid'] = $uid; + $param['udid'] = $udid; + return self::webApi(self::getUrl('getArticleBaseInfo'), $param, $onlyUrl); + } + + /** + * 文章相关品牌 + * @param $articleId + * @param bool $onlyUrl + * @return mixed + */ + public static function relateBrand($articleId, $onlyUrl = false) + { + $param['article_id'] = $articleId; + return self::webApi(self::getUrl('getBrand'), $param, $onlyUrl); + } + + /** + * 相关文章列表 + * @param $articleId + * @param $tag + * @param int $limit + * @param bool $onlyUrl + * @return mixed + */ + public static function relateList($articleId, $tag, $limit = 3, $onlyUrl = false) + { + $param['article_id'] = $articleId; + $param['tags'] = $tag; + $param['limit'] = $limit; + return self::webApi(self::getUrl('getOtherArticle'), $param, $onlyUrl); + } + + /** + * 精彩推荐(48小时内浏览最多的文章) + * + * @param string $gender + * @param int $page + * @param int $limit + * @param bool $onlyUrl + * @return mixed + */ + public static function recommend($gender, $page = 1, $limit = 10, $onlyUrl = false) + { + $param['gender'] = $gender; + $param['page'] = $page; + $param['limit'] = $limit; + return self::webApi(self::getUrl('getArticleByViewsNum'), $param, $onlyUrl); + } + + /** + * 添加文章评论 + * @param $id 文章id + * @param $uid 用户id + * @param $content 评论内容 + * @return mixed + */ + public static function addComment($id, $uid, $content) + { + $param['article_id'] = $id; + $param['uid'] = $uid; + $param['content'] = $content; + return self::webApi(self::getUrl('addComment'), $param); + } + + /** + * 点赞 + * @param $id + * @param $udid + * @return mixed + */ + public static function setPraise($id, $udid) + { + $param['article_id'] = $id; + $param['udid'] = $udid; + return self::webApi(self::getUrl('setPraise'), $param); + } + + /** + * 取消赞 + * @param $id + * @param $udid + * @return mixed + */ + public static function cancelPraise($id, $udid) + { + $param['article_id'] = $id; + $param['udid'] = $udid; + return self::webApi(self::getUrl('cancelPraise'), $param); + } + + /** + * 收藏文章 + * @param $id + * @param $uid + * @return mixed + */ + public static function setFavorite($id, $uid) + { + $param['article_id'] = $id; + $param['uid'] = $uid; + return self::webApi(self::getUrl('setFavorite'), $param); + } + + /** + * 取消文章收藏 + * @param $id + * @param $uid + * @return mixed + */ + public static function cancelFavorite($id, $uid) + { + $param['article_id'] = $id; + $param['uid'] = $uid; + return self::webApi(self::getUrl('cancelFavorite'), $param); + } +} \ No newline at end of file diff --git a/library/LibModels/Web/Guang/ListData.php b/library/LibModels/Web/Guang/ListData.php index 397a6db..15bf3f3 100644 --- a/library/LibModels/Web/Guang/ListData.php +++ b/library/LibModels/Web/Guang/ListData.php @@ -1,5 +1,132 @@ -<?php -namespace LibModels\Web\Guang; -class ListData extends \LibModels\Wap\Guang\ListData { - -} \ No newline at end of file +<?php + +namespace LibModels\Web\Guang; + +use Api\Sign; +use Api\Yohobuy; + +/** + * 逛首页列表相关的数据模型 + * + * @name ListData + * @package LibModels/Web/Guang + * @copyright yoho.inc + * @version 1.0 (2015-10-10 9:54:07) + * @author fei.hong <fei.hong@yoho.cn> + */ +class ListData +{ + const URI_CATEGORY = 'guang/api/v1/category/get'; + const URI_ARTICLELIST = 'guang/api/v2/article/getList'; + const URI_GETAUTHOR = 'guang/service/v1/author/getAuthor'; + + /** + * 逛分类 + * + * 备注: id (0:最新,1:话题,2:搭配,3:潮人,4:潮品,5:小贴士) + * + * @return array + */ + public static function category() + { + $param = Yohobuy::param(); + $param['client_secret'] = Sign::getSign($param); + + return Yohobuy::get(Yohobuy::SERVICE_URL . self::URI_CATEGORY, $param, 3600); // 有缓存1小时 + } + + /** + * 逛内容列表 + * + * @param string $gender "1,3"表示男, "2,3"表示女, "1,2,3"表示所有 + * @param int $sortId 分类ID + * @param int $uid 用户ID + * @param string $udid 客户端唯一标识 + * @param int $page 分页第几页, 默认第1页 + * @param string $tag 标签 + * @param int $authorId 作者ID + * @param int $limit 返回的限制数 + * @param bool $useCache 是否使用缓存 + * @return array + */ + public static function article($gender, $sortId, $uid = 0, $udid = '', $page = 1, $tag = null, $authorId = null, $limit = null, $useCache = false) + { + $param = Yohobuy::param(); + $param['gender'] = $gender; + $param['page'] = $page; + $param['uid'] = $uid; + $param['udid'] = $udid; + if (isset($sortId)) { + $param['sort_id'] = $sortId; + } + if (!empty($tag)) { + $param['tag'] = $tag; + } + if (isset($authorId) && is_numeric($authorId)) { + $param['author_id'] = $authorId; + } + if (isset($limit)) { + $param['limit'] = $limit; + } + $param['client_type'] = "web"; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['client_secret'] = Sign::getSign($param); + + $cache = $useCache ? 300 : false; + + return Yohobuy::get(Yohobuy::SERVICE_URL . self::URI_ARTICLELIST, $param, $cache); // 缓存5分钟 + } + + /** + * 根据分类进行分组的逛内容列表 + * + * @param array $category 分类 + * @param string $gender "1,3"表示男, "2,3"表示女 + * @param int $uid 用户ID + * @param string $udid 客户端唯一标识 + * @param int $page 分页第几页, 默认第1页 + * @return array + */ + public static function articleGroup($category, $gender, $uid = 0, $udid, $page = 1) + { + $urlList = array(); + $param = array(); + + foreach ($category as $value) { + $param = Yohobuy::param(); + $param['gender'] = $gender; + $param['page'] = $page; + $param['sort_id'] = $value['id']; + $param['uid'] = $uid; + $param['udid'] = $udid; + $param['client_secret'] = Sign::getSign($param); + + $urlList[$value['id']] = Yohobuy::httpBuildQuery(Yohobuy::SERVICE_URL . self::URI_ARTICLELIST, $param); + } + + return Yohobuy::getMulti($urlList); + } + + /** + * 获取作者信息 + * + * @param int $id 作者ID + * @return array + */ + public static function author($id) + { + $result = array(); + if (is_numeric($id)) { +// $result = Yohobuy::yarClient(Yohobuy::SERVICE_URL . self::URI_AUTHOR, 'getAuthor', array($id), 3600); // 缓存1小时 + $param = Yohobuy::param(); + $param['author_id'] = $id; + $param['client_type'] = "web"; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['client_secret'] = Sign::getSign($param); + + $result = Yohobuy::get(Yohobuy::SERVICE_URL . self::URI_GETAUTHOR, $param); // 缓存1小时 + } + return $result; + } + +} diff --git a/library/LibModels/Web/Guang/PlusstarData.php b/library/LibModels/Web/Guang/PlusstarData.php index f3cc5a3..c5fe7bd 100644 --- a/library/LibModels/Web/Guang/PlusstarData.php +++ b/library/LibModels/Web/Guang/PlusstarData.php @@ -2,7 +2,7 @@ namespace LibModels\Web\Guang; use Api\Yohobuy; use Api\Sign; -class PlusstarData extends \LibModels\Wap\Guang\PlusstarData { +class PlusstarData { const URI_BRANDLIST = 'guang/api/v3/plustar/getlist'; /** diff --git a/library/LibModels/Web/Product/PayData.php b/library/LibModels/Web/Product/PayData.php new file mode 100644 index 0000000..c208258 --- /dev/null +++ b/library/LibModels/Web/Product/PayData.php @@ -0,0 +1,222 @@ +<?php + +namespace LibModels\Web\Product; + +use Api\Sign; +use Api\Yohobuy; + +/** + * 支付操作类 + * + * @package LibModels\Web\Product + * @author Gtskk + * @copyright 2016/3/24 14:23 Gtskk<iamgtskk@gmail.com> + * @version: 0.0.1 + */ +class PayData +{ + /** + * 获取指定用户的订单数目 + * + * @param int $uid 用户ID + * @return mixed + */ + public static function getOrderCountByUid($uid) + { + $param = Yohobuy::param(); + $param['client_type'] = 'web'; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['method'] = 'web.SpaceOrders.getOrderCountByUid'; + + $param['client_secret'] = Sign::getSign($param); + + return Yohobuy::get(Yohobuy::API_URL, $param); + } + + /** + * 获取支付方式列表 + * + * @return mixed + */ + public static function getPaymentList() + { + $param = Yohobuy::param(); + $param['client_type'] = 'web'; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['method'] = 'web.SpaceOrders.getPaymentList'; + + $param['client_secret'] = Sign::getSign($param); + + return Yohobuy::get(Yohobuy::API_URL, $param); + } + + /** + * 根据支付方式id获取单个支付方式有关信息 + * + * @param int $id 支付方式id + * @return mixed + */ + public static function getPaymentById($id) + { + $param = Yohobuy::param(); + $param['client_type'] = 'web'; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['method'] = 'web.SpaceOrders.getPaymentById'; + $param['id'] = $id; + + $param['client_secret'] = Sign::getSign($param); + + return Yohobuy::get(Yohobuy::API_URL, $param); + } + + /** + * ERP提交订单状态 + * + * @param string $orderCode 订单号 + * @param int $payment 支付方式id + * @param string $bankName 银行名称 + * @param string $bankCode 银行代码 + * @param string $amount 金额 + * @param string $payOrderCode 支付订单代码 + * @param string $tradeNo 交易码 + * @param string $bankBillNo 银行订单码 + * @return mixed + */ + public static function submitOrderStatus($orderCode, $payment, $bankName, $bankCode, $amount, $payOrderCode, $tradeNo, $bankBillNo) + { + $param = Yohobuy::param(); + $param['client_type'] = 'web'; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['method'] = 'web.SpaceOrders.submitOrderStatus'; + $param['order_code'] = $orderCode; + $param['payment'] = $payment; + $param['bank_name'] = $bankName; + $param['bank_code'] = $bankCode; + $param['amount'] = $amount; + $param['payOrderCode'] = $payOrderCode; + $param['trade_no'] = $tradeNo; + $param['bank_bill_no'] = $bankBillNo; + + $param['client_secret'] = Sign::getSign($param); + + return Yohobuy::get(Yohobuy::API_URL, $param); + } + + + /** + * 更新订单的状态 + * + * @param int $id 订单ID + * @param int $uid 用户ID + * @param int $payment 支付方式ID + * @param string $paymentStatus 支付状态(Y或者N) + * @param string $bankCode 银行代码 + * @return mixed + */ + public static function updateOrderStatus($id, $uid, $payment, $paymentStatus, $bankCode) + { + $param = Yohobuy::param(); + $param['client_type'] = 'web'; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['method'] = 'web.SpaceOrders.updatePaymentStatus'; + $param['id'] = $id; + $param['uid'] = $uid; + $param['payment'] = $payment; + $param['payment_status'] = $paymentStatus; + $param['bank_code'] = $bankCode; + + $param['client_secret'] = Sign::getSign($param); + + return Yohobuy::get(Yohobuy::API_URL, $param); + } + + /** + * 获取订单的支付银行 + * + * @param string $orderCode 订单号 + * @return mixed + */ + public static function getBankByOrder($orderCode) + { + $param = Yohobuy::param(); + $param['client_type'] = 'web'; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['method'] = 'web.SpaceOrders.getOrderPayBank'; + $param['orderCode'] = $orderCode; + + $param['client_secret'] = Sign::getSign($param); + + return Yohobuy::get(Yohobuy::API_URL, $param); + } + + /** + * 添加订单支付银行记录 + * + * @param string $orderCode 订单号 + * @param int $payment 支付方式ID + * @param string $bankCode 银行码 + * @return mixed + */ + public static function setOrderPayBank($orderCode, $payment, $bankCode) + { + $param = Yohobuy::param(); + $param['client_type'] = 'web'; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['method'] = 'web.SpaceOrders.addOrderPayBank'; + $param['orderCode'] = $orderCode; + $param['payment'] = $payment; + $param['bankCode'] = $bankCode; + + $param['client_secret'] = Sign::getSign($param); + + return Yohobuy::get(Yohobuy::API_URL, $param); + } + + /** + * 更改订单支付银行记录 + * + * @param string $orderCode 订单号 + * @param int $payment 支付方式ID + * @param string $bankCode 银行码 + * @return mixed + */ + public static function updateOrderPayBank($orderCode, $payment, $bankCode) + { + $param = Yohobuy::param(); + $param['client_type'] = 'web'; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['method'] = 'web.SpaceOrders.modifyOrderPayBank'; + $param['orderCode'] = $orderCode; + $param['payment'] = $payment; + $param['bankCode'] = $bankCode; + + $param['client_secret'] = Sign::getSign($param); + + return Yohobuy::get(Yohobuy::API_URL, $param); + } + + + /** + * 发送短信息(默认不传递area参数,传递了就是给特定国家码的手机号发送短信) + * + * @param string $mobile 手机号 + * @param string $template 模板类型 + * @param string $codes 对应模板中的参数 + * @return mixed + */ + public static function sendMessage($mobile, $template, $codes) + { + $param = Yohobuy::param(); + $param['client_type'] = 'web'; + $param['private_key'] = Yohobuy::$privateKeyList['web']; + $param['method'] = 'app.message.sendMsg'; + $param['mobile'] = $mobile; + $param['template'] = $template; + $param['codes'] = $codes; + + $param['client_secret'] = Sign::getSign($param); + + return Yohobuy::get(Yohobuy::API_URL, $param); + } + +} \ No newline at end of file diff --git a/library/WebPlugin/Helpers.php b/library/WebPlugin/Helpers.php index e64fbfc..db659c0 100644 --- a/library/WebPlugin/Helpers.php +++ b/library/WebPlugin/Helpers.php @@ -343,29 +343,34 @@ class Helpers */ public static function formatArticle($articleData, $showTag = true, $isApp = false, $showAuthor = true, $uid = null) { - // 资讯ID不存在,则不显示 + // 资讯ID不存在,则不显示 if (!isset($articleData['id'])) { return false; } $width = $height = 360; + $isSquareImage = true; if($articleData['conver_image_type'] == 2) { $width = 360; $height = 240; + $isSquareImage = false; } $result = array(); $result['id'] = $articleData['id']; $result['classification'] = $articleData['category_name']; - $result['isReco'] = $articleData['is_recommended']; - $result['url'] = $isApp ? $articleData['url'] : self::url('/info/index', array('id' => $articleData['id']), 'guang'); + $result['isReco'] = $articleData['is_recommended'] ? true : false; + $result['url'] = $isApp ? $articleData['url'] : self::url('/'.$articleData['id'].'.html', array(), 'guang'); $result['img'] = self::getImageUrl($articleData['src'], $width, $height); - $result['isSquareImg'] = true; + $result['isSquareImg'] = $isSquareImage; $result['title'] = $articleData['title']; if(empty($articleData['author'])){ $articleData['author']['name'] = ''; $articleData['author']['avatar'] = ''; } $result['author'] = $articleData['author']['name']; - $result['editorUrl'] = $articleData['author']['avatar']; + if (isset($articleData['author']['author_id']) && !empty($articleData['author']['author_id'])) { + $author_id = $articleData['author']['author_id']; + $result['editorUrl'] = self::url('/Index/editor', array('author_id' => $author_id), 'guang'); + } $result['pTime'] = $articleData['publish_time']; $result['pView'] = $articleData['views_num']; $result['content'] = $articleData['intro']; @@ -428,7 +433,7 @@ class Helpers public static function formatTag($tagData, $isApp = false, $uid = null) { $result = array(); $result['tag'] = $tagData['name']; - $result['url'] = $tagData['url']; + $result['url'] = Helpers::url('/tags/index', array('query'=>urlencode($tagData['name'])), 'guang'); return $result; } diff --git a/library/WebPlugin/Pay/AliExpressgateway/Config.php b/library/WebPlugin/Pay/AliExpressgateway/Config.php new file mode 100644 index 0000000..888dc69 --- /dev/null +++ b/library/WebPlugin/Pay/AliExpressgateway/Config.php @@ -0,0 +1,94 @@ +<?php + +namespace WebPlugin\Pay\AliExpressgateway; + +class Config +{ + + var $pay_url = "https://mapi.alipay.com/gateway.do"; + + /** + * 服务名,即时到帐为create_direct_pay_by_user + * Enter description here ... + * @var String + */ + var $service = "create_direct_pay_by_user"; + + /** + * 合作伙伴在支付宝的用户ID + * Enter description here ... + * @var string + */ + var $partner = ""; + + /** + * 编码 + * Enter description here ... + * @var String + */ + var $input_charset = "utf-8"; + + /** + * 通知url,(用于后台提交) + * Enter description here ... + * @var String + */ + var $notify_url = "notice/aliexpressgatewaynotice"; + + /** + * 浏览器的返回 + * Enter description here ... + * @var string + */ + var $return_url = "notice/aliexpressgatewayreturn"; + + /** + * 签名方式 + * Enter description here ... + * @var String + */ + var $sign_type = "MD5"; + + /** + * 支付类型,1为购买 + * Enter description here ... + * @var Integer + */ + var $payment_type = "1"; + + /** + * expressGateway、expressGatewayCredit + * @var unknown_type + */ + var $paymethod = "expressGateway"; + + /** + * 自动登陆标识,N则跳到银行,Y则直接在支付宝填 + * @var array + */ + var $default_login = "Y"; + + /** + * Key + * Enter description here ... + * @var String + */ + var $alipay_key = ""; + + /** + * 销售者mail + * Enter description here ... + * @var String + */ + var $sellerMail = ""; + + /** + * 防钓鱼配置 + */ + var $anti_fishing = array( + 'ip_enable' => true, + 'timestamp_enable' =>true + ); + +} + diff --git a/library/WebPlugin/Pay/AliExpressgateway/Service.php b/library/WebPlugin/Pay/AliExpressgateway/Service.php new file mode 100644 index 0000000..d287cdf --- /dev/null +++ b/library/WebPlugin/Pay/AliExpressgateway/Service.php @@ -0,0 +1,192 @@ +<?php + +namespace WebPlugin\Pay\AliExpressgateway; + +use DOMDocument; +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; + +class Service extends PayAbstract +{ + var $config ; + + public function __construct(array $paymentParams) + { + $this->logProjectPrefix = 'AliExpressgateway'; + $this->config = new Config(); + $myConfig = json_decode($paymentParams["pay_params"]) ; + $this->config->partner = $myConfig->merchant_id; + $this->config->alipay_key = $myConfig->merchant_key; + $this->config->sellerMail = $myConfig->merchant_other_code; + } + + /** + * 获取时间戳 + */ + private function getTimestamp() { + $url = "https://mapi.alipay.com/gateway.do?service=query_timestamp&partner=" . trim(strtolower($this->config->partner)) . "&_input_charset=" . trim(strtolower($this->config->input_charset)); + + $doc = new DOMDocument(); + $doc->load($url); + $itemEncrypt_key = $doc->getElementsByTagName("encrypt_key"); + $encrypt_key = $itemEncrypt_key->item(0)->nodeValue; + + return $encrypt_key; + } + + public function getPayRequestPars(Reqparams $params) + { + $baseUrl = $this->getBaseNoticeUrl($params->isTest); + $parameter = array( + 'service' => $this->config->service, + 'partner' => $this->config->partner, + '_input_charset' => $this->config->input_charset, + 'notify_url' => $baseUrl . $this->config->notify_url, + 'return_url' => $baseUrl . $this->config->return_url, + /* 业务参数 */ + 'subject' => $params->goodsName, + 'out_trade_no' => $params->orderCode, + 'total_fee' => $params->totalFee / 100, //单位为元 + 'payment_type' => $this->config->payment_type, + 'paymethod' => $this->config->paymethod, + 'default_login' => $this->config->default_login, + 'defaultbank' => $params->paymentParameter, + 'seller_email' => $this->config->sellerMail + ); + + if($this->config->anti_fishing['timestamp_enable']) { + $anti_phishing_key = $this->getTimestamp(); + if(!empty($anti_phishing_key)) { + $parameter['anti_phishing_key'] = $anti_phishing_key; + } + } + if($this->config->anti_fishing['ip_enable']) { + $parameter['exter_invoke_ip'] = $params->spbill_create_ip; + } + + // 除去数组中的空值和签名参数 + $para_filter = array(); + foreach ($parameter AS $k => $v) { + if($k == "sign" || $k == "sign_type" || $v == "") { + continue; + } else { + $para_filter[$k] = $parameter[$k]; + } + } + + ksort($para_filter); + reset($para_filter); + + $param = ''; + $sign = ''; + foreach ($para_filter AS $key => $val) + { + $param .= "$key=" .urlencode($val). "&"; + $sign .= "$key=$val&"; + } + $param = substr($param, 0, -1); + $sign = substr($sign, 0, -1). $this->config->alipay_key; + + $result = array( + 'pay_url' => $this->config->pay_url, + 'pars' => $param . "&sign=" . md5($sign). "&sign_type=" . $this->config-> sign_type, + 'reqType' => 'get' + ); + return $result; + } + + /** + * 解析响应 + * + * @param array $arrResponse + * @return Rspparams + */ + public function parseResponse(array $arrResponse) + { + /* 返回示例 + * http://www.yohobuy.com/pay/notice/aliexpressgatewayreturn?buyer_email=tds%40smartunite.com&buyer_id=2088302294447308&exterface=create_direct_pay_by_user&is_success=T¬ify_id=RqPnCoPT3K9%252Fvwbh3I7xtEV5W65QRToFQ5fPrXsVxt12e%252FExCtC1XNiKnuRwupLaVLAR¬ify_time=2011-06-11+07%3A48%3A10¬ify_type=trade_status_sync&out_trade_no=1061003000&payment_type=1&seller_email=shop%40yoho.cn&seller_id=2088001550230585&subject=YOHO%E5%95%86%E5%93%81&total_fee=0.01&trade_no=2011061199833830&trade_status=TRADE_SUCCESS&sign=ca1c49f58d17eaa57aac308d0ac64434&sign_type=MD5 + */ + if(isset($arrResponse['q'])){ + unset($arrResponse['q']); + } + $rsp = new Rspparams(); + if(!$this->checkResponse($arrResponse)) + { + //验证不成功 + $rsp->payResult = -1; + } + else + { + $rsp->bankName = ""; + $rsp->orderCode = $arrResponse["out_trade_no"]; + $rsp->payResult = $this->convertResult($arrResponse["trade_status"]); + $rsp->payTime = $arrResponse["gmt_payment"]; + $rsp->totalFee = $arrResponse["total_fee"]; + $rsp->resultMsg = $arrResponse["notify_type"]; + //添加支付订单号和交易号 + $rsp->payOrderCode = $arrResponse["out_trade_no"]; + $rsp->tradeNo = $arrResponse['trade_no']; + $rsp->bankBillNo = ""; + } + return $rsp; + } + + protected function convertResult($resultCode) + { + if($resultCode == "TRADE_SUCCESS") + { + return 200; + } + return 400; + } + + /** + * 除去数组中的空值和签名参数 + * @param $para 签名参数组 + * @return array 去掉空值与签名参数后的新签名参数组 + */ + private function paraFilter($para) { + $para_filter = array(); + foreach ($para as $key=>$val) { + if($key == "sign" || $key == "sign_type" || $val == "")continue; + else $para_filter[$key] = $para[$key]; + } + return $para_filter; + } + + /** + * 对数组排序 + * @param $para 排序前的数组 + * @return 排序前的数组 + */ + private function argSort($para) { + ksort($para); + reset($para); + return $para; + } + + /** + * 验证回复的正确性 + * @see QPay_Utils_Abstract::verifResponse() + * @param array $arrResponse + * @return bool|void + */ + protected function checkResponse(array $arrResponse) + { + ksort($arrResponse); + reset($arrResponse); + $sign = ''; + foreach ($arrResponse AS $key=>$val) + { + if ($key != 'sign' && $key != 'sign_type' && $key != 'code') + { + $sign .= "$key=$val&"; + } + } + $sign = substr($sign, 0, -1) . $this->config->alipay_key; + + return md5($sign) != $arrResponse['sign'] ? false : true; + + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Alibank/Config.php b/library/WebPlugin/Pay/Alibank/Config.php new file mode 100644 index 0000000..5dff8fc --- /dev/null +++ b/library/WebPlugin/Pay/Alibank/Config.php @@ -0,0 +1,82 @@ +<?php + +namespace WebPlugin\Pay\Alibank; + +class Config +{ + + var $pay_url = "https://mapi.alipay.com/gateway.do"; + + /** + * 服务名,即时到帐为create_direct_pay_by_user + * Enter description here ... + * @var String + */ + var $service = "create_direct_pay_by_user"; + + /** + * 合作伙伴在支付宝的用户ID + * Enter description here ... + * @var string + */ + var $partner = ""; + + /** + * 编码 + * Enter description here ... + * @var String + */ + var $input_charset = "utf-8"; + + /** + * 通知url,(用于后台提交) + * Enter description here ... + * @var String + */ + var $notify_url = "notice/alibanknotice"; + + /** + * 浏览器的返回 + * Enter description here ... + * @var string + */ + var $return_url = "notice/alibankreturn"; + + /** + * 签名方式 + * Enter description here ... + * @var String + */ + var $sign_type = "MD5"; + + /** + * 支付类型,1为购买 + * Enter description here ... + * @var Integer + */ + var $payment_type = "1"; + + /** + * Key + * Enter description here ... + * @var String + */ + var $alipay_key = ""; + + /** + * 销售者mail + * Enter description here ... + * @var String + */ + var $sellerMail = ""; + + /** + * 防钓鱼配置 + */ + var $anti_fishing = array( + 'ip_enable' => false, + 'timestamp_enable' =>false + ); + +} + diff --git a/library/WebPlugin/Pay/Alibank/Service.php b/library/WebPlugin/Pay/Alibank/Service.php new file mode 100644 index 0000000..7fedf3e --- /dev/null +++ b/library/WebPlugin/Pay/Alibank/Service.php @@ -0,0 +1,201 @@ +<?php + +namespace WebPlugin\Pay\Alibank; + +use DOMDocument; +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; + +class Service extends PayAbstract +{ + var $config ; + + public function __construct(array $paymentParams) + { + $this->logProjectPrefix = 'alibank'; + $this->config = new Config(); + $myConfig = json_decode($paymentParams["pay_params"]) ; + $this->config->partner = $myConfig->merchant_id; + $this->config->alipay_key = $myConfig->merchant_key; + $this->config->sellerMail = $myConfig->merchant_other_code; + } + + /** + * 获取时间戳 + */ + private function getTimestamp() + { + $url = "https://mapi.alipay.com/gateway.do?service=query_timestamp&partner=" . trim(strtolower($this->config->partner)) . "&_input_charset=" . trim(strtolower($this->config->input_charset)); + + $doc = new DOMDocument(); + $doc->load($url); + $itemEncrypt_key = $doc->getElementsByTagName("encrypt_key"); + $encrypt_key = $itemEncrypt_key->item(0)->nodeValue; + + return $encrypt_key; + } + + public function getPayRequestPars(Reqparams $params) + { + $baseUrl = $this->getBaseNoticeUrl($params->isTest); + $loseTime = intval(($params->orderTime + 7200 -time())/60); + // $loseTime = intval((strtotime(date("Y-m-d 10:00:00", strtotime("+1 day")))-time())/60); + + $parameter = array( + 'service' => $this->config->service, + 'partner' => $this->config->partner, + '_input_charset' => $this->config->input_charset, + 'notify_url' => $baseUrl . $this->config->notify_url, + 'return_url' => $baseUrl . $this->config->return_url, + /* 业务参数 */ + 'subject' => $params->goodsName, + 'out_trade_no' => $params->orderCode.'_'.$params->paymentParameter, + 'total_fee' => $params->totalFee / 100, //单位为元 + 'payment_type' => $this->config->payment_type, + 'defaultbank' => $params->paymentParameter, + 'seller_email' => $this->config->sellerMail, +// 'it_b_pay' => $loseTime . 'm' + ); + if($this->config->anti_fishing['timestamp_enable']) { + $anti_phishing_key = $this->getTimestamp(); + if(!empty($anti_phishing_key)) { + $parameter['anti_phishing_key'] = $anti_phishing_key; + } + } + if($this->config->anti_fishing['ip_enable']) { + $parameter['exter_invoke_ip'] = $params->spbill_create_ip; + } + + // 除去数组中的空值和签名参数 + $para_filter = array(); + foreach ($parameter AS $k => $v) { + if($k == "sign" || $k == "sign_type" || $v == "") { + continue; + } else { + $para_filter[$k] = $parameter[$k]; + } + } + + ksort($para_filter); + reset($para_filter); + + $param = ''; + $sign = ''; + foreach ($para_filter AS $key => $val) { + $param .= "$key=" .urlencode($val). "&"; + $sign .= "$key=$val&"; + } + $param = substr($param, 0, -1); + $sign = substr($sign, 0, -1); + //如果存在转义字符,那么去掉转义 + if(get_magic_quotes_gpc()){$sign = stripslashes($sign);} + $sign .= $this->config->alipay_key; + + $result = array( + 'pay_url' => $this->config->pay_url, + 'pars' => $param . "&sign=" . md5($sign). "&sign_type=" . $this->config-> sign_type, + 'reqType' => 'get' + ); + + return $result; + } + + public function parseResponse(array $arrResponse) + { + /* 返回示例 + * http://www.yohobuy.com/pay/notice/alipayreturn?buyer_email=tds%40smartunite.com&buyer_id=2088302294447308&exterface=create_direct_pay_by_user&is_success=T¬ify_id=RqPnCoPT3K9%252Fvwbh3I7xtEV5W65QRToFQ5fPrXsVxt12e%252FExCtC1XNiKnuRwupLaVLAR¬ify_time=2011-06-11+07%3A48%3A10¬ify_type=trade_status_sync&out_trade_no=1061003000&payment_type=1&seller_email=shop%40yoho.cn&seller_id=2088001550230585&subject=YOHO%E5%95%86%E5%93%81&total_fee=0.01&trade_no=2011061199833830&trade_status=TRADE_SUCCESS&sign=ca1c49f58d17eaa57aac308d0ac64434&sign_type=MD5 + */ + if(isset($arrResponse['q'])){ + unset($arrResponse['q']); + } + $rsp = new Rspparams(); + if(!$this->checkResponse($arrResponse)) + { + //验证不成功 + $rsp->payResult = -1; + } + else + { + $rsp->bankName = ""; + $outTradeNo = $arrResponse["out_trade_no"]; +// if(strlen($outTradeNo) > 9) { +// $outTradeNo = substr($outTradeNo, 2); +// } + //支付订单处理 + $orderCodeArr = explode('_',$outTradeNo); + if(count($orderCodeArr) == 2){ + $rsp->orderCode = $orderCodeArr[0]; + $rsp->bankName = $orderCodeArr[1]; + }else{ + $rsp->orderCode = $outTradeNo; + $rsp->bankName = ""; + } + $rsp->payResult = $this->convertResult($arrResponse["trade_status"]); + $rsp->payTime = isset($arrResponse["gmt_payment"]) ? $arrResponse["gmt_payment"] : time(); + $rsp->totalFee = $arrResponse["total_fee"]; + $rsp->resultMsg = $arrResponse["notify_type"]; + //添加支付订单号和交易号和银行的流水号 + $rsp->payOrderCode = $outTradeNo; + $rsp->tradeNo = $arrResponse['trade_no']; + $rsp->bankBillNo = $arrResponse['bank_seq_no'] ? $arrResponse['bank_seq_no'] : ""; + } + return $rsp; + } + + protected function convertResult($resultCode) + { + if($resultCode == "TRADE_SUCCESS") + { + return 200; + } + return 400; + } + + /** + * 除去数组中的空值和签名参数 + * @param $para 签名参数组 + * return 去掉空值与签名参数后的新签名参数组 + */ + private function paraFilter($para) { + $para_filter = array(); + foreach ($para as $key=>$val) { + if($key == "sign" || $key == "sign_type" || $val == "")continue; + else $para_filter[$key] = $para[$key]; + } + return $para_filter; + } + + /** + * 对数组排序 + * @param $para 排序前的数组 + * return 排序后的数组 + */ + private function argSort($para) { + ksort($para); + reset($para); + return $para; + } + + /** + * 验证回复的正确性 + * @see QPay_Utils_Abstract::verifResponse() + */ + protected function checkResponse(array $arrResponse) + { + ksort($arrResponse); + reset($arrResponse); + $sign = ''; + foreach ($arrResponse AS $key=>$val) + { + if ($key != 'sign' && $key != 'sign_type' && $key != 'code') + { + $sign .= "$key=$val&"; + } + } + $sign = substr($sign, 0, -1) . $this->config->alipay_key; + + return md5($sign) != $arrResponse['sign'] ? false : true; + + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Alibarcode/Config.php b/library/WebPlugin/Pay/Alibarcode/Config.php new file mode 100644 index 0000000..c71e369 --- /dev/null +++ b/library/WebPlugin/Pay/Alibarcode/Config.php @@ -0,0 +1,96 @@ +<?php + +namespace WebPlugin\Pay\Alibarcode; + +class Config +{ + //老网关,2013年3月20日下线 +// var $pay_url = "https://www.alipay.com/cooperate/gateway.do"; + + //新网关 + var $pay_url = "https://mapi.alipay.com/gateway.do"; + + /** + * 测试网关 + * @var unknown_type + */ +// var $pay_url = 'http://mapi.d4192.alipay.net/cooperate/gateway.do'; + + /** + * 服务名,即时到帐为create_direct_pay_by_user + * Enter description here ... + * @var String + */ + var $service = "create_direct_pay_by_user"; + + /** + * 合作伙伴在支付宝的用户ID + * Enter description here ... + * @var string + */ + var $partner = ""; + + /** + * 编码 + * Enter description here ... + * @var String + */ + var $input_charset = "utf-8"; + + /** + * 通知url,(用于后台提交) + * Enter description here ... + * @var String + */ + var $notify_url = "notice/alibarcodenotice"; + + /** + * 浏览器的返回 + * Enter description here ... + * @var string + */ + var $return_url = "notice/alibarcodereturn"; + + /** + * 签名方式 + * Enter description here ... + * @var String + */ + var $sign_type = "MD5"; + + /** + * 支付类型,1为购买 + * Enter description here ... + * @var Integer + */ + var $payment_type = "1"; + + /** + * Key + * Enter description here ... + * @var String + */ + var $alipay_key = ""; + + /** + * 销售者mail + * Enter description here ... + * @var String + */ + var $sellerMail = ""; + + /** + * + * @var unknown_type + */ + var $qr_pay_mode = 2; + + /** + * 防钓鱼配置 + */ + var $anti_fishing = array( + 'ip_enable' => false, + 'timestamp_enable' =>false + ); + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Alibarcode/Service.php b/library/WebPlugin/Pay/Alibarcode/Service.php new file mode 100644 index 0000000..32500b6 --- /dev/null +++ b/library/WebPlugin/Pay/Alibarcode/Service.php @@ -0,0 +1,185 @@ +<?php + +namespace WebPlugin\Pay\Alibarcode; + +use DOMDocument; +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; + +class Service extends PayAbstract +{ + + var $config ; + + public function __construct(array $paymentParams) + { + $this->logProjectPrefix = 'alipay'; + $this->config = new Config(); + $myConfig = json_decode($paymentParams["pay_params"]); + $this->config->partner = $myConfig->merchant_id; + $this->config->alipay_key = $myConfig->merchant_key; + $this->config->sellerMail = $myConfig->merchant_other_code; + } + + /** + * 获取时间戳 + */ + private function getTimestamp() { + $url = "https://mapi.alipay.com/gateway.do?service=query_timestamp&partner=" . trim(strtolower($this->config->partner)) . "&_input_charset=" . trim(strtolower($this->config->input_charset)); + + $doc = new DOMDocument(); + $doc->load($url); + $itemEncrypt_key = $doc->getElementsByTagName("encrypt_key"); + $encrypt_key = $itemEncrypt_key->item(0)->nodeValue; + + return $encrypt_key; + + } + + public function getPayRequestPars(Reqparams $params) + { + $baseUrl = $this->getBaseNoticeUrl($params->isTest); + $loseTime = intval(($params->orderTime + 7200 -time())/60); + // $loseTime = intval((strtotime(date("Y-m-d 10:00:00", strtotime("+1 day")))-time())/60); //第二天十点 + $parameter = array( + 'service' => $this->config->service, + 'partner' => $this->config->partner, + '_input_charset' => $this->config->input_charset, + 'notify_url' => $baseUrl . $this->config->notify_url, + 'return_url' => $baseUrl . $this->config->return_url, + /* 业务参数 */ + 'subject' => $params->goodsName, + 'out_trade_no' => $params->orderCode, +// 'it_b_pay' => $loseTime . 'm', + 'total_fee' => $params->totalFee / 100, //单位为元 + 'payment_type' => $this->config->payment_type, + 'seller_email' => $this->config->sellerMail, + 'sign_id_ext' =>$params->uid, + 'sign_name_ext' => $params->userName, + 'qr_pay_mode' => $this->config->qr_pay_mode + ); + if($this->config->anti_fishing['timestamp_enable']) { + $anti_phishing_key = $this->getTimestamp(); + if(!empty($anti_phishing_key)) { + $parameter['anti_phishing_key'] = $anti_phishing_key; + } + } + if($this->config->anti_fishing['ip_enable']) { + $parameter['exter_invoke_ip'] = $params->spbill_create_ip; + } + + if(!empty($params->paymentParameter)){ + //使用快捷支付,但是支付宝扫码支付不用传token + // $parameter['token'] = $params->paymentParameter; + } + ksort($parameter); + reset($parameter); + + $param = ''; + $sign = ''; + foreach ($parameter AS $key => $val) + { + $param .= "$key=" .urlencode($val). "&"; + $sign .= "$key=$val&"; + } + $param = substr($param, 0, -1); + $sign = substr($sign, 0, -1). $this->config->alipay_key; + + $result = array( + 'pay_url' => $this->config->pay_url, + 'pars' => $param . "&sign=" . md5($sign). "&sign_type=" . $this->config-> sign_type, + 'reqType' => 'get' + ); + return $result; + } + + public function parseResponse(array $arrResponse) + { + /* 返回示例 + * http://www.yohobuy.com/pay/notice/alibarcodereturn?buyer_email=tds%40smartunite.com&buyer_id=2088302294447308&exterface=create_direct_pay_by_user&is_success=T¬ify_id=RqPnCoPT3K9%252Fvwbh3I7xtEV5W65QRToFQ5fPrXsVxt12e%252FExCtC1XNiKnuRwupLaVLAR¬ify_time=2011-06-11+07%3A48%3A10¬ify_type=trade_status_sync&out_trade_no=1061003000&payment_type=1&seller_email=shop%40yoho.cn&seller_id=2088001550230585&subject=YOHO%E5%95%86%E5%93%81&total_fee=0.01&trade_no=2011061199833830&trade_status=TRADE_SUCCESS&sign=ca1c49f58d17eaa57aac308d0ac64434&sign_type=MD5 + */ + if(isset($arrResponse['q'])){ + unset($arrResponse['q']); + } + $rsp = new Rspparams(); + if(!$this->checkResponse($arrResponse)) + { + //验证不成功 + $rsp->payResult = -1; + } + else + { + $rsp->bankName = ""; + $outTradeNo = $arrResponse["out_trade_no"]; + $rsp->orderCode = $outTradeNo; + $rsp->payResult = $this->convertResult($arrResponse["trade_status"]); + $rsp->payTime = $arrResponse["gmt_payment"]; + $rsp->totalFee = $arrResponse["total_fee"]; + $rsp->resultMsg = $arrResponse["notify_type"]; + //添加支付订单号和交易号 + $rsp->payOrderCode = $outTradeNo; + $rsp->tradeNo = $arrResponse['trade_no']; + $rsp->bankBillNo = ""; + } + return $rsp; + } + + protected function convertResult($resultCode) + { + if($resultCode == "TRADE_SUCCESS") + { + return 200; + } + return 400; + } + + /** + * 除去数组中的空值和签名参数 + * @param $para 签名参数组 + * @return array 去掉空值与签名参数后的新签名参数组 + */ + private function paraFilter($para) { + $para_filter = array(); + foreach ($para as $key=>$val) { + if($key == "sign" || $key == "sign_type" || $val == "")continue; + else $para_filter[$key] = $para[$key]; + } + return $para_filter; + } + + /** + * 对数组排序 + * @param $para 排序前的数组 + * @return 排序前的数组 + */ + private function argSort($para) { + ksort($para); + reset($para); + return $para; + } + + /** + * 验证回复的正确性 + * @see QPay_Utils_Abstract::verifResponse() + * @param array $arrResponse + * @return bool|void + */ + protected function checkResponse(array $arrResponse) + { + ksort($arrResponse); + reset($arrResponse); + $sign = ''; + foreach ($arrResponse AS $key=>$val) + { + if ($key != 'sign' && $key != 'sign_type' && $key != 'code') + { + $sign .= "$key=$val&"; + } + } + $sign = substr($sign, 0, -1) . $this->config->alipay_key; + + return md5($sign) != $arrResponse['sign'] ? false : true; + + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Alipay/Config.php b/library/WebPlugin/Pay/Alipay/Config.php new file mode 100644 index 0000000..2c3330f --- /dev/null +++ b/library/WebPlugin/Pay/Alipay/Config.php @@ -0,0 +1,84 @@ +<?php + +namespace WebPlugin\Pay\Alipay; + +class Config +{ + //老网关,2013年3月20日下线 +// var $pay_url = "https://www.alipay.com/cooperate/gateway.do"; + + //新网关 + var $pay_url = "https://mapi.alipay.com/gateway.do"; + + /** + * 服务名,即时到帐为create_direct_pay_by_user + * Enter description here ... + * @var String + */ + var $service = "create_direct_pay_by_user"; + + /** + * 合作伙伴在支付宝的用户ID + * Enter description here ... + * @var string + */ + var $partner = ""; + + /** + * 编码 + * Enter description here ... + * @var String + */ + var $input_charset = "utf-8"; + + /** + * 通知url,(用于后台提交) + * Enter description here ... + * @var String + */ + var $notify_url = "notice/alipaynotice"; + + /** + * 浏览器的返回 + * Enter description here ... + * @var string + */ + var $return_url = "notice/alipayreturn"; + + /** + * 签名方式 + * Enter description here ... + * @var String + */ + var $sign_type = "MD5"; + + /** + * 支付类型,1为购买 + * Enter description here ... + * @var Integer + */ + var $payment_type = "1"; + + /** + * Key + * Enter description here ... + * @var String + */ + var $alipay_key = ""; + + /** + * 销售者mail + * Enter description here ... + * @var String + */ + var $sellerMail = ""; + + /** + * 防钓鱼配置 + */ + var $anti_fishing = array( + 'ip_enable' => false, + 'timestamp_enable' =>false + ); + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Alipay/Service.php b/library/WebPlugin/Pay/Alipay/Service.php new file mode 100644 index 0000000..b3be6be --- /dev/null +++ b/library/WebPlugin/Pay/Alipay/Service.php @@ -0,0 +1,184 @@ +<?php + +namespace WebPlugin\Pay\Alipay; + +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; + +class Service extends PayAbstract +{ + + var $config ; + + public function __construct(array $paymentParams) + { + $this->logProjectPrefix = 'alipay'; + $this->config = new Config(); + $myConfig = json_decode($paymentParams["pay_params"]) ; + $this->config->partner = $myConfig->merchant_id; + $this->config->alipay_key = $myConfig->merchant_key; + $this->config->sellerMail = $myConfig->merchant_other_code; + } + + /** + * 获取时间戳 + */ + private function getTimestamp() { + $url = "https://mapi.alipay.com/gateway.do?service=query_timestamp&partner=" . trim(strtolower($this->config->partner)) . "&_input_charset=" . trim(strtolower($this->config->input_charset)); + + $doc = new DOMDocument(); + $doc->load($url); + $itemEncrypt_key = $doc->getElementsByTagName("encrypt_key"); + $encrypt_key = $itemEncrypt_key->item(0)->nodeValue; + + return $encrypt_key; + } + + /** + * @param Reqparams $params + * @return array + */ + public function getPayRequestPars(Reqparams $params) + { + $baseUrl = $this->getBaseNoticeUrl($params->isTest); +// $loseTime = intval(($params->orderTime + 7200 -time())/60); +// $loseTime = intval((strtotime(date("Y-m-d 10:00:00", strtotime("+1 day")))-time())/60); //第二天十点 + $parameter = array( + 'service' => $this->config->service, + 'partner' => $this->config->partner, + '_input_charset' => $this->config->input_charset, + 'notify_url' => $baseUrl . $this->config->notify_url, + 'return_url' => $baseUrl . $this->config->return_url, + /* 业务参数 */ + 'subject' => $params->goodsName, + 'out_trade_no' => $params->orderCode, +// 'it_b_pay' => $loseTime . 'm', + 'total_fee' => $params->totalFee / 100, //单位为元 + 'payment_type' => $this->config->payment_type, + 'seller_email' => $this->config->sellerMail, + 'sign_id_ext' =>$params->uid, + 'sign_name_ext' => $params->userName + ); + if($this->config->anti_fishing['timestamp_enable']) { + $anti_phishing_key = $this->getTimestamp(); + if(!empty($anti_phishing_key)) { + $parameter['anti_phishing_key'] = $anti_phishing_key; + } + } + if($this->config->anti_fishing['ip_enable']) { + $parameter['exter_invoke_ip'] = $params->spbill_create_ip; + } + + if(!empty($params->paymentParameter)){ + //使用快捷支付 + $parameter['token'] = $params->paymentParameter; + } + ksort($parameter); + reset($parameter); + + $param = ''; + $sign = ''; + foreach ($parameter AS $key => $val) + { + $param .= "$key=" .urlencode($val). "&"; + $sign .= "$key=$val&"; + } + $param = substr($param, 0, -1); + $sign = substr($sign, 0, -1). $this->config->alipay_key; + + $result = array( + 'pay_url' => $this->config->pay_url, + 'pars' => $param . "&sign=" . md5($sign). "&sign_type=" . $this->config-> sign_type, + 'reqType' => 'get' + ); + return $result; + } + + public function parseResponse(array $arrResponse) + { + /* 返回示例 + * http://www.yohobuy.com/pay/notice/alipayreturn?buyer_email=tds%40smartunite.com&buyer_id=2088302294447308&exterface=create_direct_pay_by_user&is_success=T¬ify_id=RqPnCoPT3K9%252Fvwbh3I7xtEV5W65QRToFQ5fPrXsVxt12e%252FExCtC1XNiKnuRwupLaVLAR¬ify_time=2011-06-11+07%3A48%3A10¬ify_type=trade_status_sync&out_trade_no=1061003000&payment_type=1&seller_email=shop%40yoho.cn&seller_id=2088001550230585&subject=YOHO%E5%95%86%E5%93%81&total_fee=0.01&trade_no=2011061199833830&trade_status=TRADE_SUCCESS&sign=ca1c49f58d17eaa57aac308d0ac64434&sign_type=MD5 + */ + if(isset($arrResponse['q'])){ + unset($arrResponse['q']); + } + $rsp = new Rspparams(); + if(!$this->checkResponse($arrResponse)) + { + //验证不成功 + $rsp->payResult = -1; + } + else + { + $rsp->bankName = ""; + $outTradeNo = $arrResponse["out_trade_no"]; + $rsp->orderCode = $outTradeNo; + $rsp->payResult = $this->convertResult($arrResponse["trade_status"]); + $rsp->payTime = isset($arrResponse["gmt_payment"]) ? $arrResponse["gmt_payment"] : ''; + $rsp->totalFee = $arrResponse["total_fee"]; + $rsp->resultMsg = $arrResponse["notify_type"]; + //添加支付订单号和交易号 + $rsp->payOrderCode = $outTradeNo; + $rsp->tradeNo = $arrResponse['trade_no']; + $rsp->bankBillNo = ""; + } + return $rsp; + } + + protected function convertResult($resultCode) + { + if($resultCode == "TRADE_SUCCESS") + { + return 200; + } + return 400; + } + + /** + * 除去数组中的空值和签名参数 + * @param $para 签名参数组 + * return 去掉空值与签名参数后的新签名参数组 + */ + private function paraFilter($para) { + $para_filter = array(); + foreach ($para as $key=>$val) { + if($key == "sign" || $key == "sign_type" || $val == "")continue; + else $para_filter[$key] = $para[$key]; + } + return $para_filter; + } + + /** + * 对数组排序 + * @param $para 排序前的数组 + * return 排序后的数组 + */ + private function argSort($para) { + ksort($para); + reset($para); + return $para; + } + + /** + * 验证回复的正确性 + * @see QPay_Utils_Abstract::verifResponse() + */ + protected function checkResponse(array $arrResponse) + { + ksort($arrResponse); + reset($arrResponse); + $sign = ''; + foreach ($arrResponse AS $key=>$val) + { + if ($key != 'sign' && $key != 'sign_type' && $key != 'code') + { + $sign .= "$key=$val&"; + } + } + $sign = substr($sign, 0, -1) . $this->config->alipay_key; + + return md5($sign) != $arrResponse['sign'] ? false : true; + + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Allinpay/Config.php b/library/WebPlugin/Pay/Allinpay/Config.php new file mode 100644 index 0000000..9e9c161 --- /dev/null +++ b/library/WebPlugin/Pay/Allinpay/Config.php @@ -0,0 +1,66 @@ +<?php + +namespace WebPlugin\Pay\Allinpay; + +/** + * 通联支付配置 + * @author Smile + * + */ +class Config +{ + var $pay_url = 'http://service.allinpay.com/gateway/index.do'; + + /** + * 编码 + * Enter description here ... + * @var String + */ + var $input_charset = 1; //1为utf-8, 2为gbk, 3为gb2312 + + /** + * 通知url,(用于后台提交) + * Enter description here ... + * @var String + */ + var $notify_url = "notice/allinpaynotice"; + + /** + * 浏览器的返回 + * Enter description here ... + * @var string + */ + var $return_url = "notice/allinpayreturn"; + + /** + * 签名方式, 0为md5, 1为证书 + * Enter description here ... + * @var String + */ + var $sign_type = "0"; + + /** + * 支付接口请求版本 + * @var string + */ + var $version = 'v1.0'; //必填 + + /** + * 商户号 + * @var string + */ + var $merchantId = ''; //商户号 + + /** + * 签名key + * @var unknown_type + */ + var $merchantKey = ''; + + /** + * 支付方式 + * @var unknown_type + */ + var $payType = 0; //非直连为0 + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Allinpay/Service.php b/library/WebPlugin/Pay/Allinpay/Service.php new file mode 100644 index 0000000..15c0027 --- /dev/null +++ b/library/WebPlugin/Pay/Allinpay/Service.php @@ -0,0 +1,112 @@ +<?php + +namespace WebPlugin\Pay\Allinpay; + +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; + +class Service extends PayAbstract +{ + var $config; + + public function __construct(array $paymentParams) + { + $this->logProjectPrefix = 'allinpay'; + $this->config = new Config(); + $myConfig = json_decode($paymentParams["pay_params"]); + $this->config->merchantId = $myConfig->merchant_id; + $this->config->merchantKey = $myConfig->merchant_key; + } + + /** + * @param Reqparams $params + * @return array + */ + public function getPayRequestPars(Reqparams $params) + { + $baseUrl = $this->getBaseNoticeUrl($params->isTest); + $loseTime = intval(($params->orderTime + 7200 - time()) / 60); + + $reqData = array( + 'inputCharset' => $this->config->input_charset, + 'pickupUrl' => $baseUrl . $this->config->return_url, + 'receiveUrl' => $baseUrl . $this->config->notify_url, + 'version' => $this->config->version, + 'language' => 1, + 'signType' => $this->config->sign_type, + 'merchantId' => $this->config->merchantId, + 'orderNo' => $params->orderCode, + 'orderAmount' => $params->totalFee, + 'orderCurrency' => 0, //币种,0为人民币 + 'orderDatetime' => date('YmdHis', $params->orderTime), + 'orderExpireDatetime' => $loseTime, + 'payType' => $this->config->payType + ); + + $paramsArr = array(); + foreach ($reqData as $k => $v) { + $paramsArr[] = $k . '=' . $v; + } + $reqData['signMsg'] = strtoupper(md5(implode('&', $paramsArr) . '&key=' . $this->config->merchantKey)); + return array( + 'pay_url' => $this->config->pay_url, + 'pars' => $reqData, + 'reqType' => 'post' + ); + } + + /** + * 回复解析(non-PHPdoc) + * @param array $arrResponse + * @return void|Rspparams + */ + public function parseResponse(array $arrResponse) + { + $rsp = new Rspparams(); + if (!$this->checkResponse($arrResponse)) { + $rsp->payResult = -1; + } else { + $rsp->bankName = ""; + $rsp->orderCode = $arrResponse["orderNo"]; + $rsp->payResult = $this->convertResult($arrResponse["payResult"]); + $rsp->payTime = $arrResponse["payDatetime"]; + $rsp->totalFee = $arrResponse["payAmount"] / 100; + $rsp->resultMsg = $arrResponse["payResult"]; + //添加支付订单号和交易号 + $rsp->payOrderCode = $arrResponse["orderNo"]; + $rsp->tradeNo = ""; + $rsp->bankBillNo = ""; + } + + return $rsp; + } + + protected function convertResult($resultCode) + { + if ($resultCode == 1) { + return 200; + } + return 400; + } + + + /** + * 验证回复的正确性 + * @see QPay_Utils_Abstract::verifResponse() + * @param array $arrResponse + * @return bool|void + */ + protected function checkResponse(array $arrResponse) + { + $strParams = 'merchantId=' . $arrResponse['merchantId']; + $paramKey = array('version', 'language', 'signType', 'payType', 'issuerId', 'paymentOrderId', 'orderNo', 'orderDatetime', 'orderAmount', 'payDatetime', 'payAmount', 'ext1', 'ext2', 'payResult', 'errorCode', 'returnDatetime'); + foreach ($paramKey as $k) { + if (isset($arrResponse[$k]) && $arrResponse[$k] != "") { + $strParams .= '&' . $k . '=' . $arrResponse[$k]; + } + } + $signMsg = strtoupper(md5($strParams . '&key=' . $this->config->merchantKey)); + return $signMsg == $arrResponse['signMsg'] ? true : false; + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Banks.php b/library/WebPlugin/Pay/Banks.php new file mode 100644 index 0000000..6f9e91d --- /dev/null +++ b/library/WebPlugin/Pay/Banks.php @@ -0,0 +1,122 @@ +<?php + +namespace WebPlugin\Pay; + +class Banks +{ + private static $list = array( + 'BOCB2C' => array( + 'name' => '中国银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/zhongguo.png' + ), + 'ABC' => array( + 'name' => '中国农业银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/nongye.png' + ), + 'SPABANK' => array( + 'name' => '平安银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/pingan.png' + ), + 'CMBC' => array( + 'name' => '中国民生银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/minsheng.png' + ), + "ICBCB2C" => array( + 'name' => '中国工商银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/gongshang.png' + ), + 'SPDB' => array( + 'name' => '浦发银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/pufa.png' + ), + 'BJRCB' => array( + 'name' => '北京农商银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/beijingnongshang.png' + ), + 'HZCBB2C' => array( + 'name' => '杭州银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/hangzhou.png' + ), + 'CMB' => array( + 'name' => '招商银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/zhaoshang.png' + ), + 'CIB' => array( + 'name' => '兴业银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/xingye.png' + ), + 'FDB' => array( + 'name' => '富滇银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/fudian.png' + ), + 'CEB-DEBIT' => array( + 'name' => '中国光大银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/guangda.png' + ), + 'CCB' => array( + 'name' => '中国建设银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/zhongguojianshe.png' + ), + 'GDB' => array( + 'name' => '广发银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/guangfa.png' + ), + 'POSTGC' => array( + 'name' => '中国邮政储蓄', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/zhongguoyouzhengchuxu.png' + ), + 'SHBANK' => array( + 'name' => '上海银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/shanghai.png' + ), + 'NBBANK' => array( + 'name' => '宁波银行', + 'ico' => 'http://static.yohobuy.com/images/pay/icon/ningbo.png' + ) +// 'SDB' => array( +// 'name' => '深圳发展银行', +// 'ico' => 'http://static.yohobuy.com/images/bankico/SDB.gif' +// ), + /* 'COMM' => array( + 'name' => '交通银行', + 'ico' => 'http://static.yohobuy.com/images/bankico/COMM.gif' + ), */ +// 'CITIC' => array( +// 'name' => '中信银行', +// 'ico' => 'http://static.yohobuy.com/images/bankico/CITIC.gif' +// ), + + +// 'CEB' => array( +// 'name' => '光大银行', +// 'ico' => 'http://static.yohobuy.com/images/bankico/CEB.gif' +// ), + ); + + /** + * 获取银行列表 + * + * @return array + */ + public static function getList(){ + $ret = self::$list; + unset($ret['ICBC']); + unset($ret['BOC']); +// unset($ret['CEB']); + return $ret; + } + + /** + * @return array + */ + public static function getExpressgatewayList() { + $support = array('ICBC', 'ABC', 'CMB', 'CCB', 'BOC', 'CEB-DEBIT', 'SPABANK'); + $ret = array(); + foreach ($support as $k) { + if(isset(self::$list[$k])){ + $ret[$k] = self::$list[$k]; + } + } + return $ret; + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Ccb/Config.php b/library/WebPlugin/Pay/Ccb/Config.php new file mode 100644 index 0000000..6fd199e --- /dev/null +++ b/library/WebPlugin/Pay/Ccb/Config.php @@ -0,0 +1 @@ +<?php diff --git a/library/WebPlugin/Pay/Ccb/Service.php b/library/WebPlugin/Pay/Ccb/Service.php new file mode 100644 index 0000000..6fd199e --- /dev/null +++ b/library/WebPlugin/Pay/Ccb/Service.php @@ -0,0 +1 @@ +<?php diff --git a/library/WebPlugin/Pay/Chinabank/Config.php b/library/WebPlugin/Pay/Chinabank/Config.php new file mode 100644 index 0000000..ac8c3d2 --- /dev/null +++ b/library/WebPlugin/Pay/Chinabank/Config.php @@ -0,0 +1,62 @@ +<?php + +namespace WebPlugin\Pay\Chinabank; + +/** + * 网银支付接口 + * Enter description here ... + * @author smile + * + */ +class Config +{ + + /** + * 支付地址(方式3) + * Enter description here ... + * @var String + */ + var $payUrl = "https://pay3.chinabank.com.cn/PayGate"; + + /** + * 商户的回调地址 + * Enter description here ... + * @var String + */ + var $merchantUrl = "notice/chinabank"; + + /** + * 异步通知 + */ + var $autoReceiveUrl = "notice/chinabankautorev"; + /** + * 商户ID + * Enter description here ... + * @var unknown_type + */ + var $merchantAcctId = ""; + + /** + * 分行号 + * Enter description here ... + * @var String + */ + var $branchID = ""; + + /** + * 商户Key + * Enter description here ... + * @var string + */ + var $sp_key = ""; + + /** + * 币种 + * Enter description here ... + * @var unknown_type + */ + var $feeType = "CNY"; + + + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Chinabank/Service.php b/library/WebPlugin/Pay/Chinabank/Service.php new file mode 100644 index 0000000..2115b1d --- /dev/null +++ b/library/WebPlugin/Pay/Chinabank/Service.php @@ -0,0 +1,111 @@ +<?php + +namespace WebPlugin\Pay\Chinabank; + +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; + +class Service extends PayAbstract +{ + + var $config ; + + function __construct(array $paymentParams) + { + $this->logProjectPrefix = 'chinabank'; + $this->config = new Config(); + + $myConfig = json_decode($paymentParams["pay_params"]) ; + $this->config->merchantAcctId = $myConfig->merchant_id; + $this->config->sp_key = $myConfig->merchant_key; + // $this->config->branchID = $myConfig->merchant_other_code; + + } + + public function getPayRequestPars(Reqparams $params) { + + parent::getPayRequestPars($params); + $baseUrl = $this->getBaseNoticeUrl($params->isTest); + $reqData = array(); + $reqData['v_mid'] = $this->config->merchantAcctId; //商户ID + $reqData['v_oid'] = $params->orderCode; + $reqData['v_amount'] = $params->totalFee * 0.01; + $reqData['v_moneytype'] = $this->config->feeType; + $reqData['v_url'] = $baseUrl . $this->config->merchantUrl; + $reqData['v_md5info']= strtoupper(md5($reqData['v_amount'] . $reqData['v_moneytype'] . $reqData['v_oid']. $reqData['v_mid'] . $reqData['v_url']. $this->config->sp_key)); + $reqData['remark1'] = $params->orderCode; + $reqData['remark2'] = "[url:=".$baseUrl . $this->config->autoReceiveUrl."]"; + + $result = array( + 'pay_url' => $this->config->payUrl, + 'pars' => $reqData, + 'reqType' => 'post' + ); + return $result; + } + + /** + * 解析结果 + * (non-PHPdoc) + * @see QCPay_Utils_Abstract::parseResponse() + * @param array $arrResponse + * @return void|QCPay_Utils_Rspparams + */ + function parseResponse(Array $arrResponse){ + // {"v_md5all":"8F7E33B3759DC55F0E776120B5C16A55","v_md5info":"e42e938417bd01d8eb69235c1ebe9be3","remark1":"110610002420","v_pmode":null,"remark2":"","v_idx":"5607406315","v_md5":"2E9135262B2729B23B049EBBE80E5183","v_pstatus":"20","v_pstring":null,"v_md5str":"2E9135262B2729B23B049EBBE80E5183","v_md5money":"9330e642e14622f4993ce5a6e9781bbd","v_moneytype":"CNY","v_oid":"110610002420","v_amount":"0.01"} + //把中文进行转码 + $arrResponse["v_pmode"] = mb_convert_encoding($arrResponse["v_pmode"], "UTF-8", "GBK"); + $arrResponse["v_pstring"] = mb_convert_encoding($arrResponse["v_pstring"], "UTF-8", "GBK"); + //定义结果返回变量 + $rsp = new Rspparams(); + if(!$this->checkResponse($arrResponse)){ + //验证不成功 + $rsp->payResult = 400; + } + else{ + $rsp->bankName = $arrResponse["v_pmode"]; + $rsp->orderCode = $arrResponse["v_oid"]; + $rsp->payResult = $this->convertResult($arrResponse["v_pstatus"]); + $rsp->payTime = time(); + $rsp->totalFee = $arrResponse["v_amount"]; + $rsp->resultMsg = $arrResponse["v_pstring"]; + //添加支付订单号和交易号 + $rsp->payOrderCode = $arrResponse["v_oid"]; + $rsp->tradeNo = ""; + $rsp->bankBillNo = ""; + } + return $rsp; + } + + /** + * (non-PHPdoc) + * @see QPay_Utils_Abstract::convertResult() + * @param $resultCode + * @return int|void + */ + protected function convertResult($resultCode) + { + if($resultCode == 20) //20为支付成功,30为支付失败 + { + return 200; + } + return $resultCode; + } + + /** + * 验证回复的正确性 + * @see QPay_Utils_Abstract::verifResponse() + * @param array $arrResponse + * @return bool|void + */ + protected function checkResponse(array $arrResponse) + { + $signText = $arrResponse["v_oid"]. $arrResponse['v_pstatus'] . $arrResponse['v_amount'] + . $arrResponse['v_moneytype'] . $this->config->sp_key; + if(strtoupper(md5($signText)) == $arrResponse['v_md5str']){ + return true; + } + return false; + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Cmb/Config.php b/library/WebPlugin/Pay/Cmb/Config.php new file mode 100644 index 0000000..43ca20d --- /dev/null +++ b/library/WebPlugin/Pay/Cmb/Config.php @@ -0,0 +1,51 @@ +<?php + +namespace WebPlugin\Pay\Cmb; + +/** + * 招商银行支付接口配置,使用招商银行的支付方式2,可以返回结果,但无需带上参数 + * Enter description here ... + * @author smile + * + */ +class Config +{ + + /** + * 支付地址(方式3) + * Enter description here ... + * @var String + */ + var $payUrl = "https://netpay.cmbchina.com/netpayment/BaseHttp.dll?PrePayC1"; + + /** + * 商户的回调地址 + * Enter description here ... + * @var String + */ + var $merchantUrl = "http://yohoerp.yoho.cn:10000/pay/notice/cmb"; + + + /** + * 商户ID + * Enter description here ... + * @var unknown_type + */ + var $merchantAcctId = ""; + + /** + * 分行号 + * Enter description here ... + * @var String + */ + var $branchID = ""; + + /** + * 商户Key + * Enter description here ... + * @var unknown_type + */ + var $sp_key = ""; + + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Cmb/Service.php b/library/WebPlugin/Pay/Cmb/Service.php new file mode 100644 index 0000000..5351346 --- /dev/null +++ b/library/WebPlugin/Pay/Cmb/Service.php @@ -0,0 +1,28 @@ +<?php + +namespace WebPlugin\Pay\Cmb; + +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; + +class Service extends PayAbstract +{ + + var $config ; + + function __construct(array $paymentParams) + { + $this->config = new Config(); + + $myConfig = json_decode($paymentParams["pay_params"]) ; + $this->config->merchantAcctId = $myConfig->merchant_id; + $this->config->sp_key = $myConfig->merchant_key; + $this->config->branchID = $myConfig->merchant_other_code; + + } + + public function getPayRequestPars(Reqparams $params) + { + + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Ips/Config.php b/library/WebPlugin/Pay/Ips/Config.php new file mode 100644 index 0000000..5e1de06 --- /dev/null +++ b/library/WebPlugin/Pay/Ips/Config.php @@ -0,0 +1,71 @@ +<?php + +namespace WebPlugin\Pay\Ips; + +class Config +{ + /** + * 支付地址 + * Enter description here ... + * @var String + */ + var $payUrl = "https://pay.ips.com.cn/ipayment.aspx"; + + /** + * 测试支付的url + * Enter description here ... + * @var String + */ + var $payUrlTest = "http://pay.ips.net.cn/ipayment.aspx"; + + /** + * 商户编号 + * Enter description here ... + * @var unknown_type + */ + var $merCode = ""; + + /** + * 币种 + * Enter description here ... + * @var unknown_type + */ + var $currencyType = "RMB"; + + /** + * + * Enter description here ... + * @var unknown_type + */ + var $gatewayType = ""; + + /** + * 语言 + * Enter description here ... + * @var unknown_type + */ + var $lang = "GB"; + + /** + * 支付返回结果的地址 + * Enter description here ... + * @var String + */ + var $merchantUrl = "notice/ips"; + + /** + * 订单支付接口加密方式,0为无需加密,2为MD5加密 + * Enter description here ... + * @var Integer + */ + var $orderEncodeType = "2"; + + /** + * 交易返回接口的加密方式,12为md5 + * Enter description here ... + * @var unknown_type + */ + var $retEncodeType = "12"; + + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Ips/Service.php b/library/WebPlugin/Pay/Ips/Service.php new file mode 100644 index 0000000..fb11f78 --- /dev/null +++ b/library/WebPlugin/Pay/Ips/Service.php @@ -0,0 +1,41 @@ +<?php + +namespace WebPlugin\Pay\Ips; + +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; + +class Service extends PayAbstract +{ + var $config; + + function __construct(array $paymentParams) + { + $this->config = new Config(); + + $myConfig = json_decode($paymentParams["pay_params"]) ; + $this->config->merchantAcctId = $myConfig->merchant_id; + $this->config->sp_key = $myConfig->merchant_key; + } + + public function getPayRequestPars(Reqparams $params) + { + + } + + public function parseResponse(array $arrResponse) + { + + } + + /** + * 验证回复的正确性 + */ + protected function checkResponse(array $arrResponse) + { + + } + + + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Kqshenzhou/Config.php b/library/WebPlugin/Pay/Kqshenzhou/Config.php new file mode 100644 index 0000000..343da17 --- /dev/null +++ b/library/WebPlugin/Pay/Kqshenzhou/Config.php @@ -0,0 +1,93 @@ +<?php + +namespace WebPlugin\Pay\Kqshenzhou; + +class Config +{ + /** + * 支付请求的地址 + * Enter description here ... + * @var string + */ + var $pay_url = "https://www.99bill.com/szxgateway/recvMerchantInfoAction.htm"; + + /** + * 编码,1为utf8 + * Enter description here ... + * @var unknown_type + */ + var $inputCharset = 1; + + /** + * 回调地址 + * Enter description here ... + * @var unknown_type + */ + var $bgUrl = "http://yohoerp.yoho.cn:10000/pay/notice/kqshenzhou"; + + /** + * 接受支付结果的页面地址.与[bgUrl]不能同时为空。必须是绝对地址。 + * Enter description here ... + * @var String + */ + var $pageUrl=""; + + /** + * 版本 + * Enter description here ... + * @var unknown_type + */ + var $version = "v2.0"; + + /** + * 语言种类 1为中文 + * Enter description here ... + * @var unknown_type + */ + var $language = 1; + + /** + * 签名类型,1为md5 + * Enter description here ... + * @var unknown_type + */ + var $signType = 1; + + /** + * 商户ID + * Enter description here ... + * @var unknown_type + */ + var $merchantAcctId = ""; + + /** + * 商户Key + * Enter description here ... + * @var unknown_type + */ + var $sp_key = ""; + + /** + * 00 代表显示快钱各支付方式列表;10 代表只显示银 + * 行卡支付方式;11 代表只显示电话银行支付方式;12 + * 代表只显示快钱账户支付方式; 代表只显示线下支付 + * Enter description here ... + * @var unknown_type + */ + var $payType = "00"; + + /** + * 是否可以重复提交的标记 代表同一订单号只允许提交 1 次;0 表示同一订单 1号在没有支付成功的前提下可重复提交多次 + * Enter description here ... + * @var unknown_type + */ + var $redoFlag = 0; + + + /**全额支付标志 + *只能选择数字 0 或 1 + *0代表非全额支付方式,支付完成后返回订单金额为商户提交的订单金额。如果预付费卡面额小于订单金额时,返回支付结果为失败;预付费卡面额大于或等于订单金额时,返回支付结果为成功; + *1 代表全额支付方式,支付完成后返回订单金额为用户预付费卡的面额。只要预付费卡销卡成功,返回支上海快钱信息服务有限公司 版权所有 第 6 页付结果都为成功。 + */ + var $fullAmountFlag="0"; +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Kqshenzhou/Service.php b/library/WebPlugin/Pay/Kqshenzhou/Service.php new file mode 100644 index 0000000..6d4b342 --- /dev/null +++ b/library/WebPlugin/Pay/Kqshenzhou/Service.php @@ -0,0 +1,156 @@ +<?php + +namespace WebPlugin\Pay\Kqshenzhou; + +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; + +class Service extends PayAbstract +{ + var $config; + + function __construct(array $paymentParams) + { + $this->config = new Config(); + + $myConfig = json_decode($paymentParams["pay_params"]) ; + $this->config->merchantAcctId = $myConfig->merchant_id; + $this->config->sp_key = $myConfig->merchant_key; + } + + + public function getPayRequestPars(Reqparams $params) + { + $signMsgVal = ''; + + $signMsgVal=$this->appendParam($signMsgVal,"inputCharset",$this->config->inputCharset); + $signMsgVal=$this->appendParam($signMsgVal,"bgUrl", $this->baseNoticeUrl . $this->config->bgUrl); + $signMsgVal=$this->appendParam($signMsgVal,"pageUrl",$this->config->pageUrl); + $signMsgVal=$this->appendParam($signMsgVal,"version",$this->config->version); + $signMsgVal=$this->appendParam($signMsgVal,"language",$this->config->language); + $signMsgVal=$this->appendParam($signMsgVal,"signType",$this->config->signType); + + $signMsgVal=$this->appendParam($signMsgVal,"merchantAcctId",$this->config->merchantAcctId); + $signMsgVal=$this->appendParam($signMsgVal,"payerName",""); + $signMsgVal=$this->appendParam($signMsgVal,"payerContactType",""); + $signMsgVal=$this->appendParam($signMsgVal,"payerContact",""); + + $signMsgVal=$this->appendParam($signMsgVal,"orderId",$params->orderCode); + $signMsgVal=$this->appendParam($signMsgVal,"orderAmount",$params->totalFee); + $signMsgVal=$this->appendParam($signMsgVal,"payType",$this->config->payType); + $signMsgVal=$this->appendParam($signMsgVal,"fullAmountFlag",$this->config->fullAmountFlag); + $signMsgVal=$this->appendParam($signMsgVal,"orderTime", date("YmdHis")); + $signMsgVal=$this->appendParam($signMsgVal,"productName",urlencode($params->goodsName)); + $signMsgVal=$this->appendParam($signMsgVal,"productNum",""); + $signMsgVal=$this->appendParam($signMsgVal,"productId",""); + $signMsgVal=$this->appendParam($signMsgVal,"productDesc",urlencode("")); + $signMsgVal=$this->appendParam($signMsgVal,"ext1",""); + $signMsgVal=$this->appendParam($signMsgVal,"ext2",""); + $signMsgVal=$this->appendParam($signMsgVal,"key",$this->config->sp_key); + $signMsg= strtoupper(md5($signMsgVal)); + + $result = array( + 'pay_url' => $this->config->pay_url, + 'pars' => $signMsgVal . "&signMsg=" . $signMsg, + 'reqType' => 'get' + ); + + return $result; + } + + public function parseResponse(array $arrResponse) + { + $rsp = new Rspparams(); + if(!$this->checkResponse($arrResponse)) + { + //验证不成功 + $rsp->payResult = -1; + } + else + { + $rsp->bankName = $this->getPaytypeName($arrResponse["payType"]) ; + $rsp->bargainorId = $arrResponse["merchantAcctId"]; + $rsp->orderId = $arrResponse["orderId"]; + $rsp->payResult = $this->convertResult($arrResponse["payResult"]); + $rsp->payTime = $arrResponse["billOrderTime"]; + $rsp->totalFee = $arrResponse["payAmount"]; + } + return $rsp; + } + + /** + * 获取支付方式名称 + * @return string + */ + private function getPaytypeName() + { + $res = ""; + switch($res) + { + case "00": + return "神州行卡密支付和快钱账户支付"; + case "41": + return "快钱账户支付"; + case "42": + return "神州行卡密支付和快钱账户支付"; + case "52": + return "神州行卡密支付"; + } + } + + /** + * @param $resultCode + * @return int|void + */ + protected function convertResult($resultCode) + { + return $resultCode == "10" ? 0 : 1; + } + + /** + * 验证回复的正确性 + * @see QPay_Utils_Abstract::verifResponse() + */ + protected function checkResponse(array $arrResponse) + { + $merchantSignMsgVal = ''; + + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"merchantAcctId",$arrResponse["merchantAcctId"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"version", $arrResponse["version"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"language", $arrResponse["language"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"payType", $arrResponse["payType"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"cardNumber", $arrResponse["cardNumber"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"cardPwd", $arrResponse["cardPwd"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"orderId", $arrResponse["orderId"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"orderAmount", $arrResponse["orderAmount"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"dealId", $arrResponse["dealId"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"orderTime", $arrResponse["orderTime"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"ext1", $arrResponse["ext1"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"ext2", $arrResponse["ext2"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"payAmount", $arrResponse["payAmount"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"billOrderTime", $arrResponse["billOrderTime"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"payResult", $arrResponse["payResult"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"signType", $arrResponse["signType"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"key", $this->config->sp_key); + if( strtoupper(md5($merchantSignMsgVal)) == $arrResponse["signMsg"] ) + { + return true; + } + return false; + } + + private function appendParam($returnStr, $paramId, $paramValue) { + + if ($returnStr != "") { + if ($paramValue != "") { + $returnStr .= "&" . $paramId . "=" . $paramValue; + } + } else { + If ($paramValue != "") { + $returnStr = $paramId . "=" . $paramValue; + } + } + return $returnStr; + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Kuaiqian/Config.php b/library/WebPlugin/Pay/Kuaiqian/Config.php new file mode 100644 index 0000000..9a6ec0e --- /dev/null +++ b/library/WebPlugin/Pay/Kuaiqian/Config.php @@ -0,0 +1,79 @@ +<?php + +namespace WebPlugin\Pay\Kuaiqian; + +class Config +{ + /** + * 支付请求的地址 + * Enter description here ... + * @var string + */ + var $pay_url = "https://www.99bill.com/gateway/recvMerchantInfoAction.htm"; + + /** + * 编码,1为utf8 + * Enter description here ... + * @var unknown_type + */ + var $inputCharset = 1; + + /** + * 回调地址 + * Enter description here ... + * @var unknown_type + */ + var $bgUrl = "notice/kuaiqian"; + + /** + * 版本 + * Enter description here ... + * @var unknown_type + */ + var $version = "v2.0"; + + /** + * 语言种类 1为中文 + * Enter description here ... + * @var unknown_type + */ + var $language = 1; + + /** + * 签名类型,1为md5 + * Enter description here ... + * @var unknown_type + */ + var $signType = 1; + + /** + * 商户ID + * Enter description here ... + * @var unknown_type + */ + var $merchantAcctId = ""; + + /** + * 商户Key + * Enter description here ... + * @var unknown_type + */ + var $sp_key = ""; + + /** + * 00 代表显示快钱各支付方式列表;10 代表只显示银 + * 行卡支付方式;11 代表只显示电话银行支付方式;12 + * 代表只显示快钱账户支付方式; 代表只显示线下支付 + * Enter description here ... + * @var unknown_type + */ + var $payType = "00"; + + /** + * 是否可以重复提交的标记 代表同一订单号只允许提交 1 次;0 表示同一订单 1号在没有支付成功的前提下可重复提交多次 + * Enter description here ... + * @var unknown_type + */ + var $redoFlag = 0; + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Kuaiqian/Service.php b/library/WebPlugin/Pay/Kuaiqian/Service.php new file mode 100644 index 0000000..f2bbd12 --- /dev/null +++ b/library/WebPlugin/Pay/Kuaiqian/Service.php @@ -0,0 +1,149 @@ +<?php + +namespace WebPlugin\Pay\Kuaiqian; + +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; + +class Service extends PayAbstract +{ + + var $config ; + + function __construct(array $paymentParams) + { + $this->config = new Config(); + + $myConfig = json_decode($paymentParams["pay_params"]) ; + $this->config->merchantAcctId = $myConfig->merchant_id; + $this->config->sp_key = $myConfig->merchant_key; + } + + public function getPayRequestPars(Reqparams $params) + { + $signText = ''; + + //先添加不可为空的参数 + $signText .= "inputCharset=" . $this->config-> inputCharset; + $signText .= "&bgUrl=" . $this->baseNoticeUrl . $this->config->bgUrl; + $signText .= "&version=" . $this->config->version; + $signText .= "&language=" . $this->config->language; + $signText .= "&signType=" . $this->config->signType; + $signText .= "&merchantAcctId=" . $this->config-> merchantAcctId; + $signText .= "&orderId=" . $params->orderCode; + $signText .= "&orderAmount=" . $params->totalFee; + $signText .= "&orderTime=" . date("YmdHis"); + $signText .= "&payType=" . $this->config->payType; + $signMsg = strtoupper(md5($signText . "&key=" . $this->config->sp_key)); + + return array( + 'pay_url' => $this->config->pay_url, + 'pars' => $signText . "&signMsg=" . $signMsg, + 'reqType' => 'get' + ); + } + + /** + * (non-PHPdoc) + * @see QPay_Utils_Abstract::parseResponse() + * @param array $arrResponse + * @return void|QCPay_Utils_Rspparams + */ + public function parseResponse(array $arrResponse) + { + $rsp = new QCPay_Utils_Rspparams(); + if(!$this->checkResponse($arrResponse)) + { + //验证不成功 + $rsp->payResult = -1; + } + else + { + $rsp->bankName = $arrResponse["bankId"]; + $rsp->orderCode = $arrResponse["orderId"]; + $rsp->payResult = $this->convertResult($arrResponse["payResult"]); + $rsp->payTime = $this->convertTime($arrResponse["orderTime"]); + $rsp->totalFee = $arrResponse["orderAmount"]; + $rsp->resultMsg = ""; + //添加支付订单号和交易号 + $rsp->payOrderCode = $arrResponse["orderId"]; + $rsp->tradeNo = ""; + $rsp->bankBillNo = ""; + } + return $rsp; + } + + /** + * 转化时间 + * Enter description here ... + * @param string $payTime + * @return int + */ + private function convertTime($payTime) + { + $strTime = substr($payTime, 0, 4) . '-' . substr($payTime, 4, 2) . '-' . substr($payTime, 6, 2) . ' ' . + substr($payTime, 8, 2) . ':' . substr($payTime, 10, 2) . ':' . substr($payTime, 12, 2); + return strtotime($strTime); + } + + /** + * 转换结果 + * Enter description here ... + * @param string $resultCode + * @return int|void + */ + protected function convertResult($resultCode) + { + if($resultCode == '10') + { + return 200; + } + return 400; + } + + /** + * 验证回复的正确性 + * @see QPay_Utils_Abstract::verifResponse() + */ + protected function checkResponse(array $arrResponse) + { + $merchantSignMsgVal = ''; + + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"merchantAcctId",$arrResponse["merchantAcctId"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"version",$arrResponse["version"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"language",$arrResponse["language"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"signType",$arrResponse["signType"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"payType",$arrResponse["payType"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"bankId",$arrResponse["bankId"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"orderId",$arrResponse["orderId"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"orderTime",$arrResponse["orderTime"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"orderAmount",$arrResponse["orderAmount"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"dealId",$arrResponse["dealId"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"bankDealId",$arrResponse["bankDealId"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"dealTime",$arrResponse["dealTime"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"payAmount",$arrResponse["payAmount"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"fee",$arrResponse["fee"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"ext1",$arrResponse["ext1"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"ext2",$arrResponse["ext2"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"payResult",$arrResponse["payResult"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"errCode",$arrResponse["errCode"]); + $merchantSignMsgVal=$this->appendParam($merchantSignMsgVal,"key",$this->config->sp_key); + return strtoupper(md5($merchantSignMsgVal)) == $arrResponse["signMsg"] ? true :false; + } + + private function appendParam($returnStr, $paramId, $paramValue) { + + if ($returnStr != "") { + if ($paramValue != "") { + $returnStr .= "&" . $paramId . "=" . $paramValue; + } + } else { + If ($paramValue != "") { + $returnStr = $paramId . "=" . $paramValue; + } + } + return $returnStr; + } + + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/Service.php b/library/WebPlugin/Pay/Motopay/Service.php new file mode 100644 index 0000000..60b4067 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/Service.php @@ -0,0 +1,39 @@ +<?php + +require_once('lib/chinabank_utf8.MotoClient.php'); + +class QCPay_Utils_Motopay_Service +{ + + //var $motoClient; + + + function __construct() + { + //$myConfig = json_decode($paymentParams["pay_params"]) ; +// /$this->motoClient = new MotoClient (); + //$this->motoClient->setMerchantTerminalAndKey($myConfig->merchant_id, $myConfig->other_code, $myConfig->merchant_key); + } + + function consumeF() + {$motoClient = new MotoClient(); + // $motoClient->setMerchantTerminalAndKey('20003518', '8', 'test'); + $result = $motoClient->consume("", $_POST['cardid'], $_POST['month'].$_POST['year'], $_POST['money'], array('name'=>$_POST['name'], 'idcard'=>$_POST['idcard'], 'cvv2'=>$_POST['cvv'], 'mobile'=>'139', 'note'=>'nothing')); + echo "oid: {$result[$motoClient->MOTO_KEY_OID]},<br/> authcode: {$result[$motoClient->MOTO_KEY_AUTHID]},<br/>"; + echo "result: {$result[result]}<br/>"; + echo "bankname: {$result[$motoClient->MOTO_KEY_BANKNAME]},<br/>"; + echo "cardname: {$result[$motoClient->MOTO_KEY_CARDNAME]},<br/>"; + echo 'error msg: '.iconv('UTF-8', 'GBK', $result[$motoClient->MOTO_KEY_ERROR_CN]).',<br/>'; + echo "The end <br/>"; + + $str_utf = $result[$motoClient->MOTO_KEY_ERROR_CN]; + $str_gbk = iconv('UTF-8', 'GBK', $str_utf); + echo "utf8: '$str_utf'<br/>"; + echo "gbk: '$str_gbk'<br/>"; + echo '00: '.($str_utf == $str_utf).'<br/>'; + echo '01: '.($str_utf != $str_gbk).'<br/>'; + echo 'md5($str_utf): "'.md5($str_utf).'"<br/>'; + echo 'md5($str_gbk): "'.md5($str_gbk).'"<br/>'; + echo '02: '.( md5($str_utf) != md5($str_gbk) ).'<br/>'; + } + } \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/SofeeXmlParser.php b/library/WebPlugin/Pay/Motopay/lib/SofeeXmlParser.php new file mode 100644 index 0000000..6f67b7c --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/SofeeXmlParser.php @@ -0,0 +1,262 @@ +<?php +/* + +----------------------------------------------------------------------+ + | Sofee Framework For PHP4 | + +----------------------------------------------------------------------+ + | Copyright (c) 2004-2005 The Sofee Development Team | + +----------------------------------------------------------------------+ + | This source file is subject to the GNU Lesser Public License (LGPL), | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.fsf.org/copyleft/lesser.html | + | If you did not receive a copy of the LGPL and are unable to | + | obtain it through the world-wide-web, you can get it by writing the | + | Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | + | MA 02111-1307, USA. | + +----------------------------------------------------------------------+ + | Author: Justin Wu <ezdevelop@gmail.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: SofeeXmlParser.php,v 1.3 2005/05/30 06:30:14 wenlong Exp $ */ + +/** +* Sofee XML Parser class - This is an XML parser based on PHP's "xml" extension. +* +* The SofeeXmlParser class provides a very simple and easily usable toolset to convert XML +* to an array that can be processed with array iterators. +* +* @package SofeeFramework +* @access public +* @version $Revision: 1.1 $ +* @author Justin Wu <wenlong@php.net> +* @homepage http://www.sofee.cn +* @copyright Copyright (c) 2004-2005 Sofee Development Team.(http://www.sofee.cn) +* @since 2005-05-30 +* @see PEAR:XML_Parser | SimpleXML extension +*/ +class SofeeXmlParser { + + /** + * XML parser handle + * + * @var resource + * @see xml_parser_create() + */ + var $parser; + + /** + * source encoding + * + * @var string + */ + var $srcenc; + + /** + * target encoding + * + * @var string + */ + var $dstenc; + + /** + * the original struct + * + * @access private + * @var array1 + */ + var $_struct = array(); + + /** + * Constructor + * + * @access public + * @param mixed [$srcenc] source encoding + * @param mixed [$dstenc] target encoding + * @return void + * @since + */ + function SofeeXmlParser($srcenc = null, $dstenc = null) { + $this->srcenc = $srcenc; + $this->dstenc = $dstenc; + + // initialize the variable. + $this->parser = null; + $this->_struct = array(); + } + + /** + * Free the resources + * + * @access public + * @return void + **/ + function free() { + if (isset($this->parser) && is_resource($this->parser)) { + xml_parser_free($this->parser); + unset($this->parser); + } + } + + /** + * Parses the XML file + * + * @access public + * @param string [$file] the XML file name + * @return void + * @since + */ + function parseFile($file) { + $data = @file_get_contents($file) or die("Can't open file $file for reading!"); + $this->parseString($data); + } + + /** + * Parses a string. + * + * @access public + * @param string [$data] XML data + * @return void + */ + function parseString($data) { + if ($this->srcenc === null) { + $this->parser = @xml_parser_create() or die('Unable to create XML parser resource.'); + } else { + $this->parser = @xml_parser_create($this->srcenc) or die('Unable to create XML parser resource with '. $this->srcenc .' encoding.'); + } + + if ($this->dstenc !== null) { + @xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->dstenc) or die('Invalid target encoding'); + } + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); // lowercase tags + xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, 1); // skip empty tags + if (!xml_parse_into_struct($this->parser, $data, &$this->_struct)) { + printf("XML error: %s at line %d", + xml_error_string(xml_get_error_code($this->parser)), + xml_get_current_line_number($this->parser) + ); + $this->free(); + exit(); + } + + $this->_count = count($this->_struct); + $this->free(); + } + + /** + * return the data struction + * + * @access public + * @return array + */ + function getTree() { + $i = 0; + $tree = array(); + + $tree = $this->addNode( + $tree, + $this->_struct[$i]['tag'], + (isset($this->_struct[$i]['value'])) ? $this->_struct[$i]['value'] : '', + (isset($this->_struct[$i]['attributes'])) ? $this->_struct[$i]['attributes'] : '', + $this->getChild($i) + ); + + unset($this->_struct); + return ($tree); + } + + /** + * recursion the children node data + * + * @access public + * @param integer [$i] the last struct index + * @return array + */ + function getChild(&$i) { + // contain node data + $children = array(); + + // loop + while (++$i < $this->_count) { + // node tag name + $tagname = $this->_struct[$i]['tag']; + $value = isset($this->_struct[$i]['value']) ? $this->_struct[$i]['value'] : ''; + $attributes = isset($this->_struct[$i]['attributes']) ? $this->_struct[$i]['attributes'] : ''; + + switch ($this->_struct[$i]['type']) { + case 'open': + // node has more children + $child = $this->getChild($i); + // append the children data to the current node + $children = $this->addNode($children, $tagname, $value, $attributes, $child); + break; + case 'complete': + // at end of current branch + $children = $this->addNode($children, $tagname, $value, $attributes); + break; + case 'cdata': + // node has CDATA after one of it's children + $children['value'] .= $value; + break; + case 'close': + // end of node, return collected data + return $children; + break; + } + + } + //return $children; + } + + /** + * Appends some values to an array + * + * @access public + * @param array [$target] + * @param string [$key] + * @param string [$value] + * @param array [$attributes] + * @param array [$child] the children + * @return void + * @since + */ + function addNode($target, $key, $value = '', $attributes = '', $child = '') { + if (!isset($target[$key]['value']) && !isset($target[$key][0])) { + if ($child != '') { + $target[$key] = $child; + } + if ($attributes != '') { + foreach ($attributes as $k => $v) { + $target[$key][$k] = $v; + } + } + + $target[$key]['value'] = $value; + } else { + if (!isset($target[$key][0])) { + // is string or other + $oldvalue = $target[$key]; + $target[$key] = array(); + $target[$key][0] = $oldvalue; + $index = 1; + } else { + // is array + $index = count($target[$key]); + } + + if ($child != '') { + $target[$key][$index] = $child; + } + + if ($attributes != '') { + foreach ($attributes as $k => $v) { + $target[$key][$index][$k] = $v; + } + } + $target[$key][$index]['value'] = $value; + } + return $target; + } + +} +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.CreateXML.php b/library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.CreateXML.php new file mode 100644 index 0000000..3ed1313 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.CreateXML.php @@ -0,0 +1,160 @@ +<?php +class CreateXML { + /** + * 编码 + * @access private + * @var array1 + */ + //var $encoding; + /** + * @access private + * @var array1 + */ + var $_tree; + var $encoding="UTF-8"; + /** + * Constructor + */ + function CBCreateXML($encoding = 'UTF-8') { + $this->encoding = $encoding; + $this->_tree = array(); + + } + + /** + * 建立根节点 + */ + function createRoot($sname, $sversion) { + $tree = array(); + $tree['tag'] = 'cb-xdoc'; + $tree['attrs'] = array( + 'sname' => $sname, + 'sversion' => $sversion + ); + /* + $tree['att.sname'] = $sname; + $tree['att.sversion'] = $sversion; + */ + + $this->_tree = $tree; + } + + /** + * 建立普通节点 + */ + function addNode($name, $type, $val) { + $node = array(); + $node['tag'] = 'node'; + $node['attrs'] = array( + 'name' => $name, + 'type' => $type + ); + switch ($type) { + case 'list': + case 'map': + $node['node'] = array(); + foreach($val as $k=>$v) { + $node['node'][] = $this->_recursionGetNode($k, $v); + } + break; + default: + $node['val'] = $val; + } + + + /* + $node['att.name'] = $name; + $node['att.type'] = $type; + if ($type = 'money') { + $node['att.currency'] = 'CNY'; + } + $node['val'] = $val; + */ + + $this->_tree['node'][] = $node; + } + + function _recursionGetNode($name, $val) { + $node = array(); + $node['tag'] = 'node'; + $node['attrs'] = array('name' => $name); + + $type = gettype($val); + switch ($type) { + case "array": + $node['attrs']['type'] = 'map'; + foreach($val as $k=>$v) { + $node['node'][] = $this->_recursionGetNode($k, $v); + } + break; + case "integer": + $node['attrs']['type'] = 'int'; + $node['val'] = $val; + break; + default: + $node['attrs']['type'] = 'string'; + $node['val'] = $val; + } + return $node; + } + + function getTree() { + return $this->_tree; + } + + function getString() { + $tree = $this->_tree; + $strxml = "<?xml version=\"1.0\" encoding=\"{$this->encoding}\"?>\n"; + $strxml .= "<{$tree['tag']} sname=\"{$tree['attrs']['sname']}\" sversion=\"{$tree['attrs']['sversion']}\">\n"; + + foreach ($tree['node'] as $node) { + $strxml .= $this->_2str($node); + } + $strxml .= "</{$tree['tag']}>\n"; + + return $strxml; + } + + function _2str($node, $sp=" ") { + $tag = $node['tag']; + $name = $node['attrs']['name']; + $type = $node['attrs']['type']; + $val = $node['val']; + + // 开始 <node> + if ($type == 'money') { + $str = "$sp<$tag name=\"$name\" type=\"$type\" currency=\"{$node['att.currency']}\">\n"; + } else { + $str = "$sp<$tag name=\"$name\" type=\"$type\">\n"; + } + /** + if ($type == 'string') { + $str .= '<![CDATA[' . $val . ']]>'; + } else { + $str .= $val; + }*/ + // 值 + switch($type) { + case 'NULL': + return ''; + case 'string': + $str .= "$sp <![CDATA[$val]]>\n"; + break; + case 'list': + case 'map': + if (array_key_exists('node', $node)) { + foreach ($node['node'] as $n) { + $str .= $this->_2str($n, $sp." "); + } + } + break; + default: + $str .= "$sp $val\n"; + } + // 关闭 </node> + $str .= "$sp</$tag>\n"; + + return $str; + } +} +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.MotoClient.php b/library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.MotoClient.php new file mode 100644 index 0000000..738d78e --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.MotoClient.php @@ -0,0 +1,422 @@ +<?php +/** + * 网银在线 MOTO客户端接口 + * 版本: 2.5(php) + * 开发者:ch.tommy@gmail.com + */ +require_once('nusoap.php'); +require_once('chinabank_utf8.CreateXML.php'); +require_once('chinabank_utf8.XmlParser.php'); + +class MOTOConstant { +// 固定参数 + var $encoding ="UTF-8"; //编码格式 + var $soap_method= 'invoke02'; //方法名称 + var $version = '3.0(PHP)'; //版本 + var $type = 'md5'; //加密类型 + // 可配参数 + + + #var $soap_url = 'http://motopay5.chinabank.com.cn/webservice/motoPHP'; //正式通讯地址 + var $soap_url ="http://motopaytest.chinabank.com.cn/webservice/motoPHP"; //测试通讯地址 + var $merchantid = '901'; //商户号 + var $terminalid = '90101'; //终端号 + + + var $md5key = 'test'; //传输密钥 + + /** + * 以下是常量定义 + */ + // 错误代码 + var $MOTO_RET_SUCCESS = "0"; // 交易成功 + var $MOTO_RET_SUCCESS_ING = "1"; // 交易处理中 + var $MOTO_RET_FAILURE = "E12041000"; // 交易失败 + var $MOTO_RET_ERROR = "E12041001"; // 内部错误 + var $MOTO_RET_NET = "E12041002"; // 通讯错误 + var $MOTO_RET_DB = "E12041003"; // 数据库错误 + var $MOTO_RET_AUTH = "E12041004"; // 安全验证失败 + var $MOTO_RET_OID = "E12041005"; // 交易号格式错误 + var $MOTO_RET_CARD = "E12041006"; // 信用卡格式错误 + var $MOTO_RET_CARDEXP = "E12041007"; // 信用卡有效期格式错误 + var $MOTO_RET_AMOUNT = "E12041008"; // 交易金额格式错误 + var $MOTO_RET_NAME = "E12041009"; // 持卡人姓名格式错误 + var $MOTO_RET_IDCARD = "E12041010"; // 持卡人证件格式错误 + var $MOTO_RET_MOBILE = "E12041011"; // 持卡人电话格式错误 + var $MOTO_RET_NOTE = "E12041012"; // 备注格式错误 + var $MOTO_RET_MERCHANT = "E12041013"; // 商户号错误 + var $MOTO_RET_TERMINAL = "E12041014"; // 终端号错误 + var $MOTO_RET_MERCHANTEX = "E12041015"; // 商户信息不完整 + var $MOTO_RET_PURVIEW_XF = "E12041016"; // 终端没有消费权限 + var $MOTO_RET_PURVIEW_XFCX = "E12041017"; // 终端没有撤销消费权限 + var $MOTO_RET_PURVIEW_SQ = "E12041018"; // 终端没有预授权权限 + var $MOTO_RET_PURVIEW_SQCX = "E12041019"; // 终端没有撤销预授权权限 + var $MOTO_RET_PURVIEW_QR = "E12041020"; // 终端没有预授权确认权限 + var $MOTO_RET_PURVIEW_QRCX = "E12041021"; // 终端没有撤销预授权确认权限 + var $MOTO_RET_PURVIEW_TK = "E12041022"; // 终端没有退款权限 + var $MOTO_RET_SING_LIMIT = "E12041023"; // 超出单笔交易限额 + var $MOTO_RET_MOTO_CARD = "E12041024"; // MOTO不支持此信用卡 + var $MOTO_RET_MERCHANT_CARD = "E12041025"; // 商户不支持此信用卡 + var $MOTO_RET_DAY_NUM = "E12041026"; // 信用卡日交易次数限制 + var $MOTO_RET_DAY_DATE = "E12041027"; // 信用卡日交易有效期错误次数限制 + var $MOTO_RET_DAY_AMOUNT = "E12041028"; // 信用卡日交易金额上限错误次数限制 + var $MOTO_RET_DAY_LIMIT = "E12041029"; // 超出日交易限额 + var $MOTO_RET_ORDERID = "E12041030"; // 商户交易号重复 + var $MOTO_RET_OORDER = "E12041031"; // 原交易不存在 + var $MOTO_RET_OCARD = "E12041032"; // 信用卡原交易不符 + var $MOTO_RET_OAMOUNT = "E12041033"; // 金额原交易不符 + var $MOTO_RET_OSTATE = "E12041034"; // 原交易不允许此操作 + var $MOTO_RET_OOORDER = "E12041035"; // 原原交易不存在 + var $MOTO_RET_FLOAT = "E12041036"; // 超出预授权金额浮动范围 + var $MOTO_RET_REFUND = "E12041037"; // 退款金额不正确 + var $MOTO_RET_ORDER = "E12041038"; // 查询无此交易 + var $MOTO_RET_PURVIEW = "E12041039"; // 无此交易查询权限 + var $MOTO_RET_XML = "E12041040"; // 消费成功 / 状态失败 + var $MOTO_RET_TERMINAL_TYPE = "E12041041"; // 终端接入方式错误 + var $MOTO_RET_BANK = "E12041042"; // 此卡不允许做此交易 + var $MOTO_RET_MAIL = "E12041043"; // 持卡人邮件格式不正确 + var $MOTO_RET_VERSION = "E12041044"; // 客户端版本号不正确 + var $MOTO_RET_CVV2 = "E12041045"; // CVV2不允许为空 或者cvv2错 + var $MOTO_RET_WS_IP = "E12041046"; // IP校检失败 + var $MOTO_RET_BLACKCARD = "E12041047"; // 此卡为风险卡 + + var $MOTO_CLIENT_AUTH = "E12042004"; // php客户端安全验证错误 + + + // 关键字 + var $MOTO_KEY_ENCODE = "encode"; // 密文 + var $MOTO_KEY_SIGN = "sign"; // 签名 + var $MOTO_KEY_CLIENT = "client"; // 客户端 + var $MOTO_KEY_TYPE = "type"; // 交易类型 + var $MOTO_KEY_OID = "oid"; // 交易号 + var $MOTO_KEY_OOID = "ooid"; // 原交易号 + var $MOTO_KEY_CARD = "card"; // 信用卡号 + var $MOTO_KEY_CARDEXP = "cardexp"; // 信用卡有效期 + var $MOTO_KEY_AMOUNT = "amount"; // 金额 + var $MOTO_KEY_EXTEND = "extend"; // 附加参数 + var $MOTO_KEY_TIME = "time"; // 远程时间 + var $MOTO_KEY_MERCHANT = "merchant"; // 商户号 + var $MOTO_KEY_TERMINAL = "terminal"; // 终端号 + var $name = "authid"; // 银行授权号 + var $MOTO_KEY_BANKNAME = "bankname"; // 银行名称 + var $MOTO_KEY_CARDNAME = "cardname"; // 信用卡名称 + var $MOTO_KEY_ERROR = "error"; // 错误信息 + var $MOTO_KEY_ERROR_CN = "_error"; // 错误信息解释 + + // 附加参数关键字 + var $MOTO_KEY_EXTEND_NAME = "name"; // 持卡人姓名 + var $MOTO_KEY_EXTEND_IDCARD = "idcard"; // 持卡人证件号 + var $MOTO_KEY_EXTEND_MOBILE = "mobile"; // 持卡人手机号 + var $MOTO_KEY_EXTEND_MAIL = "mail"; // 持卡人E-Mail + var $MOTO_KEY_EXTEND_NOTE = "note"; // 备注 + var $MOTO_KEY_EXTEND_CVV2 = "cvv2"; // cvv2 + + // 查询结果 + var $MOTO_SEARCH_OID = "_oid"; // 交易号 + var $MOTO_SEARCH_AID = "_aid"; // 授权号 + var $MOTO_SEARCH_TYPE = "_type"; // 交易类型 + var $MOTO_SEARCH_TYPECODE = "_typecode"; // 交易类型码 + var $MOTO_SEARCH_CARD = "_card"; // 信用卡号 + var $MOTO_SEARCH_AMOUNT = "_amount"; // 交易金额 + var $MOTO_SEARCH_DATE = "_date"; // 交易日期 + var $MOTO_SEARCH_STATE = "_state"; // 交易状态 + var $MOTO_SEARCH_STATECODE = "_statecode"; // 交易状态码 + var $MOTO_SEARCH_CODE = "_code"; // 交易结果 + var $MOTO_SEARCH_BANKNAME = "_bankname"; // 银行名称 + var $MOTO_SEARCH_CARDNAME = "_cardname"; // 信用卡名称 + var $MOTO_SEARCH_SETTLE = "_settle"; // 结算标识 + var $MOTO_SEARCH_RECEIVE = "_receive"; // 是否受理卡 + var $MOTO_SEARCH_RECCARD = "_reccard"; // 商户受理卡 + var $MOTO_SEARCH_RECCARDCB = "_reccardcb"; // 网银受理卡 + + // 远程调用服务名称 + var $MOTO_REMOTE_CONSUME = "ConsumeService"; // 消费交易 + var $MOTO_REMOTE_CONSUME_REVOKE = "ConsumeRevokeService"; // 撤销消费 + var $MOTO_REMOTE_AUTHORIZE = "AuthorizeService"; // 预授权交易 + var $MOTO_REMOTE_AUTHORIZE_REVOKE = "AuthorizeRevokeService"; // 撤销预授权交易 + var $MOTO_REMOTE_CONFIRM = "ConfirmService"; // 确认交易 + var $MOTO_REMOTE_CONFIRM_REVOKE = "ConfirmRevokeService"; // 撤销确认交易 + var $MOTO_REMOTE_REFUND = "RefundService"; // 退款申请 + var $MOTO_REMOTE_SEARCH = "SearchService"; // 交易查询 + var $MOTO_REMOTE_REVERSE = "ReverseService"; // 冲正交易 + var $MOTO_REMOTE_SEARCHCARD = "SearchCardService"; // 查询受理卡 +} + +class MotoClient extends MOTOConstant { + + function CBInterface($encoding = 'UTF-8') { + $this->encoding=$encoding ; //初始化编码格式 + } + + /** + * 函数功能:设置商户号 终端号 和 传输密钥 + * 说 明:当商户使用多个MOTO商户号时可使用此函数设置每次交易的商户号和传输密钥 + */ + function setMerchantTerminalAndKey($merchantid, $terminalid, $md5key) { + $this->merchantid = $merchantid; + $this->terminalid = $terminalid; + $this->md5key = $md5key; + } + + /** + * 函数功能:原创调用适配 + */ + function remoteInvoke($service, $parameter) { + // 合成XML + $xdoc = new CreateXML($this->encoding); + $xdoc->createRoot($service, $this->version); + foreach($parameter as $key => $val) { + $xdoc->addNode($key, $val['type'], $val['value']); + } + // 加密 签名 + $xstr = $xdoc->getString(); + // echo "xstr: $xstr"; + $req_sign = strtoupper(md5($xstr.$this->md5key)); + $req_code = base64_encode ($xstr); + // 远程调用 + //生成SOAP调用是的参数 + $param = array( + 'service' => $service, //服务名 + 'merchant' => $this->merchantid, //服务名 + 'encoding' => $this->encoding, //编码类型 + 'type' => $this->type, //加密类型(采用什么方式进行加密的) + 'code' => $req_code, //经过BASE64编码的明文 + 'sign' => $req_sign //加密后的数据 + ); + // print_r($param); + //调用网银提供的soap方法 + echo "<b>url: $this->soap_url </b></br>"; + $soap_client = new soapclientw($this->soap_url, true); + $rs = $soap_client->call($this->soap_method, $param); + + //判断是否连接主机成功,若失败则报错 + if($soap_client->getError()){ + echo $soap_client->getError() . '<br/>'; + return array( + 'sname' => $service, + 'result' => $this->MOTO_RET_NET, + 'error' => $this->MOTO_RET_NET, + '_error' => $soap_client->getError()); + } + + //echo "-----------------------------<br/>\n"; + //print_a('rs', $rs); + + // 处理返回值 + $rtcode = $rs['string'][0]; + $rtmsg = base64_decode( $rs['string'][1] ); + + //echo "code: $rtmsg<br\>\n"; + if ( strtoupper(md5($rtmsg.$this->md5key)) == $rs['string'][2] ) { + echo "return sign OK! <br>\n"; + // 解码 +// $rtmsg = iconv('GBK', 'UTF-8', $rtmsg); +// $rtmsg = iconv('UTF-8', 'GBK', $rtmsg); + echo "<pre>\n $rtmsg \n<pre>"; + return xml2array( $rtmsg ); +// return xml2array($rtmsg); + } else { + echo "Chinabank Soap SIGN ERR! <br>\n"; + return array( + 'sname' => $service, + 'result' => $this->MOTO_CLIENT_AUTH, + 'error' => $this->MOTO_CLIENT_AUTH, + '_error' => 'SING ERR'); + } + } + + function consume2($orderid, $card, $cardexp, $amount, $extend) { + $service = 'ConsumeService'; + $today = getdate(); + $parameter = array(); + $parameter['oid'] = array('type' => 'string', 'value' => ($orderid==null ? '' : $orderid) ); + $parameter['card'] = array('type' => 'string', 'value' => $card); + $parameter['cardexp'] = array('type' => 'string', 'value' => $cardexp); + $parameter['amount'] = array('type' => 'int', 'value' => $amount); + $parameter['merchant'] = array('type' => 'string', 'value' => $this->merchantid); + $parameter['terminal'] = array('type' => 'string', 'value' => $this->terminalid); + $parameter['time'] = array('type' => 'date', 'value' => date('Y-m-d H:i:s', $today[0]) ); + $parameter['extend'] = array('type' => 'map', 'value' => ($extend==null ? array() : $extend) ); + + return $this->remoteInvoke($service, $parameter); + } + + + function consume($orderid, $card, $cardexp, $amount, $extend) { + $service = $this->MOTO_REMOTE_CONSUME; + $today = getdate(); + + $parameter = array(); + $parameter[$this->MOTO_KEY_OID] = array('type' => 'string', 'value' => ($orderid == null ? '' : $orderid) ); + $parameter[$this->MOTO_KEY_CARD] = array('type' => 'string', 'value' => $card); + $parameter[$this->MOTO_KEY_CARDEXP] = array('type' => 'string', 'value' => $cardexp); + $parameter[$this->MOTO_KEY_AMOUNT] = array('type' => 'int', 'value' => $amount); + $parameter[$this->MOTO_KEY_MERCHANT] = array('type' => 'string', 'value' => $this->merchantid); + $parameter[$this->MOTO_KEY_TERMINAL] = array('type' => 'string', 'value' => $this->terminalid); + $parameter[$this->MOTO_KEY_TIME] = array('type' => 'date', 'value' => date('Y-m-d H:i:s', $today[0]) ); + $parameter[$this->MOTO_KEY_EXTEND] = array('type' => 'map', 'value' => ($extend==null ? array() : $extend) ); + + return $this->remoteInvoke($service, $parameter); + } + + function consumeRevoke($orderid, $oldid, $card, $cardexp, $amount, $extend) { + $service = $this->MOTO_REMOTE_CONSUME_REVOKE; + $today = getdate(); + + $parameter = array(); + $parameter[$this->MOTO_KEY_OID] = array('type' => 'string', 'value' => ($orderid == null ? '' : $orderid) ); + $parameter[$this->MOTO_KEY_OOID] = array('type' => 'string', 'value' => ($oldid == null ? '' : $oldid) ); + $parameter[$this->MOTO_KEY_CARD] = array('type' => 'string', 'value' => $card); + $parameter[$this->MOTO_KEY_CARDEXP] = array('type' => 'string', 'value' => $cardexp); + $parameter[$this->MOTO_KEY_AMOUNT] = array('type' => 'int', 'value' => $amount); + $parameter[$this->MOTO_KEY_MERCHANT] = array('type' => 'string', 'value' => $this->merchantid); + $parameter[$this->MOTO_KEY_TERMINAL] = array('type' => 'string', 'value' => $this->terminalid); + $parameter[$this->MOTO_KEY_TIME] = array('type' => 'date', 'value' => date('Y-m-d H:i:s', $today[0]) ); + $parameter[$this->MOTO_KEY_EXTEND] = array('type' => 'map', 'value' => ($extend==null ? array() : $extend) ); + + return $this->remoteInvoke($service, $parameter); + } + + // 预授权 + function authorize($orderid, $card, $cardexp, $amount, $extend) { + $service = $this->MOTO_REMOTE_AUTHORIZE; + $today = getdate(); + + $parameter = array(); + $parameter[$this->MOTO_KEY_OID] = array('type' => 'string', 'value' => ($orderid == null ? '' : $orderid) ); + $parameter[$this->MOTO_KEY_CARD] = array('type' => 'string', 'value' => $card); + $parameter[$this->MOTO_KEY_CARDEXP] = array('type' => 'string', 'value' => $cardexp); + $parameter[$this->MOTO_KEY_AMOUNT] = array('type' => 'int', 'value' => $amount); + $parameter[$this->MOTO_KEY_MERCHANT] = array('type' => 'string', 'value' => $this->merchantid); + $parameter[$this->MOTO_KEY_TERMINAL] = array('type' => 'string', 'value' => $this->terminalid); + $parameter[$this->MOTO_KEY_TIME] = array('type' => 'date', 'value' => date('Y-m-d H:i:s', $today[0]) ); + $parameter[$this->MOTO_KEY_EXTEND] = array('type' => 'map', 'value' => ($extend==null ? array() : $extend) ); + + return $this->remoteInvoke($service, $parameter); + } + + function authorizeRevoke($orderid, $oldid, $card, $cardexp, $amount, $extend) { + $service = $this->MOTO_REMOTE_AUTHORIZE_REVOKE; + $today = getdate(); + + $parameter = array(); + $parameter[$this->MOTO_KEY_OID] = array('type' => 'string', 'value' => ($orderid == null ? '' : $orderid) ); + $parameter[$this->MOTO_KEY_OOID] = array('type' => 'string', 'value' => ($oldid == null ? '' : $oldid) ); + $parameter[$this->MOTO_KEY_CARD] = array('type' => 'string', 'value' => $card); + $parameter[$this->MOTO_KEY_CARDEXP] = array('type' => 'string', 'value' => $cardexp); + $parameter[$this->MOTO_KEY_AMOUNT] = array('type' => 'int', 'value' => $amount); + $parameter[$this->MOTO_KEY_MERCHANT] = array('type' => 'string', 'value' => $this->merchantid); + $parameter[$this->MOTO_KEY_TERMINAL] = array('type' => 'string', 'value' => $this->terminalid); + $parameter[$this->MOTO_KEY_TIME] = array('type' => 'date', 'value' => date('Y-m-d H:i:s', $today[0]) ); + $parameter[$this->MOTO_KEY_EXTEND] = array('type' => 'map', 'value' => ($extend==null ? array() : $extend) ); + + return $this->remoteInvoke($service, $parameter); + } + + function authorizeCfm($orderid, $oldid, $card, $cardexp, $amount, $extend) { + $service = $this->MOTO_REMOTE_CONFIRM; + $today = getdate(); + + $parameter = array(); + $parameter[$this->MOTO_KEY_OID] = array('type' => 'string', 'value' => ($orderid == null ? '' : $orderid) ); + $parameter[$this->MOTO_KEY_OOID] = array('type' => 'string', 'value' => ($oldid == null ? '' : $oldid) ); + $parameter[$this->MOTO_KEY_CARD] = array('type' => 'string', 'value' => $card); + $parameter[$this->MOTO_KEY_CARDEXP] = array('type' => 'string', 'value' => $cardexp); + $parameter[$this->MOTO_KEY_AMOUNT] = array('type' => 'int', 'value' => $amount); + $parameter[$this->MOTO_KEY_MERCHANT] = array('type' => 'string', 'value' => $this->merchantid); + $parameter[$this->MOTO_KEY_TERMINAL] = array('type' => 'string', 'value' => $this->terminalid); + $parameter[$this->MOTO_KEY_TIME] = array('type' => 'date', 'value' => date('Y-m-d H:i:s', $today[0]) ); + $parameter[$this->MOTO_KEY_EXTEND] = array('type' => 'map', 'value' => ($extend==null ? array() : $extend) ); + + return $this->remoteInvoke($service, $parameter); + } + + function authorizeCfmRevoke($orderid, $oldid, $card, $cardexp, $amount, $extend) { + $service = $this->MOTO_REMOTE_CONFIRM_REVOKE; + $today = getdate(); + + $parameter = array(); + $parameter[$this->MOTO_KEY_OID] = array('type' => 'string', 'value' => ($orderid == null ? '' : $orderid) ); + $parameter[$this->MOTO_KEY_OOID] = array('type' => 'string', 'value' => ($oldid == null ? '' : $oldid) ); + $parameter[$this->MOTO_KEY_CARD] = array('type' => 'string', 'value' => $card); + $parameter[$this->MOTO_KEY_CARDEXP] = array('type' => 'string', 'value' => $cardexp); + $parameter[$this->MOTO_KEY_AMOUNT] = array('type' => 'int', 'value' => $amount); + $parameter[$this->MOTO_KEY_MERCHANT] = array('type' => 'string', 'value' => $this->merchantid); + $parameter[$this->MOTO_KEY_TERMINAL] = array('type' => 'string', 'value' => $this->terminalid); + $parameter[$this->MOTO_KEY_TIME] = array('type' => 'date', 'value' => date('Y-m-d H:i:s', $today[0]) ); + $parameter[$this->MOTO_KEY_EXTEND] = array('type' => 'map', 'value' => ($extend==null ? array() : $extend) ); + + return $this->remoteInvoke($service, $parameter); + } + + function refundment($orderid, $oldid, $card, $cardexp, $amount, $extend) { + $service = $this->MOTO_REMOTE_REFUND; + $today = getdate(); + + $parameter = array(); + $parameter[$this->MOTO_KEY_OID] = array('type' => 'string', 'value' => ($orderid == null ? '' : $orderid) ); + $parameter[$this->MOTO_KEY_OOID] = array('type' => 'string', 'value' => ($oldid == null ? '' : $oldid) ); + $parameter[$this->MOTO_KEY_CARD] = array('type' => 'string', 'value' => $card); + $parameter[$this->MOTO_KEY_CARDEXP] = array('type' => 'string', 'value' => $cardexp); + $parameter[$this->MOTO_KEY_AMOUNT] = array('type' => 'int', 'value' => $amount); + $parameter[$this->MOTO_KEY_MERCHANT] = array('type' => 'string', 'value' => $this->merchantid); + $parameter[$this->MOTO_KEY_TERMINAL] = array('type' => 'string', 'value' => $this->terminalid); + $parameter[$this->MOTO_KEY_TIME] = array('type' => 'date', 'value' => date('Y-m-d H:i:s', $today[0]) ); + $parameter[$this->MOTO_KEY_EXTEND] = array('type' => 'map', 'value' => ($extend==null ? array() : $extend) ); + + return $this->remoteInvoke($service, $parameter); + } + + function search($orderid) { + $service = $this->MOTO_REMOTE_SEARCH; + $today = getdate(); + + $parameter = array(); + $parameter[$this->MOTO_KEY_OID] = array('type' => 'string', 'value' => $orderid); + $parameter[$this->MOTO_KEY_MERCHANT] = array('type' => 'string', 'value' => $this->merchantid); + $parameter[$this->MOTO_KEY_TERMINAL] = array('type' => 'string', 'value' => $this->terminalid); + $parameter[$this->MOTO_KEY_EXTEND] = array('type' => 'map', 'value' => ($extend==null ? array() : $extend) ); + + return $this->remoteInvoke($service, $parameter); + } + + function reverse($orderid) { + $service = $this->MOTO_REMOTE_REVERSE; + + $parameter = array(); + $parameter[$this->MOTO_KEY_OID] = array('type' => 'string', 'value' => $orderid); + $parameter[$this->MOTO_KEY_MERCHANT] = array('type' => 'string', 'value' => $this->merchantid); + $parameter[$this->MOTO_KEY_TERMINAL] = array('type' => 'string', 'value' => $this->terminalid); + $parameter[$this->MOTO_KEY_EXTEND] = array('type' => 'map', 'value' => ($extend==null ? array() : $extend) ); + + return $this->remoteInvoke($service, $parameter); + } +} + +class CBResult { + var $rtcode; + var $map; + function CBResult($rtcode) { + $this->rtcode = $rtcode; + $this->map = array(); + } + function getRtcode() { + return $this->rtcode; + } + function setRtcode($rtcode) { + $this->rtcode = $rtcode; + } + function getValue($key) { + return $this->map[$key]; + } + function setValue($key, $value) { + $this->map[$key] = $value; + } + function setMap($map) { + $this->map = $map; + } + function getMap() { + return $this->map; + } +} +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.XmlParser.php b/library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.XmlParser.php new file mode 100644 index 0000000..bbfd695 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/chinabank_utf8.XmlParser.php @@ -0,0 +1,175 @@ +<?php +function print_a($name, $arr) { + echo "$name: "; + print_r($arr); + echo "<br/>\n"; +} + +class SaxElement { + var $parentNode; + var $tagName; + var $val; + var $attrs; + var $childs; + function SaxElement($tagName) { + $this->tagName = $tagName; + $this->attrs = array(); + $this->childs = array(); + } + function setParentNode(& $parentNode) { + $this->parentNode = & $parentNode; + } + function setValue($val) { + $this->val = $val; + } + function addAttr($key, $val) { + $this->attrs[$key] = $val; + } + function setAttrs($attrs) { + $this->attrs = $attrs; + } + function addChild(& $element) { + array_push($this->childs, &$element); + } + function getParent() { + return $this->parent; + } + function getChilds() { + return $this->childs; + } + function isRoot() { + return $this->parent == NULL; + } + /** + * 得到类XML的结构 + */ + function getArray() { + $arr = array(); + $arr['tag'] = $this->tagName; + $arr['attrs'] = $this->attrs; + if ($this->val != NULL) { + $arr['value'] = $this->val; + } elseif ( sizeof($this->childs) ) { + $arr['childs'] = array(); + foreach($this->childs as $childElement) { + $arr['childs'][] = $childElement->getArray(); + } + } + return $arr; + } + /** + * 得到简化的结构 + */ + function getArray2() { + $rs = array(); + $rs['sname'] = $this->attrs['sname']; + $rs['result'] = $this->attrs['result']; + foreach($this->childs as $child) { + $rt = $child->_getArray2(); + $rs[ $rt['key'] ] = $rt['value']; + } + return $rs; + } + function _getArray2() { + $rt = array(); + $name = $this->attrs['name']; + $type = $this->attrs['type']; + switch ($type) { + case 'list': + case 'map': + $var = array(); + foreach($this->childs as $i => $child) { + $_rt = $child->_getArray2(); + $k = $_rt['key']; + $k = ($k==null ? $i : $k); + $var[$k] = $_rt['value']; + } + break; + default: + $var = $this->val; + } + $rt['key'] = $name; + $rt['value'] = $var; + return $rt; + } +} + +$rootDom; +$stack = array(); + +function startElement($parser, $name, $attrs) { + global $rootDom, $stack; + + if ( sizeof($stack)==0 ) { + // 当栈为空时认为是XML的根节点 + $rootDom = new SaxElement($name); + $rootDom->setAttrs($attrs); + array_push($stack, &$rootDom); + } else { + $element = new SaxElement($name); + $element->setAttrs($attrs); + $parent = &$stack[sizeof($stack)-1]; + $element->setParentNode($parent); + $parent->addChild($element); + array_push($stack, &$element); + } +} +function endElement($parser, $name) { + global $stack; + array_pop($stack); +} +function characterData($parser, $data) { + if ( trim($data)!="" ) { + global $stack; + $element = &$stack[sizeof($stack)-1]; + $element->setValue($data); + } +} + +function xml2array($xml) { + $xml_parser = xml_parser_create(); + xml_set_element_handler($xml_parser, "startElement", "endElement"); + xml_set_character_data_handler($xml_parser, "characterData"); + + xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0); + xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 1); + + if (!xml_parse($xml_parser, $xml)) { + die(sprintf("XML error: %s at line %d", + xml_error_string(xml_get_error_code($xml_parser)), + xml_get_current_line_number($xml_parser))); + } + xml_parser_free($xml_parser); + + global $rootDom; + return $rootDom->getArray2(); +} + +/* + * 测试 +$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> +<root sname=\"ConsumeService\" result=\"0\"> + <node name=\"time\" type=\"date\">2008-01-22</node> + <node name=\"merchantid\" type=\"string\">1001</node> + <node name=\"ch\" type=\"list\"> + <node type=\"int\">22</node> + <node type=\"int\">33</node> + <node type=\"string\">44</node> + </node> + <node name=\"mapping\" type=\"map\"> + <node name=\"aaa\" type=\"string\">22</node> + <node name=\"bbb\" type=\"int\">33</node> + <node name=\"ccc\" type=\"int\">44</node> + </node> +</root>"; + +$arr = xml2array($xml); +print_a('return', $arr); + + +$xml = "<?xml version=\"1.0\" encoding=\"GBK\"?> +<cb-xdoc sname=\"ConsumeService\" result=\"E12042000\"><node name=\"_error\" type=\"string\"><![CDATA[银行不允许此交易]]></node><node name=\"error\" type=\"string\"><![CDATA[E12042000]]></node></cb-xdoc>"; +$arr = xml2array($xml); +print_a('return', $arr); +*/ +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/class.nusoap_base.php b/library/WebPlugin/Pay/Motopay/lib/class.nusoap_base.php new file mode 100644 index 0000000..f77f743 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/class.nusoap_base.php @@ -0,0 +1,905 @@ +<?php + +/* +$Id: class.nusoap_base.php,v 1.43 2005/08/04 01:27:42 snichol Exp $ + +NuSOAP - Web Services Toolkit for PHP + +Copyright (c) 2002 NuSphere Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +If you have any questions or comments, please email: + +Dietrich Ayala +dietrich@ganx4.com +http://dietrich.ganx4.com/nusoap + +NuSphere Corporation +http://www.nusphere.com + +*/ + +/* load classes + +// necessary classes +require_once('class.soapclientw.php'); +require_once('class.soap_val.php'); +require_once('class.soap_parser.php'); +require_once('class.soap_fault.php'); + +// transport classes +require_once('class.soap_transport_http.php'); + +// optional add-on classes +require_once('class.xmlschema.php'); +require_once('class.wsdl.php'); + +// server class +require_once('class.soap_server.php');*/ + +// class variable emulation +// cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html +$GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9; + +/** +* +* nusoap_base +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: class.nusoap_base.php,v 1.43 2005/08/04 01:27:42 snichol Exp $ +* @access public +*/ +class nusoap_base { + /** + * Identification for HTTP headers. + * + * @var string + * @access private + */ + var $title = 'NuSOAP'; + /** + * Version for HTTP headers. + * + * @var string + * @access private + */ + var $version = '0.7.2'; + /** + * CVS revision for HTTP headers. + * + * @var string + * @access private + */ + var $revision = '$Revision: 1.43 $'; + /** + * Current error string (manipulated by getError/setError) + * + * @var string + * @access private + */ + var $error_str = ''; + /** + * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) + * + * @var string + * @access private + */ + var $debug_str = ''; + /** + * toggles automatic encoding of special characters as entities + * (should always be true, I think) + * + * @var boolean + * @access private + */ + var $charencoding = true; + /** + * the debug level for this instance + * + * @var integer + * @access private + */ + var $debugLevel; + + /** + * set schema version + * + * @var string + * @access public + */ + var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; + + /** + * charset encoding for outgoing messages + * + * @var string + * @access public + */ + var $soap_defencoding = 'ISO-8859-1'; + //var $soap_defencoding = 'UTF-8'; + + /** + * namespaces in an array of prefix => uri + * + * this is "seeded" by a set of constants, but it may be altered by code + * + * @var array + * @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/' + ); + + /** + * namespaces used in the current context, e.g. during serialization + * + * @var array + * @access private + */ + var $usedNamespaces = array(); + + /** + * XML Schema types in an array of uri => (array of xml type => php type) + * is this legacy yet? + * no, this is used by the xmlschema class to verify type => namespace mappings. + * @var array + * @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', + // abstract "any" types + 'anyType'=>'string','anySimpleType'=>'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/2000/10/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://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') + ); + + /** + * XML entities to convert + * + * @var array + * @access public + * @deprecated + * @see expandEntities + */ + var $xmlEntities = array('quot' => '"','amp' => '&', + 'lt' => '<','gt' => '>','apos' => "'"); + + /** + * constructor + * + * @access public + */ + function nusoap_base() { + $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; + } + + /** + * gets the global debug level, which applies to future instances + * + * @return integer Debug level 0-9, where 0 turns off + * @access public + */ + function getGlobalDebugLevel() { + return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; + } + + /** + * sets the global debug level, which applies to future instances + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setGlobalDebugLevel($level) { + $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level; + } + + /** + * gets the debug level for this instance + * + * @return int Debug level 0-9, where 0 turns off + * @access public + */ + function getDebugLevel() { + return $this->debugLevel; + } + + /** + * sets the debug level for this instance + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setDebugLevel($level) { + $this->debugLevel = $level; + } + + /** + * adds debug data to the instance debug string with formatting + * + * @param string $string debug data + * @access private + */ + function debug($string){ + if ($this->debugLevel > 0) { + $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); + } + } + + /** + * adds debug data to the instance debug string without formatting + * + * @param string $string debug data + * @access public + */ + function appendDebug($string){ + if ($this->debugLevel > 0) { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str .= $string; + } + } + + /** + * clears the current debug data for this instance + * + * @access public + */ + function clearDebug() { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str = ''; + } + + /** + * gets the current debug data for this instance + * + * @return debug data + * @access public + */ + function &getDebug() { + // it would be nice to use a memory stream here to use + // memory more efficiently + return $this->debug_str; + } + + /** + * gets the current debug data for this instance as an XML comment + * this may change the contents of the debug data + * + * @return debug data as an XML comment + * @access public + */ + function &getDebugAsXMLComment() { + // it would be nice to use a memory stream here to use + // memory more efficiently + while (strpos($this->debug_str, '--')) { + $this->debug_str = str_replace('--', '- -', $this->debug_str); + } + return "<!--\n" . $this->debug_str . "\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 mixed error string or false + * @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 mixed $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'. + * + * @param mixed $val The value to serialize + * @param string $name The name (local part) of the XML element + * @param string $type The XML schema type (local part) for the element + * @param string $name_ns The namespace for the name of the XML element + * @param string $type_ns The namespace for the type of the element + * @param array $attributes The attributes to serialize as name=>value pairs + * @param string $use The WSDL "use" (encoded|literal) + * @return string The serialized element, possibly with child elements + * @access public + */ + function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){ + $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use"); + $this->appendDebug('value=' . $this->varDump($val)); + $this->appendDebug('attributes=' . $this->varDump($attributes)); + + if(is_object($val) && get_class($val) == 'soapval'){ + return $val->serialize($use); + } + // force valid name if necessary + if (is_numeric($name)) { + $name = '__numeric_' . $name; + } elseif (! $name) { + $name = 'noname'; + } + // 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=\"".$this->expandEntities($v).'"'; + } + } + // serialize null value + if (is_null($val)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + return "<$name$xmlns $atts/>"; + } else { + if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + return "<$name$xmlns$type_str $atts xsi:nil=\"true\"/>"; + } + } + // 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 $atts>$val</$name>"; + } else { + return "<$name$xmlns $atts xsi:type=\"xsd:$type\">$val</$name>"; + } + } + // detect type and serialize + $xml = ''; + switch(true) { + 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): + if (! $name) { + $name = get_class($val); + $this->debug("In serialize_val, used class name $name as element name"); + } else { + $this->debug("In serialize_val, do not override name $name for element name for class " . 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; + // TODO: for literal, the name should be $name + $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); + ++$i; + } + if(count($array_types) > 1){ + $array_typename = 'xsd:anyType'; + } 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\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; + } + } + // TODO: for array in literal, there is no wrapper here + $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 .= '<item>'; + $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); + $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); + $xml .= '</item>'; + } 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; + } + + /** + * serializes a message + * + * @param string $body the XML of the SOAP body + * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers + * @param array $namespaces optional the namespaces used in generating the body and headers + * @param string $style optional (rpc|document) + * @param string $use optional (encoded|literal) + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @return string the message + * @access public + */ + function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ + // 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 + + $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); + $this->debug("headers:"); + $this->appendDebug($this->varDump($headers)); + $this->debug("namespaces:"); + $this->appendDebug($this->varDump($namespaces)); + + // serialize namespaces + $ns_string = ''; + foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ + $ns_string .= " xmlns:$k=\"$v\""; + } + if($encodingStyle) { + $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; + } + + // serialize headers + if($headers){ + if (is_array($headers)) { + $xml = ''; + foreach ($headers as $header) { + $xml .= $this->serialize_val($header, false, false, false, false, false, $use); + } + $headers = $xml; + $this->debug("In serializeEnvelope, serialzied array of headers to $headers"); + } + $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>"; + } + // serialize envelope + return + '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">". + '<SOAP-ENV:Envelope'.$ns_string.">". + $headers. + "<SOAP-ENV:Body>". + $body. + "</SOAP-ENV:Body>". + "</SOAP-ENV:Envelope>"; + } + + /** + * formats a string to be inserted into an HTML stream + * + * @param string $str The string to format + * @return string The formatted string + * @access public + * @deprecated + */ + function formatDump($str){ + $str = htmlspecialchars($str); + return nl2br($str); + } + + /** + * contracts (changes namespace to prefix) a qualified name + * + * @param string $qname 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 (changes prefix to namespace) 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 $str The prefixed string + * @return string The local part + * @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 $str The prefixed string + * @return mixed The prefix or false if there is no prefix + * @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 + * + * @param string $prefix The prefix + * @return mixed The namespace, false if no namespace has the specified prefix + * @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 $ns The namespace + * @return mixed The prefix, false if the namespace has no prefixes + * @access public + */ + function getPrefixFromNamespace($ns) { + foreach ($this->namespaces as $p => $n) { + if ($ns == $n || $ns == $p) { + $this->usedNamespaces[$p] = $n; + return $p; + } + } + return false; + } + + /** + * returns the time in ODBC canonical form with microseconds + * + * @return string The time in ODBC canonical form with microseconds + * @access public + */ + function getmicrotime() { + if (function_exists('gettimeofday')) { + $tod = gettimeofday(); + $sec = $tod['sec']; + $usec = $tod['usec']; + } else { + $sec = time(); + $usec = 0; + } + return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); + } + + /** + * Returns a string with the output of var_dump + * + * @param mixed $data The variable to var_dump + * @return string The output of var_dump + * @access public + */ + function varDump($data) { + ob_start(); + var_dump($data); + $ret_val = ob_get_contents(); + ob_end_clean(); + return $ret_val; + } +} + +// 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; + } +} + +/** +* sleeps some number of microseconds +* +* @param string $usec the number of microseconds to sleep +* @access public +* @deprecated +*/ +function usleepWindows($usec) +{ + $start = gettimeofday(); + + do + { + $stop = gettimeofday(); + $timePassed = 1000000 * ($stop['sec'] - $start['sec']) + + $stop['usec'] - $start['usec']; + } + while ($timePassed < $usec); +} + + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/class.soap_fault.php b/library/WebPlugin/Pay/Motopay/lib/class.soap_fault.php new file mode 100644 index 0000000..139d375 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/class.soap_fault.php @@ -0,0 +1,86 @@ +<?php + + + + +/** +* Contains information for a SOAP fault. +* Mainly used for returning faults from deployed functions +* in a server instance. +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: class.soap_fault.php,v 1.12 2005/07/27 19:24:42 snichol Exp $ +* @access public +*/ +class soap_fault extends nusoap_base { + /** + * The fault code (client|server) + * @var string + * @access private + */ + var $faultcode; + /** + * The fault actor + * @var string + * @access private + */ + var $faultactor; + /** + * The fault string, a description of the fault + * @var string + * @access private + */ + var $faultstring; + /** + * The fault detail, typically a string or array of string + * @var mixed + * @access private + */ + 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 mixed $faultdetail detail, typically a string or array of string + */ + function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ + parent::nusoap_base(); + $this->faultcode = $faultcode; + $this->faultactor = $faultactor; + $this->faultstring = $faultstring; + $this->faultdetail = $faultdetail; + } + + /** + * serialize a fault + * + * @return string The serialization of the fault instance. + * @access public + */ + function serialize(){ + $ns_string = ''; + foreach($this->namespaces as $k => $v){ + $ns_string .= "\n xmlns:$k=\"$v\""; + } + $return_msg = + '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'. + '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n". + '<SOAP-ENV:Body>'. + '<SOAP-ENV:Fault>'. + $this->serialize_val($this->faultcode, 'faultcode'). + $this->serialize_val($this->faultactor, 'faultactor'). + $this->serialize_val($this->faultstring, 'faultstring'). + $this->serialize_val($this->faultdetail, 'detail'). + '</SOAP-ENV:Fault>'. + '</SOAP-ENV:Body>'. + '</SOAP-ENV:Envelope>'; + return $return_msg; + } +} + + + + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/class.soap_parser.php b/library/WebPlugin/Pay/Motopay/lib/class.soap_parser.php new file mode 100644 index 0000000..098d158 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/class.soap_parser.php @@ -0,0 +1,599 @@ +<?php + + + + +/** +* +* soap_parser class parses SOAP XML messages into native PHP values +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: class.soap_parser.php,v 1.36 2005/08/04 01:27:42 snichol 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 that actually does the parsing + * + * @param string $xml SOAP message + * @param string $encoding character encoding scheme of message + * @param string $method method for which XML is parsed (unused?) + * @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){ + parent::nusoap_base(); + $this->xml = $xml; + $this->xml_encoding = $encoding; + $this->method = $method; + $this->decode_utf8 = $decode_utf8; + + // Check whether content has been read. + if(!empty($xml)){ + // Check XML encoding + $pos_xml = strpos($xml, '<?xml'); + if ($pos_xml !== FALSE) { + $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1); + if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { + $xml_encoding = $res[1]; + if (strtoupper($xml_encoding) != $encoding) { + $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; + $this->debug($err); + if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { + $this->setError($err); + return; + } + // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed + } else { + $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); + } + } else { + $this->debug('No encoding specified in XML declaration'); + } + } else { + $this->debug('No XML declaration'); + } + $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]); + if (is_array($idVal) && isset($idVal['!id'])) { + unset($idVal['!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 resource $parser XML parser object + * @param string $name element name + * @param array $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]; + } + // specifies nil value (or not) + } elseif ($key_localpart == 'nil'){ + $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); + // some other attribute + } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { + $this->message[$pos]['xattrs']['!' . $key] = $value; + } + + if ($key == 'xmlns') { + $this->default_namespace = $value; + } + // 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 resource $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 complexType 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); + } + // build complexType values of attributes and possibly simpleContent + } elseif (isset($this->message[$pos]['xattrs'])) { + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + if (isset($this->message[$pos]['type'])) { + $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } 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]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; + } + } + } + $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; + // set value of simpleType (or nil complexType) + } else { + //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (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 resource $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 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 + * @return mixed PHP value + * @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') { + $this->debug('Decode base64 value'); + 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; + } + // bogus: parser treats array with no elements as a simple type + if ($type == 'array') { + return array(); + } + // everything else + return (string) $value; + } + + /** + * builds response structures for compound values (arrays/structs) + * and scalars + * + * @param integer $pos position in node tree + * @return mixed PHP value + * @access private + */ + function buildVal($pos){ + if(!isset($this->message[$pos]['type'])){ + $this->message[$pos]['type'] = ''; + } + $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); + // if there are children... + if($this->message[$pos]['children'] != ''){ + $this->debug('in buildVal, there are 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("in buildVal, 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('in buildVal, 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'){ + $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); + 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 + $this->debug('in buildVal, adding Java Vector '.$this->message[$pos]['name']); + if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { + $notstruct = 1; + } else { + $notstruct = 0; + } + // + foreach($children as $child_pos){ + if($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']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { + $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']; + } + } + } + } + if (isset($this->message[$pos]['xattrs'])) { + $this->debug('in buildVal, handling attributes'); + foreach ($this->message[$pos]['xattrs'] as $n => $v) { + $params[$n] = $v; + } + } + // handle simpleContent + if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + $this->debug('in buildVal, handling simpleContent'); + if (isset($this->message[$pos]['type'])) { + $params['!'] = $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'])) { + $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $params['!'] = $this->message[$pos]['cdata']; + } + } + } + return is_array($params) ? $params : array(); + } else { + $this->debug('in buildVal, no children, building scalar'); + $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; + if (isset($this->message[$pos]['type'])) { + return $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + return $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } + return $this->message[$pos]['cdata']; + } + } +} + + + + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/class.soap_server.php b/library/WebPlugin/Pay/Motopay/lib/class.soap_server.php new file mode 100644 index 0000000..b4e9764 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/class.soap_server.php @@ -0,0 +1,1038 @@ +<?php + + + + +/** +* +* soap_server allows the user to create a SOAP server +* that is capable of receiving messages and returning responses +* +* NOTE: WSDL functionality is experimental +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: class.soap_server.php,v 1.48 2005/08/04 01:27:42 snichol Exp $ +* @access public +*/ +class soap_server extends nusoap_base { + /** + * HTTP headers of request + * @var array + * @access private + */ + var $headers = array(); + /** + * HTTP request + * @var string + * @access private + */ + var $request = ''; + /** + * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $requestHeaders = ''; + /** + * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $document = ''; + /** + * SOAP payload for request (text) + * @var string + * @access public + */ + var $requestSOAP = ''; + /** + * requested method namespace URI + * @var string + * @access private + */ + var $methodURI = ''; + /** + * name of method requested + * @var string + * @access private + */ + var $methodname = ''; + /** + * method parameters from request + * @var array + * @access private + */ + var $methodparams = array(); + /** + * SOAP Action from request + * @var string + * @access private + */ + var $SOAPAction = ''; + /** + * character set encoding of incoming (request) messages + * @var string + * @access public + */ + var $xml_encoding = ''; + /** + * toggles whether the parser decodes element content w/ utf8_decode() + * @var boolean + * @access public + */ + var $decode_utf8 = true; + + /** + * HTTP headers of response + * @var array + * @access public + */ + var $outgoing_headers = array(); + /** + * HTTP response + * @var string + * @access private + */ + var $response = ''; + /** + * SOAP headers for response (text) + * @var string + * @access public + */ + var $responseHeaders = ''; + /** + * SOAP payload for response (text) + * @var string + * @access private + */ + var $responseSOAP = ''; + /** + * method return value to place in response + * @var mixed + * @access private + */ + var $methodreturn = false; + /** + * whether $methodreturn is a string of literal XML + * @var boolean + * @access public + */ + var $methodreturnisliteralxml = false; + /** + * SOAP fault for response (or false) + * @var mixed + * @access private + */ + var $fault = false; + /** + * text indication of result (for debugging) + * @var string + * @access private + */ + var $result = 'successful'; + + /** + * assoc array of operations => opData; operations are added by the register() + * method or by parsing an external WSDL definition + * @var array + * @access private + */ + var $operations = array(); + /** + * wsdl instance (if one) + * @var mixed + * @access private + */ + var $wsdl = false; + /** + * URL for WSDL (if one) + * @var mixed + * @access private + */ + var $externalWSDLURL = false; + /** + * whether to append debug to response as XML comment + * @var boolean + * @access public + */ + var $debug_flag = false; + + + /** + * 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){ + parent::nusoap_base(); + // turn on debugging? + global $debug; + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $this->debug("_SERVER is defined:"); + $this->appendDebug($this->varDump($_SERVER)); + } elseif (isset($HTTP_SERVER_VARS)) { + $this->debug("HTTP_SERVER_VARS is defined:"); + $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); + } else { + $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); + } + + if (isset($debug)) { + $this->debug("In soap_server, set debug_flag=$debug based on global flag"); + $this->debug_flag = $debug; + } elseif (isset($_SERVER['QUERY_STRING'])) { + $qs = explode('&', $_SERVER['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In soap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); + $this->debug_flag = substr($v, 6); + } + } + } elseif (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("In soap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); + $this->debug_flag = substr($v, 6); + } + } + } + + // wsdl + if($wsdl){ + $this->debug("In soap_server, WSDL is specified"); + if (is_object($wsdl) && (get_class($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->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + 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 $HTTP_SERVER_VARS; + + if (isset($_SERVER['QUERY_STRING'])) { + $qs = $_SERVER['QUERY_STRING']; + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = $HTTP_SERVER_VARS['QUERY_STRING']; + } else { + $qs = ''; + } + $this->debug("In service, query string=$qs"); + + if (ereg('wsdl', $qs) ){ + $this->debug("In service, 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); + } + } elseif ($this->wsdl) { + header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); + print $this->wsdl->serialize($this->debug_flag); + if ($this->debug_flag) { + $this->debug('wsdl:'); + $this->appendDebug($this->varDump($this->wsdl)); + print $this->getDebugAsXMLComment(); + } + } else { + header("Content-Type: text/html; charset=ISO-8859-1\r\n"); + print "This service does not provide WSDL"; + } + } elseif ($data == '' && $this->wsdl) { + $this->debug("In service, there is no data, so return Web description"); + print $this->wsdl->webDescription(); + } else { + $this->debug("In service, invoke 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; + + $this->request = ''; + $this->SOAPAction = ''; + if(function_exists('getallheaders')){ + $this->debug("In parse_http_headers, use getallheaders"); + $headers = getallheaders(); + foreach($headers as $k=>$v){ + $k = strtolower($k); + $this->headers[$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(isset($this->headers['content-type']) && 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 for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } elseif(isset($_SERVER) && is_array($_SERVER)){ + $this->debug("In parse_http_headers, use _SERVER"); + foreach ($_SERVER as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($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 for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } elseif (is_array($HTTP_SERVER_VARS)) { + $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); + foreach ($HTTP_SERVER_VARS as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($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 for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } else { + $this->debug("In parse_http_headers, HTTP headers not accessible"); + $this->setError("HTTP headers not accessible"); + } + } + + /** + * 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()'); + $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('Client', 'Errors occurred when trying to decode the data'); + return; + } + } else { + $this->fault('Client', 'This Server does not support compressed data'); + return; + } + } + } + $this->request .= "\r\n".$data; + $data = $this->parseRequest($this->headers, $data); + $this->requestSOAP = $data; + $this->debug('leaving parse_request'); + } + + /** + * 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('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); + + if ($this->wsdl) { + if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { + $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { + // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element + $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + $this->methodname = $this->opData['name']; + } else { + $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); + $this->fault('Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); + return; + } + } else { + $this->debug('in invoke_method, no WSDL to validate method'); + } + + // if a . is present in $this->methodname, we see if there is a class in scope, + // which could be referred to. We will also distinguish between two deliminators, + // to allow methods to be called a the class or an instance + $class = ''; + $method = ''; + if (strpos($this->methodname, '..') > 0) { + $delim = '..'; + } else if (strpos($this->methodname, '.') > 0) { + $delim = '.'; + } else { + $delim = ''; + } + + if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 && + class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) { + // get the class and method name + $class = substr($this->methodname, 0, strpos($this->methodname, $delim)); + $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); + $this->debug("in invoke_method, class=$class method=$method delim=$delim"); + } + + // does method exist? + if ($class == '') { + if (!function_exists($this->methodname)) { + $this->debug("in invoke_method, function '$this->methodname' not found!"); + $this->result = 'fault: method not found'; + $this->fault('Client',"method '$this->methodname' not defined in service"); + return; + } + } else { + $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; + if (!in_array($method_to_compare, get_class_methods($class))) { + $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); + $this->result = 'fault: method not found'; + $this->fault('Client',"method '$this->methodname' not defined in service"); + return; + } + } + + // 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('Client',"Operation '$this->methodname' not defined in service."); + return; + } + + // if there are parameters to pass + $this->debug('in invoke_method, params:'); + $this->appendDebug($this->varDump($this->methodparams)); + $this->debug("in invoke_method, calling '$this->methodname'"); + if (!function_exists('call_user_func_array')) { + if ($class == '') { + $this->debug('in invoke_method, calling function using eval()'); + $funcCall = "\$this->methodreturn = $this->methodname("; + } else { + if ($delim == '..') { + $this->debug('in invoke_method, calling class method using eval()'); + $funcCall = "\$this->methodreturn = ".$class."::".$method."("; + } else { + $this->debug('in invoke_method, calling instance method using eval()'); + // generate unique instance name + $instname = "\$inst_".time(); + $funcCall = $instname." = new ".$class."(); "; + $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; + } + } + if ($this->methodparams) { + foreach ($this->methodparams as $param) { + if (is_array($param)) { + $this->fault('Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); + return; + } + $funcCall .= "\"$param\","; + } + $funcCall = substr($funcCall, 0, -1); + } + $funcCall .= ');'; + $this->debug('in invoke_method, function call: '.$funcCall); + @eval($funcCall); + } else { + if ($class == '') { + $this->debug('in invoke_method, calling function using call_user_func_array()'); + $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() + } elseif ($delim == '..') { + $this->debug('in invoke_method, calling class method using call_user_func_array()'); + $call_arg = array ($class, $method); + } else { + $this->debug('in invoke_method, calling instance method using call_user_func_array()'); + $instance = new $class (); + $call_arg = array(&$instance, $method); + } + $this->methodreturn = call_user_func_array($call_arg, $this->methodparams); + } + $this->debug('in invoke_method, methodreturn:'); + $this->appendDebug($this->varDump($this->methodreturn)); + $this->debug("in 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 methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); + // if fault + if (isset($this->methodreturn) && (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); + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if($errstr = $this->wsdl->getError()){ + $this->debug('got wsdl error: '.$errstr); + $this->fault('Server', 'unable to serialize result'); + return; + } + } else { + if (isset($this->methodreturn)) { + $return_val = $this->serialize_val($this->methodreturn, 'return'); + } else { + $return_val = ''; + $this->debug('in absence of WSDL, assume void return for backward compatibility'); + } + } + } + $this->debug('return value:'); + $this->appendDebug($this->varDump($return_val)); + + $this->debug('serializing response'); + if ($this->wsdl) { + $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); + if ($this->opData['style'] == 'rpc') { + $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); + if ($this->opData['output']['use'] == 'literal') { + $payload = '<'.$this->methodname.'Response xmlns="'.$this->methodURI.'">'.$return_val.'</'.$this->methodname."Response>"; + } else { + $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; + } + } else { + $this->debug('style is not rpc for serialization: assume document'); + $payload = $return_val; + } + } else { + $this->debug('do not have WSDL for serialization: assume rpc/encoded'); + $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; + } + $this->result = 'successful'; + if($this->wsdl){ + //if($this->debug_flag){ + $this->appendDebug($this->wsdl->getDebug()); + // } + if (isset($opData['output']['encodingStyle'])) { + $encodingStyle = $opData['output']['encodingStyle']; + } else { + $encodingStyle = ''; + } + // 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'],$encodingStyle); + } 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){ + $payload .= $this->getDebugAsXMLComment(); + } + $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"; + $payload = $this->getHTTPBody($payload); + $type = $this->getHTTPContentType(); + $charset = $this->getHTTPContentTypeCharset(); + $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); + //begin code to compress payload - by John + // NOTE: there is no way to know whether the Web server will also compress + // this data. + if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { + if (strstr($this->headers['accept-encoding'], 'gzip')) { + if (function_exists('gzencode')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= "<!-- Content being gzipped -->"; + } + $this->outgoing_headers[] = "Content-Encoding: gzip"; + $payload = gzencode($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= "<!-- Content will not be gzipped: no gzencode -->"; + } + } + } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { + // Note: MSIE requires gzdeflate output (no Zlib header and checksum), + // instead of gzcompress output, + // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) + if (function_exists('gzdeflate')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= "<!-- Content being deflated -->"; + } + $this->outgoing_headers[] = "Content-Encoding: deflate"; + $payload = gzdeflate($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= "<!-- Content will not be deflated: no gzcompress -->"; + } + } + } + } + //end code + $this->outgoing_headers[] = "Content-Length: ".strlen($payload); + reset($this->outgoing_headers); + foreach($this->outgoing_headers as $hdr){ + header($hdr, false); + } + print $payload; + $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; + } + + /** + * takes the value that was created by parsing the request + * and compares to the method's signature, if available. + * + * @param string $operation The operation to be invoked + * @param array $request The array of parameter values + * @return boolean Whether the operation was found + * @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; + } + + /** + * processes SOAP message received from client + * + * @param array $headers The HTTP headers + * @param string $data unprocessed request data from client + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseRequest($headers, $data) { + $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']); + if (!strstr($headers['content-type'], 'text/xml')) { + $this->setError('Request 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 for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser'); + // parse response, get soap parser obj + $parser = new soap_parser($data,$this->xml_encoding,'',$this->decode_utf8); + // parser debug + $this->debug("parser debug: \n".$parser->getDebug()); + // if fault occurred during message parsing + if($err = $parser->getError()){ + $this->result = 'fault: error in msg parsing: '.$err; + $this->fault('Client',"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('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); + $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; + } + } + + /** + * gets the HTTP body for the current response. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + return $soapmsg; + } + + /** + * gets the HTTP content type for the current response. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current response. + * @access private + */ + function getHTTPContentType() { + return 'text/xml'; + } + + /** + * gets the HTTP content type charset for the current response. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current response. + * @access private + */ + function getHTTPContentTypeCharset() { + return $this->soap_defencoding; + } + + /** + * add a method to the dispatch map (this has been replaced by the register method) + * + * @param string $methodname + * @param string $in array of input values + * @param string $out array of output values + * @access public + * @deprecated + */ + function add_to_map($methodname,$in,$out){ + $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); + } + + /** + * register a service function with the server + * + * @param string $name the name of the PHP function, class.method or class..method + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $out assoc array of output values: key = param name, value = param type + * @param mixed $namespace the element namespace for the method or false + * @param mixed $soapaction the soapaction for the method or false + * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @param mixed $use optional (encoded|literal) or false + * @param string $documentation optional Description to include in WSDL + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ + global $HTTP_SERVER_VARS; + + 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 (! $name) { + die('You must specify a name when you register an operation'); + } + if (!is_array($in)) { + die('You must provide an array for operation inputs'); + } + if (!is_array($out)) { + die('You must provide an array for operation outputs'); + } + if(false == $namespace) { + } + if(false == $soapaction) { + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + $soapaction = "http://$SERVER_NAME$SCRIPT_NAME/$name"; + } + if(false == $style) { + $style = "rpc"; + } + if(false == $use) { + $use = "encoded"; + } + if ($use == 'encoded' && $encodingStyle = '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + $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,$encodingStyle); + } + return true; + } + + /** + * Specify a fault to be returned to the client. + * 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=''){ + if ($faultdetail == '' && $this->debug_flag) { + $faultdetail = $this->getDebug(); + } + $this->fault = new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail); + $this->fault->soap_defencoding = $this->soap_defencoding; + } + + /** + * Sets up wsdl object. + * Acts as a flag to enable internal WSDL generation + * + * @param string $serviceName, name of the service + * @param mixed $namespace optional 'tns' service namespace or false + * @param mixed $endpoint optional URL of service endpoint or false + * @param string $style optional (rpc|document) WSDL style (also specified by operation) + * @param string $transport optional SOAP transport + * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false + */ + function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) + { + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SERVER_PORT = $_SERVER['SERVER_PORT']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = $_SERVER['HTTPS']; + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = $HTTP_SERVER_VARS['HTTPS']; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + if ($SERVER_PORT == 80) { + $SERVER_PORT = ''; + } else { + $SERVER_PORT = ':' . $SERVER_PORT; + } + if(false == $namespace) { + $namespace = "http://$SERVER_NAME/soap/$serviceName"; + } + + if(false == $endpoint) { + 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/'); + } +} + + + + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/class.soap_transport_http.php b/library/WebPlugin/Pay/Motopay/lib/class.soap_transport_http.php new file mode 100644 index 0000000..9e9449a --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/class.soap_transport_http.php @@ -0,0 +1,1038 @@ +<?php + + + + +/** +* transport class for sending/receiving data via HTTP and HTTPS +* NOTE: PHP must be compiled with the CURL extension for HTTPS support +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: class.soap_transport_http.php,v 1.57 2005/07/27 19:24:42 snichol Exp $ +* @access public +*/ +class soap_transport_http extends nusoap_base { + + var $url = ''; + var $uri = ''; + var $digest_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 $incoming_cookies = array(); + var $outgoing_payload = ''; + var $incoming_payload = ''; + var $useSOAPAction = true; + var $persistentConnection = false; + var $ch = false; // cURL handle + var $username = ''; + var $password = ''; + var $authtype = ''; + var $digestRequest = array(); + var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional) + // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' + // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' + // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' + // passphrase: SSL key password/passphrase + // verifypeer: default is 1 + // verifyhost: default is 1 + + /** + * constructor + */ + function soap_transport_http($url){ + parent::nusoap_base(); + $this->setURL($url); + ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev); + $this->outgoing_headers['User-Agent'] = $this->title.'/'.$this->version.' ('.$rev[1].')'; + $this->debug('set User-Agent: ' . $this->outgoing_headers['User-Agent']); + } + + function setURL($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; + $this->digest_uri = $this->uri; + + // build headers + if (!isset($u['port'])) { + $this->outgoing_headers['Host'] = $this->host; + } else { + $this->outgoing_headers['Host'] = $this->host.':'.$this->port; + } + $this->debug('set Host: ' . $this->outgoing_headers['Host']); + + if (isset($u['user']) && $u['user'] != '') { + $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($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 . ' connection_timeout ' . $connection_timeout); + + // 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 + $this->debug('set response timeout to ' . $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); + // follow location headers (re-directs) + curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 1); + // 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'; + $this->debug('set Connection: ' . $this->outgoing_headers['Connection']); + } + // set timeout + if ($connection_timeout != 0) { + curl_setopt($this->ch, CURLOPT_TIMEOUT, $connection_timeout); + } + // TODO: cURL has added a connection timeout separate from the response timeout + //if ($connection_timeout != 0) { + // curl_setopt($this->ch, CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); + //} + //if ($response_timeout != 0) { + // curl_setopt($this->ch, CURLOPT_TIMEOUT, $response_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); + + // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) + if ($this->authtype == 'certificate') { + if (isset($this->certRequest['cainfofile'])) { + curl_setopt($this->ch, CURLOPT_CAINFO, $this->certRequest['cainfofile']); + } + if (isset($this->certRequest['verifypeer'])) { + curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); + } else { + curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 1); + } + if (isset($this->certRequest['verifyhost'])) { + curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); + } else { + curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 1); + } + if (isset($this->certRequest['sslcertfile'])) { + curl_setopt($this->ch, CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); + } + if (isset($this->certRequest['sslkeyfile'])) { + curl_setopt($this->ch, CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); + } + if (isset($this->certRequest['passphrase'])) { + curl_setopt($this->ch, CURLOPT_SSLKEYPASSWD , $this->certRequest['passphrase']); + } + } + $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 + * @param array $cookies cookies to send + * @return string data + * @access public + */ + function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { + + $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, $cookies)){ + 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 + * @param array $cookies cookies to send + * @return string data + * @access public + */ + function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { + return $this->send($data, $timeout, $response_timeout, $cookies); + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic, digest, certificate) + * @param array $digestRequest (keys must be nonce, nc, realm, qop) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { + $this->debug("Set credentials for authtype $authtype"); + // cf. RFC 2617 + if ($authtype == 'basic') { + $this->outgoing_headers['Authorization'] = 'Basic '.base64_encode(str_replace(':','',$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. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; + + // H(A1) = MD5(A1) + $HA1 = md5($A1); + + // A2 = Method ":" digest-uri-value + $A2 = 'POST:' . $this->digest_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->digest_uri . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'; + } + } elseif ($authtype == 'certificate') { + $this->certRequest = $certRequest; + } + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->digestRequest = $digestRequest; + + if (isset($this->outgoing_headers['Authorization'])) { + $this->debug('set Authorization: ' . 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 . '"'; + $this->debug('set SOAPAction: ' . $this->outgoing_headers['SOAPAction']); + } + + /** + * use http encoding + * + * @param string $enc encoding style. supported values: gzip, deflate, or both + * @access public + */ + function setEncoding($enc='gzip, deflate') { + if (function_exists('gzdeflate')) { + $this->protocol_version = '1.1'; + $this->outgoing_headers['Accept-Encoding'] = $enc; + $this->debug('set Accept-Encoding: ' . $this->outgoing_headers['Accept-Encoding']); + if (!isset($this->outgoing_headers['Connection'])) { + $this->outgoing_headers['Connection'] = 'close'; + $this->persistentConnection = false; + $this->debug('set Connection: ' . $this->outgoing_headers['Connection']); + } + 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); + $this->debug('set Proxy-Authorization: ' . $this->outgoing_headers['Proxy-Authorization']); + } + } + + /** + * 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 + * @deprecated + */ + 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, $cookie_str = '') { + // add content-length header + $this->outgoing_headers['Content-Length'] = strlen($data); + $this->debug('set Content-Length: ' . $this->outgoing_headers['Content-Length']); + + // start building outgoing payload: + $req = "$this->request_method $this->uri HTTP/$this->protocol_version"; + $this->debug("HTTP request: $req"); + $this->outgoing_payload = "$req\r\n"; + + // loop thru headers, serializing + foreach($this->outgoing_headers as $k => $v){ + $hdr = $k.': '.$v; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // add any cookies + if ($cookie_str != '') { + $hdr = 'Cookie: '.$cookie_str; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // header/body separator + $this->outgoing_payload .= "\r\n"; + + // add data + $this->outgoing_payload .= $data; + } + + function sendRequest($data, $cookies = NULL) { + // build cookie string + $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); + + // build payload + $this->buildPayload($data, $cookie_str); + + 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"; + } + if ($cookie_str != '') { + $curl_headers[] = 'Cookie: ' . $cookie_str; + } + 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: " . $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(); + $this->incoming_cookies = 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]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } else if (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + + // loop until msg has been received + if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { + $content_length = 2147483647; // ignore any content-length header + $chunked = true; + $this->debug("want to read chunked content"); + } elseif (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; + $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 "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>"; + // 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.'<br>'; + // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE + foreach(curl_getinfo($this->ch) as $k => $v){ + $err .= "$k: $v<br>"; + } + $this->debug($err); + $this->setError($err); + curl_close($this->ch); + return false; + } else { + //echo '<pre>'; + //var_dump(curl_getinfo($this->ch)); + //echo '</pre>'; + } + // close curl + $this->debug('No cURL error, closing cURL'); + curl_close($this->ch); + + // remove 100 header(s) + while (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){ + $header_name = strtolower(trim($arr[0])); + $this->incoming_headers[$header_name] = trim($arr[1]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } else if (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + } + + $arr = explode(' ', $header_array[0], 3); + $http_version = $arr[0]; + $http_status = intval($arr[1]); + $http_reason = count($arr) > 2 ? $arr[2] : ''; + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['location']) && $http_status == 301) { + $this->debug("Got 301 $http_reason with Location: " . $this->incoming_headers['location']); + $this->setURL($this->incoming_headers['location']); + $this->tryagain = true; + return false; + } + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { + $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); + if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { + $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), 2); + $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; + } + + if ( + ($http_status >= 300 && $http_status <= 307) || + ($http_status >= 400 && $http_status <= 417) || + ($http_status >= 501 && $http_status <= 505) + ) { + $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclientw->response has contents of the response)"); + 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('gzinflate')){ + //$timer->setMarker('starting decoding of gzip/deflated content'); + // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) + // this means there are no Zlib headers, although there should be + $this->debug('The gzinflate function exists'); + $datalen = strlen($data); + if ($this->incoming_headers['content-encoding'] == 'deflate') { + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The inflated payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to inflate the payload'); + $this->setError('Error using gzinflate to inflate the payload'); + } + } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { + if ($degzdata = @gzinflate(substr($data, 10))) { // do our best + $data = $degzdata; + $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate(substr($data, 10))) { + $data = $degzdata; + $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to un-gzip the payload'); + $this->setError('Error using gzinflate to un-gzip the payload'); + } + } + //$timer->setMarker('finished decoding of gzip/deflated content'); + //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>"; + // set decoded payload + $this->incoming_payload = $header_data.$lb.$lb.$data; + } else { + $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + } + } else { + $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + } + } else { + $this->debug('No Content-Encoding header'); + } + + 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 : ''); + $this->debug('set Content-Type: ' . $this->outgoing_headers['Content-Type']); + } + + 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'; + $this->debug('set Connection: ' . $this->outgoing_headers['Connection']); + return true; + } + + /** + * parse an incoming Cookie into it's parts + * + * @param string $cookie_str content of cookie + * @return array with data of that cookie + * @access private + */ + /* + * TODO: allow a Set-Cookie string to be parsed into multiple cookies + */ + function parseCookie($cookie_str) { + $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; + $data = split(';', $cookie_str); + $value_str = $data[0]; + + $cookie_param = 'domain='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $domain = substr($cookie_str, $start + strlen($cookie_param)); + $domain = substr($domain, 0, strpos($domain, ';')); + } else { + $domain = ''; + } + + $cookie_param = 'expires='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $expires = substr($cookie_str, $start + strlen($cookie_param)); + $expires = substr($expires, 0, strpos($expires, ';')); + } else { + $expires = ''; + } + + $cookie_param = 'path='; + $start = strpos($cookie_str, $cookie_param); + if ( $start > 0 ) { + $path = substr($cookie_str, $start + strlen($cookie_param)); + $path = substr($path, 0, strpos($path, ';')); + } else { + $path = '/'; + } + + $cookie_param = ';secure;'; + if (strpos($cookie_str, $cookie_param) !== FALSE) { + $secure = true; + } else { + $secure = false; + } + + $sep_pos = strpos($value_str, '='); + + if ($sep_pos) { + $name = substr($value_str, 0, $sep_pos); + $value = substr($value_str, $sep_pos + 1); + $cookie= array( 'name' => $name, + 'value' => $value, + 'domain' => $domain, + 'path' => $path, + 'expires' => $expires, + 'secure' => $secure + ); + return $cookie; + } + return false; + } + + /** + * sort out cookies for the current request + * + * @param array $cookies array with all cookies + * @param boolean $secure is the send-content secure or not? + * @return string for Cookie-HTTP-Header + * @access private + */ + function getCookiesForRequest($cookies, $secure=false) { + $cookie_str = ''; + if ((! is_null($cookies)) && (is_array($cookies))) { + foreach ($cookies as $cookie) { + if (! is_array($cookie)) { + continue; + } + $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); + if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { + if (strtotime($cookie['expires']) <= time()) { + $this->debug('cookie has expired'); + continue; + } + } + if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { + $domain = preg_quote($cookie['domain']); + if (! preg_match("'.*$domain$'i", $this->host)) { + $this->debug('cookie has different domain'); + continue; + } + } + if ((isset($cookie['path'])) && (! empty($cookie['path']))) { + $path = preg_quote($cookie['path']); + if (! preg_match("'^$path.*'i", $this->path)) { + $this->debug('cookie is for a different path'); + continue; + } + } + if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { + $this->debug('cookie is secure, transport is not'); + continue; + } + $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; + $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); + } + } + return $cookie_str; + } +} + + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/class.soap_val.php b/library/WebPlugin/Pay/Motopay/lib/class.soap_val.php new file mode 100644 index 0000000..c3618eb --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/class.soap_val.php @@ -0,0 +1,107 @@ +<?php + + + + +/** +* For creating serializable abstractions of native PHP types. This class +* allows element name/namespace, XSD type, and XML attributes to be +* associated with a value. This is extremely useful when WSDL is not +* used, but is also useful when WSDL is used with polymorphic types, including +* xsd:anyType and user-defined types. +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: class.soap_val.php,v 1.9 2005/07/27 19:24:42 snichol Exp $ +* @access public +*/ +class soapval extends nusoap_base { + /** + * The XML element name + * + * @var string + * @access private + */ + var $name; + /** + * The XML type name (string or false) + * + * @var mixed + * @access private + */ + var $type; + /** + * The PHP value + * + * @var mixed + * @access private + */ + var $value; + /** + * The XML element namespace (string or false) + * + * @var mixed + * @access private + */ + var $element_ns; + /** + * The XML type namespace (string or false) + * + * @var mixed + * @access private + */ + var $type_ns; + /** + * The XML element attributes (array or false) + * + * @var mixed + * @access private + */ + var $attributes; + + /** + * constructor + * + * @param string $name optional name + * @param mixed $type optional type name + * @param mixed $value optional value + * @param mixed $element_ns optional namespace of value + * @param mixed $type_ns optional namespace of type + * @param mixed $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) { + parent::nusoap_base(); + $this->name = $name; + $this->type = $type; + $this->value = $value; + $this->element_ns = $element_ns; + $this->type_ns = $type_ns; + $this->attributes = $attributes; + } + + /** + * return serialized value + * + * @param string $use The WSDL use value (encoded|literal) + * @return string XML data + * @access public + */ + 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 + * + * @return mixed + * @access public + */ + function decode(){ + return $this->value; + } +} + + + + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/class.soapclient.php b/library/WebPlugin/Pay/Motopay/lib/class.soapclient.php new file mode 100644 index 0000000..51e6345 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/class.soapclient.php @@ -0,0 +1,859 @@ +<?php + + + + +/** +* +* soapclient higher level class for easy usage. +* +* usage: +* +* // instantiate client with server info +* $soapclient = new soapclient( string path [ ,boolean wsdl] ); +* +* // call method, get results +* echo $soapclient->call( string methodname [ ,array parameters] ); +* +* // bye bye client +* unset($soapclient); +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: class.soapclient.php,v 1.52 2005/07/27 19:24:42 snichol Exp $ +* @access public +*/ +class soapclientw extends nusoap_base { + + var $username = ''; + var $password = ''; + var $authtype = ''; + var $certRequest = array(); + 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 $forceEndpoint = ''; // overrides WSDL endpoint + 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 = ''; // soap|wsdl, empty for WSDL initialization error + 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 + var $cookies = array(); // Cookies from response or for request + var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() + var $operations = array(); // WSDL operations, empty for WSDL initialization error + + /* + * fault related variables + */ + /** + * @var fault + * @access public + */ + var $fault; + /** + * @var faultcode + * @access public + */ + var $faultcode; + /** + * @var faultstring + * @access public + */ + var $faultstring; + /** + * @var faultdetail + * @access public + */ + var $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 soapclientw($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){ + parent::nusoap_base(); + $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){ + if (is_object($endpoint) && (get_class($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->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + // 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); + $this->endpointType = 'wsdl'; + } else { + $this->debug( 'getOperations returned false'); + $this->setError('no operations defined in the WSDL document!'); + } + } else { + $this->debug("instantiate SOAP with endpoint at $endpoint"); + $this->endpointType = 'soap'; + } + } + + /** + * calls method, returns PHP native type + * + * @param string $method SOAP server URL or path + * @param mixed $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 mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP 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 response from SOAP call + * @access public + */ + function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ + $this->operation = $operation; + $this->fault = false; + $this->setError(''); + $this->request = ''; + $this->response = ''; + $this->responseData = ''; + $this->faultstring = ''; + $this->faultcode = ''; + $this->opData = array(); + + $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); + $this->appendDebug('params=' . $this->varDump($params)); + $this->appendDebug('headers=' . $this->varDump($headers)); + if ($headers) { + $this->requestHeaders = $headers; + } + // serialize parameters + if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ + // use WSDL for operation + $this->opData = $opData; + $this->debug("found operation"); + $this->appendDebug('opData=' . $this->varDump($opData)); + if (isset($opData['soapAction'])) { + $soapAction = $opData['soapAction']; + } + if (! $this->forceEndpoint) { + $this->endpoint = $opData['endpoint']; + } else { + $this->endpoint = $this->forceEndpoint; + } + $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; + $style = $opData['style']; + $use = $opData['input']['use']; + // add ns to ns array + if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ + $nsPrefix = 'ns' . rand(1000, 9999); + $this->wsdl->namespaces[$nsPrefix] = $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; + if (isset($opData['input']['encodingStyle'])) { + $encodingStyle = $opData['input']['encodingStyle']; + } else { + $encodingStyle = ''; + } + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + 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->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->setError( 'operation '.$operation.' not present.'); + $this->debug("operation '$operation' not present."); + return false; + } else { + // no WSDL + //$this->namespaces['ns1'] = $namespace; + $nsPrefix = 'ns' . rand(1000, 9999); + // 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(); + if ($use == 'encoded') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } else { + $encodingStyle = ''; + } + } + // wrap RPC calls with method element + if ($style == 'rpc') { + if ($use == 'literal') { + $this->debug("wrapping RPC request with literal method element"); + if ($namespace) { + $payload = "<$operation xmlns=\"$namespace\">" . $payload . "</$operation>"; + } else { + $payload = "<$operation>" . $payload . "</$operation>"; + } + } else { + $this->debug("wrapping RPC request with encoded method element"); + if ($namespace) { + $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . + $payload . + "</$nsPrefix:$operation>"; + } else { + $payload = "<$operation>" . + $payload . + "</$operation>"; + } + } + } + // serialize envelope + $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); + $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); + $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . 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)); + $this->appendDebug('return=' . $this->varDump($return)); + + // 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<br>"); + } + return $return; + } elseif ($style == 'document') { + // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), + // we are only going to return the first part here...sorry about that + return $return; + } else { + // array of return values + if(is_array($return)){ + // multiple 'out' parameters, which we return wrapped up + // in the array + if(sizeof($return) > 1){ + return $return; + } + // single 'out' parameter (normally the return value) + $return = array_shift($return); + $this->debug('return shifted value: '); + $this->appendDebug($this->varDump($return)); + return $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) { + $this->checkCookies(); + // 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->authtype != '') { + $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); + } + 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,$this->cookies); + } 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 + $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); + } else { + $this->setError('no http/s in endpoint url'); + } + $this->request = $http->outgoing_payload; + $this->response = $http->incoming_payload; + $this->appendDebug($http->getDebug()); + $this->UpdateCookies($http->incoming_cookies); + + // save transport object if using persistent connections + if ($this->persistentConnection) { + $http->clearDebug(); + 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 private + */ + 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 for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $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->appendDebug($parser->getDebug()); + // 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; + } + } + + /** + * sets the SOAP endpoint, which can override WSDL + * + * @param $endpoint string The endpoint URL to use, or empty string or false to prevent override + * @access public + */ + function setEndpoint($endpoint) { + $this->forceEndpoint = $endpoint; + } + + /** + * set the SOAP headers + * + * @param $headers mixed String of XML with SOAP header content, or array of soapval objects for SOAP headers + * @access public + */ + function setHeaders($headers){ + $this->requestHeaders = $headers; + } + + /** + * get the SOAP response headers (namespace resolution incomplete) + * + * @return string + * @access public + */ + function getHeaders(){ + 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|certificate) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->certRequest = $certRequest; + } + + /** + * 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. + * + * @return boolean + * @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. + * + * This is no longer used. + * + * @param boolean $rpcParams + * @access public + * @deprecated + */ + function setDefaultRpcParams($rpcParams) { + $this->defaultRpcParams = $rpcParams; + } + + /** + * dynamically creates an instance of a proxy class, + * allowing user to directly call methods from wsdl + * + * @return object soap_proxy object + * @access public + */ + function getProxy(){ + $r = rand(); + $evalStr = $this->_getProxyClassCode($r); + //$this->debug("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->authtype = $this->authtype; + $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; + $proxy->requestHeaders = $this->requestHeaders; + $proxy->soap_defencoding = $this->soap_defencoding; + $proxy->endpoint = $this->endpoint; + $proxy->forceEndpoint = $this->forceEndpoint; + return $proxy; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access private + */ + function _getProxyClassCode($r) { + if ($this->endpointType != 'wsdl') { + $evalStr = 'A proxy can only be created for a WSDL client'; + $this->setError($evalStr); + return $evalStr; + } + $evalStr = ''; + foreach ($this->operations as $operation => $opData) { + if ($operation != '') { + // create param string and param comment string + if (sizeof($opData['input']['parts']) > 0) { + $paramStr = ''; + $paramArrayStr = ''; + $paramCommentStr = ''; + foreach ($opData['input']['parts'] as $name => $type) { + $paramStr .= "\$$name, "; + $paramArrayStr .= "'$name' => \$$name, "; + $paramCommentStr .= "$type \$$name, "; + } + $paramStr = substr($paramStr, 0, strlen($paramStr)-2); + $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); + $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); + } else { + $paramStr = ''; + $paramCommentStr = 'void'; + } + $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; + $evalStr .= "// $paramCommentStr + function " . str_replace('.', '__', $operation) . "($paramStr) { + \$params = array($paramArrayStr); + return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); + } + "; + unset($paramStr); + unset($paramCommentStr); + } + } + $evalStr = 'class soap_proxy_'.$r.' extends soapclientw { + '.$evalStr.' +}'; + return $evalStr; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access public + */ + function getProxyClassCode() { + $r = rand(); + return $this->_getProxyClassCode($r); + } + + /** + * 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 private + */ + 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 private + */ + 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 private + */ + 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; + } + + /** + * adds a new Cookie into $this->cookies array + * + * @param string $name Cookie Name + * @param string $value Cookie Value + * @return if cookie-set was successful returns true, else false + * @access public + */ + function setCookie($name, $value) { + if (strlen($name) == 0) { + return false; + } + $this->cookies[] = array('name' => $name, 'value' => $value); + return true; + } + + /** + * gets all Cookies + * + * @return array with all internal cookies + * @access public + */ + function getCookies() { + return $this->cookies; + } + + /** + * checks all Cookies and delete those which are expired + * + * @return always return true + * @access private + */ + function checkCookies() { + if (sizeof($this->cookies) == 0) { + return true; + } + $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); + $curr_cookies = $this->cookies; + $this->cookies = array(); + foreach ($curr_cookies as $cookie) { + if (! is_array($cookie)) { + $this->debug('Remove cookie that is not an array'); + continue; + } + if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { + if (strtotime($cookie['expires']) > time()) { + $this->cookies[] = $cookie; + } else { + $this->debug('Remove expired cookie ' . $cookie['name']); + } + } else { + $this->cookies[] = $cookie; + } + } + $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); + return true; + } + + /** + * updates the current cookies with a new set + * + * @param array $cookies new cookies with which to update current ones + * @return always return true + * @access private + */ + function UpdateCookies($cookies) { + if (sizeof($this->cookies) == 0) { + // no existing cookies: take whatever is new + if (sizeof($cookies) > 0) { + $this->debug('Setting new cookie(s)'); + $this->cookies = $cookies; + } + return true; + } + if (sizeof($cookies) == 0) { + // no new cookies: keep what we've got + return true; + } + // merge + foreach ($cookies as $newCookie) { + if (!is_array($newCookie)) { + continue; + } + if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { + continue; + } + $newName = $newCookie['name']; + + $found = false; + for ($i = 0; $i < count($this->cookies); $i++) { + $cookie = $this->cookies[$i]; + if (!is_array($cookie)) { + continue; + } + if (!isset($cookie['name'])) { + continue; + } + if ($newName != $cookie['name']) { + continue; + } + $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; + $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; + if ($newDomain != $domain) { + continue; + } + $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; + $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; + if ($newPath != $path) { + continue; + } + $this->cookies[$i] = $newCookie; + $found = true; + $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); + break; + } + if (! $found) { + $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); + $this->cookies[] = $newCookie; + } + } + return true; + } +} +?> diff --git a/library/WebPlugin/Pay/Motopay/lib/class.wsdl.php b/library/WebPlugin/Pay/Motopay/lib/class.wsdl.php new file mode 100644 index 0000000..0d41009 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/class.wsdl.php @@ -0,0 +1,1727 @@ +<?php + + + + +/** +* parses a WSDL file, allows access to it's data, other utility methods +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: class.wsdl.php,v 1.56 2005/08/04 01:27:42 snichol 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){ + parent::nusoap_base(); + $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'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . + 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'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . + 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); + } + $tr->setEncoding('gzip, deflate'); + $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->appendDebug($tr->getDebug()); + // catch errors + if($err = $tr->getError() ){ + $errstr = 'HTTP ERROR: '.$err; + $this->debug($errstr); + $this->setError($errstr); + unset($tr); + return false; + } + unset($tr); + $this->debug("got WSDL URL"); + } 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; + } + } + $this->debug('Parse WSDL'); + // 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); + $this->debug('Parsing WSDL done'); + // 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->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } elseif (ereg('schema$', $name)) { + $this->debug('Parsing WSDL schema'); + // $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->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } 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' => ''); + // process attributes + if (count($attrs) > 0) { + // register namespace declarations + foreach($attrs as $k => $v) { + 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' || $v == 'http://www.w3.org/2000/10/XMLSchema') { + $this->XMLSchemaVersion = $v; + $this->namespaces['xsi'] = $v . '-instance'; + } + } + } + // expand each attribute prefix to its namespace + foreach($attrs as $k => $v) { + $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(); + } + // get element prefix, namespace and name + 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); + } + // process attributes, expanding any prefixes to namespaces + // 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->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs)); + $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->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; + $this->debug('Parsing WSDL schema done'); + } + 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) { + // note that we could/should also check the namespace here + if ($operation == $bOperation) { + $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; + return $opData; + } + } + } + } + } + + /** + * returns an associative array of data necessary for calling an operation + * + * @param string $soapAction soapAction for operation + * @param string $bindingType type of binding eg: soap + * @return array + * @access public + */ + function getOperationDataForSoapAction($soapAction, $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) { + // loop through operations for the binding + foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { + if ($opData['soapAction'] == $soapAction) { + 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 the type + * @param $ns string namespace (not prefix) of the type + * @return mixed + * @access public + * @see xmlschema + */ + function getTypeDef($type, $ns) { + $this->debug("in getTypeDef: type=$type, ns=$ns"); + if ((! $ns) && isset($this->namespaces['tns'])) { + $ns = $this->namespaces['tns']; + $this->debug("in getTypeDef: type namespace forced to $ns"); + } + if (isset($this->schemas[$ns])) { + $this->debug("in getTypeDef: have schema for namespace $ns"); + for ($i = 0; $i < count($this->schemas[$ns]); $i++) { + $xs = &$this->schemas[$ns][$i]; + $t = $xs->getTypeDef($type); + $this->appendDebug($xs->getDebug()); + $xs->clearDebug(); + if ($t) { + if (!isset($t['phpType'])) { + // get info for type to tack onto the element + $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); + $ns = substr($t['type'], 0, strrpos($t['type'], ':')); + $etype = $this->getTypeDef($uqType, $ns); + if ($etype) { + $this->debug("found type for [element] $type:"); + $this->debug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $t['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $t['elements'] = $etype['elements']; + } + if (isset($etype['attrs'])) { + $t['attrs'] = $etype['attrs']; + } + } + } + return $t; + } + } + } else { + $this->debug("in getTypeDef: do not have schema for namespace $ns"); + } + return false; + } + + /** + * prints html description of services + * + * @access private + */ + function webDescription(){ + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $PHP_SELF = $_SERVER['PHP_SELF']; + } elseif (isset($HTTP_SERVER_VARS)) { + $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + + $b = ' + <html><head><title>NuSOAP: '.$this->serviceName.'</title> + <style type="text/css"> + body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; } + p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; } + pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;} + ul { margin-top: 10px; margin-left: 20px; } + li { list-style-type: none; margin-top: 10px; color: #000000; } + .content{ + margin-left: 0px; padding-bottom: 2em; } + .nav { + padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em; + margin-top: 10px; margin-left: 0px; color: #000000; + background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; } + .title { + font-family: arial; font-size: 26px; color: #ffffff; + background-color: #999999; width: 105%; margin-left: 0px; + padding-top: 10px; padding-bottom: 10px; padding-left: 15px;} + .hidden { + position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px; + font-family: arial; overflow: hidden; width: 600; + padding: 20px; font-size: 10px; background-color: #999999; + layer-background-color:#FFFFFF; } + a,a:active { color: charcoal; font-weight: bold; } + a:visited { color: #666666; font-weight: bold; } + a:hover { color: cc3300; font-weight: bold; } + </style> + <script language="JavaScript" type="text/javascript"> + <!-- + // POP-UP CAPTIONS... + function lib_bwcheck(){ //Browsercheck (needed) + this.ver=navigator.appVersion + this.agent=navigator.userAgent + this.dom=document.getElementById?1:0 + this.opera5=this.agent.indexOf("Opera 5")>-1 + this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0; + this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0; + this.ie4=(document.all && !this.dom && !this.opera5)?1:0; + this.ie=this.ie4||this.ie5||this.ie6 + this.mac=this.agent.indexOf("Mac")>-1 + this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; + this.ns4=(document.layers && !this.dom)?1:0; + this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5) + return this + } + var bw = new lib_bwcheck() + //Makes crossbrowser object. + function makeObj(obj){ + this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0; + if(!this.evnt) return false + this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0; + this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0; + this.writeIt=b_writeIt; + return this + } + // A unit of measure that will be added when setting the position of a layer. + //var px = bw.ns4||window.opera?"":"px"; + function b_writeIt(text){ + if (bw.ns4){this.wref.write(text);this.wref.close()} + else this.wref.innerHTML = text + } + //Shows the messages + var oDesc; + function popup(divid){ + if(oDesc = new makeObj(divid)){ + oDesc.css.visibility = "visible" + } + } + function popout(){ // Hides message + if(oDesc) oDesc.css.visibility = "hidden" + } + //--> + </script> + </head> + <body> + <div class=content> + <br><br> + <div class=title>'.$this->serviceName.'</div> + <div class=nav> + <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service. + Click on an operation name to view it's details.</p> + <ul>'; + foreach($this->getOperations() as $op => $data){ + $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>"; + // create hidden div + $b .= "<div id='$op' class='hidden'> + <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>"; + foreach($data as $donnie => $marie){ // loop through opdata + if($donnie == 'input' || $donnie == 'output'){ // show input/output data + $b .= "<font color='white'>".ucfirst($donnie).':</font><br>'; + foreach($marie as $captain => $tenille){ // loop through data + if($captain == 'parts'){ // loop thru parts + $b .= " $captain:<br>"; + //if(is_array($tenille)){ + foreach($tenille as $joanie => $chachi){ + $b .= " $joanie: $chachi<br>"; + } + //} + } else { + $b .= " $captain: $tenille<br>"; + } + } + } else { + $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>"; + } + } + $b .= '</div>'; + } + $b .= ' + <ul> + </div> + </div></body></html>'; + return $b; + } + + /** + * serialize the parsed wsdl + * + * @param mixed $debug whether to put debug=1 in endpoint URL + * @return string serialization of WSDL + * @access public + */ + function serialize($debug = 0) + { + $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>'; + $xml .= "\n<definitions"; + foreach($this->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 .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />'; + } else { + $xml .= '<import namespace="' . $ns . '" />'; + } + } + } + } + // types + if (count($this->schemas)>=1) { + $xml .= "\n<types>"; + foreach ($this->schemas as $ns => $list) { + foreach ($list as $xs) { + $xml .= $xs->serializeSchema(); + } + } + $xml .= '</types>'; + } + // messages + if (count($this->messages) >= 1) { + foreach($this->messages as $msgName => $msgParts) { + $xml .= "\n<message name=\"" . $msgName . '">'; + if(is_array($msgParts)){ + foreach($msgParts as $partName => $partType) { + // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>'; + if (strpos($partType, ':')) { + $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); + } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { + // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>'; + $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!"); + } + } + $ns = $this->getNamespaceFromPrefix($typePrefix); + $typeDef = $this->getTypeDef($this->getLocalPart($partType), $ns); + if ($typeDef['typeClass'] == 'element') { + $elementortype = 'element'; + } else { + $elementortype = 'type'; + } + $xml .= '<part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />'; + } + } + $xml .= '</message>'; + } + } + // bindings & porttypes + if (count($this->bindings) >= 1) { + $binding_xml = ''; + $portType_xml = ''; + foreach($this->bindings as $bindingName => $attrs) { + $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">'; + $binding_xml .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>'; + $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">'; + foreach($attrs['operations'] as $opName => $opParts) { + $binding_xml .= '<operation name="' . $opName . '">'; + $binding_xml .= '<soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>'; + if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= '<input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>'; + if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>'; + $binding_xml .= '</operation>'; + $portType_xml .= '<operation name="' . $opParts['name'] . '"'; + if (isset($opParts['parameterOrder'])) { + $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"'; + } + $portType_xml .= '>'; + if(isset($opParts['documentation']) && $opParts['documentation'] != '') { + $portType_xml .= '<documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>'; + } + $portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>'; + $portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>'; + $portType_xml .= '</operation>'; + } + $portType_xml .= '</portType>'; + $binding_xml .= '</binding>'; + } + $xml .= $portType_xml . $binding_xml; + } + // services + $xml .= "\n<service name=\"" . $this->serviceName . '">'; + if (count($this->ports) >= 1) { + foreach($this->ports as $pName => $attrs) { + $xml .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">'; + $xml .= '<soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>'; + $xml .= '</port>'; + } + } + $xml .= '</service>'; + return $xml . "\n</definitions>"; + } + + /** + * serialize PHP values according to a WSDL message definition + * + * TODO + * - multi-ref serialization + * - validate PHP values against type definitions, return errors if invalid + * + * @param string $operation operation name + * @param string $direction (input|output) + * @param mixed $parameters parameter value(s) + * @return mixed parameters serialized as XML or false on error (e.g. operation not found) + * @access public + */ + function serializeRPCParameters($operation, $direction, $parameters) + { + $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + 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('opData:'); + $this->appendDebug($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('have ' . count($opData[$direction]['parts']) . ' part(s) to serialize'); + if (is_array($parameters)) { + $parametersArrayType = $this->isArraySimpleOrStruct($parameters); + $this->debug('have ' . count($parameters) . ' parameter(s) provided as ' . $parametersArrayType . ' to serialize'); + 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.'); + } + } + $this->debug("serializeRPCParameters returning: $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 + * @access public + * @deprecated + */ + function serializeParameters($operation, $direction, $parameters) + { + $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + 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('opData:'); + $this->appendDebug($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.'); + } + } + $this->debug("serializeParameters returning: $xml"); + return $xml; + } + + /** + * serializes a PHP value according a given type definition + * + * @param string $name name of value (part or element) + * @param string $type XML schema type of value (type or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @param boolean $unqualified a kludge for what should be XML namespace form handling + * @return string value serialized as an XML string + * @access private + */ + function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) + { + $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); + $this->appendDebug("value=" . $this->varDump($value)); + if($use == 'encoded' && $encodingStyle) { + $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; + } + + // if a soapval has been supplied, let its type override the WSDL + if (is_object($value) && get_class($value) == 'soapval') { + if ($value->type_ns) { + $type = $value->type_ns . ':' . $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } elseif ($value->type) { + $type = $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } else { + $forceType = false; + $this->debug("in serializeType: soapval does not override type"); + } + $attrs = $value->attributes; + $value = $value->value; + $this->debug("in serializeType: soapval overrides value to $value"); + if ($attrs) { + if (!is_array($value)) { + $value['!'] = $value; + } + foreach ($attrs as $n => $v) { + $value['!' . $n] = $v; + } + $this->debug("in serializeType: soapval provides attributes"); + } + } else { + $forceType = false; + } + + $xml = ''; + if (strpos($type, ':')) { + $uqType = substr($type, strrpos($type, ':') + 1); + $ns = substr($type, 0, strrpos($type, ':')); + $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); + } + + if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ + $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); + if ($unqualified && $use == 'literal') { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + // TODO: depends on nillable, which should be checked before calling this method + $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if ($uqType == 'boolean') { + if ((is_string($value) && $value == 'false') || (! $value)) { + $value = 'false'; + } else { + $value = 'true'; + } + } + if ($uqType == 'string' && gettype($value) == 'string') { + $value = $this->expandEntities($value); + } + if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { + $value = sprintf("%.0lf", $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) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; + } else { + $xml = "<$name$elementNS>$value</$name>"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); + } else if ($ns == 'http://xml.apache.org/xml-soap') { + $this->debug('in serializeType: appears to be Apache SOAP type'); + if ($uqType == 'Map') { + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + if (! $tt_prefix) { + $this->debug('in serializeType: Add namespace for Apache SOAP type'); + $tt_prefix = 'ns' . rand(1000, 9999); + $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; + // force this to be added to usedNamespaces + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + } + $contents = ''; + foreach($value as $k => $v) { + $this->debug("serializing map element: key $k, value $v"); + $contents .= '<item>'; + $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); + $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); + $contents .= '</item>'; + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>"; + } else { + $xml = "<$name>$contents</$name>"; + } + } else { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('in serializeType: Apache SOAP type, but only support Map'); + } + } else { + // TODO: should the type be compared to types in XSD, and the namespace + // set to XSD if the type matches? + $this->debug("in serializeType: 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("in serializeType: $type ($uqType) is not a supported type."); + return false; + } else { + $this->debug("in serializeType: found typeDef"); + $this->appendDebug('typeDef=' . $this->varDump($typeDef)); + } + $phpType = $typeDef['phpType']; + $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); + // if php type == struct, map value to the <all> 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 { + $elementNS = " xmlns=\"\""; + } + } else { + $elementName = $name; + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$elementName$elementNS/>"; + } else { + $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if (is_object($value)) { + $value = get_object_vars($value); + } + if (is_array($value)) { + $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); + if ($use == 'literal') { + if ($forceType) { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; + } else { + $xml = "<$elementName$elementNS$elementAttrs>"; + } + } else { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; + } + + $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); + $xml .= "</$elementName>"; + } else { + $this->debug("in serializeType: phpType is struct, but value is not an array"); + $this->setError("phpType is struct, but value is not an array: see debug output for details"); + $xml = ''; + } + } elseif ($phpType == 'array') { + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + $xml = "<$name$elementNS xsi:nil=\"true\" 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'])."[0]\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + 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); + } + } + } 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 { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; + } else { + $xml = "<$name$elementNS>$value</$name>"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; + } + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + + /** + * serializes the attributes for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { + $xml = ''; + if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { + $this->debug("serialize attributes for XML Schema type $ns:$uqType"); + 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(); + } + foreach ($typeDef['attrs'] as $aName => $attrs) { + if (isset($xvalue['!' . $aName])) { + $xname = '!' . $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($xvalue[$aName])) { + $xname = $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($attrs['default'])) { + $xname = '!' . $aName; + $xvalue[$xname] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); + } else { + $xname = ''; + $this->debug("no value provided for attribute $aName"); + } + if ($xname) { + $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; + } + } + } else { + $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); + } + if (isset($typeDef['extensionBase'])) { + $ns = $this->getPrefix($typeDef['extensionBase']); + $uqType = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + } + if ($typeDef = $this->getTypeDef($uqType, $ns)) { + $this->debug("serialize attributes for extension base $ns:$uqType"); + $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); + } else { + $this->debug("extension base $ns:$uqType is not a supported type"); + } + } + return $xml; + } + + /** + * serializes the elements for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { + $xml = ''; + if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { + $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); + 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 (!isset($xvalue[$eName])) { + if (isset($attrs['default'])) { + $xvalue[$eName] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); + } + } + // if user took advantage of a minOccurs=0, then only serialize named parameters + if (isset($optionals) + && (!isset($xvalue[$eName])) + && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') + ){ + if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { + $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); + } + // do nothing + $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); + } else { + // get value + if (isset($xvalue[$eName])) { + $v = $xvalue[$eName]; + } else { + $v = null; + } + if (isset($attrs['form'])) { + $unqualified = ($attrs['form'] == 'unqualified'); + } else { + $unqualified = false; + } + if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { + $vv = $v; + foreach ($vv as $k => $v) { + if (isset($attrs['type']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $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']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $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("no elements to serialize for XML Schema type $ns:$uqType"); + } + if (isset($typeDef['extensionBase'])) { + $ns = $this->getPrefix($typeDef['extensionBase']); + $uqType = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + } + if ($typeDef = $this->getTypeDef($uqType, $ns)) { + $this->debug("serialize elements for extension base $ns:$uqType"); + $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); + } else { + $this->debug("extension base $ns:$uqType is not a supported type"); + } + } + return $xml; + } + + /** + * adds an XML Schema complex type to the WSDL types + * + * @param string name + * @param string typeClass (complexType|simpleType|attribute) + * @param string phpType: currently supported are array and struct (php assoc array) + * @param string compositor (all|sequence|choice) + * @param string restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param array elements = array ( name => array(name=>'',type=>'') ) + * @param array attrs = array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]')) + * @param string arrayType: namespace:name (xsd:string) + * @see xmlschema + * @access public + */ + 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 string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @see xmlschema + * @access public + */ + function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { + $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, $enumeration); + } + + /** + * adds an element to the WSDL types + * + * @param array $attrs attributes that must include name and type + * @see xmlschema + * @access public + */ + function addElement($attrs) { + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addElement($attrs); + } + + /** + * register an operation with the server + * + * @param string $name operation (method) name + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $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 Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @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 + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ + if ($use == 'encoded' && $encodingStyle == '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + if ($style == 'document') { + $elements = array(); + foreach ($in as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t); + } + $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); + $in = array('parameters' => 'tns:' . $name); + + $elements = array(); + foreach ($out as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t); + } + $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType')); + $out = array('parameters' => 'tns:' . $name . 'Response'); + } + + // 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; + } +} + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/class.wsdlcache.php b/library/WebPlugin/Pay/Motopay/lib/class.wsdlcache.php new file mode 100644 index 0000000..4258ea1 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/class.wsdlcache.php @@ -0,0 +1,184 @@ +<?php + + + +/** +* caches instances of the wsdl class +* +* @author Scott Nichol <snichol@computer.org> +* @author Ingo Fischer <ingo@apollon.de> +* @version $Id: class.wsdlcache.php,v 1.5 2005/05/20 17:58:17 snichol Exp $ +* @access public +*/ +class wsdlcache { + /** + * @var resource + * @access private + */ + var $fplock; + /** + * @var integer + * @access private + */ + var $cache_lifetime; + /** + * @var string + * @access private + */ + var $cache_dir; + /** + * @var string + * @access public + */ + var $debug_str = ''; + + /** + * constructor + * + * @param string $cache_dir directory for cache-files + * @param integer $cache_lifetime lifetime for caching-files in seconds or 0 for unlimited + * @access public + */ + function wsdlcache($cache_dir='.', $cache_lifetime=0) { + $this->fplock = array(); + $this->cache_dir = $cache_dir != '' ? $cache_dir : '.'; + $this->cache_lifetime = $cache_lifetime; + } + + /** + * creates the filename used to cache a wsdl instance + * + * @param string $wsdl The URL of the wsdl instance + * @return string The filename used to cache the instance + * @access private + */ + function createFilename($wsdl) { + return $this->cache_dir.'/wsdlcache-' . md5($wsdl); + } + + /** + * 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"; + } + + /** + * gets a wsdl instance from the cache + * + * @param string $wsdl The URL of the wsdl instance + * @return object wsdl The cached wsdl instance, null if the instance is not in the cache + * @access public + */ + function get($wsdl) { + $filename = $this->createFilename($wsdl); + if ($this->obtainMutex($filename, "r")) { + // check for expired WSDL that must be removed from the cache + if ($this->cache_lifetime > 0) { + if (file_exists($filename) && (time() - filemtime($filename) > $this->cache_lifetime)) { + unlink($filename); + $this->debug("Expired $wsdl ($filename) from cache"); + $this->releaseMutex($filename); + return null; + } + } + // see what there is to return + $fp = @fopen($filename, "r"); + if ($fp) { + $s = implode("", @file($filename)); + fclose($fp); + $this->debug("Got $wsdl ($filename) from cache"); + } else { + $s = null; + $this->debug("$wsdl ($filename) not in cache"); + } + $this->releaseMutex($filename); + return (!is_null($s)) ? unserialize($s) : null; + } else { + $this->debug("Unable to obtain mutex for $filename in get"); + } + return null; + } + + /** + * obtains the local mutex + * + * @param string $filename The Filename of the Cache to lock + * @param string $mode The open-mode ("r" or "w") or the file - affects lock-mode + * @return boolean Lock successfully obtained ?! + * @access private + */ + function obtainMutex($filename, $mode) { + if (isset($this->fplock[md5($filename)])) { + $this->debug("Lock for $filename already exists"); + return false; + } + $this->fplock[md5($filename)] = fopen($filename.".lock", "w"); + if ($mode == "r") { + return flock($this->fplock[md5($filename)], LOCK_SH); + } else { + return flock($this->fplock[md5($filename)], LOCK_EX); + } + } + + /** + * adds a wsdl instance to the cache + * + * @param object wsdl $wsdl_instance The wsdl instance to add + * @return boolean WSDL successfully cached + * @access public + */ + function put($wsdl_instance) { + $filename = $this->createFilename($wsdl_instance->wsdl); + $s = serialize($wsdl_instance); + if ($this->obtainMutex($filename, "w")) { + $fp = fopen($filename, "w"); + fputs($fp, $s); + fclose($fp); + $this->debug("Put $wsdl_instance->wsdl ($filename) in cache"); + $this->releaseMutex($filename); + return true; + } else { + $this->debug("Unable to obtain mutex for $filename in put"); + } + return false; + } + + /** + * releases the local mutex + * + * @param string $filename The Filename of the Cache to lock + * @return boolean Lock successfully released + * @access private + */ + function releaseMutex($filename) { + $ret = flock($this->fplock[md5($filename)], LOCK_UN); + fclose($this->fplock[md5($filename)]); + unset($this->fplock[md5($filename)]); + if (! $ret) { + $this->debug("Not able to release lock for $filename"); + } + return $ret; + } + + /** + * removes a wsdl instance from the cache + * + * @param string $wsdl The URL of the wsdl instance + * @return boolean Whether there was an instance to remove + * @access public + */ + function remove($wsdl) { + $filename = $this->createFilename($wsdl); + // ignore errors obtaining mutex + $this->obtainMutex($filename, "w"); + $ret = unlink($filename); + $this->debug("Removed ($ret) $wsdl ($filename) from cache"); + $this->releaseMutex($filename); + return $ret; + } +} +?> diff --git a/library/WebPlugin/Pay/Motopay/lib/class.xmlschema.php b/library/WebPlugin/Pay/Motopay/lib/class.xmlschema.php new file mode 100644 index 0000000..7a4ece4 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/class.xmlschema.php @@ -0,0 +1,906 @@ +<?php + + + + +/** +* parses an XML Schema, allows access to it's data, other utility methods +* no validation... yet. +* very experimental and limited. As is discussed on XML-DEV, I'm one of the people +* that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty +* tutorials I refer to :) +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: class.xmlschema.php,v 1.39 2005/08/04 01:27:42 snichol 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 $complexTypeStack = array(); + var $currentComplexType = null; + var $elements = array(); + var $elementStack = array(); + var $currentElement = null; + var $simpleTypes = array(); + var $simpleTypeStack = array(); + var $currentSimpleType = null; + // 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()){ + parent::nusoap_base(); + $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' || $v == 'http://www.w3.org/2000/10/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': // (optional) compositor content for a complexType + case 'choice': + case 'group': + 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': // complexType attribute + //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); + $this->xdebug("parsing attribute:"); + $this->appendDebug($this->varDump($attrs)); + if (!isset($attrs['form'])) { + $attrs['form'] = $this->schemaInfo['attributeFormDefault']; + } + 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($this->currentComplexType){ // This should *always* be + $this->complexTypes[$this->currentComplexType]['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 'complexContent': // (optional) content for a complexType + break; + case 'complexType': + array_push($this->complexTypeStack, $this->currentComplexType); + 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'; + // This is for constructs like + // <complexType name="ListOfString" base="soap:Array"> + // <sequence> + // <element name="string" type="xsd:string" + // minOccurs="0" maxOccurs="unbounded" /> + // </sequence> + // </complexType> + if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ + $this->xdebug('complexType is unusual array'); + $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'; + // This is for constructs like + // <complexType name="ListOfString" base="soap:Array"> + // <sequence> + // <element name="string" type="xsd:string" + // minOccurs="0" maxOccurs="unbounded" /> + // </sequence> + // </complexType> + if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ + $this->xdebug('complexType is unusual array'); + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } else { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + } + } + break; + case 'element': + array_push($this->elementStack, $this->currentElement); + // 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['form'])) { + $attrs['form'] = $this->schemaInfo['elementFormDefault']; + } + if(isset($attrs['type'])){ + $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); + if (! $this->getPrefix($attrs['type'])) { + if ($this->defaultNamespace[$pos]) { + $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; + $this->xdebug('used default namespace to make type ' . $attrs['type']); + } + } + // This is for constructs like + // <complexType name="ListOfString" base="soap:Array"> + // <sequence> + // <element name="string" type="xsd:string" + // minOccurs="0" maxOccurs="unbounded" /> + // </sequence> + // </complexType> + if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { + $this->xdebug('arrayType for unusual array is ' . $attrs['type']); + $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; + } + $this->currentElement = $attrs['name']; + $this->elements[ $attrs['name'] ] = $attrs; + $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; + $ename = $attrs['name']; + } elseif(isset($attrs['ref'])){ + $this->xdebug("processing element as ref to ".$attrs['ref']); + $this->currentElement = "ref to ".$attrs['ref']; + $ename = $this->getLocalPart($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'; + $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType'; + $this->elements[ $attrs['name'] ]['type'] = $attrs['type']; + $ename = $attrs['name']; + } + if(isset($ename) && $this->currentComplexType){ + $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; + } + break; + case 'enumeration': // restriction value list member + $this->xdebug('enumeration ' . $attrs['value']); + if ($this->currentSimpleType) { + $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; + } elseif ($this->currentComplexType) { + $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; + } + break; + case 'extension': // simpleContent or complexContent type extension + $this->xdebug('extension ' . $attrs['base']); + if ($this->currentComplexType) { + $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; + } + 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 'list': // simpleType value list + break; + case 'restriction': // simpleType, simpleContent or complexContent value restriction + $this->xdebug('restriction ' . $attrs['base']); + if($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'; + } + if (!isset($attrs['attributeFormDefault'])) { + $this->schemaInfo['attributeFormDefault'] = 'unqualified'; + } + break; + case 'simpleContent': // (optional) content for a complexType + break; + case 'simpleType': + array_push($this->simpleTypeStack, $this->currentSimpleType); + 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 { + $this->xdebug('processing unnamed simpleType for element '.$this->currentElement); + $this->currentSimpleType = $this->currentElement . '_ContainedType'; + //$this->currentElement = false; + $this->simpleTypes[$this->currentSimpleType] = $attrs; + $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; + } + break; + case 'union': // simpleType type list + 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]; + } + // get element prefix + if ($prefix = $this->getPrefix($name)){ + // get unqualified name + $name = $this->getLocalPart($name); + } else { + $prefix = ''; + } + // move on... + if($name == 'complexType'){ + $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); + $this->currentComplexType = array_pop($this->complexTypeStack); + //$this->currentElement = false; + } + if($name == 'element'){ + $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); + $this->currentElement = array_pop($this->elementStack); + } + if($name == 'simpleType'){ + $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); + $this->currentSimpleType = array_pop($this->simpleTypeStack); + } + } + + /** + * 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']) . "\""; + foreach ($eParts as $aName => $aValue) { + // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable + if ($aName != 'name' && $aName != 'type') { + $contentStr .= " $aName=\"$aValue\""; + } + } + $contentStr .= "/>\n"; + } + } + // compositor wraps elements + if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { + $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n"; + } + } + // attributes + if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ + foreach($attrs['attrs'] as $attr => $aParts){ + $contentStr .= " <$schemaPrefix:attribute"; + foreach ($aParts as $a => $v) { + if ($a == 'ref' || $a == 'type') { + $contentStr .= " $a=\"".$this->contractQName($v).'"'; + } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { + $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; + $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; + } else { + $contentStr .= " $a=\"$v\""; + } + } + $contentStr .= "/>\n"; + } + } + // if restriction + if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ + $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n"; + // complex or simple content + if ((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 => $eParts){ + $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\"/>\n"; + if (isset($eParts['enumeration'])) { + foreach ($eParts['enumeration'] as $e) { + $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; + } + } + $xml .= " </$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 + * @deprecated + */ + function getPHPType($type,$ns){ + if(isset($this->typemap[$ns][$type])){ + //print "found type '$type' and ns $ns in typemap<br>"; + return $this->typemap[$ns][$type]; + } elseif(isset($this->complexTypes[$type])){ + //print "getting type '$type' and ns $ns from complexTypes array<br>"; + return $this->complexTypes[$type]['phpType']; + } + return false; + } + + /** + * returns an associative array of information about a given type + * returns false if no type exists by the given name + * + * For a complexType typeDef = array( + * 'restrictionBase' => '', + * 'phpType' => '', + * 'compositor' => '(sequence|all)', + * 'elements' => array(), // refs to elements array + * 'attrs' => array() // refs to attributes array + * ... and so on (see addComplexType) + * ) + * + * For simpleType or element, the array has different keys. + * + * @param string + * @return mixed + * @access public + * @see addComplexType + * @see addSimpleType + * @see addElement + */ + 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) { + $this->xdebug("in getTypeDef, found type for simpleType $type:"); + $this->xdebug($this->varDump($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) { + $this->xdebug("in getTypeDef, found type for element $type:"); + $this->xdebug($this->varDump($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->xdebug("in getTypeDef, element $type is an XSD type"); + $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]; + } elseif (ereg('_ContainedType$', $type)) { + $this->xdebug("in getTypeDef, have an untyped element $type"); + $typeDef['typeClass'] = 'simpleType'; + $typeDef['phpType'] = 'scalar'; + $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; + return $typeDef; + } + $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 + * @deprecated + */ + function serializeTypeDef($type){ + //print "in sTD() for type $type<br>"; + 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 + * @deprecated + */ + function typeToForm($name,$type){ + // get typedef + if($typeDef = $this->getTypeDef($type)){ + // if struct + if($typeDef['phpType'] == 'struct'){ + $buffer .= '<table>'; + foreach($typeDef['elements'] as $child => $childDef){ + $buffer .= " + <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td> + <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>"; + } + $buffer .= '</table>'; + // if array + } elseif($typeDef['phpType'] == 'array'){ + $buffer .= '<table>'; + for($i=0;$i < 3; $i++){ + $buffer .= " + <tr><td align='right'>array item (type: $typeDef[arrayType]):</td> + <td><input type='text' name='parameters[".$name."][]'></td></tr>"; + } + $buffer .= '</table>'; + // if scalar + } else { + $buffer .= "<input type='text' name='parameters[$name]'>"; + } + } else { + $buffer .= "<input type='text' name='parameters[$name]'>"; + } + 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) + * @access public + * @see getTypeDef + */ + 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->appendDebug($this->varDump($this->complexTypes[$name])); + } + + /** + * adds a simple type to the schema + * + * @param string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @access public + * @see xmlschema + * @see getTypeDef + */ + function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { + $this->simpleTypes[$name] = array( + 'name' => $name, + 'typeClass' => $typeClass, + 'phpType' => $phpType, + 'type' => $restrictionBase, + 'enumeration' => $enumeration + ); + + $this->xdebug("addSimpleType $name:"); + $this->appendDebug($this->varDump($this->simpleTypes[$name])); + } + + /** + * adds an element to the schema + * + * @param array $attrs attributes that must include name and type + * @see xmlschema + * @access public + */ + function addElement($attrs) { + if (! $this->getPrefix($attrs['type'])) { + $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; + } + $this->elements[ $attrs['name'] ] = $attrs; + $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; + + $this->xdebug("addElement " . $attrs['name']); + $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); + } +} + + + + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Motopay/lib/nusoap.php b/library/WebPlugin/Pay/Motopay/lib/nusoap.php new file mode 100644 index 0000000..dc34d2b --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/nusoap.php @@ -0,0 +1,7241 @@ +<?php + +/* +$Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ + +NuSOAP - Web Services Toolkit for PHP + +Copyright (c) 2002 NuSphere Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +If you have any questions or comments, please email: + +Dietrich Ayala +dietrich@ganx4.com +http://dietrich.ganx4.com/nusoap + +NuSphere Corporation +http://www.nusphere.com + +*/ + +/* load classes + +// necessary classes +require_once('class.soapclient.php'); +require_once('class.soap_val.php'); +require_once('class.soap_parser.php'); +require_once('class.soap_fault.php'); + +// transport classes +require_once('class.soap_transport_http.php'); + +// optional add-on classes +require_once('class.xmlschema.php'); +require_once('class.wsdl.php'); + +// server class +require_once('class.soap_server.php');*/ + +// class variable emulation +// cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html +@$GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9; + +/** +* +* nusoap_base +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ +* @access public +*/ +class nusoap_base { + /** + * Identification for HTTP headers. + * + * @var string + * @access private + */ + var $title = 'NuSOAP'; + /** + * Version for HTTP headers. + * + * @var string + * @access private + */ + var $version = '0.7.2'; + /** + * CVS revision for HTTP headers. + * + * @var string + * @access private + */ + var $revision = '$Revision: 1.94 $'; + /** + * Current error string (manipulated by getError/setError) + * + * @var string + * @access private + */ + var $error_str = ''; + /** + * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) + * + * @var string + * @access private + */ + var $debug_str = ''; + /** + * toggles automatic encoding of special characters as entities + * (should always be true, I think) + * + * @var boolean + * @access private + */ + var $charencoding = true; + /** + * the debug level for this instance + * + * @var integer + * @access private + */ + var $debugLevel; + + /** + * set schema version + * + * @var string + * @access public + */ + var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; + + /** + * charset encoding for outgoing messages + * + * @var string + * @access public + */ + var $soap_defencoding = 'ISO-8859-1'; + //var $soap_defencoding = 'UTF-8'; + + /** + * namespaces in an array of prefix => uri + * + * this is "seeded" by a set of constants, but it may be altered by code + * + * @var array + * @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/' + ); + + /** + * namespaces used in the current context, e.g. during serialization + * + * @var array + * @access private + */ + var $usedNamespaces = array(); + + /** + * XML Schema types in an array of uri => (array of xml type => php type) + * is this legacy yet? + * no, this is used by the xmlschema class to verify type => namespace mappings. + * @var array + * @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', + // abstract "any" types + 'anyType'=>'string','anySimpleType'=>'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/2000/10/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://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') + ); + + /** + * XML entities to convert + * + * @var array + * @access public + * @deprecated + * @see expandEntities + */ + var $xmlEntities = array('quot' => '"','amp' => '&', + 'lt' => '<','gt' => '>','apos' => "'"); + + /** + * constructor + * + * @access public + */ + function nusoap_base() { + $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; + } + + /** + * gets the global debug level, which applies to future instances + * + * @return integer Debug level 0-9, where 0 turns off + * @access public + */ + function getGlobalDebugLevel() { + return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; + } + + /** + * sets the global debug level, which applies to future instances + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setGlobalDebugLevel($level) { + $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level; + } + + /** + * gets the debug level for this instance + * + * @return int Debug level 0-9, where 0 turns off + * @access public + */ + function getDebugLevel() { + return $this->debugLevel; + } + + /** + * sets the debug level for this instance + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setDebugLevel($level) { + $this->debugLevel = $level; + } + + /** + * adds debug data to the instance debug string with formatting + * + * @param string $string debug data + * @access private + */ + function debug($string){ + if ($this->debugLevel > 0) { + $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); + } + } + + /** + * adds debug data to the instance debug string without formatting + * + * @param string $string debug data + * @access public + */ + function appendDebug($string){ + if ($this->debugLevel > 0) { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str .= $string; + } + } + + /** + * clears the current debug data for this instance + * + * @access public + */ + function clearDebug() { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str = ''; + } + + /** + * gets the current debug data for this instance + * + * @return debug data + * @access public + */ + function &getDebug() { + // it would be nice to use a memory stream here to use + // memory more efficiently + return $this->debug_str; + } + + /** + * gets the current debug data for this instance as an XML comment + * this may change the contents of the debug data + * + * @return debug data as an XML comment + * @access public + */ + function &getDebugAsXMLComment() { + // it would be nice to use a memory stream here to use + // memory more efficiently + while (strpos($this->debug_str, '--')) { + $this->debug_str = str_replace('--', '- -', $this->debug_str); + } + return "<!--\n" . $this->debug_str . "\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 mixed error string or false + * @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 mixed $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'. + * + * @param mixed $val The value to serialize + * @param string $name The name (local part) of the XML element + * @param string $type The XML schema type (local part) for the element + * @param string $name_ns The namespace for the name of the XML element + * @param string $type_ns The namespace for the type of the element + * @param array $attributes The attributes to serialize as name=>value pairs + * @param string $use The WSDL "use" (encoded|literal) + * @return string The serialized element, possibly with child elements + * @access public + */ + function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){ + $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use"); + $this->appendDebug('value=' . $this->varDump($val)); + $this->appendDebug('attributes=' . $this->varDump($attributes)); + + if(is_object($val) && get_class($val) == 'soapval'){ + return $val->serialize($use); + } + // force valid name if necessary + if (is_numeric($name)) { + $name = '__numeric_' . $name; + } elseif (! $name) { + $name = 'noname'; + } + // 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=\"".$this->expandEntities($v).'"'; + } + } + // serialize null value + if (is_null($val)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + return "<$name$xmlns $atts/>"; + } else { + if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + return "<$name$xmlns$type_str $atts xsi:nil=\"true\"/>"; + } + } + // 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 $atts>$val</$name>"; + } else { + return "<$name$xmlns $atts xsi:type=\"xsd:$type\">$val</$name>"; + } + } + // detect type and serialize + $xml = ''; + switch(true) { + 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): + if (! $name) { + $name = get_class($val); + $this->debug("In serialize_val, used class name $name as element name"); + } else { + $this->debug("In serialize_val, do not override name $name for element name for class " . 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; + // TODO: for literal, the name should be $name + $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); + ++$i; + } + if(count($array_types) > 1){ + $array_typename = 'xsd:anyType'; + } 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\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; + } + } + // TODO: for array in literal, there is no wrapper here + $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 .= '<item>'; + $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); + $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); + $xml .= '</item>'; + } 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; + } + + /** + * serializes a message + * + * @param string $body the XML of the SOAP body + * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers + * @param array $namespaces optional the namespaces used in generating the body and headers + * @param string $style optional (rpc|document) + * @param string $use optional (encoded|literal) + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @return string the message + * @access public + */ + function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ + // 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 + + $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); + $this->debug("headers:"); + $this->appendDebug($this->varDump($headers)); + $this->debug("namespaces:"); + $this->appendDebug($this->varDump($namespaces)); + + // serialize namespaces + $ns_string = ''; + foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ + $ns_string .= " xmlns:$k=\"$v\""; + } + if($encodingStyle) { + $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; + } + + // serialize headers + if($headers){ + if (is_array($headers)) { + $xml = ''; + foreach ($headers as $header) { + $xml .= $this->serialize_val($header, false, false, false, false, false, $use); + } + $headers = $xml; + $this->debug("In serializeEnvelope, serialzied array of headers to $headers"); + } + $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>"; + } + // serialize envelope + return + '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">". + '<SOAP-ENV:Envelope'.$ns_string.">". + $headers. + "<SOAP-ENV:Body>". + $body. + "</SOAP-ENV:Body>". + "</SOAP-ENV:Envelope>"; + } + + /** + * formats a string to be inserted into an HTML stream + * + * @param string $str The string to format + * @return string The formatted string + * @access public + * @deprecated + */ + function formatDump($str){ + $str = htmlspecialchars($str); + return nl2br($str); + } + + /** + * contracts (changes namespace to prefix) a qualified name + * + * @param string $qname 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 (changes prefix to namespace) 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 $str The prefixed string + * @return string The local part + * @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 $str The prefixed string + * @return mixed The prefix or false if there is no prefix + * @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 + * + * @param string $prefix The prefix + * @return mixed The namespace, false if no namespace has the specified prefix + * @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 $ns The namespace + * @return mixed The prefix, false if the namespace has no prefixes + * @access public + */ + function getPrefixFromNamespace($ns) { + foreach ($this->namespaces as $p => $n) { + if ($ns == $n || $ns == $p) { + $this->usedNamespaces[$p] = $n; + return $p; + } + } + return false; + } + + /** + * returns the time in ODBC canonical form with microseconds + * + * @return string The time in ODBC canonical form with microseconds + * @access public + */ + function getmicrotime() { + if (function_exists('gettimeofday')) { + $tod = gettimeofday(); + $sec = $tod['sec']; + $usec = $tod['usec']; + } else { + $sec = time(); + $usec = 0; + } + return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); + } + + /** + * Returns a string with the output of var_dump + * + * @param mixed $data The variable to var_dump + * @return string The output of var_dump + * @access public + */ + function varDump($data) { + ob_start(); + var_dump($data); + $ret_val = ob_get_contents(); + ob_end_clean(); + return $ret_val; + } +} + +// 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; + } +} + +/** +* sleeps some number of microseconds +* +* @param string $usec the number of microseconds to sleep +* @access public +* @deprecated +*/ +function usleepWindows($usec) +{ + $start = gettimeofday(); + + do + { + $stop = gettimeofday(); + $timePassed = 1000000 * ($stop['sec'] - $start['sec']) + + $stop['usec'] - $start['usec']; + } + while ($timePassed < $usec); +} + +?><?php + + + +/** +* Contains information for a SOAP fault. +* Mainly used for returning faults from deployed functions +* in a server instance. +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ +* @access public +*/ +class soap_fault extends nusoap_base { + /** + * The fault code (client|server) + * @var string + * @access private + */ + var $faultcode; + /** + * The fault actor + * @var string + * @access private + */ + var $faultactor; + /** + * The fault string, a description of the fault + * @var string + * @access private + */ + var $faultstring; + /** + * The fault detail, typically a string or array of string + * @var mixed + * @access private + */ + 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 mixed $faultdetail detail, typically a string or array of string + */ + function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ + parent::nusoap_base(); + $this->faultcode = $faultcode; + $this->faultactor = $faultactor; + $this->faultstring = $faultstring; + $this->faultdetail = $faultdetail; + } + + /** + * serialize a fault + * + * @return string The serialization of the fault instance. + * @access public + */ + function serialize(){ + $ns_string = ''; + foreach($this->namespaces as $k => $v){ + $ns_string .= "\n xmlns:$k=\"$v\""; + } + $return_msg = + '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'. + '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n". + '<SOAP-ENV:Body>'. + '<SOAP-ENV:Fault>'. + $this->serialize_val($this->faultcode, 'faultcode'). + $this->serialize_val($this->faultactor, 'faultactor'). + $this->serialize_val($this->faultstring, 'faultstring'). + $this->serialize_val($this->faultdetail, 'detail'). + '</SOAP-ENV:Fault>'. + '</SOAP-ENV:Body>'. + '</SOAP-ENV:Envelope>'; + return $return_msg; + } +} + + + +?><?php + + + +/** +* parses an XML Schema, allows access to it's data, other utility methods +* no validation... yet. +* very experimental and limited. As is discussed on XML-DEV, I'm one of the people +* that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty +* tutorials I refer to :) +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol 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 $complexTypeStack = array(); + var $currentComplexType = null; + var $elements = array(); + var $elementStack = array(); + var $currentElement = null; + var $simpleTypes = array(); + var $simpleTypeStack = array(); + var $currentSimpleType = null; + // 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()){ + parent::nusoap_base(); + $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' || $v == 'http://www.w3.org/2000/10/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': // (optional) compositor content for a complexType + case 'choice': + case 'group': + 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': // complexType attribute + //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); + $this->xdebug("parsing attribute:"); + $this->appendDebug($this->varDump($attrs)); + if (!isset($attrs['form'])) { + $attrs['form'] = $this->schemaInfo['attributeFormDefault']; + } + 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($this->currentComplexType){ // This should *always* be + $this->complexTypes[$this->currentComplexType]['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 'complexContent': // (optional) content for a complexType + break; + case 'complexType': + array_push($this->complexTypeStack, $this->currentComplexType); + 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'; + // This is for constructs like + // <complexType name="ListOfString" base="soap:Array"> + // <sequence> + // <element name="string" type="xsd:string" + // minOccurs="0" maxOccurs="unbounded" /> + // </sequence> + // </complexType> + if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ + $this->xdebug('complexType is unusual array'); + $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'; + // This is for constructs like + // <complexType name="ListOfString" base="soap:Array"> + // <sequence> + // <element name="string" type="xsd:string" + // minOccurs="0" maxOccurs="unbounded" /> + // </sequence> + // </complexType> + if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ + $this->xdebug('complexType is unusual array'); + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } else { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + } + } + break; + case 'element': + array_push($this->elementStack, $this->currentElement); + // 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['form'])) { + $attrs['form'] = $this->schemaInfo['elementFormDefault']; + } + if(isset($attrs['type'])){ + $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); + if (! $this->getPrefix($attrs['type'])) { + if ($this->defaultNamespace[$pos]) { + $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; + $this->xdebug('used default namespace to make type ' . $attrs['type']); + } + } + // This is for constructs like + // <complexType name="ListOfString" base="soap:Array"> + // <sequence> + // <element name="string" type="xsd:string" + // minOccurs="0" maxOccurs="unbounded" /> + // </sequence> + // </complexType> + if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { + $this->xdebug('arrayType for unusual array is ' . $attrs['type']); + $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; + } + $this->currentElement = $attrs['name']; + $this->elements[ $attrs['name'] ] = $attrs; + $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; + $ename = $attrs['name']; + } elseif(isset($attrs['ref'])){ + $this->xdebug("processing element as ref to ".$attrs['ref']); + $this->currentElement = "ref to ".$attrs['ref']; + $ename = $this->getLocalPart($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'; + $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType'; + $this->elements[ $attrs['name'] ]['type'] = $attrs['type']; + $ename = $attrs['name']; + } + if(isset($ename) && $this->currentComplexType){ + $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; + } + break; + case 'enumeration': // restriction value list member + $this->xdebug('enumeration ' . $attrs['value']); + if ($this->currentSimpleType) { + $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; + } elseif ($this->currentComplexType) { + $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; + } + break; + case 'extension': // simpleContent or complexContent type extension + $this->xdebug('extension ' . $attrs['base']); + if ($this->currentComplexType) { + $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; + } + 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 'list': // simpleType value list + break; + case 'restriction': // simpleType, simpleContent or complexContent value restriction + $this->xdebug('restriction ' . $attrs['base']); + if($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'; + } + if (!isset($attrs['attributeFormDefault'])) { + $this->schemaInfo['attributeFormDefault'] = 'unqualified'; + } + break; + case 'simpleContent': // (optional) content for a complexType + break; + case 'simpleType': + array_push($this->simpleTypeStack, $this->currentSimpleType); + 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 { + $this->xdebug('processing unnamed simpleType for element '.$this->currentElement); + $this->currentSimpleType = $this->currentElement . '_ContainedType'; + //$this->currentElement = false; + $this->simpleTypes[$this->currentSimpleType] = $attrs; + $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; + } + break; + case 'union': // simpleType type list + 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]; + } + // get element prefix + if ($prefix = $this->getPrefix($name)){ + // get unqualified name + $name = $this->getLocalPart($name); + } else { + $prefix = ''; + } + // move on... + if($name == 'complexType'){ + $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); + $this->currentComplexType = array_pop($this->complexTypeStack); + //$this->currentElement = false; + } + if($name == 'element'){ + $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); + $this->currentElement = array_pop($this->elementStack); + } + if($name == 'simpleType'){ + $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); + $this->currentSimpleType = array_pop($this->simpleTypeStack); + } + } + + /** + * 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']) . "\""; + foreach ($eParts as $aName => $aValue) { + // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable + if ($aName != 'name' && $aName != 'type') { + $contentStr .= " $aName=\"$aValue\""; + } + } + $contentStr .= "/>\n"; + } + } + // compositor wraps elements + if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { + $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n"; + } + } + // attributes + if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ + foreach($attrs['attrs'] as $attr => $aParts){ + $contentStr .= " <$schemaPrefix:attribute"; + foreach ($aParts as $a => $v) { + if ($a == 'ref' || $a == 'type') { + $contentStr .= " $a=\"".$this->contractQName($v).'"'; + } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { + $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; + $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; + } else { + $contentStr .= " $a=\"$v\""; + } + } + $contentStr .= "/>\n"; + } + } + // if restriction + if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ + $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n"; + // complex or simple content + if ((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 => $eParts){ + $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\"/>\n"; + if (isset($eParts['enumeration'])) { + foreach ($eParts['enumeration'] as $e) { + $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; + } + } + $xml .= " </$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 + * @deprecated + */ + function getPHPType($type,$ns){ + if(isset($this->typemap[$ns][$type])){ + //print "found type '$type' and ns $ns in typemap<br>"; + return $this->typemap[$ns][$type]; + } elseif(isset($this->complexTypes[$type])){ + //print "getting type '$type' and ns $ns from complexTypes array<br>"; + return $this->complexTypes[$type]['phpType']; + } + return false; + } + + /** + * returns an associative array of information about a given type + * returns false if no type exists by the given name + * + * For a complexType typeDef = array( + * 'restrictionBase' => '', + * 'phpType' => '', + * 'compositor' => '(sequence|all)', + * 'elements' => array(), // refs to elements array + * 'attrs' => array() // refs to attributes array + * ... and so on (see addComplexType) + * ) + * + * For simpleType or element, the array has different keys. + * + * @param string + * @return mixed + * @access public + * @see addComplexType + * @see addSimpleType + * @see addElement + */ + 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) { + $this->xdebug("in getTypeDef, found type for simpleType $type:"); + $this->xdebug($this->varDump($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) { + $this->xdebug("in getTypeDef, found type for element $type:"); + $this->xdebug($this->varDump($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->xdebug("in getTypeDef, element $type is an XSD type"); + $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]; + } elseif (ereg('_ContainedType$', $type)) { + $this->xdebug("in getTypeDef, have an untyped element $type"); + $typeDef['typeClass'] = 'simpleType'; + $typeDef['phpType'] = 'scalar'; + $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; + return $typeDef; + } + $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 + * @deprecated + */ + function serializeTypeDef($type){ + //print "in sTD() for type $type<br>"; + 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 + * @deprecated + */ + function typeToForm($name,$type){ + // get typedef + if($typeDef = $this->getTypeDef($type)){ + // if struct + if($typeDef['phpType'] == 'struct'){ + $buffer .= '<table>'; + foreach($typeDef['elements'] as $child => $childDef){ + $buffer .= " + <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td> + <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>"; + } + $buffer .= '</table>'; + // if array + } elseif($typeDef['phpType'] == 'array'){ + $buffer .= '<table>'; + for($i=0;$i < 3; $i++){ + $buffer .= " + <tr><td align='right'>array item (type: $typeDef[arrayType]):</td> + <td><input type='text' name='parameters[".$name."][]'></td></tr>"; + } + $buffer .= '</table>'; + // if scalar + } else { + $buffer .= "<input type='text' name='parameters[$name]'>"; + } + } else { + $buffer .= "<input type='text' name='parameters[$name]'>"; + } + 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) + * @access public + * @see getTypeDef + */ + 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->appendDebug($this->varDump($this->complexTypes[$name])); + } + + /** + * adds a simple type to the schema + * + * @param string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @access public + * @see xmlschema + * @see getTypeDef + */ + function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { + $this->simpleTypes[$name] = array( + 'name' => $name, + 'typeClass' => $typeClass, + 'phpType' => $phpType, + 'type' => $restrictionBase, + 'enumeration' => $enumeration + ); + + $this->xdebug("addSimpleType $name:"); + $this->appendDebug($this->varDump($this->simpleTypes[$name])); + } + + /** + * adds an element to the schema + * + * @param array $attrs attributes that must include name and type + * @see xmlschema + * @access public + */ + function addElement($attrs) { + if (! $this->getPrefix($attrs['type'])) { + $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; + } + $this->elements[ $attrs['name'] ] = $attrs; + $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; + + $this->xdebug("addElement " . $attrs['name']); + $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); + } +} + + + +?><?php + + + +/** +* For creating serializable abstractions of native PHP types. This class +* allows element name/namespace, XSD type, and XML attributes to be +* associated with a value. This is extremely useful when WSDL is not +* used, but is also useful when WSDL is used with polymorphic types, including +* xsd:anyType and user-defined types. +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ +* @access public +*/ +class soapval extends nusoap_base { + /** + * The XML element name + * + * @var string + * @access private + */ + var $name; + /** + * The XML type name (string or false) + * + * @var mixed + * @access private + */ + var $type; + /** + * The PHP value + * + * @var mixed + * @access private + */ + var $value; + /** + * The XML element namespace (string or false) + * + * @var mixed + * @access private + */ + var $element_ns; + /** + * The XML type namespace (string or false) + * + * @var mixed + * @access private + */ + var $type_ns; + /** + * The XML element attributes (array or false) + * + * @var mixed + * @access private + */ + var $attributes; + + /** + * constructor + * + * @param string $name optional name + * @param mixed $type optional type name + * @param mixed $value optional value + * @param mixed $element_ns optional namespace of value + * @param mixed $type_ns optional namespace of type + * @param mixed $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) { + parent::nusoap_base(); + $this->name = $name; + $this->type = $type; + $this->value = $value; + $this->element_ns = $element_ns; + $this->type_ns = $type_ns; + $this->attributes = $attributes; + } + + /** + * return serialized value + * + * @param string $use The WSDL use value (encoded|literal) + * @return string XML data + * @access public + */ + 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 + * + * @return mixed + * @access public + */ + function decode(){ + return $this->value; + } +} + + + +?><?php + + + +/** +* transport class for sending/receiving data via HTTP and HTTPS +* NOTE: PHP must be compiled with the CURL extension for HTTPS support +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ +* @access public +*/ +class soap_transport_http extends nusoap_base { + + var $url = ''; + var $uri = ''; + var $digest_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 $incoming_cookies = array(); + var $outgoing_payload = ''; + var $incoming_payload = ''; + var $useSOAPAction = true; + var $persistentConnection = false; + var $ch = false; // cURL handle + var $username = ''; + var $password = ''; + var $authtype = ''; + var $digestRequest = array(); + var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional) + // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' + // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' + // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' + // passphrase: SSL key password/passphrase + // verifypeer: default is 1 + // verifyhost: default is 1 + + /** + * constructor + */ + function soap_transport_http($url){ + parent::nusoap_base(); + $this->setURL($url); + ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev); + $this->outgoing_headers['User-Agent'] = $this->title.'/'.$this->version.' ('.$rev[1].')'; + $this->debug('set User-Agent: ' . $this->outgoing_headers['User-Agent']); + } + + function setURL($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; + $this->digest_uri = $this->uri; + + // build headers + if (!isset($u['port'])) { + $this->outgoing_headers['Host'] = $this->host; + } else { + $this->outgoing_headers['Host'] = $this->host.':'.$this->port; + } + $this->debug('set Host: ' . $this->outgoing_headers['Host']); + + if (isset($u['user']) && $u['user'] != '') { + $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); + } + } + + function connect($connection_timeout=0,$response_timeout=50){ + // 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 . ' connection_timeout ' . $connection_timeout); + + // 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 + $this->debug('set response timeout to ' . $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); + // follow location headers (re-directs) + curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 1); + // 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'; + $this->debug('set Connection: ' . $this->outgoing_headers['Connection']); + } + // set timeout + if ($connection_timeout != 0) { + curl_setopt($this->ch, CURLOPT_TIMEOUT, $connection_timeout); + } + // TODO: cURL has added a connection timeout separate from the response timeout + //if ($connection_timeout != 0) { + // curl_setopt($this->ch, CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); + //} + //if ($response_timeout != 0) { + // curl_setopt($this->ch, CURLOPT_TIMEOUT, $response_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); + + // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) + if ($this->authtype == 'certificate') { + if (isset($this->certRequest['cainfofile'])) { + curl_setopt($this->ch, CURLOPT_CAINFO, $this->certRequest['cainfofile']); + } + if (isset($this->certRequest['verifypeer'])) { + curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); + } else { + curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 1); + } + if (isset($this->certRequest['verifyhost'])) { + curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); + } else { + curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 1); + } + if (isset($this->certRequest['sslcertfile'])) { + curl_setopt($this->ch, CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); + } + if (isset($this->certRequest['sslkeyfile'])) { + curl_setopt($this->ch, CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); + } + if (isset($this->certRequest['passphrase'])) { + curl_setopt($this->ch, CURLOPT_SSLKEYPASSWD , $this->certRequest['passphrase']); + } + } + $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 + * @param array $cookies cookies to send + * @return string data + * @access public + */ + function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { + + $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, $cookies)){ + 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 + * @param array $cookies cookies to send + * @return string data + * @access public + */ + function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { + return $this->send($data, $timeout, $response_timeout, $cookies); + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic, digest, certificate) + * @param array $digestRequest (keys must be nonce, nc, realm, qop) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { + $this->debug("Set credentials for authtype $authtype"); + // cf. RFC 2617 + if ($authtype == 'basic') { + $this->outgoing_headers['Authorization'] = 'Basic '.base64_encode(str_replace(':','',$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. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; + + // H(A1) = MD5(A1) + $HA1 = md5($A1); + + // A2 = Method ":" digest-uri-value + $A2 = 'POST:' . $this->digest_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->digest_uri . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'; + } + } elseif ($authtype == 'certificate') { + $this->certRequest = $certRequest; + } + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->digestRequest = $digestRequest; + + if (isset($this->outgoing_headers['Authorization'])) { + $this->debug('set Authorization: ' . 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 . '"'; + $this->debug('set SOAPAction: ' . $this->outgoing_headers['SOAPAction']); + } + + /** + * use http encoding + * + * @param string $enc encoding style. supported values: gzip, deflate, or both + * @access public + */ + function setEncoding($enc='gzip, deflate') { + if (function_exists('gzdeflate')) { + $this->protocol_version = '1.1'; + $this->outgoing_headers['Accept-Encoding'] = $enc; + $this->debug('set Accept-Encoding: ' . $this->outgoing_headers['Accept-Encoding']); + if (!isset($this->outgoing_headers['Connection'])) { + $this->outgoing_headers['Connection'] = 'close'; + $this->persistentConnection = false; + $this->debug('set Connection: ' . $this->outgoing_headers['Connection']); + } + 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); + $this->debug('set Proxy-Authorization: ' . $this->outgoing_headers['Proxy-Authorization']); + } + } + + /** + * 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 + * @deprecated + */ + 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, $cookie_str = '') { + // add content-length header + $this->outgoing_headers['Content-Length'] = strlen($data); + $this->debug('set Content-Length: ' . $this->outgoing_headers['Content-Length']); + + // start building outgoing payload: + $req = "$this->request_method $this->uri HTTP/$this->protocol_version"; + $this->debug("HTTP request: $req"); + $this->outgoing_payload = "$req\r\n"; + + // loop thru headers, serializing + foreach($this->outgoing_headers as $k => $v){ + $hdr = $k.': '.$v; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // add any cookies + if ($cookie_str != '') { + $hdr = 'Cookie: '.$cookie_str; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // header/body separator + $this->outgoing_payload .= "\r\n"; + + // add data + $this->outgoing_payload .= $data; + } + + function sendRequest($data, $cookies = NULL) { + // build cookie string + $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); + + // build payload + $this->buildPayload($data, $cookie_str); + + 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"; + } + if ($cookie_str != '') { + $curl_headers[] = 'Cookie: ' . $cookie_str; + } + 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: " . $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(); + $this->incoming_cookies = 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]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } else if (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + + // loop until msg has been received + if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { + $content_length = 2147483647; // ignore any content-length header + $chunked = true; + $this->debug("want to read chunked content"); + } elseif (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; + $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 "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>"; + // 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.'<br>'; + // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE + foreach(curl_getinfo($this->ch) as $k => $v){ + $err .= "$k: $v<br>"; + } + $this->debug($err); + $this->setError($err); + curl_close($this->ch); + return false; + } else { + //echo '<pre>'; + //var_dump(curl_getinfo($this->ch)); + //echo '</pre>'; + } + // close curl + $this->debug('No cURL error, closing cURL'); + curl_close($this->ch); + + // remove 100 header(s) + while (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){ + $header_name = strtolower(trim($arr[0])); + $this->incoming_headers[$header_name] = trim($arr[1]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } else if (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + } + + $arr = explode(' ', $header_array[0], 3); + $http_version = $arr[0]; + $http_status = intval($arr[1]); + $http_reason = count($arr) > 2 ? $arr[2] : ''; + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['location']) && $http_status == 301) { + $this->debug("Got 301 $http_reason with Location: " . $this->incoming_headers['location']); + $this->setURL($this->incoming_headers['location']); + $this->tryagain = true; + return false; + } + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { + $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); + if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { + $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), 2); + $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; + } + + if ( + ($http_status >= 300 && $http_status <= 307) || + ($http_status >= 400 && $http_status <= 417) || + ($http_status >= 501 && $http_status <= 505) + ) { + $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); + 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('gzinflate')){ + //$timer->setMarker('starting decoding of gzip/deflated content'); + // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) + // this means there are no Zlib headers, although there should be + $this->debug('The gzinflate function exists'); + $datalen = strlen($data); + if ($this->incoming_headers['content-encoding'] == 'deflate') { + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The inflated payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to inflate the payload'); + $this->setError('Error using gzinflate to inflate the payload'); + } + } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { + if ($degzdata = @gzinflate(substr($data, 10))) { // do our best + $data = $degzdata; + $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate(substr($data, 10))) { + $data = $degzdata; + $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to un-gzip the payload'); + $this->setError('Error using gzinflate to un-gzip the payload'); + } + } + //$timer->setMarker('finished decoding of gzip/deflated content'); + //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>"; + // set decoded payload + $this->incoming_payload = $header_data.$lb.$lb.$data; + } else { + $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + } + } else { + $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + } + } else { + $this->debug('No Content-Encoding header'); + } + + 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 : ''); + $this->debug('set Content-Type: ' . $this->outgoing_headers['Content-Type']); + } + + 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'; + $this->debug('set Connection: ' . $this->outgoing_headers['Connection']); + return true; + } + + /** + * parse an incoming Cookie into it's parts + * + * @param string $cookie_str content of cookie + * @return array with data of that cookie + * @access private + */ + /* + * TODO: allow a Set-Cookie string to be parsed into multiple cookies + */ + function parseCookie($cookie_str) { + $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; + $data = split(';', $cookie_str); + $value_str = $data[0]; + + $cookie_param = 'domain='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $domain = substr($cookie_str, $start + strlen($cookie_param)); + $domain = substr($domain, 0, strpos($domain, ';')); + } else { + $domain = ''; + } + + $cookie_param = 'expires='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $expires = substr($cookie_str, $start + strlen($cookie_param)); + $expires = substr($expires, 0, strpos($expires, ';')); + } else { + $expires = ''; + } + + $cookie_param = 'path='; + $start = strpos($cookie_str, $cookie_param); + if ( $start > 0 ) { + $path = substr($cookie_str, $start + strlen($cookie_param)); + $path = substr($path, 0, strpos($path, ';')); + } else { + $path = '/'; + } + + $cookie_param = ';secure;'; + if (strpos($cookie_str, $cookie_param) !== FALSE) { + $secure = true; + } else { + $secure = false; + } + + $sep_pos = strpos($value_str, '='); + + if ($sep_pos) { + $name = substr($value_str, 0, $sep_pos); + $value = substr($value_str, $sep_pos + 1); + $cookie= array( 'name' => $name, + 'value' => $value, + 'domain' => $domain, + 'path' => $path, + 'expires' => $expires, + 'secure' => $secure + ); + return $cookie; + } + return false; + } + + /** + * sort out cookies for the current request + * + * @param array $cookies array with all cookies + * @param boolean $secure is the send-content secure or not? + * @return string for Cookie-HTTP-Header + * @access private + */ + function getCookiesForRequest($cookies, $secure=false) { + $cookie_str = ''; + if ((! is_null($cookies)) && (is_array($cookies))) { + foreach ($cookies as $cookie) { + if (! is_array($cookie)) { + continue; + } + $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); + if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { + if (strtotime($cookie['expires']) <= time()) { + $this->debug('cookie has expired'); + continue; + } + } + if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { + $domain = preg_quote($cookie['domain']); + if (! preg_match("'.*$domain$'i", $this->host)) { + $this->debug('cookie has different domain'); + continue; + } + } + if ((isset($cookie['path'])) && (! empty($cookie['path']))) { + $path = preg_quote($cookie['path']); + if (! preg_match("'^$path.*'i", $this->path)) { + $this->debug('cookie is for a different path'); + continue; + } + } + if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { + $this->debug('cookie is secure, transport is not'); + continue; + } + $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; + $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); + } + } + return $cookie_str; + } +} + +?><?php + + + +/** +* +* soap_server allows the user to create a SOAP server +* that is capable of receiving messages and returning responses +* +* NOTE: WSDL functionality is experimental +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ +* @access public +*/ +class soap_server extends nusoap_base { + /** + * HTTP headers of request + * @var array + * @access private + */ + var $headers = array(); + /** + * HTTP request + * @var string + * @access private + */ + var $request = ''; + /** + * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $requestHeaders = ''; + /** + * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $document = ''; + /** + * SOAP payload for request (text) + * @var string + * @access public + */ + var $requestSOAP = ''; + /** + * requested method namespace URI + * @var string + * @access private + */ + var $methodURI = ''; + /** + * name of method requested + * @var string + * @access private + */ + var $methodname = ''; + /** + * method parameters from request + * @var array + * @access private + */ + var $methodparams = array(); + /** + * SOAP Action from request + * @var string + * @access private + */ + var $SOAPAction = ''; + /** + * character set encoding of incoming (request) messages + * @var string + * @access public + */ + var $xml_encoding = ''; + /** + * toggles whether the parser decodes element content w/ utf8_decode() + * @var boolean + * @access public + */ + var $decode_utf8 = true; + + /** + * HTTP headers of response + * @var array + * @access public + */ + var $outgoing_headers = array(); + /** + * HTTP response + * @var string + * @access private + */ + var $response = ''; + /** + * SOAP headers for response (text) + * @var string + * @access public + */ + var $responseHeaders = ''; + /** + * SOAP payload for response (text) + * @var string + * @access private + */ + var $responseSOAP = ''; + /** + * method return value to place in response + * @var mixed + * @access private + */ + var $methodreturn = false; + /** + * whether $methodreturn is a string of literal XML + * @var boolean + * @access public + */ + var $methodreturnisliteralxml = false; + /** + * SOAP fault for response (or false) + * @var mixed + * @access private + */ + var $fault = false; + /** + * text indication of result (for debugging) + * @var string + * @access private + */ + var $result = 'successful'; + + /** + * assoc array of operations => opData; operations are added by the register() + * method or by parsing an external WSDL definition + * @var array + * @access private + */ + var $operations = array(); + /** + * wsdl instance (if one) + * @var mixed + * @access private + */ + var $wsdl = false; + /** + * URL for WSDL (if one) + * @var mixed + * @access private + */ + var $externalWSDLURL = false; + /** + * whether to append debug to response as XML comment + * @var boolean + * @access public + */ + var $debug_flag = false; + + + /** + * 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){ + parent::nusoap_base(); + // turn on debugging? + global $debug; + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $this->debug("_SERVER is defined:"); + $this->appendDebug($this->varDump($_SERVER)); + } elseif (isset($HTTP_SERVER_VARS)) { + $this->debug("HTTP_SERVER_VARS is defined:"); + $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); + } else { + $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); + } + + if (isset($debug)) { + $this->debug("In soap_server, set debug_flag=$debug based on global flag"); + $this->debug_flag = $debug; + } elseif (isset($_SERVER['QUERY_STRING'])) { + $qs = explode('&', $_SERVER['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In soap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); + $this->debug_flag = substr($v, 6); + } + } + } elseif (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("In soap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); + $this->debug_flag = substr($v, 6); + } + } + } + + // wsdl + if($wsdl){ + $this->debug("In soap_server, WSDL is specified"); + if (is_object($wsdl) && (get_class($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->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + 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 $HTTP_SERVER_VARS; + + if (isset($_SERVER['QUERY_STRING'])) { + $qs = $_SERVER['QUERY_STRING']; + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = $HTTP_SERVER_VARS['QUERY_STRING']; + } else { + $qs = ''; + } + $this->debug("In service, query string=$qs"); + + if (ereg('wsdl', $qs) ){ + $this->debug("In service, 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); + } + } elseif ($this->wsdl) { + header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); + print $this->wsdl->serialize($this->debug_flag); + if ($this->debug_flag) { + $this->debug('wsdl:'); + $this->appendDebug($this->varDump($this->wsdl)); + print $this->getDebugAsXMLComment(); + } + } else { + header("Content-Type: text/html; charset=ISO-8859-1\r\n"); + print "This service does not provide WSDL"; + } + } elseif ($data == '' && $this->wsdl) { + $this->debug("In service, there is no data, so return Web description"); + print $this->wsdl->webDescription(); + } else { + $this->debug("In service, invoke 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; + + $this->request = ''; + $this->SOAPAction = ''; + if(function_exists('getallheaders')){ + $this->debug("In parse_http_headers, use getallheaders"); + $headers = getallheaders(); + foreach($headers as $k=>$v){ + $k = strtolower($k); + $this->headers[$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(isset($this->headers['content-type']) && 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 for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } elseif(isset($_SERVER) && is_array($_SERVER)){ + $this->debug("In parse_http_headers, use _SERVER"); + foreach ($_SERVER as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($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 for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } elseif (is_array($HTTP_SERVER_VARS)) { + $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); + foreach ($HTTP_SERVER_VARS as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($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 for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } else { + $this->debug("In parse_http_headers, HTTP headers not accessible"); + $this->setError("HTTP headers not accessible"); + } + } + + /** + * 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()'); + $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('Client', 'Errors occurred when trying to decode the data'); + return; + } + } else { + $this->fault('Client', 'This Server does not support compressed data'); + return; + } + } + } + $this->request .= "\r\n".$data; + $data = $this->parseRequest($this->headers, $data); + $this->requestSOAP = $data; + $this->debug('leaving parse_request'); + } + + /** + * 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('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); + + if ($this->wsdl) { + if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { + $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { + // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element + $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + $this->methodname = $this->opData['name']; + } else { + $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); + $this->fault('Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); + return; + } + } else { + $this->debug('in invoke_method, no WSDL to validate method'); + } + + // if a . is present in $this->methodname, we see if there is a class in scope, + // which could be referred to. We will also distinguish between two deliminators, + // to allow methods to be called a the class or an instance + $class = ''; + $method = ''; + if (strpos($this->methodname, '..') > 0) { + $delim = '..'; + } else if (strpos($this->methodname, '.') > 0) { + $delim = '.'; + } else { + $delim = ''; + } + + if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 && + class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) { + // get the class and method name + $class = substr($this->methodname, 0, strpos($this->methodname, $delim)); + $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); + $this->debug("in invoke_method, class=$class method=$method delim=$delim"); + } + + // does method exist? + if ($class == '') { + if (!function_exists($this->methodname)) { + $this->debug("in invoke_method, function '$this->methodname' not found!"); + $this->result = 'fault: method not found'; + $this->fault('Client',"method '$this->methodname' not defined in service"); + return; + } + } else { + $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; + if (!in_array($method_to_compare, get_class_methods($class))) { + $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); + $this->result = 'fault: method not found'; + $this->fault('Client',"method '$this->methodname' not defined in service"); + return; + } + } + + // 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('Client',"Operation '$this->methodname' not defined in service."); + return; + } + + // if there are parameters to pass + $this->debug('in invoke_method, params:'); + $this->appendDebug($this->varDump($this->methodparams)); + $this->debug("in invoke_method, calling '$this->methodname'"); + if (!function_exists('call_user_func_array')) { + if ($class == '') { + $this->debug('in invoke_method, calling function using eval()'); + $funcCall = "\$this->methodreturn = $this->methodname("; + } else { + if ($delim == '..') { + $this->debug('in invoke_method, calling class method using eval()'); + $funcCall = "\$this->methodreturn = ".$class."::".$method."("; + } else { + $this->debug('in invoke_method, calling instance method using eval()'); + // generate unique instance name + $instname = "\$inst_".time(); + $funcCall = $instname." = new ".$class."(); "; + $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; + } + } + if ($this->methodparams) { + foreach ($this->methodparams as $param) { + if (is_array($param)) { + $this->fault('Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); + return; + } + $funcCall .= "\"$param\","; + } + $funcCall = substr($funcCall, 0, -1); + } + $funcCall .= ');'; + $this->debug('in invoke_method, function call: '.$funcCall); + @eval($funcCall); + } else { + if ($class == '') { + $this->debug('in invoke_method, calling function using call_user_func_array()'); + $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() + } elseif ($delim == '..') { + $this->debug('in invoke_method, calling class method using call_user_func_array()'); + $call_arg = array ($class, $method); + } else { + $this->debug('in invoke_method, calling instance method using call_user_func_array()'); + $instance = new $class (); + $call_arg = array(&$instance, $method); + } + $this->methodreturn = call_user_func_array($call_arg, $this->methodparams); + } + $this->debug('in invoke_method, methodreturn:'); + $this->appendDebug($this->varDump($this->methodreturn)); + $this->debug("in 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 methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); + // if fault + if (isset($this->methodreturn) && (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); + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if($errstr = $this->wsdl->getError()){ + $this->debug('got wsdl error: '.$errstr); + $this->fault('Server', 'unable to serialize result'); + return; + } + } else { + if (isset($this->methodreturn)) { + $return_val = $this->serialize_val($this->methodreturn, 'return'); + } else { + $return_val = ''; + $this->debug('in absence of WSDL, assume void return for backward compatibility'); + } + } + } + $this->debug('return value:'); + $this->appendDebug($this->varDump($return_val)); + + $this->debug('serializing response'); + if ($this->wsdl) { + $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); + if ($this->opData['style'] == 'rpc') { + $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); + if ($this->opData['output']['use'] == 'literal') { + $payload = '<'.$this->methodname.'Response xmlns="'.$this->methodURI.'">'.$return_val.'</'.$this->methodname."Response>"; + } else { + $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; + } + } else { + $this->debug('style is not rpc for serialization: assume document'); + $payload = $return_val; + } + } else { + $this->debug('do not have WSDL for serialization: assume rpc/encoded'); + $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; + } + $this->result = 'successful'; + if($this->wsdl){ + //if($this->debug_flag){ + $this->appendDebug($this->wsdl->getDebug()); + // } + if (isset($opData['output']['encodingStyle'])) { + $encodingStyle = $opData['output']['encodingStyle']; + } else { + $encodingStyle = ''; + } + // 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'],$encodingStyle); + } 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){ + $payload .= $this->getDebugAsXMLComment(); + } + $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"; + $payload = $this->getHTTPBody($payload); + $type = $this->getHTTPContentType(); + $charset = $this->getHTTPContentTypeCharset(); + $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); + //begin code to compress payload - by John + // NOTE: there is no way to know whether the Web server will also compress + // this data. + if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { + if (strstr($this->headers['accept-encoding'], 'gzip')) { + if (function_exists('gzencode')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= "<!-- Content being gzipped -->"; + } + $this->outgoing_headers[] = "Content-Encoding: gzip"; + $payload = gzencode($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= "<!-- Content will not be gzipped: no gzencode -->"; + } + } + } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { + // Note: MSIE requires gzdeflate output (no Zlib header and checksum), + // instead of gzcompress output, + // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) + if (function_exists('gzdeflate')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= "<!-- Content being deflated -->"; + } + $this->outgoing_headers[] = "Content-Encoding: deflate"; + $payload = gzdeflate($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= "<!-- Content will not be deflated: no gzcompress -->"; + } + } + } + } + //end code + $this->outgoing_headers[] = "Content-Length: ".strlen($payload); + reset($this->outgoing_headers); + foreach($this->outgoing_headers as $hdr){ + header($hdr, false); + } + print $payload; + $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; + } + + /** + * takes the value that was created by parsing the request + * and compares to the method's signature, if available. + * + * @param string $operation The operation to be invoked + * @param array $request The array of parameter values + * @return boolean Whether the operation was found + * @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; + } + + /** + * processes SOAP message received from client + * + * @param array $headers The HTTP headers + * @param string $data unprocessed request data from client + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseRequest($headers, $data) { + $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']); + if (!strstr($headers['content-type'], 'text/xml')) { + $this->setError('Request 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 for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser'); + // parse response, get soap parser obj + $parser = new soap_parser($data,$this->xml_encoding,'',$this->decode_utf8); + // parser debug + $this->debug("parser debug: \n".$parser->getDebug()); + // if fault occurred during message parsing + if($err = $parser->getError()){ + $this->result = 'fault: error in msg parsing: '.$err; + $this->fault('Client',"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('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); + $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; + } + } + + /** + * gets the HTTP body for the current response. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + return $soapmsg; + } + + /** + * gets the HTTP content type for the current response. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current response. + * @access private + */ + function getHTTPContentType() { + return 'text/xml'; + } + + /** + * gets the HTTP content type charset for the current response. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current response. + * @access private + */ + function getHTTPContentTypeCharset() { + return $this->soap_defencoding; + } + + /** + * add a method to the dispatch map (this has been replaced by the register method) + * + * @param string $methodname + * @param string $in array of input values + * @param string $out array of output values + * @access public + * @deprecated + */ + function add_to_map($methodname,$in,$out){ + $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); + } + + /** + * register a service function with the server + * + * @param string $name the name of the PHP function, class.method or class..method + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $out assoc array of output values: key = param name, value = param type + * @param mixed $namespace the element namespace for the method or false + * @param mixed $soapaction the soapaction for the method or false + * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @param mixed $use optional (encoded|literal) or false + * @param string $documentation optional Description to include in WSDL + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ + global $HTTP_SERVER_VARS; + + 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 (! $name) { + die('You must specify a name when you register an operation'); + } + if (!is_array($in)) { + die('You must provide an array for operation inputs'); + } + if (!is_array($out)) { + die('You must provide an array for operation outputs'); + } + if(false == $namespace) { + } + if(false == $soapaction) { + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + $soapaction = "http://$SERVER_NAME$SCRIPT_NAME/$name"; + } + if(false == $style) { + $style = "rpc"; + } + if(false == $use) { + $use = "encoded"; + } + if ($use == 'encoded' && $encodingStyle = '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + $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,$encodingStyle); + } + return true; + } + + /** + * Specify a fault to be returned to the client. + * 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=''){ + if ($faultdetail == '' && $this->debug_flag) { + $faultdetail = $this->getDebug(); + } + $this->fault = new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail); + $this->fault->soap_defencoding = $this->soap_defencoding; + } + + /** + * Sets up wsdl object. + * Acts as a flag to enable internal WSDL generation + * + * @param string $serviceName, name of the service + * @param mixed $namespace optional 'tns' service namespace or false + * @param mixed $endpoint optional URL of service endpoint or false + * @param string $style optional (rpc|document) WSDL style (also specified by operation) + * @param string $transport optional SOAP transport + * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false + */ + function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) + { + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SERVER_PORT = $_SERVER['SERVER_PORT']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = $_SERVER['HTTPS']; + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = $HTTP_SERVER_VARS['HTTPS']; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + if ($SERVER_PORT == 80) { + $SERVER_PORT = ''; + } else { + $SERVER_PORT = ':' . $SERVER_PORT; + } + if(false == $namespace) { + $namespace = "http://$SERVER_NAME/soap/$serviceName"; + } + + if(false == $endpoint) { + 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/'); + } +} + + + +?><?php + + + +/** +* parses a WSDL file, allows access to it's data, other utility methods +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol 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){ + parent::nusoap_base(); + $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'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . + 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'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . + 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); + } + $tr->setEncoding('gzip, deflate'); + $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->appendDebug($tr->getDebug()); + // catch errors + if($err = $tr->getError() ){ + $errstr = 'HTTP ERROR: '.$err; + $this->debug($errstr); + $this->setError($errstr); + unset($tr); + return false; + } + unset($tr); + $this->debug("got WSDL URL"); + } 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; + } + } + $this->debug('Parse WSDL'); + // 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); + $this->debug('Parsing WSDL done'); + // 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->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } elseif (ereg('schema$', $name)) { + $this->debug('Parsing WSDL schema'); + // $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->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } 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' => ''); + // process attributes + if (count($attrs) > 0) { + // register namespace declarations + foreach($attrs as $k => $v) { + 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' || $v == 'http://www.w3.org/2000/10/XMLSchema') { + $this->XMLSchemaVersion = $v; + $this->namespaces['xsi'] = $v . '-instance'; + } + } + } + // expand each attribute prefix to its namespace + foreach($attrs as $k => $v) { + $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(); + } + // get element prefix, namespace and name + 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); + } + // process attributes, expanding any prefixes to namespaces + // 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->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs)); + $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->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; + $this->debug('Parsing WSDL schema done'); + } + 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) { + // note that we could/should also check the namespace here + if ($operation == $bOperation) { + $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; + return $opData; + } + } + } + } + } + + /** + * returns an associative array of data necessary for calling an operation + * + * @param string $soapAction soapAction for operation + * @param string $bindingType type of binding eg: soap + * @return array + * @access public + */ + function getOperationDataForSoapAction($soapAction, $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) { + // loop through operations for the binding + foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { + if ($opData['soapAction'] == $soapAction) { + 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 the type + * @param $ns string namespace (not prefix) of the type + * @return mixed + * @access public + * @see xmlschema + */ + function getTypeDef($type, $ns) { + $this->debug("in getTypeDef: type=$type, ns=$ns"); + if ((! $ns) && isset($this->namespaces['tns'])) { + $ns = $this->namespaces['tns']; + $this->debug("in getTypeDef: type namespace forced to $ns"); + } + if (isset($this->schemas[$ns])) { + $this->debug("in getTypeDef: have schema for namespace $ns"); + for ($i = 0; $i < count($this->schemas[$ns]); $i++) { + $xs = &$this->schemas[$ns][$i]; + $t = $xs->getTypeDef($type); + $this->appendDebug($xs->getDebug()); + $xs->clearDebug(); + if ($t) { + if (!isset($t['phpType'])) { + // get info for type to tack onto the element + $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); + $ns = substr($t['type'], 0, strrpos($t['type'], ':')); + $etype = $this->getTypeDef($uqType, $ns); + if ($etype) { + $this->debug("found type for [element] $type:"); + $this->debug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $t['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $t['elements'] = $etype['elements']; + } + if (isset($etype['attrs'])) { + $t['attrs'] = $etype['attrs']; + } + } + } + return $t; + } + } + } else { + $this->debug("in getTypeDef: do not have schema for namespace $ns"); + } + return false; + } + + /** + * prints html description of services + * + * @access private + */ + function webDescription(){ + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $PHP_SELF = $_SERVER['PHP_SELF']; + } elseif (isset($HTTP_SERVER_VARS)) { + $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + + $b = ' + <html><head><title>NuSOAP: '.$this->serviceName.'</title> + <style type="text/css"> + body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; } + p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; } + pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;} + ul { margin-top: 10px; margin-left: 20px; } + li { list-style-type: none; margin-top: 10px; color: #000000; } + .content{ + margin-left: 0px; padding-bottom: 2em; } + .nav { + padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em; + margin-top: 10px; margin-left: 0px; color: #000000; + background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; } + .title { + font-family: arial; font-size: 26px; color: #ffffff; + background-color: #999999; width: 105%; margin-left: 0px; + padding-top: 10px; padding-bottom: 10px; padding-left: 15px;} + .hidden { + position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px; + font-family: arial; overflow: hidden; width: 600; + padding: 20px; font-size: 10px; background-color: #999999; + layer-background-color:#FFFFFF; } + a,a:active { color: charcoal; font-weight: bold; } + a:visited { color: #666666; font-weight: bold; } + a:hover { color: cc3300; font-weight: bold; } + </style> + <script language="JavaScript" type="text/javascript"> + <!-- + // POP-UP CAPTIONS... + function lib_bwcheck(){ //Browsercheck (needed) + this.ver=navigator.appVersion + this.agent=navigator.userAgent + this.dom=document.getElementById?1:0 + this.opera5=this.agent.indexOf("Opera 5")>-1 + this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0; + this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0; + this.ie4=(document.all && !this.dom && !this.opera5)?1:0; + this.ie=this.ie4||this.ie5||this.ie6 + this.mac=this.agent.indexOf("Mac")>-1 + this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; + this.ns4=(document.layers && !this.dom)?1:0; + this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5) + return this + } + var bw = new lib_bwcheck() + //Makes crossbrowser object. + function makeObj(obj){ + this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0; + if(!this.evnt) return false + this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0; + this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0; + this.writeIt=b_writeIt; + return this + } + // A unit of measure that will be added when setting the position of a layer. + //var px = bw.ns4||window.opera?"":"px"; + function b_writeIt(text){ + if (bw.ns4){this.wref.write(text);this.wref.close()} + else this.wref.innerHTML = text + } + //Shows the messages + var oDesc; + function popup(divid){ + if(oDesc = new makeObj(divid)){ + oDesc.css.visibility = "visible" + } + } + function popout(){ // Hides message + if(oDesc) oDesc.css.visibility = "hidden" + } + //--> + </script> + </head> + <body> + <div class=content> + <br><br> + <div class=title>'.$this->serviceName.'</div> + <div class=nav> + <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service. + Click on an operation name to view it's details.</p> + <ul>'; + foreach($this->getOperations() as $op => $data){ + $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>"; + // create hidden div + $b .= "<div id='$op' class='hidden'> + <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>"; + foreach($data as $donnie => $marie){ // loop through opdata + if($donnie == 'input' || $donnie == 'output'){ // show input/output data + $b .= "<font color='white'>".ucfirst($donnie).':</font><br>'; + foreach($marie as $captain => $tenille){ // loop through data + if($captain == 'parts'){ // loop thru parts + $b .= " $captain:<br>"; + //if(is_array($tenille)){ + foreach($tenille as $joanie => $chachi){ + $b .= " $joanie: $chachi<br>"; + } + //} + } else { + $b .= " $captain: $tenille<br>"; + } + } + } else { + $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>"; + } + } + $b .= '</div>'; + } + $b .= ' + <ul> + </div> + </div></body></html>'; + return $b; + } + + /** + * serialize the parsed wsdl + * + * @param mixed $debug whether to put debug=1 in endpoint URL + * @return string serialization of WSDL + * @access public + */ + function serialize($debug = 0) + { + $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>'; + $xml .= "\n<definitions"; + foreach($this->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 .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />'; + } else { + $xml .= '<import namespace="' . $ns . '" />'; + } + } + } + } + // types + if (count($this->schemas)>=1) { + $xml .= "\n<types>"; + foreach ($this->schemas as $ns => $list) { + foreach ($list as $xs) { + $xml .= $xs->serializeSchema(); + } + } + $xml .= '</types>'; + } + // messages + if (count($this->messages) >= 1) { + foreach($this->messages as $msgName => $msgParts) { + $xml .= "\n<message name=\"" . $msgName . '">'; + if(is_array($msgParts)){ + foreach($msgParts as $partName => $partType) { + // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>'; + if (strpos($partType, ':')) { + $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); + } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { + // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>'; + $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!"); + } + } + $ns = $this->getNamespaceFromPrefix($typePrefix); + $typeDef = $this->getTypeDef($this->getLocalPart($partType), $ns); + if ($typeDef['typeClass'] == 'element') { + $elementortype = 'element'; + } else { + $elementortype = 'type'; + } + $xml .= '<part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />'; + } + } + $xml .= '</message>'; + } + } + // bindings & porttypes + if (count($this->bindings) >= 1) { + $binding_xml = ''; + $portType_xml = ''; + foreach($this->bindings as $bindingName => $attrs) { + $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">'; + $binding_xml .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>'; + $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">'; + foreach($attrs['operations'] as $opName => $opParts) { + $binding_xml .= '<operation name="' . $opName . '">'; + $binding_xml .= '<soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>'; + if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= '<input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>'; + if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>'; + $binding_xml .= '</operation>'; + $portType_xml .= '<operation name="' . $opParts['name'] . '"'; + if (isset($opParts['parameterOrder'])) { + $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"'; + } + $portType_xml .= '>'; + if(isset($opParts['documentation']) && $opParts['documentation'] != '') { + $portType_xml .= '<documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>'; + } + $portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>'; + $portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>'; + $portType_xml .= '</operation>'; + } + $portType_xml .= '</portType>'; + $binding_xml .= '</binding>'; + } + $xml .= $portType_xml . $binding_xml; + } + // services + $xml .= "\n<service name=\"" . $this->serviceName . '">'; + if (count($this->ports) >= 1) { + foreach($this->ports as $pName => $attrs) { + $xml .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">'; + $xml .= '<soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>'; + $xml .= '</port>'; + } + } + $xml .= '</service>'; + return $xml . "\n</definitions>"; + } + + /** + * serialize PHP values according to a WSDL message definition + * + * TODO + * - multi-ref serialization + * - validate PHP values against type definitions, return errors if invalid + * + * @param string $operation operation name + * @param string $direction (input|output) + * @param mixed $parameters parameter value(s) + * @return mixed parameters serialized as XML or false on error (e.g. operation not found) + * @access public + */ + function serializeRPCParameters($operation, $direction, $parameters) + { + $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + 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('opData:'); + $this->appendDebug($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('have ' . count($opData[$direction]['parts']) . ' part(s) to serialize'); + if (is_array($parameters)) { + $parametersArrayType = $this->isArraySimpleOrStruct($parameters); + $this->debug('have ' . count($parameters) . ' parameter(s) provided as ' . $parametersArrayType . ' to serialize'); + 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.'); + } + } + $this->debug("serializeRPCParameters returning: $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 + * @access public + * @deprecated + */ + function serializeParameters($operation, $direction, $parameters) + { + $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + 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('opData:'); + $this->appendDebug($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.'); + } + } + $this->debug("serializeParameters returning: $xml"); + return $xml; + } + + /** + * serializes a PHP value according a given type definition + * + * @param string $name name of value (part or element) + * @param string $type XML schema type of value (type or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @param boolean $unqualified a kludge for what should be XML namespace form handling + * @return string value serialized as an XML string + * @access private + */ + function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) + { + $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); + $this->appendDebug("value=" . $this->varDump($value)); + if($use == 'encoded' && $encodingStyle) { + $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; + } + + // if a soapval has been supplied, let its type override the WSDL + if (is_object($value) && get_class($value) == 'soapval') { + if ($value->type_ns) { + $type = $value->type_ns . ':' . $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } elseif ($value->type) { + $type = $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } else { + $forceType = false; + $this->debug("in serializeType: soapval does not override type"); + } + $attrs = $value->attributes; + $value = $value->value; + $this->debug("in serializeType: soapval overrides value to $value"); + if ($attrs) { + if (!is_array($value)) { + $value['!'] = $value; + } + foreach ($attrs as $n => $v) { + $value['!' . $n] = $v; + } + $this->debug("in serializeType: soapval provides attributes"); + } + } else { + $forceType = false; + } + + $xml = ''; + if (strpos($type, ':')) { + $uqType = substr($type, strrpos($type, ':') + 1); + $ns = substr($type, 0, strrpos($type, ':')); + $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); + } + + if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ + $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); + if ($unqualified && $use == 'literal') { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + // TODO: depends on nillable, which should be checked before calling this method + $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if ($uqType == 'boolean') { + if ((is_string($value) && $value == 'false') || (! $value)) { + $value = 'false'; + } else { + $value = 'true'; + } + } + if ($uqType == 'string' && gettype($value) == 'string') { + $value = $this->expandEntities($value); + } + if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { + $value = sprintf("%.0lf", $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) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; + } else { + $xml = "<$name$elementNS>$value</$name>"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); + } else if ($ns == 'http://xml.apache.org/xml-soap') { + $this->debug('in serializeType: appears to be Apache SOAP type'); + if ($uqType == 'Map') { + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + if (! $tt_prefix) { + $this->debug('in serializeType: Add namespace for Apache SOAP type'); + $tt_prefix = 'ns' . rand(1000, 9999); + $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; + // force this to be added to usedNamespaces + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + } + $contents = ''; + foreach($value as $k => $v) { + $this->debug("serializing map element: key $k, value $v"); + $contents .= '<item>'; + $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); + $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); + $contents .= '</item>'; + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>"; + } else { + $xml = "<$name>$contents</$name>"; + } + } else { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('in serializeType: Apache SOAP type, but only support Map'); + } + } else { + // TODO: should the type be compared to types in XSD, and the namespace + // set to XSD if the type matches? + $this->debug("in serializeType: 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("in serializeType: $type ($uqType) is not a supported type."); + return false; + } else { + $this->debug("in serializeType: found typeDef"); + $this->appendDebug('typeDef=' . $this->varDump($typeDef)); + } + $phpType = $typeDef['phpType']; + $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); + // if php type == struct, map value to the <all> 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 { + $elementNS = " xmlns=\"\""; + } + } else { + $elementName = $name; + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$elementName$elementNS/>"; + } else { + $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if (is_object($value)) { + $value = get_object_vars($value); + } + if (is_array($value)) { + $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); + if ($use == 'literal') { + if ($forceType) { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; + } else { + $xml = "<$elementName$elementNS$elementAttrs>"; + } + } else { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; + } + + $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); + $xml .= "</$elementName>"; + } else { + $this->debug("in serializeType: phpType is struct, but value is not an array"); + $this->setError("phpType is struct, but value is not an array: see debug output for details"); + $xml = ''; + } + } elseif ($phpType == 'array') { + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + $xml = "<$name$elementNS xsi:nil=\"true\" 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'])."[0]\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + 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); + } + } + } 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 { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; + } else { + $xml = "<$name$elementNS>$value</$name>"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; + } + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + + /** + * serializes the attributes for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { + $xml = ''; + if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { + $this->debug("serialize attributes for XML Schema type $ns:$uqType"); + 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(); + } + foreach ($typeDef['attrs'] as $aName => $attrs) { + if (isset($xvalue['!' . $aName])) { + $xname = '!' . $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($xvalue[$aName])) { + $xname = $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($attrs['default'])) { + $xname = '!' . $aName; + $xvalue[$xname] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); + } else { + $xname = ''; + $this->debug("no value provided for attribute $aName"); + } + if ($xname) { + $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; + } + } + } else { + $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); + } + if (isset($typeDef['extensionBase'])) { + $ns = $this->getPrefix($typeDef['extensionBase']); + $uqType = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + } + if ($typeDef = $this->getTypeDef($uqType, $ns)) { + $this->debug("serialize attributes for extension base $ns:$uqType"); + $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); + } else { + $this->debug("extension base $ns:$uqType is not a supported type"); + } + } + return $xml; + } + + /** + * serializes the elements for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { + $xml = ''; + if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { + $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); + 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 (!isset($xvalue[$eName])) { + if (isset($attrs['default'])) { + $xvalue[$eName] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); + } + } + // if user took advantage of a minOccurs=0, then only serialize named parameters + if (isset($optionals) + && (!isset($xvalue[$eName])) + && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') + ){ + if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { + $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); + } + // do nothing + $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); + } else { + // get value + if (isset($xvalue[$eName])) { + $v = $xvalue[$eName]; + } else { + $v = null; + } + if (isset($attrs['form'])) { + $unqualified = ($attrs['form'] == 'unqualified'); + } else { + $unqualified = false; + } + if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { + $vv = $v; + foreach ($vv as $k => $v) { + if (isset($attrs['type']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $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']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $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("no elements to serialize for XML Schema type $ns:$uqType"); + } + if (isset($typeDef['extensionBase'])) { + $ns = $this->getPrefix($typeDef['extensionBase']); + $uqType = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + } + if ($typeDef = $this->getTypeDef($uqType, $ns)) { + $this->debug("serialize elements for extension base $ns:$uqType"); + $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); + } else { + $this->debug("extension base $ns:$uqType is not a supported type"); + } + } + return $xml; + } + + /** + * adds an XML Schema complex type to the WSDL types + * + * @param string name + * @param string typeClass (complexType|simpleType|attribute) + * @param string phpType: currently supported are array and struct (php assoc array) + * @param string compositor (all|sequence|choice) + * @param string restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param array elements = array ( name => array(name=>'',type=>'') ) + * @param array attrs = array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]')) + * @param string arrayType: namespace:name (xsd:string) + * @see xmlschema + * @access public + */ + 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 string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @see xmlschema + * @access public + */ + function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { + $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, $enumeration); + } + + /** + * adds an element to the WSDL types + * + * @param array $attrs attributes that must include name and type + * @see xmlschema + * @access public + */ + function addElement($attrs) { + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addElement($attrs); + } + + /** + * register an operation with the server + * + * @param string $name operation (method) name + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $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 Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @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 + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ + if ($use == 'encoded' && $encodingStyle == '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + if ($style == 'document') { + $elements = array(); + foreach ($in as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t); + } + $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); + $in = array('parameters' => 'tns:' . $name); + + $elements = array(); + foreach ($out as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t); + } + $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType')); + $out = array('parameters' => 'tns:' . $name . 'Response'); + } + + // 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; + } +} +?><?php + + + +/** +* +* soap_parser class parses SOAP XML messages into native PHP values +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol 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 that actually does the parsing + * + * @param string $xml SOAP message + * @param string $encoding character encoding scheme of message + * @param string $method method for which XML is parsed (unused?) + * @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){ + parent::nusoap_base(); + $this->xml = $xml; + $this->xml_encoding = $encoding; + $this->method = $method; + $this->decode_utf8 = $decode_utf8; + + // Check whether content has been read. + if(!empty($xml)){ + // Check XML encoding + $pos_xml = strpos($xml, '<?xml'); + if ($pos_xml !== FALSE) { + $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1); + if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { + $xml_encoding = $res[1]; + if (strtoupper($xml_encoding) != $encoding) { + $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; + $this->debug($err); + if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { + $this->setError($err); + return; + } + // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed + } else { + $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); + } + } else { + $this->debug('No encoding specified in XML declaration'); + } + } else { + $this->debug('No XML declaration'); + } + $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]); + if (is_array($idVal) && isset($idVal['!id'])) { + unset($idVal['!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 resource $parser XML parser object + * @param string $name element name + * @param array $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]; + } + // specifies nil value (or not) + } elseif ($key_localpart == 'nil'){ + $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); + // some other attribute + } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { + $this->message[$pos]['xattrs']['!' . $key] = $value; + } + + if ($key == 'xmlns') { + $this->default_namespace = $value; + } + // 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 resource $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 complexType 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); + } + // build complexType values of attributes and possibly simpleContent + } elseif (isset($this->message[$pos]['xattrs'])) { + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + if (isset($this->message[$pos]['type'])) { + $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } 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]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; + } + } + } + $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; + // set value of simpleType (or nil complexType) + } else { + //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (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 resource $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 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 + * @return mixed PHP value + * @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') { + $this->debug('Decode base64 value'); + 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; + } + // bogus: parser treats array with no elements as a simple type + if ($type == 'array') { + return array(); + } + // everything else + return (string) $value; + } + + /** + * builds response structures for compound values (arrays/structs) + * and scalars + * + * @param integer $pos position in node tree + * @return mixed PHP value + * @access private + */ + function buildVal($pos){ + if(!isset($this->message[$pos]['type'])){ + $this->message[$pos]['type'] = ''; + } + $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); + // if there are children... + if($this->message[$pos]['children'] != ''){ + $this->debug('in buildVal, there are 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("in buildVal, 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('in buildVal, 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'){ + $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); + 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 + $this->debug('in buildVal, adding Java Vector '.$this->message[$pos]['name']); + if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { + $notstruct = 1; + } else { + $notstruct = 0; + } + // + foreach($children as $child_pos){ + if($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']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { + $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']; + } + } + } + } + if (isset($this->message[$pos]['xattrs'])) { + $this->debug('in buildVal, handling attributes'); + foreach ($this->message[$pos]['xattrs'] as $n => $v) { + $params[$n] = $v; + } + } + // handle simpleContent + if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + $this->debug('in buildVal, handling simpleContent'); + if (isset($this->message[$pos]['type'])) { + $params['!'] = $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'])) { + $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $params['!'] = $this->message[$pos]['cdata']; + } + } + } + return is_array($params) ? $params : array(); + } else { + $this->debug('in buildVal, no children, building scalar'); + $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; + if (isset($this->message[$pos]['type'])) { + return $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + return $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } + return $this->message[$pos]['cdata']; + } + } +} + + + +?><?php + + + +/** +* +* soapclient higher level class for easy usage. +* +* usage: +* +* // instantiate client with server info +* $soapclient = new soapclient( string path [ ,boolean wsdl] ); +* +* // call method, get results +* echo $soapclient->call( string methodname [ ,array parameters] ); +* +* // bye bye client +* unset($soapclient); +* +* @author Dietrich Ayala <dietrich@ganx4.com> +* @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ +* @access public +*/ +class soapclientw extends nusoap_base { + + var $username = ''; + var $password = ''; + var $authtype = ''; + var $certRequest = array(); + 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 $forceEndpoint = ''; // overrides WSDL endpoint + 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 = ''; // soap|wsdl, empty for WSDL initialization error + 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 + var $cookies = array(); // Cookies from response or for request + var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() + var $operations = array(); // WSDL operations, empty for WSDL initialization error + + /* + * fault related variables + */ + /** + * @var fault + * @access public + */ + var $fault; + /** + * @var faultcode + * @access public + */ + var $faultcode; + /** + * @var faultstring + * @access public + */ + var $faultstring; + /** + * @var faultdetail + * @access public + */ + var $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 soapclientw($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){ + parent::nusoap_base(); + $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){ + if (is_object($endpoint) && (get_class($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->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + // 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); + $this->endpointType = 'wsdl'; + } else { + $this->debug( 'getOperations returned false'); + $this->setError('no operations defined in the WSDL document!'); + } + } else { + $this->debug("instantiate SOAP with endpoint at $endpoint"); + $this->endpointType = 'soap'; + } + } + + /** + * calls method, returns PHP native type + * + * @param string $method SOAP server URL or path + * @param mixed $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 mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP 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 response from SOAP call + * @access public + */ + function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ + $this->operation = $operation; + $this->fault = false; + $this->setError(''); + $this->request = ''; + $this->response = ''; + $this->responseData = ''; + $this->faultstring = ''; + $this->faultcode = ''; + $this->opData = array(); + + $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); + $this->appendDebug('params=' . $this->varDump($params)); + $this->appendDebug('headers=' . $this->varDump($headers)); + if ($headers) { + $this->requestHeaders = $headers; + } + // serialize parameters + if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ + // use WSDL for operation + $this->opData = $opData; + $this->debug("found operation"); + $this->appendDebug('opData=' . $this->varDump($opData)); + if (isset($opData['soapAction'])) { + $soapAction = $opData['soapAction']; + } + if (! $this->forceEndpoint) { + $this->endpoint = $opData['endpoint']; + } else { + $this->endpoint = $this->forceEndpoint; + } + $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; + $style = $opData['style']; + $use = $opData['input']['use']; + // add ns to ns array + if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ + $nsPrefix = 'ns' . rand(1000, 9999); + $this->wsdl->namespaces[$nsPrefix] = $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; + if (isset($opData['input']['encodingStyle'])) { + $encodingStyle = $opData['input']['encodingStyle']; + } else { + $encodingStyle = ''; + } + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + 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->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->setError( 'operation '.$operation.' not present.'); + $this->debug("operation '$operation' not present."); + return false; + } else { + // no WSDL + //$this->namespaces['ns1'] = $namespace; + $nsPrefix = 'ns' . rand(1000, 9999); + // 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(); + if ($use == 'encoded') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } else { + $encodingStyle = ''; + } + } + // wrap RPC calls with method element + if ($style == 'rpc') { + if ($use == 'literal') { + $this->debug("wrapping RPC request with literal method element"); + if ($namespace) { + $payload = "<$operation xmlns=\"$namespace\">" . $payload . "</$operation>"; + } else { + $payload = "<$operation>" . $payload . "</$operation>"; + } + } else { + $this->debug("wrapping RPC request with encoded method element"); + if ($namespace) { + $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . + $payload . + "</$nsPrefix:$operation>"; + } else { + $payload = "<$operation>" . + $payload . + "</$operation>"; + } + } + } + // serialize envelope + $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); + $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); + $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . 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)); + $this->appendDebug('return=' . $this->varDump($return)); + + // 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<br>"); + } + return $return; + } elseif ($style == 'document') { + // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), + // we are only going to return the first part here...sorry about that + return $return; + } else { + // array of return values + if(is_array($return)){ + // multiple 'out' parameters, which we return wrapped up + // in the array + if(sizeof($return) > 1){ + return $return; + } + // single 'out' parameter (normally the return value) + $return = array_shift($return); + $this->debug('return shifted value: '); + $this->appendDebug($this->varDump($return)); + return $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) { + $this->checkCookies(); + // 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->authtype != '') { + $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); + } + 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,$this->cookies); + } 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 + $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); + } else { + $this->setError('no http/s in endpoint url'); + } + $this->request = $http->outgoing_payload; + $this->response = $http->incoming_payload; + $this->appendDebug($http->getDebug()); + $this->UpdateCookies($http->incoming_cookies); + + // save transport object if using persistent connections + if ($this->persistentConnection) { + $http->clearDebug(); + 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 private + */ + 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 for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $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->appendDebug($parser->getDebug()); + // 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; + } + } + + /** + * sets the SOAP endpoint, which can override WSDL + * + * @param $endpoint string The endpoint URL to use, or empty string or false to prevent override + * @access public + */ + function setEndpoint($endpoint) { + $this->forceEndpoint = $endpoint; + } + + /** + * set the SOAP headers + * + * @param $headers mixed String of XML with SOAP header content, or array of soapval objects for SOAP headers + * @access public + */ + function setHeaders($headers){ + $this->requestHeaders = $headers; + } + + /** + * get the SOAP response headers (namespace resolution incomplete) + * + * @return string + * @access public + */ + function getHeaders(){ + 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|certificate) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->certRequest = $certRequest; + } + + /** + * 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. + * + * @return boolean + * @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. + * + * This is no longer used. + * + * @param boolean $rpcParams + * @access public + * @deprecated + */ + function setDefaultRpcParams($rpcParams) { + $this->defaultRpcParams = $rpcParams; + } + + /** + * dynamically creates an instance of a proxy class, + * allowing user to directly call methods from wsdl + * + * @return object soap_proxy object + * @access public + */ + function getProxy(){ + $r = rand(); + $evalStr = $this->_getProxyClassCode($r); + //$this->debug("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->authtype = $this->authtype; + $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; + $proxy->requestHeaders = $this->requestHeaders; + $proxy->soap_defencoding = $this->soap_defencoding; + $proxy->endpoint = $this->endpoint; + $proxy->forceEndpoint = $this->forceEndpoint; + return $proxy; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access private + */ + function _getProxyClassCode($r) { + if ($this->endpointType != 'wsdl') { + $evalStr = 'A proxy can only be created for a WSDL client'; + $this->setError($evalStr); + return $evalStr; + } + $evalStr = ''; + foreach ($this->operations as $operation => $opData) { + if ($operation != '') { + // create param string and param comment string + if (sizeof($opData['input']['parts']) > 0) { + $paramStr = ''; + $paramArrayStr = ''; + $paramCommentStr = ''; + foreach ($opData['input']['parts'] as $name => $type) { + $paramStr .= "\$$name, "; + $paramArrayStr .= "'$name' => \$$name, "; + $paramCommentStr .= "$type \$$name, "; + } + $paramStr = substr($paramStr, 0, strlen($paramStr)-2); + $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); + $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); + } else { + $paramStr = ''; + $paramCommentStr = 'void'; + } + $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; + $evalStr .= "// $paramCommentStr + function " . str_replace('.', '__', $operation) . "($paramStr) { + \$params = array($paramArrayStr); + return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); + } + "; + unset($paramStr); + unset($paramCommentStr); + } + } + $evalStr = 'class soap_proxy_'.$r.' extends soapclientw { + '.$evalStr.' +}'; + return $evalStr; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access public + */ + function getProxyClassCode() { + $r = rand(); + return $this->_getProxyClassCode($r); + } + + /** + * 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 private + */ + 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 private + */ + 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 private + */ + 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; + } + + /** + * adds a new Cookie into $this->cookies array + * + * @param string $name Cookie Name + * @param string $value Cookie Value + * @return if cookie-set was successful returns true, else false + * @access public + */ + function setCookie($name, $value) { + if (strlen($name) == 0) { + return false; + } + $this->cookies[] = array('name' => $name, 'value' => $value); + return true; + } + + /** + * gets all Cookies + * + * @return array with all internal cookies + * @access public + */ + function getCookies() { + return $this->cookies; + } + + /** + * checks all Cookies and delete those which are expired + * + * @return always return true + * @access private + */ + function checkCookies() { + if (sizeof($this->cookies) == 0) { + return true; + } + $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); + $curr_cookies = $this->cookies; + $this->cookies = array(); + foreach ($curr_cookies as $cookie) { + if (! is_array($cookie)) { + $this->debug('Remove cookie that is not an array'); + continue; + } + if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { + if (strtotime($cookie['expires']) > time()) { + $this->cookies[] = $cookie; + } else { + $this->debug('Remove expired cookie ' . $cookie['name']); + } + } else { + $this->cookies[] = $cookie; + } + } + $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); + return true; + } + + /** + * updates the current cookies with a new set + * + * @param array $cookies new cookies with which to update current ones + * @return always return true + * @access private + */ + function UpdateCookies($cookies) { + if (sizeof($this->cookies) == 0) { + // no existing cookies: take whatever is new + if (sizeof($cookies) > 0) { + $this->debug('Setting new cookie(s)'); + $this->cookies = $cookies; + } + return true; + } + if (sizeof($cookies) == 0) { + // no new cookies: keep what we've got + return true; + } + // merge + foreach ($cookies as $newCookie) { + if (!is_array($newCookie)) { + continue; + } + if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { + continue; + } + $newName = $newCookie['name']; + + $found = false; + for ($i = 0; $i < count($this->cookies); $i++) { + $cookie = $this->cookies[$i]; + if (!is_array($cookie)) { + continue; + } + if (!isset($cookie['name'])) { + continue; + } + if ($newName != $cookie['name']) { + continue; + } + $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; + $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; + if ($newDomain != $domain) { + continue; + } + $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; + $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; + if ($newPath != $path) { + continue; + } + $this->cookies[$i] = $newCookie; + $found = true; + $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); + break; + } + if (! $found) { + $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); + $this->cookies[] = $newCookie; + } + } + return true; + } +} +?> diff --git a/library/WebPlugin/Pay/Motopay/lib/nusoapmime.php b/library/WebPlugin/Pay/Motopay/lib/nusoapmime.php new file mode 100644 index 0000000..c9aa229 --- /dev/null +++ b/library/WebPlugin/Pay/Motopay/lib/nusoapmime.php @@ -0,0 +1,478 @@ +<?php +/* +$Id: nusoapmime.php,v 1.7 2005/07/27 19:24:42 snichol Exp $ + +NuSOAP - Web Services Toolkit for PHP + +Copyright (c) 2002 NuSphere Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +If you have any questions or comments, please email: + +Dietrich Ayala +dietrich@ganx4.com +http://dietrich.ganx4.com/nusoap + +NuSphere Corporation +http://www.nusphere.com + +*/ + +/*require_once('nusoap.php');*/ +/* PEAR Mail_MIME library */ +require_once('Mail/mimeDecode.php'); +require_once('Mail/mimePart.php'); + +/** +* soapclientmime client supporting MIME attachments defined at +* http://www.w3.org/TR/SOAP-attachments. It depends on the PEAR Mail_MIME library. +* +* @author Scott Nichol <snichol@sourceforge.net> +* @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list +* @version $Id: nusoapmime.php,v 1.7 2005/07/27 19:24:42 snichol Exp $ +* @access public +*/ +class soapclientmime extends soapclientw { + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $requestAttachments = array(); + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $responseAttachments; + /** + * @var string + * @access private + */ + var $mimeContentType; + + /** + * adds a MIME attachment to the current request. + * + * If the $data parameter contains an empty string, this method will read + * the contents of the file named by the $filename parameter. + * + * If the $cid parameter is false, this method will generate the cid. + * + * @param string $data The data of the attachment + * @param string $filename The filename of the attachment (default is empty string) + * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) + * @param string $cid The content-id (cid) of the attachment (default is false) + * @return string The content-id (cid) of the attachment + * @access public + */ + function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { + if (! $cid) { + $cid = md5(uniqid(time())); + } + + $info['data'] = $data; + $info['filename'] = $filename; + $info['contenttype'] = $contenttype; + $info['cid'] = $cid; + + $this->requestAttachments[] = $info; + + return $cid; + } + + /** + * clears the MIME attachments for the current request. + * + * @access public + */ + function clearAttachments() { + $this->requestAttachments = array(); + } + + /** + * gets the MIME attachments from the current response. + * + * Each array element in the return is an associative array with keys + * data, filename, contenttype, cid. These keys correspond to the parameters + * for addAttachment. + * + * @return array The attachments. + * @access public + */ + function getAttachments() { + return $this->responseAttachments; + } + + /** + * 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 private + */ + function getHTTPBody($soapmsg) { + if (count($this->requestAttachments) > 0) { + $params['content_type'] = 'multipart/related; type=text/xml'; + $mimeMessage =& new Mail_mimePart('', $params); + unset($params); + + $params['content_type'] = 'text/xml'; + $params['encoding'] = '8bit'; + $params['charset'] = $this->soap_defencoding; + $mimeMessage->addSubpart($soapmsg, $params); + + foreach ($this->requestAttachments as $att) { + unset($params); + + $params['content_type'] = $att['contenttype']; + $params['encoding'] = 'base64'; + $params['disposition'] = 'attachment'; + $params['dfilename'] = $att['filename']; + $params['cid'] = $att['cid']; + + if ($att['data'] == '' && $att['filename'] <> '') { + if ($fd = fopen($att['filename'], 'rb')) { + $data = fread($fd, filesize($att['filename'])); + fclose($fd); + } else { + $data = ''; + } + $mimeMessage->addSubpart($data, $params); + } else { + $mimeMessage->addSubpart($att['data'], $params); + } + } + + $output = $mimeMessage->encode(); + $mimeHeaders = $output['headers']; + + foreach ($mimeHeaders as $k => $v) { + $this->debug("MIME header $k: $v"); + if (strtolower($k) == 'content-type') { + // PHP header() seems to strip leading whitespace starting + // the second line, so force everything to one line + $this->mimeContentType = str_replace("\r\n", " ", $v); + } + } + + return $output['body']; + } + + return parent::getHTTPBody($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 private + */ + function getHTTPContentType() { + if (count($this->requestAttachments) > 0) { + return $this->mimeContentType; + } + return parent::getHTTPContentType(); + } + + /** + * 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 private + */ + function getHTTPContentTypeCharset() { + if (count($this->requestAttachments) > 0) { + return false; + } + return parent::getHTTPContentTypeCharset(); + } + + /** + * 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 private + */ + function parseResponse($headers, $data) { + $this->debug('Entering parseResponse() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); + $this->responseAttachments = array(); + if (strstr($headers['content-type'], 'multipart/related')) { + $this->debug('Decode multipart/related'); + $input = ''; + foreach ($headers as $k => $v) { + $input .= "$k: $v\r\n"; + } + $params['input'] = $input . "\r\n" . $data; + $params['include_bodies'] = true; + $params['decode_bodies'] = true; + $params['decode_headers'] = true; + + $structure = Mail_mimeDecode::decode($params); + + foreach ($structure->parts as $part) { + if (!isset($part->disposition)) { + $this->debug('Have root part of type ' . $part->headers['content-type']); + $return = parent::parseResponse($part->headers, $part->body); + } else { + $this->debug('Have an attachment of type ' . $part->headers['content-type']); + $info['data'] = $part->body; + $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; + $info['contenttype'] = $part->headers['content-type']; + $info['cid'] = $part->headers['content-id']; + $this->responseAttachments[] = $info; + } + } + + if (isset($return)) { + return $return; + } + + $this->setError('No root part found in multipart/related content'); + return; + } + $this->debug('Not multipart/related'); + return parent::parseResponse($headers, $data); + } +} + +/** +* nusoapservermime server supporting MIME attachments defined at +* http://www.w3.org/TR/SOAP-attachments. It depends on the PEAR Mail_MIME library. +* +* @author Scott Nichol <snichol@sourceforge.net> +* @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list +* @version $Id: nusoapmime.php,v 1.7 2005/07/27 19:24:42 snichol Exp $ +* @access public +*/ +class nusoapservermime extends soap_server { + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $requestAttachments = array(); + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $responseAttachments; + /** + * @var string + * @access private + */ + var $mimeContentType; + + /** + * adds a MIME attachment to the current response. + * + * If the $data parameter contains an empty string, this method will read + * the contents of the file named by the $filename parameter. + * + * If the $cid parameter is false, this method will generate the cid. + * + * @param string $data The data of the attachment + * @param string $filename The filename of the attachment (default is empty string) + * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) + * @param string $cid The content-id (cid) of the attachment (default is false) + * @return string The content-id (cid) of the attachment + * @access public + */ + function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { + if (! $cid) { + $cid = md5(uniqid(time())); + } + + $info['data'] = $data; + $info['filename'] = $filename; + $info['contenttype'] = $contenttype; + $info['cid'] = $cid; + + $this->responseAttachments[] = $info; + + return $cid; + } + + /** + * clears the MIME attachments for the current response. + * + * @access public + */ + function clearAttachments() { + $this->responseAttachments = array(); + } + + /** + * gets the MIME attachments from the current request. + * + * Each array element in the return is an associative array with keys + * data, filename, contenttype, cid. These keys correspond to the parameters + * for addAttachment. + * + * @return array The attachments. + * @access public + */ + function getAttachments() { + return $this->requestAttachments; + } + + /** + * gets the HTTP body for the current response. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + if (count($this->responseAttachments) > 0) { + $params['content_type'] = 'multipart/related; type=text/xml'; + $mimeMessage =& new Mail_mimePart('', $params); + unset($params); + + $params['content_type'] = 'text/xml'; + $params['encoding'] = '8bit'; + $params['charset'] = $this->soap_defencoding; + $mimeMessage->addSubpart($soapmsg, $params); + + foreach ($this->responseAttachments as $att) { + unset($params); + + $params['content_type'] = $att['contenttype']; + $params['encoding'] = 'base64'; + $params['disposition'] = 'attachment'; + $params['dfilename'] = $att['filename']; + $params['cid'] = $att['cid']; + + if ($att['data'] == '' && $att['filename'] <> '') { + if ($fd = fopen($att['filename'], 'rb')) { + $data = fread($fd, filesize($att['filename'])); + fclose($fd); + } else { + $data = ''; + } + $mimeMessage->addSubpart($data, $params); + } else { + $mimeMessage->addSubpart($att['data'], $params); + } + } + + $output = $mimeMessage->encode(); + $mimeHeaders = $output['headers']; + + foreach ($mimeHeaders as $k => $v) { + $this->debug("MIME header $k: $v"); + if (strtolower($k) == 'content-type') { + // PHP header() seems to strip leading whitespace starting + // the second line, so force everything to one line + $this->mimeContentType = str_replace("\r\n", " ", $v); + } + } + + return $output['body']; + } + + return parent::getHTTPBody($soapmsg); + } + + /** + * gets the HTTP content type for the current response. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current response. + * @access private + */ + function getHTTPContentType() { + if (count($this->responseAttachments) > 0) { + return $this->mimeContentType; + } + return parent::getHTTPContentType(); + } + + /** + * gets the HTTP content type charset for the current response. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current response. + * @access private + */ + function getHTTPContentTypeCharset() { + if (count($this->responseAttachments) > 0) { + return false; + } + return parent::getHTTPContentTypeCharset(); + } + + /** + * processes SOAP message received from client + * + * @param array $headers The HTTP headers + * @param string $data unprocessed request data from client + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseRequest($headers, $data) { + $this->debug('Entering parseRequest() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); + $this->requestAttachments = array(); + if (strstr($headers['content-type'], 'multipart/related')) { + $this->debug('Decode multipart/related'); + $input = ''; + foreach ($headers as $k => $v) { + $input .= "$k: $v\r\n"; + } + $params['input'] = $input . "\r\n" . $data; + $params['include_bodies'] = true; + $params['decode_bodies'] = true; + $params['decode_headers'] = true; + + $structure = Mail_mimeDecode::decode($params); + + foreach ($structure->parts as $part) { + if (!isset($part->disposition)) { + $this->debug('Have root part of type ' . $part->headers['content-type']); + $return = parent::parseRequest($part->headers, $part->body); + } else { + $this->debug('Have an attachment of type ' . $part->headers['content-type']); + $info['data'] = $part->body; + $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; + $info['contenttype'] = $part->headers['content-type']; + $info['cid'] = $part->headers['content-id']; + $this->requestAttachments[] = $info; + } + } + + if (isset($return)) { + return $return; + } + + $this->setError('No root part found in multipart/related content'); + return; + } + $this->debug('Not multipart/related'); + return parent::parseRequest($headers, $data); + } +} +?> diff --git a/library/WebPlugin/Pay/PayAbstract.php b/library/WebPlugin/Pay/PayAbstract.php new file mode 100644 index 0000000..dddb7f3 --- /dev/null +++ b/library/WebPlugin/Pay/PayAbstract.php @@ -0,0 +1,73 @@ +<?php + +namespace WebPlugin\Pay; + +abstract class PayAbstract implements PayInterface { + + /** + * 记录日志的前缀,每种支付方式都有三个项目,请求、回复成功,回复失败,如:alipay_request, alipay_success_response, alipay_error_response + */ + public $logProjectPrefix = ''; + + /** + * 用于存储通知回调的基础url + * + * @var + */ + public $baseNoticeUrl = "http://www.yohobuy.com/pay/"; + +// public $baseNoticeUrl = "http://www.yohobuy.com/pay/"; + + /** + * 测试的回调地址 + * Enter description here ... + * @var string + */ + public $testBaseNoticeUrl = "http://www.yohobuy.com/pay/"; + + /** + * 获取支付的基地址 + * + * @param bool $isTest + * @return string + */ + public function getBaseNoticeUrl($isTest){ + return $isTest ? $this->testBaseNoticeUrl : $this->baseNoticeUrl; + } + + /** + * h(non-PHPdoc) + * @see QPay_Utils_Interface::getPayRequestPars() + * @param Reqparams $params + */ + public function getPayRequestPars(Reqparams $params) { + + } + + /** + * (non-PHPdoc) + * @see QPay_Utils_Interface::parseResponse() + * @param array $arrResponse + * @return void + */ + public function parseResponse(array $arrResponse){ + + } + + /** + * (non-PHPdoc) + * @see QPay_Utils_Interface::convertResult() + */ + protected function convertResult($resultCode) { + + } + + /** + * (non-PHPdoc) + * @see QPay_Utils_Interface::verifResponse() + */ + protected function checkResponse(array $arrResponse){ + + } + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/PayFactory.php b/library/WebPlugin/Pay/PayFactory.php new file mode 100644 index 0000000..71a74c7 --- /dev/null +++ b/library/WebPlugin/Pay/PayFactory.php @@ -0,0 +1,19 @@ +<?php + +namespace WebPlugin\Pay; + +class PayFactory { + + static public function factory(array $paymentParams) { + + $payCode = $paymentParams['pay_code']; + if(empty($payCode)) { + return false; + } + $className = __NAMESPACE__ . '\\' . $payCode . '\\Service'; + if(class_exists($className)){ + return new $className ( $paymentParams ); + } + return false; + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/PayInterface.php b/library/WebPlugin/Pay/PayInterface.php new file mode 100644 index 0000000..0b78159 --- /dev/null +++ b/library/WebPlugin/Pay/PayInterface.php @@ -0,0 +1,21 @@ +<?php + +namespace WebPlugin\Pay; + +interface PayInterface +{ + /** + * 获取支付请求的url + * Enter description here ... + * @param Reqparams $params + */ + function getPayRequestPars(Reqparams $params); + + /** + * 解析返回的参数 + * Enter description here ... + * @param array $arrResponse + * @return QPay_Utils_Rspparams + */ + function parseResponse(Array $arrResponse); +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Reqparams.php b/library/WebPlugin/Pay/Reqparams.php new file mode 100644 index 0000000..522850d --- /dev/null +++ b/library/WebPlugin/Pay/Reqparams.php @@ -0,0 +1,89 @@ +<?php + +namespace WebPlugin\Pay; + +/** + * 请求付款的参数类 + * Enter description here ... + * @author smile + * + */ +class Reqparams +{ + + public function __construct($_orderCode, $_totalFee, $_goodName, $client_ip, $_orderTime, $_paymentParameter="", $_isTest=false, $uid=0, $userName='') + { + $this->orderCode = $_orderCode; + $this->totalFee = $_totalFee; + $this->goodsName = $_goodName; + $this->spbill_create_ip = $client_ip; + $this->orderTime = $_orderTime; + $this->paymentParameter = $_paymentParameter; + $this->isTest = $_isTest; + $this->uid = $uid; + $this->userName = $userName; + } + + /** + * 订单Code + * Enter description here ... + * @var Integer + */ + var $orderCode = 0; + + /** + * 付款金额,统一采用分为单位 + * Enter description here ... + * @var double + */ + var $totalFee = 0; + + + /** + * 商品名称 + * Enter description here ... + * @var String + */ + var $goodsName = ""; + + /** + * 客户的ip + * Enter description here ... + * @var string + */ + var $spbill_create_ip = ""; + + /** + * 订单时间 + * Enter description here ... + * @var unknown_type + */ + var $orderTime = ""; + + /** + * 支付方式参数 + * Enter description here ... + * @var string + */ + var $paymentParameter = ""; + + /** + * 是否为测试 + * Enter description here ... + * @var bool + */ + var $isTest = false; + + /** + * 用户ID + * @var integer + */ + var $uid = 0; + + /** + * 用户名 + * @var string + */ + var $userName = ''; + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Rspparams.php b/library/WebPlugin/Pay/Rspparams.php new file mode 100644 index 0000000..a95cd65 --- /dev/null +++ b/library/WebPlugin/Pay/Rspparams.php @@ -0,0 +1,67 @@ +<?php + +namespace WebPlugin\Pay; + +/** + * 回复参数 + * Enter description here ... + * @author smile + * + */ +class Rspparams +{ + /** + * 支付结果,0为成功,1为失败 + * Enter description here ... + * @var Integer + */ + var $payResult; + + /** + * 付款时间 + * Enter description here ... + * @var Integer + */ + var $payTime ; + + /** + * 订单Code + * Enter description here ... + * @var unknown_type + */ + var $orderCode; + + /** + * 支付的总金额 + * Enter description here ... + * @var unknown_type + */ + var $totalFee; + + /** + * 银行名称,中文名 + * Enter description here ... + * @var String + */ + var $bankName = ""; + + /** + * 银行代码 + * Enter description here ... + * @var string + */ + var $bankCode = ""; + + /** + * 结果信息 + * Enter description here ... + * @var string + */ + var $resultMsg; + + /** + * 要返回的数据 + * @var string + */ + var $returnData; +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Shengpay/Config.php b/library/WebPlugin/Pay/Shengpay/Config.php new file mode 100644 index 0000000..62ad5dd --- /dev/null +++ b/library/WebPlugin/Pay/Shengpay/Config.php @@ -0,0 +1,110 @@ +<?php + +namespace WebPlugin\Pay\Shengpay; + +class Config +{ + /** + * 直连方式支付地址 + * Enter description here ... + * @var string + */ + var $direct_pay_url = "http://mas.sdo.com/web-acquire-channel/cashier30direct.htm"; + + /** + * 直连方式支付测试地址 + * Enter description here ... + * @var string + */ + var $direct_pay_url_test = "http://mas.sdo.com/web-acquire-channel/cashier30direct.htm"; + + /** + * 非直连方式支付地址 + */ + var $pay_url = "http://mas.sdo.com/web-acquire-channel/cashier30.htm"; + + /** + * 非直连方式支付测试地址 + * Enter description here ... + * @var string + */ + var $pay_url_test = "http://mas.sdo.com/web-acquire-channel/cashier30.htm"; + + /** + * 版本号 + * Enter description here ... + * @var string + */ + var $version = "3.0"; + + /** + * 商户号 + * Enter description here ... + * @var unknown_type + */ + var $merchant_no = ""; + + + /** + * 商户MD5加密串 + * Enter description here ... + * @var string + */ + var $merchant_key = ""; + + /** + * 支付渠道,网银B2C + * Enter description here ... + * @var string + */ + var $pay_channel = "04"; + + /** + * 客户端回调地址 + * Enter description here ... + * @var string + */ + var $post_back_url = "notice/shengpayreturn"; + + /** + * 服务器端通知地址 + * Enter description here ... + * @var string + */ + var $notify_url = "notice/shengpaynotice"; + + /** + * 商户下单地址 + * Enter description here ... + * @var string + */ + var $back_url = "http://www.yohobuy.com/home"; + + /** + * 货币类型 + * Enter description here ... + * @var string + */ + var $currency_type = "RMB"; + + /** + * 发货通知方式 + * Enter description here ... + * @var string + */ + var $notify_url_type = "http"; + + /** + * 签名方式,1-rsa,2-md5 + * Enter description here ... + * @var string + */ + var $sign_type = "2"; + + /** + * 支付银行 + * Enter description here ... + * @var string + */ + var $test_bank_code = "SDTBNK"; +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Shengpay/Service.php b/library/WebPlugin/Pay/Shengpay/Service.php new file mode 100644 index 0000000..e87dbf6 --- /dev/null +++ b/library/WebPlugin/Pay/Shengpay/Service.php @@ -0,0 +1,155 @@ +<?php + +namespace WebPlugin\Pay\Shengpay; + +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; + +class Service extends PayAbstract +{ + + var $config ; + + public function __construct(array $paymentParams) + { + $this->logProjectPrefix = 'shengpay'; + $this->config = new Config(); + $myConfig = json_decode($paymentParams["pay_params"]) ; + $this->config->merchant_no = $myConfig->merchant_id; + $this->config->merchant_key = $myConfig->merchant_key; + } + + /** + * @param Reqparams $params + * @return array|void + */ + public function getPayRequestPars(Reqparams $params) + { + $bankCode = $params->paymentParameter == 'platform' ? '' : $params->paymentParameter; + $baseUrl = $this->getBaseNoticeUrl($params->isTest); + $parameters = array( + 'Version' => $this->config->version, + 'Amount' => sprintf("%.2f", $params->totalFee * 0.01), + 'OrderNo' => $params->orderCode, + 'MerchantNo' => $this->config->merchant_no, + 'PayChannel' => $this->config->pay_channel, + 'PostBackUrl' => $baseUrl . $this->config->post_back_url, + 'NotifyUrl' => $baseUrl . $this->config->notify_url, + 'BackUrl' => $this->config->back_url, + 'OrderTime' => date('YmdHis', $params->orderTime), + 'CurrencyType' => $this->config->currency_type, + 'NotifyUrlType' => $this->config->notify_url_type, + 'SignType' => $this->config->sign_type, + 'BankCode' => $bankCode //银行代码 + ); + $parameters["MAC"] = $this->getSign($parameters); + + $isDirect = empty($bankCode) ? false : TRUE; + $result = array( + 'pay_url' => $this->getPayUrl($isDirect, $params->isTest), + 'pars' => $parameters, + 'reqType' => 'post' + ); + + return $result; + } + + /** + * 获取支付地址 + * Enter description here ... + * @param bool $isDirect 是否为直连 + * @param bool $isTest 是否为测试环境 + * @return string + */ + public function getPayUrl($isDirect, $isTest){ + if($isDirect){ + if($isTest){ + return $this->config->direct_pay_url_test; + }else{ + return $this->config->direct_pay_url; + } + } else { + if($isTest){ + return $this->config->pay_url_test; + } else { + return $this->config->pay_url; + } + } + } + + /** + * 获取签名 + * @param array $pars + * @return string + */ + public function getSign(array $pars) + { + $strPars = $pars['Version'] . $pars['Amount'] . $pars['OrderNo'] . $pars['MerchantNo'] . $pars['PayChannel'] + . $pars['PostBackUrl'] . $pars['NotifyUrl'] . $pars['BackUrl'] . $pars['OrderTime'] . $pars['CurrencyType'] + . $pars['NotifyUrlType'] . $pars['SignType'] . $pars['BankCode']; + return md5($strPars . $this->config->merchant_key); + } + + /** + * 解析结果 + * @param array $arrResponse + * @return void|Rspparams + */ + function parseResponse(Array $arrResponse){ + + $rsp = new Rspparams(); + if(!$this->checkResponse($arrResponse)){ + //验证不成功 + $rsp->payResult = -1; + } + else{ + $rsp->bankName = ""; + $rsp->orderCode = $arrResponse["OrderNo"]; + $rsp->payResult = $this->convertResult($arrResponse["Status"]); + $rsp->payTime = time(); + $rsp->totalFee = $arrResponse["Amount"]; + $rsp->resultMsg = $arrResponse["ExInfo"]; + //添加支付订单号和交易号 + $rsp->payOrderCode = $arrResponse["orderNo"]; + $rsp->tradeNo = ""; + $rsp->bankBillNo = ""; + } + + return $rsp; + } + + /** + * 验证回复的正确性 + * @param array $arrResponse + * @return bool|void + */ + protected function checkResponse(array $arrResponse) + { + $strPars = $arrResponse["Amount"] . '|' . $arrResponse['PayAmount'] . '|' . $arrResponse['OrderNo'] . '|' . $arrResponse['serialno'] . + '|' . $arrResponse['Status'] . '|' . $arrResponse['MerchantNo'] . '|' . $arrResponse['PayChannel'] . '|' . $arrResponse['Discount'] + . '|' . $arrResponse["SignType"] . '|' . $arrResponse['PayTime'] . '|' . $arrResponse['CurrencyType'] . '|' . $arrResponse['ProductNo'] + . '|' . $arrResponse['ProductDesc'] . '|' . $arrResponse['Remark1'] . '|' . $arrResponse['Remark2'] . '|' . $arrResponse['ExInfo']; + $vaildSign = md5($strPars . '|' . $this->config->merchant_key); + if(strtoupper($vaildSign) == $arrResponse["MAC"]){ + return true; + } + + return false; + } + + /** + * @param $resultCode + * @return int|void + */ + protected function convertResult($resultCode) + { + if($resultCode == "01") //20为支付成功,30为支付失败 + { + return 200; + } + return $resultCode; + } + + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Signature.php b/library/WebPlugin/Pay/Signature.php new file mode 100644 index 0000000..8e8a7f5 --- /dev/null +++ b/library/WebPlugin/Pay/Signature.php @@ -0,0 +1,46 @@ +<?php + +namespace WebPlugin\Pay; + +/** + * 接口签名 + */ +class Signature +{ + /** + * 排序参数 + * @param array $package + * @return array + */ + static function packageSort(array $package) + { + ksort($package); + reset($package); + return $package; + } + + /** + * 组合签名 + * @param array $package + * @return string + */ + static function makeSign(array $package) + { + $packageList = array(); + foreach ($package as $key => $val) { + $packageList[] = trim($key . '=' . $val); + } + return strtolower(md5(implode('&', $packageList))); + } + + /** + * 校验签名 + * @param $submitSign + * @param $makeSign + * @return bool + */ + static function verifySign($submitSign, $makeSign) + { + return strtolower($submitSign) == strtolower($makeSign); + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Tenpay/Config.php b/library/WebPlugin/Pay/Tenpay/Config.php new file mode 100644 index 0000000..6b00408 --- /dev/null +++ b/library/WebPlugin/Pay/Tenpay/Config.php @@ -0,0 +1,56 @@ +<?php + +namespace WebPlugin\Pay\Tenpay; + +class Config +{ + + /** + * 支付请求的地址 + * Enter description here ... + * @var string + */ + var $pay_url = "https://www.tenpay.com/cgi-bin/v1.0/pay_gate.cgi"; + + /** + * 业务代码,财付通支付接口用户填1 + * Enter description here ... + * @var Integer + */ + var $cmdno = 1; + + /** + * 银行类型,财务通添0 + * Enter description here ... + * @var Integer + */ + var $bank_type = 0; + + /** + * 商户ID + * Enter description here ... + * @var String + */ + var $bargainor_id = ""; + + /** + * 商户Key + * Enter description here ... + * @var unknown_type + */ + var $sp_key = ""; + + /** + * 接受财付通返回结果的url + * Enter description here ... + * @var unknown_type + */ + var $return_url = "notice/tenpay"; + + /** + * 货币类型 + * Enter description here ... + * @var unknown_type + */ + var $fee_type = 1; //人民币 +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Tenpay/Service.php b/library/WebPlugin/Pay/Tenpay/Service.php new file mode 100644 index 0000000..68edfe8 --- /dev/null +++ b/library/WebPlugin/Pay/Tenpay/Service.php @@ -0,0 +1,125 @@ +<?php + +namespace WebPlugin\Pay\Tenpay; + +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; + +class Service extends PayAbstract +{ + + var $config; + + /** + * Service constructor. + * @param array $paymentParams + */ + public function __construct(array $paymentParams) + { + $this->logProjectPrefix = 'tenpay'; + $this->config = new Config(); + $myConfig = json_decode($paymentParams["pay_params"]); + $this->config->bargainor_id = $myConfig->merchant_id; + $this->config->sp_key = $myConfig->merchant_key; + } + + /** + * @param Reqparams $params + * @return array + */ + public function getPayRequestPars(Reqparams $params) + { + parent::getPayRequestPars($params); + $baseUrl = $this->getBaseNoticeUrl($params->isTest); + + $reqData = array(); + $sign_text = "cmdno=" . $this->config->cmdno; + $sign_text .= "&date=" . date('Ymd'); + // $sign_text .= "&bank_type=0"; + $goodName = urlencode(iconv("UTF-8", "GB2312", $params->goodsName)); + $sign_text .= "&bargainor_id=" . $this->config->bargainor_id; + $sign_text .= "&transaction_id=" . $this->config->bargainor_id . date('Ymd') . date('mdHis'); + $sign_text .= "&sp_billno=" . $params->orderCode; //内部订单号 + $sign_text .= "&total_fee=" . $params->totalFee; + $sign_text .= "&fee_type=" . $this->config->fee_type; + $sign_text .= "&return_url=" . $baseUrl . $this->config->return_url; + $sign_text .= "&attach=" . $params->orderCode; + if (!empty($params->spbill_create_ip)) { + $sign_text .= "&spbill_create_ip=" . $params->spbill_create_ip; + } + + $sign = strtoupper(md5($sign_text . "&key=" . $this->config->sp_key)); + + $sign_text = $sign_text . "&sign=" . $sign . "&desc=" . $goodName . "&bank_type=0&cs=gb2312"; + $result = array( + 'pay_url' => $this->config->pay_url, + 'pars' => $sign_text, + 'reqType' => 'get' + ); + + return $result; + } + + /** + * 解析返回的参数 + * @param Array $arrResponse + * @return void|Rspparams + */ + public function parseResponse(array $arrResponse) + { + $rsp = new Rspparams(); + if (!$this->checkResponse($arrResponse)) { + //验证不成功 + $rsp->payResult = 400; + } else { + $rsp->bankName = ""; + $rsp->orderCode = $arrResponse["sp_billno"]; + $rsp->payResult = $this->convertResult($arrResponse["pay_result"]); + $rsp->payTime = $arrResponse["pay_time"]; + $rsp->totalFee = round($arrResponse["total_fee"], 2) / 100; //返回的是分,要转化成元 + $rsp->resultMsg = $arrResponse['pay_info']; + //添加支付订单号和交易号 + $rsp->payOrderCode = $arrResponse["sp_billno"]; + $rsp->tradeNo = ""; + $rsp->bankBillNo = ""; + } + return $rsp; + } + + /** + * @param $resultCode + * @return int|void + */ + protected function convertResult($resultCode) + { + if ($resultCode == 0) { + return 200; + } + return $resultCode; + } + + /** + * 验证回复的正确性 + * @param array $arrResponse + * @return bool|void + */ + protected function checkResponse(array $arrResponse) + { + $strResponseText = "cmdno=" . $arrResponse["cmdno"]; + $strResponseText .= "&pay_result=" . $arrResponse["pay_result"]; + $strResponseText .= "&date=" . $arrResponse["date"]; + $strResponseText .= "&transaction_id=" . $arrResponse["transaction_id"]; + $strResponseText .= "&sp_billno=" . $arrResponse["sp_billno"]; + $strResponseText .= "&total_fee=" . $arrResponse["total_fee"]; + $strResponseText .= "&fee_type=" . $arrResponse["fee_type"]; + $strResponseText .= "&attach=" . $arrResponse["attach"]; + $strResponseText .= "&key=" . $this->config->sp_key; + + if (strtoupper(md5($strResponseText)) == $arrResponse["sign"]) { + return true; + } + return false; + } + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/Func/PhpLog.php b/library/WebPlugin/Pay/Unionpayweb/Func/PhpLog.php new file mode 100644 index 0000000..1222ea8 --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/Func/PhpLog.php @@ -0,0 +1,273 @@ +<?php + +namespace WebPlugin\Pay\Unionpayweb\Func; + +class PhpLog +{ + const DEBUG = 1;// Most Verbose + const INFO = 2;// ... + const WARN = 3;// ... + const ERROR = 4;// ... + const FATAL = 5;// Least Verbose + const OFF = 6;// Nothing at all. + + const LOG_OPEN = 1; + const OPEN_FAILED = 2; + const LOG_CLOSED = 3; + + /* Public members: Not so much of an example of encapsulation, but that's okay. */ + public $Log_Status = PhpLog::LOG_CLOSED; + public $DateFormat = "Y-m-d G:i:s"; + public $MessageQueue; + + private $filename; + private $log_file; + private $priority = PhpLog::INFO; + + private $file_handle; + + /** + * AUTHOR: gu_yongkang + * DATA: 20110322 + * Enter description here ... + * @param $filepath + * 文件存储的路径 + * @param $timezone + * 时间格式,此处设置为"PRC"(中国) + * @param $priority + * + * 设置运行级别 + */ + + public function __construct($filepath, $timezone, $priority) + { + if ($priority == PhpLog::OFF) return; + + $this->filename = date('Y-m-d', time()) . '.log'; //默认为以时间+.log的文件文件 + $this->log_file = $this->createPath($filepath, $this->filename); + $this->MessageQueue = array(); + $this->priority = $priority; + date_default_timezone_set($timezone); + + if (!file_exists($filepath)) //判断文件路径是否存在 + { + if (!empty($filepath)) //判断路径是否为空 + { + if (!($this->_createDir($filepath))) { + die("创建目录失败!"); + } + if (!is_writable($this->log_file)) { + $this->Log_Status = PhpLog::OPEN_FAILED; + $this->MessageQueue[] = "The file exists, but could not be opened for writing. Check that appropriate permissions have been set."; + return; + } + } + } + + if ($this->file_handle = fopen($this->log_file, "a+")) { + $this->Log_Status = PhpLog::LOG_OPEN; + $this->MessageQueue[] = "The log file was opened successfully."; + } else { + $this->Log_Status = PhpLog::OPEN_FAILED; + $this->MessageQueue[] = "The file could not be opened. Check permissions."; + } + return; + } + + public function __destruct() + { + if ($this->file_handle) + fclose($this->file_handle); + } + + /** + *作用:创建目录 + *输入:要创建的目录 + *输出:true | false + */ + private function _createDir($dir) + { + return is_dir($dir) or (self::_createDir(dirname($dir)) and mkdir($dir, 0777)); + } + + /** + *作用:构建路径 + *输入:文件的路径,要写入的文件名 + *输出:构建好的路径字串 + */ + private function createPath($dir, $filename) + { + if (empty($dir)) { + return $filename; + } else { + return $dir . "/" . $filename; + } + } + + public function LogInfo($line) + { + /** + * AUTHOR : gu_yongkang + * 增加打印函数和文件名的功能 + */ + $sAarray = array(); + $sAarray = debug_backtrace(); + $sGetFilePath = $sAarray[0]["file"]; + $sGetFileLine = $sAarray[0]["line"]; + $this->Log($line, PhpLog::INFO, $sGetFilePath, $sGetFileLine); + unset($sAarray); + unset($sGetFilePath); + unset($sGetFileLine); + } + + public function LogDebug($line) + { + /** + * AUTHOR : gu_yongkang + * 增加打印函数和文件名的功能 + */ + $sAarray = array(); + $sAarray = debug_backtrace(); + $sGetFilePath = $sAarray[0]["file"]; + $sGetFileLine = $sAarray[0]["line"]; + $this->Log($line, PhpLog::DEBUG, $sGetFilePath, $sGetFileLine); + unset($sAarray); + unset($sGetFilePath); + unset($sGetFileLine); + } + + public function LogWarn($line) + { + /** + * AUTHOR : gu_yongkang + * 增加打印函数和文件名的功能 + */ + $sAarray = array(); + $sAarray = debug_backtrace(); + $sGetFilePath = $sAarray[0]["file"]; + $sGetFileLine = $sAarray[0]["line"]; + $this->Log($line, PhpLog::WARN, $sGetFilePath, $sGetFileLine); + unset($sAarray); + unset($sGetFilePath); + unset($sGetFileLine); + } + + public function LogError($line) + { + /** + * AUTHOR : gu_yongkang + * 增加打印函数和文件名的功能 + */ + $sAarray = array(); + $sAarray = debug_backtrace(); + $sGetFilePath = $sAarray[0]["file"]; + $sGetFileLine = $sAarray[0]["line"]; + $this->Log($line, PhpLog::ERROR, $sGetFilePath, $sGetFileLine); + unset($sAarray); + unset($sGetFilePath); + unset($sGetFileLine); + } + + public function LogFatal($line) + { + /** + * AUTHOR : gu_yongkang + * 增加打印函数和文件名的功能 + */ + $sAarray = array(); + $sAarray = debug_backtrace(); + $sGetFilePath = $sAarray[0]["file"]; + $sGetFileLine = $sAarray[0]["line"]; + $this->Log($line, PhpLog::FATAL, $sGetFilePath, $sGetFileLine); + unset($sAarray); + unset($sGetFilePath); + unset($sGetFileLine); + } + + /** + * Author : gu_yongkang + * Enter description here ... + * @param unknown_type $line + * content 内容 + * @param unknown_type $priority + * 打印级别 + * @param unknown_type $sFile + * 调用打印日志的文件名 + * @param unknown_type $iLine + * 打印文件的位置(行数) + */ + public function Log($line, $priority, $sFile, $iLine) + { + if ($iLine > 0) { +// $line = iconv('GBK', 'UTF-8', $line); + if ($this->priority <= $priority) { + $status = $this->getTimeLine($priority, $sFile, $iLine); + $this->WriteFreeFormLine("$status $line \n"); + } + } else { + /** + * AUTHOR : gu_yongkang + * 增加打印函数和文件名的功能 + */ + $sAarray = array(); + $sAarray = debug_backtrace(); + $sGetFilePath = $sAarray[0]["file"]; + $sGetFileLine = $sAarray[0]["line"]; + if ($this->priority <= $priority) { + $status = $this->getTimeLine($priority, $sGetFilePath, $sGetFileLine); + unset($sAarray); + unset($sGetFilePath); + unset($sGetFileLine); + $this->WriteFreeFormLine("$status $line \n"); + } + } + } + + // 支持输入多个参数 + public function WriteFreeFormLine($line) + { + if ($this->Log_Status == PhpLog::LOG_OPEN && $this->priority != PhpLog::OFF) { + if (fwrite($this->file_handle, $line) === false) { + $this->MessageQueue[] = "The file could not be written to. Check that appropriate permissions have been set."; + } + } + } + + private function getRemoteIP() + { + foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key) { + if (array_key_exists($key, $_SERVER) === true) { + foreach (explode(',', $_SERVER[$key]) as $ip) { + $ip = trim($ip); + if (!empty($ip)) { + return $ip; + } + } + } + } + return "_NO_IP"; + } + + + private function getTimeLine($level, $FilePath, $FileLine) + { + $time = date($this->DateFormat); + $ip = $this->getRemoteIP(); + switch ($level) { + case PhpLog::INFO: + return "$time, " . "INFO, " . "$ip, " . "File[ $FilePath ], " . "Line[$FileLine]" . "------"; + case PhpLog::WARN: + return "$time, " . "WARN, " . "$ip, " . "File[ $FilePath ], " . "Line[$FileLine]" . "------"; + case PhpLog::DEBUG: + return "$time, " . "DEBUG, " . "$ip, " . "File[ $FilePath ], " . "Line[$FileLine]" . "------"; + case PhpLog::ERROR: + return "$time, " . "ERROR, " . "$ip, " . "File[ $FilePath ], " . "Line[$FileLine]" . "------"; + case PhpLog::FATAL: + return "$time, " . "FATAL, " . "$ip, " . "File[ $FilePath ], " . "Line[$FileLine]" . "------"; + default: + return "$time, " . "LOG, " . "$ip, " . "File[ $FilePath ], " . "Line[$FileLine]" . "------"; + } + } +} + +?> diff --git a/library/WebPlugin/Pay/Unionpayweb/Func/PinBlock.php b/library/WebPlugin/Pay/Unionpayweb/Func/PinBlock.php new file mode 100644 index 0000000..f50159d --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/Func/PinBlock.php @@ -0,0 +1,124 @@ +<?php + /** + * Author: gu_yongkang + * data: 20110510 + * 密码转PIN + * Enter description here ... + * @param $spin + */ + function Pin2PinBlock( &$sPin ) + { + // $sPin = "123456"; + $iTemp = 1; + $sPinLen = strlen($sPin); + $sBuf = array(); + //密码域大于10位 + $sBuf[0]=intval($sPinLen, 10); + + if($sPinLen % 2 ==0) + { + for ($i=0; $i<$sPinLen;) + { + $tBuf = substr($sPin, $i, 2); + $sBuf[$iTemp] = intval($tBuf, 16); + unset($tBuf); + if ($i == ($sPinLen - 2)) + { + if ($iTemp < 7) + { + $t = 0; + for ($t=($iTemp+1); $t<8; $t++) + { + $sBuf[$t] = 0xff; + } + } + } + $iTemp++; + $i = $i + 2; //linshi + } + } + else + { + for ($i=0; $i<$sPinLen;) + { + if ($i ==($sPinLen-1)) + { + $mBuf = substr($sPin, $i, 1) . "f"; + $sBuf[$iTemp] = intval($mBuf, 16); + unset($mBuf); + if (($iTemp)<7) + { + $t = 0; + for ($t=($iTemp+1); $t<8; $t++) + { + $sBuf[$t] = 0xff; + } + } + } + else + { + $tBuf = substr($sPin, $i, 2); + $sBuf[$iTemp] = intval($tBuf, 16); + unset($tBuf); + } + $iTemp++; + $i = $i + 2; + } + } + return $sBuf; + } + /** + * Author: gu_yongkang + * data: 20110510 + * Enter description here ... + * @param $sPan + */ + function FormatPan(&$sPan) + { + $iPanLen = strlen($sPan); + $iTemp = $iPanLen - 13; + $sBuf = array(); + $sBuf[0] = 0x00; + $sBuf[1] = 0x00; + for ($i=2; $i<8; $i++) + { + $tBuf = substr($sPan, $iTemp, 2); + $sBuf[$i] = intval($tBuf, 16); + $iTemp = $iTemp + 2; + } + return $sBuf; + } + + function Pin2PinBlockWithCardNO(&$sPin, &$sCardNO) + { + global $log; + $sPinBuf = Pin2PinBlock($sPin); + $iCardLen = strlen($sCardNO); +// $log->LogInfo("CardNO length : " . $iCardLen); + if ($iCardLen <= 10) + { + return (1); + } + elseif ($iCardLen==11){ + $sCardNO = "00" . $sCardNO; + } + elseif ($iCardLen==12){ + $sCardNO = "0" . $sCardNO; + } + $sPanBuf = FormatPan($sCardNO); + $sBuf = array(); + + for ($i=0; $i<8; $i++) + { +// $sBuf[$i] = $sPinBuf[$i] ^ $sPanBuf[$i]; //十进制 +// $sBuf[$i] = vsprintf("%02X", ($sPinBuf[$i] ^ $sPanBuf[$i])); + $sBuf[$i] = vsprintf("%c", ($sPinBuf[$i] ^ $sPanBuf[$i])); + } + unset($sPinBuf); + unset($sPanBuf); +// return $sBuf; + $sOutput = implode("", $sBuf); //数组转换为字符串 + return $sOutput; + } + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/Func/PublicEncrypte.php b/library/WebPlugin/Pay/Unionpayweb/Func/PublicEncrypte.php new file mode 100644 index 0000000..b5510fd --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/Func/PublicEncrypte.php @@ -0,0 +1,51 @@ +<?php + include_once 'PinBlock.php'; + function EncryptedPin($sPin, $sCardNo ,$sPubKeyURL) + { + global $log; + $sPubKeyURL = trim(SDK_ENCRYPT_CERT_PATH," "); + // $log->LogInfo("DisSpaces : " . PubKeyURL); + $fp = fopen($sPubKeyURL, "r"); + if ($fp != NULL) + { + $sCrt = fread($fp, 8192); + // $log->LogInfo("fread PubKeyURL : " . $sCrt); + fclose($fp); + } + $sPubCrt = openssl_x509_read($sCrt); + if ($sPubCrt === FALSE) + { + print("openssl_x509_read in false!"); + return (-1); + } + // $log->LogInfo($sPubCrt); + // $sPubKeyId = openssl_x509_parse($sCrt); + // $log->LogInfo($sPubKeyId); + $sPubKey = openssl_x509_parse($sPubCrt); + // $log->LogInfo($sPubKey); + // openssl_x509_free($sPubCrt); + // print_r(openssl_get_publickey($sCrt)); + + $sInput = Pin2PinBlockWithCardNO($sPin, $sCardNo); + if ($sInput == 1) + { + print("Pin2PinBlockWithCardNO Error ! : " . $sInput); + return (1); + } + $iRet = openssl_public_encrypt($sInput, $sOutData, $sCrt, OPENSSL_PKCS1_PADDING); + if ($iRet === TRUE) + { + // $log->LogInfo($sOutData); + $sBase64EncodeOutData = base64_encode($sOutData); + //print("PayerPin : " . $sBase64EncodeOutData); + return $sBase64EncodeOutData; + } + else + { + print("openssl_public_encrypt Error !"); + return (-1); + } + } + + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/Func/common.php b/library/WebPlugin/Pay/Unionpayweb/Func/common.php new file mode 100644 index 0000000..fd36522 --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/Func/common.php @@ -0,0 +1,166 @@ +<?php +// 初始化日志 +use WebPlugin\Pay\Unionpayweb\Func\PhpLog; + +$log = new PhpLog (SDK_LOG_FILE_PATH, "PRC", SDK_LOG_LEVEL); +/** + * 数组 排序后转化为字体串 + * + * @param array $params + * @return string + */ +function coverParamsToString($params) +{ + $sign_str = ''; + // 排序 + ksort($params); + foreach ($params as $key => $val) { + if ($key == 'signature') { + continue; + } + $sign_str .= sprintf("%s=%s&", $key, $val); + // $sign_str .= $key . '=' . $val . '&'; + } + return substr($sign_str, 0, strlen($sign_str) - 1); +} + +/** + * 字符串转换为 数组 + * + * @param unknown_type $str + * @return multitype:unknown + */ +function coverStringToArray($str) +{ + $result = array(); + + if (!empty ($str)) { + $temp = preg_split('/&/', $str); + if (!empty ($temp)) { + foreach ($temp as $key => $val) { + $arr = preg_split('/=/', $val, 2); + if (!empty ($arr)) { + $k = $arr ['0']; + $v = $arr ['1']; + $result [$k] = $v; + } + } + } + } + return $result; +} + +/** + * 处理返回报文 解码客户信息 , 如果编码为utf-8 则转为utf-8 + * + * @param unknown_type $params + */ +function deal_params(&$params) +{ + /** + * 解码 customerInfo + */ + if (!empty ($params ['customerInfo'])) { + $params ['customerInfo'] = base64_decode($params ['customerInfo']); + } + + if (!empty ($params ['encoding']) && strtoupper($params ['encoding']) == 'utf-8') { + foreach ($params as $key => $val) { + $params [$key] = iconv('utf-8', 'UTF-8', $val); + } + } +} + +/** + * 压缩文件 对应java deflate + * + * @param unknown_type $params + */ +function deflate_file(&$params) +{ + global $log; + foreach ($_FILES as $file) { + $log->LogInfo("---------处理文件---------"); + if (file_exists($file ['tmp_name'])) { + $params ['fileName'] = $file ['name']; + + $file_content = file_get_contents($file ['tmp_name']); + $file_content_deflate = gzcompress($file_content); + + $params ['fileContent'] = base64_encode($file_content_deflate); + $log->LogInfo("压缩后文件内容为>" . base64_encode($file_content_deflate)); + } else { + $log->LogInfo(">>>>文件上传失败<<<<<"); + } + } +} + +/** + * 处理报文中的文件 + * + * @param unknown_type $params + */ +function deal_file($params) +{ + global $log; + if (isset ($params ['fileContent'])) { + $log->LogInfo("---------处理后台报文返回的文件---------"); + $fileContent = $params ['fileContent']; + + if (empty ($fileContent)) { + $log->LogInfo('文件内容为空'); + } else { + // 文件内容 解压缩 + $content = gzuncompress(base64_decode($fileContent)); + $root = SDK_FILE_DOWN_PATH; + $filePath = null; + if (empty ($params ['fileName'])) { + $log->LogInfo("文件名为空"); + $filePath = $root . $params ['merId'] . '_' . $params ['batchNo'] . '_' . $params ['txnTime'] . 'txt'; + } else { + $filePath = $root . $params ['fileName']; + } + $handle = fopen($filePath, "w+"); + if (!is_writable($filePath)) { + $log->LogInfo("文件:" . $filePath . "不可写,请检查!"); + } else { + file_put_contents($filePath, $content); + $log->LogInfo("文件位置 >:" . $filePath); + } + fclose($handle); + } + } +} + +/** + * 构造自动提交表单 + * + * @param unknown_type $params + * @param unknown_type $action + * @return string + */ +function create_html($params, $action) +{ + $encodeType = isset ($params ['encoding']) ? $params ['encoding'] : 'UTF-8'; + $html = <<<eot +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset={$encodeType}" /> +</head> +<body onload="javascript:document.pay_form.submit();"> + <form id="pay_form" name="pay_form" action="{$action}" method="post"> + +eot; + foreach ($params as $key => $value) { + $html .= " <input type=\"hidden\" name=\"{$key}\" id=\"{$key}\" value=\"{$value}\" />\n"; + } + $html .= <<<eot + <input type="submit" type="hidden"> + </form> +</body> +</html> +eot; + return $html; +} + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/Func/httpClient.php b/library/WebPlugin/Pay/Unionpayweb/Func/httpClient.php new file mode 100644 index 0000000..b948bf1 --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/Func/httpClient.php @@ -0,0 +1,47 @@ +<?php +header ( 'Content-type:text/html;charset=utf-8' ); +/** + * 后台交易 HttpClient通信 + * @param unknown_type $params + * @param unknown_type $url + * @return mixed + */ +function sendHttpRequest($params, $url) { + $opts = getRequestParamString ( $params ); + + $ch = curl_init (); + curl_setopt ( $ch, CURLOPT_URL, $url ); + curl_setopt ( $ch, CURLOPT_POST, 1 ); + curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, false);//不验证证书 + curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, false);//不验证HOST + curl_setopt ( $ch, CURLOPT_SSLVERSION, 3); + curl_setopt ( $ch, CURLOPT_HTTPHEADER, array ( + 'Content-type:application/x-www-form-urlencoded;charset=UTF-8' + ) ); + curl_setopt ( $ch, CURLOPT_POSTFIELDS, $opts ); + + /** + * 设置cURL 参数,要求结果保存到字符串中还是输出到屏幕上。 + */ + curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true ); + + // 运行cURL,请求网页 + $html = curl_exec ( $ch ); + // close cURL resource, and free up system resources + curl_close ( $ch ); + return $html; +} + +/** + * 组装报文 + * + * @param unknown_type $params + * @return string + */ +function getRequestParamString($params) { + $params_str = ''; + foreach ( $params as $key => $value ) { + $params_str .= ($key . '=' . (!isset ( $value ) ? '' : urlencode( $value )) . '&'); + } + return substr ( $params_str, 0, strlen ( $params_str ) - 1 ); +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/Func/secureUtil.php b/library/WebPlugin/Pay/Unionpayweb/Func/secureUtil.php new file mode 100644 index 0000000..6bbe9f4 --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/Func/secureUtil.php @@ -0,0 +1,252 @@ +<?php + +use WebPlugin\Pay\Unionpayweb\Func\PhpLog; + +include_once 'PublicEncrypte.php'; + +/** + * 签名 + * + * @param String $params_str + */ +function sign(&$params) +{ + $log = new PhpLog (SDK_LOG_FILE_PATH, "PRC", SDK_LOG_LEVEL); + $log->LogInfo('=====签名报文开始======'); + if (isset($params['transTempUrl'])) { + unset($params['transTempUrl']); + } + // 转换成key=val&串 + $params_str = coverParamsToString($params); + $log->LogInfo("签名key=val&...串 >" . $params_str); + + $params_sha1x16 = sha1($params_str, FALSE); + $log->LogInfo("摘要sha1x16 >" . $params_sha1x16); + // 签名证书路径 + $cert_path = SDK_SIGN_CERT_PATH; + $private_key = getPrivateKey($cert_path); + // 签名 + $sign_falg = openssl_sign($params_sha1x16, $signature, $private_key, OPENSSL_ALGO_SHA1); + if ($sign_falg) { + $signature_base64 = base64_encode($signature); + $log->LogInfo("签名串为 >" . $signature_base64); + $params ['signature'] = $signature_base64; + } else { + $log->LogInfo(">>>>>签名失败<<<<<<<"); + } + $log->LogInfo('=====签名报文结束======'); +} + +/** + * 验签 + * + * @param String $params_str + * @param String $signature_str + */ +function verify($params) +{ + $log = new PhpLog (SDK_LOG_FILE_PATH, "PRC", SDK_LOG_LEVEL);; + // 公钥 + $public_key = getPulbicKeyByCertId($params ['certId']); +// echo $public_key.'<br/>'; + // 签名串 + $signature_str = $params ['signature']; + unset ($params ['signature']); + $params_str = coverParamsToString($params); + $log->LogInfo('报文去[signature] key=val&串>' . $params_str); + $signature = base64_decode($signature_str); +// echo date('Y-m-d',time()); + $params_sha1x16 = sha1($params_str, FALSE); + $log->LogInfo('摘要shax16>' . $params_sha1x16); + $isSuccess = openssl_verify($params_sha1x16, $signature, $public_key, OPENSSL_ALGO_SHA1); + $log->LogInfo($isSuccess ? '验签成功' : '验签失败'); + return $isSuccess; +} + +/** + * 根据证书ID 加载 证书 + * + * @param unknown_type $certId + * @return string NULL + */ +function getPulbicKeyByCertId($certId) +{ + $log = new PhpLog (SDK_LOG_FILE_PATH, "PRC", SDK_LOG_LEVEL);; + $log->LogInfo('报文返回的证书ID>' . $certId); + // 证书目录 + $cert_dir = SDK_VERIFY_CERT_DIR; + $log->LogInfo('验证签名证书目录 :>' . $cert_dir); + $handle = opendir($cert_dir); + if ($handle) { + while ($file = readdir($handle)) { + clearstatcache(); + $filePath = $cert_dir . '/' . $file; + if (is_file($filePath)) { + if (pathinfo($file, PATHINFO_EXTENSION) == 'cer') { + if (getCertIdByCerPath($filePath) == $certId) { + closedir($handle); + $log->LogInfo('加载验签证书成功'); + return getPublicKey($filePath); + } + } + } + } + $log->LogInfo('没有找到证书ID为[' . $certId . ']的证书'); + } else { + $log->LogInfo('证书目录 ' . $cert_dir . '不正确'); + } + closedir($handle); + return null; +} + +/** + * 取证书ID(.pfx) + * + * @return unknown + */ +function getCertId($cert_path) +{ + $pkcs12certdata = file_get_contents($cert_path); + + openssl_pkcs12_read($pkcs12certdata, $certs, SDK_SIGN_CERT_PWD); + $x509data = $certs ['cert']; + openssl_x509_read($x509data); + $certdata = openssl_x509_parse($x509data); + $cert_id = $certdata ['serialNumber']; + return $cert_id; +} + +/** + * 取证书ID(.cer) + * + * @param unknown_type $cert_path + */ +function getCertIdByCerPath($cert_path) +{ + $x509data = file_get_contents($cert_path); + openssl_x509_read($x509data); + $certdata = openssl_x509_parse($x509data); + $cert_id = $certdata ['serialNumber']; + return $cert_id; +} + +/** + * 签名证书ID + * + * @return unknown + */ +function getSignCertId() +{ + // 签名证书路径 + + return getCertId(SDK_SIGN_CERT_PATH); +} + +function getEncryptCertId() +{ + // 签名证书路径 + return getCertIdByCerPath(SDK_ENCRYPT_CERT_PATH); +} + +/** + * 取证书公钥 -验签 + * + * @return string + */ +function getPublicKey($cert_path) +{ + return file_get_contents($cert_path); +} + +/** + * 返回(签名)证书私钥 - + * + * @return unknown + */ +function getPrivateKey($cert_path) +{ + $pkcs12 = file_get_contents($cert_path); + openssl_pkcs12_read($pkcs12, $certs, SDK_SIGN_CERT_PWD); + return $certs ['pkey']; +} + +/** + * 加密 卡号 + * + * @param String $pan + * 卡号 + * @return String + */ +function encryptPan($pan) +{ + $cert_path = MPI_ENCRYPT_CERT_PATH; + $public_key = getPublicKey($cert_path); + + openssl_public_encrypt($pan, $cryptPan, $public_key); + return base64_encode($cryptPan); +} + +/** + * pin 加密 + * + * @param unknown_type $pan + * @param unknown_type $pwd + * @return Ambigous <number, string> + */ +function encryptPin($pan, $pwd) +{ + $cert_path = SDK_ENCRYPT_CERT_PATH; + $public_key = getPublicKey($cert_path); + + return EncryptedPin($pwd, $pan, $public_key); +} + +/** + * cvn2 加密 + * + * @param unknown_type $cvn2 + * @return unknown + */ +function encryptCvn2($cvn2) +{ + $cert_path = SDK_ENCRYPT_CERT_PATH; + $public_key = getPublicKey($cert_path); + + openssl_public_encrypt($cvn2, $crypted, $public_key); + + return base64_encode($crypted); +} + +/** + * 加密 有效期 + * + * @param unknown_type $certDate + * @return unknown + */ +function encryptDate($certDate) +{ + $cert_path = SDK_ENCRYPT_CERT_PATH; + $public_key = getPublicKey($cert_path); + + openssl_public_encrypt($certDate, $crypted, $public_key); + + return base64_encode($crypted); +} + +/** + * 加密 数据 + * + * @param unknown_type $certDatatype + * @return unknown + */ +function encryptDateType($certDataType) +{ + $cert_path = SDK_ENCRYPT_CERT_PATH; + $public_key = getPublicKey($cert_path); + + openssl_public_encrypt($certDataType, $crypted, $public_key); + + return base64_encode($crypted); +} + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/Service.php b/library/WebPlugin/Pay/Unionpayweb/Service.php new file mode 100644 index 0000000..ad8c5c0 --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/Service.php @@ -0,0 +1,109 @@ +<?php + +namespace WebPlugin\Pay\Unionpayweb; + +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; +use WebPlugin\Pay\Unionpayweb\Func\PhpLog; + +class Service extends PayAbstract +{ + private $merId; + private $log; + + public function __construct(array $paymentParams) + { + $env = APPLICATION_ENV == 'production' ? 'release' : 'test'; + include_once 'conf/' . $env . '/SDKConfig.php'; + include_once 'Func/common.php'; + include_once 'Func/secureUtil.php'; + + $this->log = new PhpLog(SDK_LOG_FILE_PATH, "PRC", SDK_LOG_LEVEL); + $this->merId = array( + 'mobile' => '898111453110482',//手机支付 + 'pc_nocard' => '898111453110464',//无卡支付 + 'pc_bank' => '898111453110466'//网银支付 + ); + } + + /** + * 解析返回的参数 + * + * @param array $package + * @return bool|string + */ + public function parseResponse(array $package) + { + $verify = false; + if (isset($package ['signature']) && verify($package)) { + $verify = true; + $this->log->LogInfo('验签成功'); + } else { + return false; + } + + if ($package['respCode'] !== '00') { + $this->log->LogInfo('支付返回码有误'); + return false; + } + + $responseData = new Rspparams(); + if ($verify) { + //更改订单状态 + $responseData->orderCode = $package['orderId']; + $responseData->payResult = 0; + $responseData->payTime = time(); + $responseData->totalFee = $package['txnAmt'] * 0.01; + $responseData->bankName = ''; + $responseData->bankCode = ''; + //添加支付订单号和交易号 + $responseData->payOrderCode = $package['orderId']; + $responseData->tradeNo = $package['queryId']; + $responseData->bankBillNo = ""; + } else { + $responseData->payResult = -1; + } + + return $responseData; + } + + public function getPayRequestPars(Reqparams $params) + { + $front_notify_url = SDK_FRONT_NOTIFY_URL . '?order_code=' . $params->orderCode; + $requestParams = array( + 'version' => '5.0.0', //版本号 + 'encoding' => 'utf-8', //编码方式 + 'certId' => getSignCertId(), //证书ID + 'txnType' => '01', //交易类型 + 'txnSubType' => '01', //交易子类 + 'bizType' => '000201', //业务类型 + 'frontUrl' => $front_notify_url, //前台通知地址 + 'backUrl' => SDK_BACK_NOTIFY_URL, //后台通知地址 + 'signMethod' => '01', //签名方法 + 'channelType' => '07', //渠道类型,07-PC,08-手机 + 'accessType' => '0', //接入类型 + 'merId' => $this->merId['pc_bank'], //商户代码,请改自己的测试商户号 + 'orderId' => $params->orderCode, //商户订单号 + 'txnTime' => date('YmdHis', $params->orderTime), //订单发送时间 + 'txnAmt' => $params->totalFee, //交易金额,单位分 + 'currencyCode' => '156', //交易币种 + 'defaultPayType' => '0201', //默认支付方式 + //'orderDesc' => '订单描述', //订单描述,网关支付和wap支付暂时不起作用 + 'reqReserved' => $params->goodsName //请求方保留域,透传字段,查询、通知、对账文件中均会原样出现 + ); + // 签名 + sign($requestParams); + // 前台请求地址 + $result = array( + 'pay_url' => SDK_FRONT_TRANS_URL, + 'pars' => $requestParams, + 'reqType' => 'post' + ); + + $this->log->LogInfo(var_export($requestParams, true)); + + return $result; + } + +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/conf/release/SDKConfig.php b/library/WebPlugin/Pay/Unionpayweb/conf/release/SDKConfig.php new file mode 100644 index 0000000..613acfb --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/conf/release/SDKConfig.php @@ -0,0 +1,66 @@ +<?php + +// ######(以下配置为生产环境配置,请根据商户系统自身情况修改)####### + +// cvn2加密 1:加密 0:不加密 +const SDK_CVN2_ENC = 0; +// 有效期加密 1:加密 0:不加密 +const SDK_DATE_ENC = 0; +// 卡号加密 1:加密 0:不加密 +const SDK_PAN_ENC = 0; + + +// 签名证书路径 (联系运营获取两码,在CFCA网站下载后配置,自行设置证书密码并配置) +const SDK_SIGN_CERT_PATH = '/Data/code/git/web/yohobuy/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/pc_online_banking.pfx'; + +// 签名证书密码 +const SDK_SIGN_CERT_PWD = 'yoho12'; + +// 验签证书 +const SDK_VERIFY_CERT_PATH = '/Data/code/git/web/yohobuy/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/UpopRsaCert.cer'; + +// 密码加密证书 +const SDK_ENCRYPT_CERT_PATH = '/Data/code/git/web/yohobuy/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/RSA2048_PROD_index_22.cer'; + +// 验签证书路径 +const SDK_VERIFY_CERT_DIR = '/Data/code/git/web/yohobuy/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/'; + +// 前台请求地址 +const SDK_FRONT_TRANS_URL = 'https://gateway.95516.com/gateway/api/frontTransReq.do'; + +// 后台请求地址 +const SDK_BACK_TRANS_URL = 'https://gateway.95516.com/gateway/api/backTransReq.do'; + +// 批量交易 +const SDK_BATCH_TRANS_URL = 'https://gateway.95516.com/gateway/api/batchTrans.do'; + +//单笔查询请求地址 +const SDK_SINGLE_QUERY_URL = 'https://gateway.95516.com/gateway/api/queryTrans.do'; + +//文件传输请求地址 +const SDK_FILE_QUERY_URL = 'https://filedownload.95516.com/'; + +//有卡交易地址 +const SDK_Card_Request_Url = 'https://gateway.95516.com/gateway/api/cardTransReq.do'; + +//App交易地址 +const SDK_App_Request_Url = 'https://gateway.95516.com/gateway/api/appTransReq.do'; + + +// 前台通知地址 (商户自行配置通知地址) +const SDK_FRONT_NOTIFY_URL = 'http://www.yohobuy.com/pay/notice/unionpaywebreturn'; +// 后台通知地址 (商户自行配置通知地址) +const SDK_BACK_NOTIFY_URL = 'http://pay.yohobuy.com/notify/unionpaywebnotice'; + +//文件下载目录 +const SDK_FILE_DOWN_PATH = '/tmp/unionpay/files/'; + +//日志 目录 +const SDK_LOG_FILE_PATH = '/tmp/unionpay/logs/'; + +//日志级别 +const SDK_LOG_LEVEL = 6; + + + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/RSA2048_PROD_index_22.cer b/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/RSA2048_PROD_index_22.cer new file mode 100644 index 0000000..4b66e5d --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/RSA2048_PROD_index_22.cer @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEEDCCAvigAwIBAgIFEBNHISEwDQYJKoZIhvcNAQEFBQAwITELMAkGA1UEBhMC +Q04xEjAQBgNVBAoTCUNGQ0EgT0NBMTAeFw0xNDAxMDIwOTA3MThaFw0xOTAxMDIw +OTA3MThaMIGFMQswCQYDVQQGEwJjbjESMBAGA1UEChMJQ0ZDQSBPQ0ExMRYwFAYD +VQQLEw1Mb2NhbCBSQSBPQ0ExMRQwEgYDVQQLEwtFbnRlcnByaXNlczE0MDIGA1UE +AxQrMDQxQFoxMjAwMDQwMDAwOlNJR05AMDAwNDAwMDA6U0lHTkAwMDAwMDAwMjCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN3BsX/kyJ2BRh2IW4GyYfFs +4g5RcIEPhzGfo0IztDeqM8cfwRGqklavYHuZfFG6XPb1N/p1rXQlwyBJ6UQwgnVu +ACyWa9+Cqf664XNp+vIVx9grqor9lzrJK6jTPrd57AJNuhpFGAW0dRAjfF5ZAdpZ +56gYiWFgp2zTIXGjXoA0MHqYKBGMMYdFSZ3EkRhsJ0jyJeaBep2VmsFDtODliW0X +5T+cSgPn1+zzlHwu1svmBYxh3ZpEY3hEwR8KQwja5d5b0kUZ5eCepg9OyB8y+K6P +5VxCN8YHwVsXFYz1rpEmjGp2qObO2A+vyJaaCdtB3AeppsGLwGCIXQ/t5wyjOqEC +AwEAAaOB6TCB5jAfBgNVHSMEGDAWgBTR2+mIguXdGo9MqgCMvnzyqxv22TBIBgNV +HSAEQTA/MD0GCGCBHIbvKgEBMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2Zj +YS5jb20uY24vdXMvdXMtMTQuaHRtMDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly9j +cmwuY2ZjYS5jb20uY24vUlNBL2NybDE1Mjk4LmNybDALBgNVHQ8EBAMCA+gwHQYD +VR0OBBYEFAIndZ83GnekyNLXDbnxhC6+p4aCMBMGA1UdJQQMMAoGCCsGAQUFBwMC +MA0GCSqGSIb3DQEBBQUAA4IBAQBKgpV4bGWiQdNy38evxrR8NIWHIwSinNL7JGZz +EFMRc0ld8PRcztdK6NpmZSbJLz/6HUD+ou8CrFHxfgvWleoQzSZtwdICb06MTz3T +gp8RyJNZEQ3HErDRGSa0vecT1Tuk1qAbrxZ1KRWkjyHciam7Sr8junEBfSx3VaZ+ +JU/wKs3gb1GO/h9VD5YSKqXYqvQ0CZamJgFDgkgXP8+3+HIe64BRspkTmlnR+Zf0 +ZUYqMgsGF9kSy2yajSkJvyyriezko9VrIBqvITM6615W9YxaDAfQISmw8bjpUg99 +rs3vzfwHTAGXiDXyWng+mVe8UDOv0roIJxaWzfx1XZFVEuCR +-----END CERTIFICATE----- \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/UpopRsaCert.cer b/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/UpopRsaCert.cer new file mode 100644 index 0000000..7c0c9cf --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/UpopRsaCert.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNjCCAh6gAwIBAgIQEAAAAAAAAAAAAAAQBQdAIDANBgkqhkiG9w0BAQUFADAh +MQswCQYDVQQGEwJDTjESMBAGA1UEChMJQ0ZDQSBPQ0ExMB4XDTEyMTIxODAyMDA1 +MVoXDTE1MTIxODAyMDA1MVowfDELMAkGA1UEBhMCQ04xDTALBgNVBAoTBE9DQTEx +ETAPBgNVBAsTCENGQ0EgTFJBMRkwFwYDVQQLExBPcmdhbml6YXRpb25hbC0xMTAw +LgYDVQQDFCc4MzEwMDAwMDAwMDgzMDQwQDAwMDQwMDAwOlNJR05AMDAwMDAwMDEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFG+NnBXN++aUUAbgVFOt/ +pi2McB79P+tmkS98Pnlj+pEvCc2nltq2VZzfJvGb1UE6lXKXoCG+NosZMj64uda9 +Du2up78Z92HGdT2tkZ0RaoouR4jCY0Bmz0+5zObjR607vwBTvln9idG9ZGK2Lm35 +QSxjpLolRPEnz/rgxFG9ezxVfI9eQ7JmuBk/OXyzjA1JQwAMhdAT3GJO0JMmMDvC +Q0pNyTsu1oyQPJoCaV3qPfpcvatMKYsVxo2Zeogqw2x2L6KE8BODrj6m6Ue1aUMn +9Ch1XbR/dB8M2M+nVtOAVb6DA6kVuNFlMl2uzxD8MQlhos8aT+vCx1v9p21k3+jz +AgMBAAGjDzANMAsGA1UdDwQEAwIGwDANBgkqhkiG9w0BAQUFAAOCAQEAhgW/gcDa +fqs0oWDH81XnTVvDCp5mwDo+wxgzVRTEtudU6seKcc2kiBe1RqegtUX2le/eAzcD +mo7nxHMy73ANdP/wha+P2gp+mo3buhO244pQphMV+Yu8djHTFH8+hRkCbnsrndYc +qNiJ/yhsUpaJ4nY+oEoyut0id6QddKiNPYoTFz0fy/VqNP6g+23zFy6sIg+gffVZ +6o3CsZVu9z5umUjzfV384iSWovq+/IdSZ4g/jerdPtje/CKYTmzG5nsCa/s+i7Rf +D5scSlfi7iW2Q7Sc/HlrtOAglt7IyjRSsFPPxuBXmSITc2GDKyKI46u8RXpccAUh +YspJ5MXOYLZN7A== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/mobile.pfx b/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/mobile.pfx new file mode 100644 index 0000000..6b7618c Binary files /dev/null and b/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/mobile.pfx differ diff --git a/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/pc_nocard_payment.pfx b/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/pc_nocard_payment.pfx new file mode 100644 index 0000000..dbaa7ec Binary files /dev/null and b/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/pc_nocard_payment.pfx differ diff --git a/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/pc_online_banking.pfx b/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/pc_online_banking.pfx new file mode 100644 index 0000000..fdf40be Binary files /dev/null and b/library/WebPlugin/Pay/Unionpayweb/conf/release/certs/pc_online_banking.pfx differ diff --git a/library/WebPlugin/Pay/Unionpayweb/conf/test/SDKConfig.php b/library/WebPlugin/Pay/Unionpayweb/conf/test/SDKConfig.php new file mode 100644 index 0000000..e0780c7 --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/conf/test/SDKConfig.php @@ -0,0 +1,61 @@ +<?php +// cvn2加密 1:加密 0:不加密 +const SDK_CVN2_ENC = 0; +// 有效期加密 1:加密 0:不加密 +const SDK_DATE_ENC = 0; +// 卡号加密 1:加密 0:不加密 +const SDK_PAN_ENC = 0; + +// ######(以下配置为PM环境:入网测试环境用,生产环境配置见文档说明)####### +// 签名证书路径 +//const SDK_SIGN_CERT_PATH = 'D:\\wamp\\www\\yohobuy\\library\\WebPlugin\\Pay\\Unionpayweb\\conf\\test\\certs\\PM_700000000000001_acp.pfx'; +const SDK_SIGN_CERT_PATH = '/Data/code/git/web/yohobuy/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/PM_700000000000001_acp.pfx'; + +// 签名证书密码 +const SDK_SIGN_CERT_PWD = '000000'; + +// 密码加密证书(这条用不到的请随便配) +const SDK_ENCRYPT_CERT_PATH = '/Data/code/git/web/yohobuy/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/verify_sign_acp.cer'; +//const SDK_ENCRYPT_CERT_PATH = 'D:\\wamp\\www\\yohobuy\\library\\WebPlugin\\Pay\\Unionpayweb\\conf\\test\\certs\\verify_sign_acp.cer'; + +// 验签证书路径(请配到文件夹,不要配到具体文件) +const SDK_VERIFY_CERT_DIR = '/Data/code/git/web/yohobuy/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/'; + +// 前台请求地址 +const SDK_FRONT_TRANS_URL = 'https://101.231.204.80:5000/gateway/api/frontTransReq.do'; + +// 后台请求地址 +const SDK_BACK_TRANS_URL = 'https://101.231.204.80:5000/gateway/api/backTransReq.do'; + +// 批量交易 +const SDK_BATCH_TRANS_URL = 'https://101.231.204.80:5000/gateway/api/batchTrans.do'; + +//单笔查询请求地址 +const SDK_SINGLE_QUERY_URL = 'https://101.231.204.80:5000/gateway/api/queryTrans.do'; + +//文件传输请求地址 +const SDK_FILE_QUERY_URL = 'https://101.231.204.80:9080/'; + +//有卡交易地址 +const SDK_Card_Request_Url = 'https://101.231.204.80:5000/gateway/api/cardTransReq.do'; + +//App交易地址 +const SDK_App_Request_Url = 'https://101.231.204.80:5000/gateway/api/appTransReq.do'; + + +// 前台通知地址 (商户自行配置通知地址) +const SDK_FRONT_NOTIFY_URL = 'http://www.yohobuy.com/pay/notice/unionpaywebreturn'; +// 后台通知地址 (商户自行配置通知地址) +const SDK_BACK_NOTIFY_URL = 'http://pay.test.yohobuy.com/notify/unionpaywebnotice'; + +//文件下载目录 +const SDK_FILE_DOWN_PATH = '/tmp/unionpay/files/'; + +//日志 目录 +const SDK_LOG_FILE_PATH = '/tmp/unionpay/logs/'; + +//日志级别 +const SDK_LOG_LEVEL = 2; + + +?> \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/PM_700000000000001_acp.pfx b/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/PM_700000000000001_acp.pfx new file mode 100644 index 0000000..ea3dcca Binary files /dev/null and b/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/PM_700000000000001_acp.pfx differ diff --git a/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/encrypt.cer b/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/encrypt.cer new file mode 100644 index 0000000..9c487cd --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/encrypt.cer @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDpDCCAw2gAwIBAgIQQdwbgeStSukUTliGHkR2AjANBgkqhkiG9w0BAQUFADAk +MQswCQYDVQQGEwJDTjEVMBMGA1UEChMMQ0ZDQSBURVNUIENBMB4XDTEwMDYyNTAz +MDAzN1oXDTExMDYyNTAzMDAzN1owdTELMAkGA1UEBhMCQ04xFTATBgNVBAoTDENG +Q0EgVEVTVCBDQTERMA8GA1UECxMITG9jYWwgUkExFDASBgNVBAsTC0VudGVycHJp +c2VzMSYwJAYDVQQDFB0wNDFAWjVAMDAwNDAwMDA6U0lHTkAwMDAwMDAxODCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5UPlV6wmGwpBFHX9n78V1O8KMx6D5yj4 +j4Sg4BW3hJ6WU7TPzWPHrjOGulmdAYpdziZROS6ygtu6mtB6s/54u7un8JUB1H+t +3l4ll8DXvE2+vX6xoKqnmUuyAHA26oavHU2xIQrGb5OLQ0aSgCn9eYjsqLRZwaNP +EItSBP99xT0CAwEAAaOCAYQwggGAMB8GA1UdIwQYMBaAFEZy3CVynwJOVYO1gPkL +2+mTs/RFMB0GA1UdDgQWBBSFJUyNA4zif3+Z8b+ioyJZCw9qSjALBgNVHQ8EBAMC +BaAwDAYDVR0TBAUwAwEBADA7BgNVHSUENDAyBggrBgEFBQcDAQYIKwYBBQUHAwIG +CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgwgeUGA1UdHwSB3TCB2jBOoEyg +SqRIMEYxCzAJBgNVBAYTAkNOMRUwEwYDVQQKEwxDRkNBIFRFU1QgQ0ExDDAKBgNV +BAsTA0NSTDESMBAGA1UEAxMJY3JsMTI3Xzk2MIGHoIGEoIGBhn9sZGFwOi8vMjEw +Ljc0LjQxLjg3OjM4OS9DTj1jcmwxMjdfOTYsT1U9Q1JMLE89Q0ZDQSBURVNUIENB +LEM9Q04/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdGNsYXNz +PWNSTERpc3RyaWJ1dGlvblBvaW50MA0GCSqGSIb3DQEBBQUAA4GBABYv6ZeKB3Ry +60ZbOy7GmSpBZ/VNPuPPnsjVoEEAOpw+Wv+EQrJHd4TCIo213Su38bJiBTOJCWqj +xg5PhsmOI62IVkKXPoLvSQe6EfpkTZIevZAdZ6KHuH+CM49Ym13akDp0VN3+Q3j+ +FOU/6yHJbc3CGcydnTf6Dv+QsmbIMPI+ +-----END CERTIFICATE----- \ No newline at end of file diff --git a/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/verify_sign_acp.cer b/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/verify_sign_acp.cer new file mode 100644 index 0000000..1f4735b --- /dev/null +++ b/library/WebPlugin/Pay/Unionpayweb/conf/test/certs/verify_sign_acp.cer @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEOjCCA6OgAwIBAgIQAp05hXtzN+zGp6RHK8FdhjANBgkqhkiG9w0BAQUFADAk +MQswCQYDVQQGEwJDTjEVMBMGA1UEChMMQ0ZDQSBURVNUIENBMB4XDTEyMDkwNzA4 +MzQ1NloXDTEzMDkwNzA4MzQ1NlowfDELMAkGA1UEBhMCQ04xFTATBgNVBAoTDENG +Q0EgVEVTVCBDQTERMA8GA1UECxMITG9jYWwgUkExFDASBgNVBAsTC0VudGVycHJp +c2VzMS0wKwYDVQQDFCQwNDFAWjIwMTItOS03QDAwMDQ5OTk5OlNJR05AMDAwMDAw +NTcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7VU6b07MNQxHwxM2E +1ymje/FxXLJhQTcwsKHHnq88KBcS8q1oz5fOMmuJ50zGlYfKEAbrZXlKKIdZtaqz +Bs9ISXkLj3ZfYxUDLpJU2HdVb7DKNuVcCTSauRHMwYee2V8RTAmN/MrYVUe3b5J+ +mpymmFXfvYdCprCC6a1F3yRvTOMVWFhREx4NlIRSuiOuQTtpEgBNFxa/h6xBYJnQ +PLpgQH4cmiQJvXB0g6SBRMMCoHb3rTo97W7SWbiDoflmAkFYgfSdD8Qh+8hqo1QB +C1EDAWE+GiGHhcXjsQbVq6bL4b7JHb4iSEyCQvcKcCrIcOGM+HVS08wFsg89lsK1 +RbJnAgMBAAGjggGPMIIBizAfBgNVHSMEGDAWgBRGctwlcp8CTlWDtYD5C9vpk7P0 +RTAdBgNVHQ4EFgQUhscavD0jmCmKd6n0W1NIfTIfFLowCwYDVR0PBAQDAgTwMAwG +A1UdEwQFMAMBAQAwOwYDVR0lBDQwMgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEF +BQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIMIHwBgNVHR8EgegwgeUwT6BNoEukSTBH +MQswCQYDVQQGEwJDTjEVMBMGA1UEChMMQ0ZDQSBURVNUIENBMQwwCgYDVQQLEwND +UkwxEzARBgNVBAMTCmNybDEyN18yMzgwgZGggY6ggYuGgYhsZGFwOi8vdGVzdGxk +YXAuY2ZjYS5jb20uY246Mzg5L0NOPWNybDEyN18yMzgsT1U9Q1JMLE89Q0ZDQSBU +RVNUIENBLEM9Q04/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVj +dGNsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MA0GCSqGSIb3DQEBBQUAA4GBABaV +4RvJ+dQPr7sOANet1TYW5EbEKhKozrYvkX46ImJJUsnxYO/2ZStccJkR4F32q0gp +WHusJbDoVwbMJPCYer3NJgYikkx22Foy5wlaoFBVBDHjownHZdb+qGjAEFc4KwyS +82rDuGyt6zvVVe1kaABnZhuOYKMHG9sycoVRskQO +-----END CERTIFICATE----- diff --git a/library/WebPlugin/Pay/Wechatqrcode/Config.php b/library/WebPlugin/Pay/Wechatqrcode/Config.php new file mode 100644 index 0000000..510b22c --- /dev/null +++ b/library/WebPlugin/Pay/Wechatqrcode/Config.php @@ -0,0 +1,18 @@ +<?php + +namespace WebPlugin\Pay\Wechatqrcode; + +class Config +{ + var $payment_url = "http://www.yohobuy.com/pay/wechatqrcode"; + //pay.yohobuy.com + var $pay_url = "http://pay.test.yohobuy.com/payment/cashier"; + + var $pay_developer_url = "http://pay.test.yohobuy.com/payment/cashier";//本地 + var $pay_testing_url = "http://pay.test.yohobuy.com/payment/cashier";//测试 + var $pay_preview_url = "http://pay.yohobuy.com/payment/cashier";//预生产 + var $pay_production_url = "http://pay.yohobuy.com/payment/cashier";//正式 + //平台app_key private_key + var $app_key = "adbf5a778175ee75"; + var $private_key = "adbf5a778175ee757c34d0eba4e932bc"; +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/Wechatqrcode/Service.php b/library/WebPlugin/Pay/Wechatqrcode/Service.php new file mode 100644 index 0000000..54013c7 --- /dev/null +++ b/library/WebPlugin/Pay/Wechatqrcode/Service.php @@ -0,0 +1,99 @@ +<?php + +namespace WebPlugin\Pay\Wechatqrcode; + +use WebPlugin\Pay\PayAbstract; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; +use WebPlugin\Pay\Signature; + +class Service extends PayAbstract +{ + + private $config; + private $orderCode; + private $paymentCode; + private $appKey; + private $privateKey; + private $payCurl; + + public function __construct(array $paymentParams) { + $this->logProjectPrefix = 'wechatpay'; + $this->config = new Config(); + $environParam = 'pay_'.APPLICATION_ENV.'_url'; + $this->payCurl = $this->config->$environParam; + $this->appKey = $this->config->app_key; + $this->privateKey = $this->config->private_key; + $this->paymentCode = $paymentParams['id']; + } + + public function getPayRequestPars(Reqparams $params) { + $this->orderCode = $params->orderCode; + $result = array( + 'pay_url' => $this->config->payment_url, + 'pars' => 'order_code=' . $this->orderCode . '&payment_code=' . $this->paymentCode, + 'reqType' => 'get' + ); + return $result; + } + + /** + * 微信支付页 + * @param array $orderInfo + * @return string + * @internal param array $orderCode + */ + public function pay(array $orderInfo) { + //生成签名 + $this->orderCode = $orderInfo['order_code']; + $payParams = array( + 'order_code' => $this->orderCode, + 'app_key' => $this->appKey, + 'payment_code' => $this->paymentCode, + 'private_key' => $this->privateKey + ); + $_params = Signature::packageSort($payParams); + $client_secret = Signature::makeSign($_params); + $parameter = array( + 'order_code' => $this->orderCode, + 'app_key' => $this->appKey, + //这里payment.yoho_pay表与payment.q_pay表数据需一致 + 'payment_code' => $this->paymentCode, + 'client_secret' => $client_secret, + 'client' => 'web' + ); + $pars = ''; + foreach ($parameter as $p_key => $p_val) { + $pars.=$p_key . '=' . urlencode($p_val) . '&'; + } + $payUrlInfo = array( + 'pay_url' => $this->payCurl, + 'pars' => trim($pars, '&') + ); + $payUrl = $payUrlInfo['pay_url'] . '?' . $payUrlInfo['pars']; + return array('pay_url' => $payUrl); + } + + public function parseResponse(array $arrResponse) { + /* 返回示例 + * http://www.yohobuy.com/pay/notice/wechatqrcodereturn?ordercode=93465435 + */ + $rsp = new Rspparams(); + if($arrResponse['payResult'] == 200){ + $rsp->payResult = 200; + $rsp->bankName = "WX"; + $rsp->orderCode = $arrResponse['order_code']; + $rsp->payTime = $arrResponse["arrive_time"]; + $rsp->totalFee = $arrResponse["amount"]; + $rsp->resultMsg = '支付成功'; + //添加支付订单号和交易号 + $rsp->payOrderCode = $arrResponse["order_code"]; + $rsp->tradeNo = ""; + $rsp->bankBillNo = ""; + }else{ + $rsp->payResult = -1; + } + return $rsp; + } + +} diff --git a/library/WebPlugin/Pay/weixin/lib/WxPayConfig.php b/library/WebPlugin/Pay/weixin/lib/WxPayConfig.php index 2770dc2..61ca780 100644 --- a/library/WebPlugin/Pay/weixin/lib/WxPayConfig.php +++ b/library/WebPlugin/Pay/weixin/lib/WxPayConfig.php @@ -1,66 +1,63 @@ -<?php - -namespace WebPlugin\Pay\weixin\lib; - -/** - * 配置账号信息 - */ -class WxPayConfig -{ - - //=======【基本信息设置】===================================== - // - /** - * TODO: 修改这里配置为您自己申请的商户信息 - * 微信公众号信息配置 - * - * APPID:绑定支付的APPID(必须配置,开户邮件中可查看) - * - * MCHID:商户号(必须配置,开户邮件中可查看) - * - * KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置) - * 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert - * - * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置), - * 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN - * @var string - */ - const APPID = 'wx75e5a7c0c88e45c2'; - const MCHID = '1227694201'; - const KEY = '7e6f3307b64cc87c79c472814b88f7fb'; - const APPSECRET = 'ce21ae4a3f93852279175a167e54509b'; - //=======【JSAPI路径设置】=================================== - //获取access_token过程中的跳转uri,通过跳转将code传入jsapi支付页面 - const JS_API_CALL_URL = 'http://m.yohobuy.com/shopping/pay/wechatwap'; - //=======【异步通知url设置】=================================== - //异步通知url,商户根据实际开发过程设定 - const NOTIFY_URL = 'http://pay.yohobuy.com/notify/wechatwap'; - //=======【证书路径设置】===================================== - /** - * TODO:设置商户证书路径 - * 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载, - * API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书) - * @var path - */ - const SSLCERT_PATH = '../cert/apiclient_cert.pem'; - const SSLKEY_PATH = '../cert/apiclient_key.pem'; - //=======【curl代理设置】=================================== - /** - * TODO:这里设置代理机器,只有需要代理的时候才设置,不需要代理,请设置为0.0.0.0和0 - * 本例程通过curl使用HTTP POST方法,此处可修改代理服务器, - * 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(如有需要才设置) - * @var unknown_type - */ - const CURL_PROXY_HOST = "0.0.0.0"; //"10.152.18.220"; - const CURL_PROXY_PORT = 0; //8080; - //=======【上报信息配置】=================================== - /** - * TODO:接口调用上报等级,默认紧错误上报(注意:上报超时间为【1s】,上报无论成败【永不抛出异常】, - * 不会影响接口调用流程),开启上报之后,方便微信监控请求调用的质量,建议至少 - * 开启错误上报。 - * 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报 - * @var int - */ - const REPORT_LEVENL = 1; - -} +<?php + +namespace WebPlugin\Pay\weixin\lib; + +/** + * 配置账号信息 + */ +class WxPayConfig +{ + + //=======【基本信息设置】===================================== + // + /** + * TODO: 修改这里配置为您自己申请的商户信息 + * 微信公众号信息配置 + * + * APPID:绑定支付的APPID(必须配置,开户邮件中可查看) + * + * MCHID:商户号(必须配置,开户邮件中可查看) + * + * KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置) + * 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert + * + * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置), + * 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN + * @var string + */ + const APPID = 'wx75e5a7c0c88e45c2'; + const MCHID = '1227694201'; + const KEY = '7e6f3307b64cc87c79c472814b88f7fb'; + const APPSECRET = 'ce21ae4a3f93852279175a167e54509b'; + //=======【异步通知url设置】=================================== + //异步通知url,商户根据实际开发过程设定 + const NOTIFY_URL = 'http://www.yohobuy.com/pay/notice/wechatqrcodereturn'; + //=======【证书路径设置】===================================== + /** + * TODO:设置商户证书路径 + * 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载, + * API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书) + * @var path + */ + const SSLCERT_PATH = '../cert/apiclient_cert.pem'; + const SSLKEY_PATH = '../cert/apiclient_key.pem'; + //=======【curl代理设置】=================================== + /** + * TODO:这里设置代理机器,只有需要代理的时候才设置,不需要代理,请设置为0.0.0.0和0 + * 本例程通过curl使用HTTP POST方法,此处可修改代理服务器, + * 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(如有需要才设置) + * @var unknown_type + */ + const CURL_PROXY_HOST = "0.0.0.0"; //"10.152.18.220"; + const CURL_PROXY_PORT = 0; //8080; + //=======【上报信息配置】=================================== + /** + * TODO:接口调用上报等级,默认紧错误上报(注意:上报超时间为【1s】,上报无论成败【永不抛出异常】, + * 不会影响接口调用流程),开启上报之后,方便微信监控请求调用的质量,建议至少 + * 开启错误上报。 + * 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报 + * @var int + */ + const REPORT_LEVENL = 1; + +} diff --git a/library/WebPlugin/Pay/weixin/lib/WxPayNativePay.php b/library/WebPlugin/Pay/weixin/lib/WxPayNativePay.php new file mode 100644 index 0000000..ca1a86e --- /dev/null +++ b/library/WebPlugin/Pay/weixin/lib/WxPayNativePay.php @@ -0,0 +1,63 @@ +<?php + +namespace WebPlugin\Pay\weixin\lib; + +/** + * 刷卡支付实现类 + * + * @package WebPlugin\Pay\weixin\lib + * @author Gtskk + * @copyright 2016/3/21 21:01 Gtskk<iamgtskk@gmail.com> + * @version: 0.0.1 + */ +class WxPayNativePay +{ + /** + * + * 生成扫描支付URL,模式一 + * @param $productId + * @return string + * @throws WxPayException + */ + public function GetPrePayUrl($productId) + { + $biz = new WxPayBizPayUrl(); + $biz->SetProduct_id($productId); + $values = WxpayApi::bizpayurl($biz); + $url = "weixin://wxpay/bizpayurl?" . $this->ToUrlParams($values); + return $url; + } + + /** + * + * 参数数组转换为url参数 + * @param array $urlObj + * @return string + */ + private function ToUrlParams($urlObj) + { + $buff = ""; + foreach ($urlObj as $k => $v) + { + $buff .= $k . "=" . $v . "&"; + } + + $buff = trim($buff, "&"); + return $buff; + } + + /** + * + * 生成直接支付url,支付url有效期为2小时,模式二 + * @param UnifiedOrderInput $input + * @return array + */ + public function GetPayUrl($input) + { + if($input->GetTrade_type() == "NATIVE") + { + $result = WxPayApi::unifiedOrder($input); + return $result; + } + } +} \ No newline at end of file diff --git a/library/WebPlugin/Pay/weixin/lib/WxPayUnifiedOrder.php b/library/WebPlugin/Pay/weixin/lib/WxPayUnifiedOrder.php index dc53209..fd36514 100644 --- a/library/WebPlugin/Pay/weixin/lib/WxPayUnifiedOrder.php +++ b/library/WebPlugin/Pay/weixin/lib/WxPayUnifiedOrder.php @@ -1,507 +1,506 @@ -<?php - -/** - * Created by PhpStorm. - * User: DELL - * Date: 2015/12/23 - * Time: 17:52 - */ - -namespace WebPlugin\Pay\weixin\lib; - -/** - * - * 统一下单输入对象 - * @author widyhu - * - */ -class WxPayUnifiedOrder extends WxPayDataBase -{ - - /** - * 设置微信分配的公众账号ID - * @param string $value - * */ - public function SetAppid($value) - { - $this->values['appid'] = $value; - } - - /** - * 获取微信分配的公众账号ID的值 - * @return 值 - * */ - public function GetAppid() - { - return $this->values['appid']; - } - - /** - * 判断微信分配的公众账号ID是否存在 - * @return true 或 false - * */ - public function IsAppidSet() - { - return array_key_exists('appid', $this->values); - } - - /** - * 设置微信支付分配的商户号 - * @param string $value - * */ - public function SetMch_id($value) - { - $this->values['mch_id'] = $value; - } - - /** - * 获取微信支付分配的商户号的值 - * @return 值 - * */ - public function GetMch_id() - { - return $this->values['mch_id']; - } - - /** - * 判断微信支付分配的商户号是否存在 - * @return true 或 false - * */ - public function IsMch_idSet() - { - return array_key_exists('mch_id', $this->values); - } - - /** - * 设置微信支付分配的终端设备号,商户自定义 - * @param string $value - * */ - public function SetDevice_info($value) - { - $this->values['device_info'] = $value; - } - - /** - * 获取微信支付分配的终端设备号,商户自定义的值 - * @return 值 - * */ - public function GetDevice_info() - { - return $this->values['device_info']; - } - - /** - * 判断微信支付分配的终端设备号,商户自定义是否存在 - * @return true 或 false - * */ - public function IsDevice_infoSet() - { - return array_key_exists('device_info', $this->values); - } - - /** - * 设置随机字符串,不长于32位。推荐随机数生成算法 - * @param string $value - * */ - public function SetNonce_str($value) - { - $this->values['nonce_str'] = $value; - } - - /** - * 获取随机字符串,不长于32位。推荐随机数生成算法的值 - * @return 值 - * */ - public function GetNonce_str() - { - return $this->values['nonce_str']; - } - - /** - * 判断随机字符串,不长于32位。推荐随机数生成算法是否存在 - * @return true 或 false - * */ - public function IsNonce_strSet() - { - return array_key_exists('nonce_str', $this->values); - } - - /** - * 设置商品或支付单简要描述 - * @param string $value - * */ - public function SetBody($value) - { - $this->values['body'] = $value; - } - - /** - * 获取商品或支付单简要描述的值 - * @return 值 - * */ - public function GetBody() - { - return $this->values['body']; - } - - /** - * 判断商品或支付单简要描述是否存在 - * @return true 或 false - * */ - public function IsBodySet() - { - return array_key_exists('body', $this->values); - } - - /** - * 设置商品名称明细列表 - * @param string $value - * */ - public function SetDetail($value) - { - $this->values['detail'] = $value; - } - - /** - * 获取商品名称明细列表的值 - * @return 值 - * */ - public function GetDetail() - { - return $this->values['detail']; - } - - /** - * 判断商品名称明细列表是否存在 - * @return true 或 false - * */ - public function IsDetailSet() - { - return array_key_exists('detail', $this->values); - } - - /** - * 设置附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 - * @param string $value - * */ - public function SetAttach($value) - { - $this->values['attach'] = $value; - } - - /** - * 获取附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据的值 - * @return 值 - * */ - public function GetAttach() - { - return $this->values['attach']; - } - - /** - * 判断附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据是否存在 - * @return true 或 false - * */ - public function IsAttachSet() - { - return array_key_exists('attach', $this->values); - } - - /** - * 设置商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号 - * @param string $value - * */ - public function SetOut_trade_no($value) - { - $this->values['out_trade_no'] = $value; - } - - /** - * 获取商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号的值 - * @return 值 - * */ - public function GetOut_trade_no() - { - return $this->values['out_trade_no']; - } - - /** - * 判断商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号是否存在 - * @return true 或 false - * */ - public function IsOut_trade_noSet() - { - return array_key_exists('out_trade_no', $this->values); - } - - /** - * 设置符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型 - * @param string $value - * */ - public function SetFee_type($value) - { - $this->values['fee_type'] = $value; - } - - /** - * 获取符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型的值 - * @return 值 - * */ - public function GetFee_type() - { - return $this->values['fee_type']; - } - - /** - * 判断符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型是否存在 - * @return true 或 false - * */ - public function IsFee_typeSet() - { - return array_key_exists('fee_type', $this->values); - } - - /** - * 设置订单总金额,只能为整数,详见支付金额 - * @param string $value - * */ - public function SetTotal_fee($value) - { - $this->values['total_fee'] = $value; - } - - /** - * 获取订单总金额,只能为整数,详见支付金额的值 - * @return 值 - * */ - public function GetTotal_fee() - { - return $this->values['total_fee']; - } - - /** - * 判断订单总金额,只能为整数,详见支付金额是否存在 - * @return true 或 false - * */ - public function IsTotal_feeSet() - { - return array_key_exists('total_fee', $this->values); - } - - /** - * 设置APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。 - * @param string $value - * */ - public function SetSpbill_create_ip($value) - { - $this->values['spbill_create_ip'] = $value; - } - - /** - * 获取APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。的值 - * @return 值 - * */ - public function GetSpbill_create_ip() - { - return $this->values['spbill_create_ip']; - } - - /** - * 判断APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。是否存在 - * @return true 或 false - * */ - public function IsSpbill_create_ipSet() - { - return array_key_exists('spbill_create_ip', $this->values); - } - - /** - * 设置订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则 - * @param string $value - * */ - public function SetTime_start($value) - { - $this->values['time_start'] = $value; - } - - /** - * 获取订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则的值 - * @return 值 - * */ - public function GetTime_start() - { - return $this->values['time_start']; - } - - /** - * 判断订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则是否存在 - * @return true 或 false - * */ - public function IsTime_startSet() - { - return array_key_exists('time_start', $this->values); - } - - /** - * 设置订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则 - * @param string $value - * */ - public function SetTime_expire($value) - { - $this->values['time_expire'] = $value; - } - - /** - * 获取订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则的值 - * @return 值 - * */ - public function GetTime_expire() - { - return $this->values['time_expire']; - } - - /** - * 判断订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则是否存在 - * @return true 或 false - * */ - public function IsTime_expireSet() - { - return array_key_exists('time_expire', $this->values); - } - - /** - * 设置商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠 - * @param string $value - * */ - public function SetGoods_tag($value) - { - $this->values['goods_tag'] = $value; - } - - /** - * 获取商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠的值 - * @return 值 - * */ - public function GetGoods_tag() - { - return $this->values['goods_tag']; - } - - /** - * 判断商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠是否存在 - * @return true 或 false - * */ - public function IsGoods_tagSet() - { - return array_key_exists('goods_tag', $this->values); - } - - /** - * 设置接收微信支付异步通知回调地址 - * @param string $value - * */ - public function SetNotify_url($value) - { - $this->values['notify_url'] = $value; - } - - /** - * 获取接收微信支付异步通知回调地址的值 - * @return 值 - * */ - public function GetNotify_url() - { - return $this->values['notify_url']; - } - - /** - * 判断接收微信支付异步通知回调地址是否存在 - * @return true 或 false - * */ - public function IsNotify_urlSet() - { - return array_key_exists('notify_url', $this->values); - } - - /** - * 设置取值如下:JSAPI,NATIVE,APP,详细说明见参数规定 - * @param string $value - * */ - public function SetTrade_type($value) - { - $this->values['trade_type'] = $value; - } - - /** - * 获取取值如下:JSAPI,NATIVE,APP,详细说明见参数规定的值 - * @return 值 - * */ - public function GetTrade_type() - { - return $this->values['trade_type']; - } - - /** - * 判断取值如下:JSAPI,NATIVE,APP,详细说明见参数规定是否存在 - * @return true 或 false - * */ - public function IsTrade_typeSet() - { - return array_key_exists('trade_type', $this->values); - } - - /** - * 设置trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。 - * @param string $value - * */ - public function SetProduct_id($value) - { - $this->values['product_id'] = $value; - } - - /** - * 获取trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。的值 - * @return 值 - * */ - public function GetProduct_id() - { - return $this->values['product_id']; - } - - /** - * 判断trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。是否存在 - * @return true 或 false - * */ - public function IsProduct_idSet() - { - return array_key_exists('product_id', $this->values); - } - - /** - * 设置trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 - * @param string $value - * */ - public function SetOpenid($value) - { - $this->values['openid'] = $value; - } - - /** - * 获取trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 的值 - * @return 值 - * */ - public function GetOpenid() - { - return $this->values['openid']; - } - - /** - * 判断trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 是否存在 - * @return true 或 false - * */ - public function IsOpenidSet() - { - return array_key_exists('openid', $this->values); - } - -} +<?php + +/** + * Created by PhpStorm. + * User: DELL + * Date: 2015/12/23 + * Time: 17:52 + */ + +namespace WebPlugin\Pay\weixin\lib; + +/** + * + * 统一下单输入对象 + * @author widyhu + * + */ +class WxPayUnifiedOrder extends WxPayDataBase +{ + + /** + * 设置微信分配的公众账号ID + * @param string $value + * */ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + * */ + public function GetAppid() + { + return $this->values['appid']; + } + + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + * */ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + /** + * 设置微信支付分配的商户号 + * @param string $value + * */ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + + /** + * 获取微信支付分配的商户号的值 + * @return 值 + * */ + public function GetMch_id() + { + return $this->values['mch_id']; + } + + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + * */ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + /** + * 设置微信支付分配的终端设备号,商户自定义 + * @param string $value + * */ + public function SetDevice_info($value) + { + $this->values['device_info'] = $value; + } + + /** + * 获取微信支付分配的终端设备号,商户自定义的值 + * @return 值 + * */ + public function GetDevice_info() + { + return $this->values['device_info']; + } + + /** + * 判断微信支付分配的终端设备号,商户自定义是否存在 + * @return true 或 false + * */ + public function IsDevice_infoSet() + { + return array_key_exists('device_info', $this->values); + } + + /** + * 设置随机字符串,不长于32位。推荐随机数生成算法 + * @param string $value + * */ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + + /** + * 获取随机字符串,不长于32位。推荐随机数生成算法的值 + * @return 值 + * */ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + + /** + * 判断随机字符串,不长于32位。推荐随机数生成算法是否存在 + * @return true 或 false + * */ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } + + /** + * 设置商品或支付单简要描述 + * @param string $value + * */ + public function SetBody($value) + { + $this->values['body'] = $value; + } + + /** + * 获取商品或支付单简要描述的值 + * @return 值 + * */ + public function GetBody() + { + return $this->values['body']; + } + + /** + * 判断商品或支付单简要描述是否存在 + * @return true 或 false + * */ + public function IsBodySet() + { + return array_key_exists('body', $this->values); + } + + /** + * 设置商品名称明细列表 + * @param string $value + * */ + public function SetDetail($value) + { + $this->values['detail'] = $value; + } + + /** + * 获取商品名称明细列表的值 + * @return 值 + * */ + public function GetDetail() + { + return $this->values['detail']; + } + + /** + * 判断商品名称明细列表是否存在 + * @return true 或 false + * */ + public function IsDetailSet() + { + return array_key_exists('detail', $this->values); + } + + /** + * 设置附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 + * @param string $value + * */ + public function SetAttach($value) + { + $this->values['attach'] = $value; + } + + /** + * 获取附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据的值 + * @return 值 + * */ + public function GetAttach() + { + return $this->values['attach']; + } + + /** + * 判断附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据是否存在 + * @return true 或 false + * */ + public function IsAttachSet() + { + return array_key_exists('attach', $this->values); + } + + /** + * 设置商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号 + * @param string $value + * */ + public function SetOut_trade_no($value) + { + $this->values['out_trade_no'] = $value; + } + + /** + * 获取商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号的值 + * @return 值 + * */ + public function GetOut_trade_no() + { + return $this->values['out_trade_no']; + } + + /** + * 判断商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号是否存在 + * @return true 或 false + * */ + public function IsOut_trade_noSet() + { + return array_key_exists('out_trade_no', $this->values); + } + + /** + * 设置符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型 + * @param string $value + * */ + public function SetFee_type($value) + { + $this->values['fee_type'] = $value; + } + + /** + * 获取符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型的值 + * @return 值 + * */ + public function GetFee_type() + { + return $this->values['fee_type']; + } + + /** + * 判断符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型是否存在 + * @return true 或 false + * */ + public function IsFee_typeSet() + { + return array_key_exists('fee_type', $this->values); + } + + /** + * 设置订单总金额,只能为整数,详见支付金额 + * @param string $value + * */ + public function SetTotal_fee($value) + { + $this->values['total_fee'] = $value; + } + + /** + * 获取订单总金额,只能为整数,详见支付金额的值 + * @return 值 + * */ + public function GetTotal_fee() + { + return $this->values['total_fee']; + } + + /** + * 判断订单总金额,只能为整数,详见支付金额是否存在 + * @return true 或 false + * */ + public function IsTotal_feeSet() + { + return array_key_exists('total_fee', $this->values); + } + + /** + * 设置APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。 + * @param string $value + * */ + public function SetSpbill_create_ip($value) + { + $this->values['spbill_create_ip'] = $value; + } + + /** + * 获取APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。的值 + * @return 值 + * */ + public function GetSpbill_create_ip() + { + return $this->values['spbill_create_ip']; + } + + /** + * 判断APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。是否存在 + * @return true 或 false + * */ + public function IsSpbill_create_ipSet() + { + return array_key_exists('spbill_create_ip', $this->values); + } + + /** + * 设置订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则 + * @param string $value + * */ + public function SetTime_start($value) + { + $this->values['time_start'] = $value; + } + + /** + * 获取订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则的值 + * @return 值 + * */ + public function GetTime_start() + { + return $this->values['time_start']; + } + + /** + * 判断订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则是否存在 + * @return true 或 false + * */ + public function IsTime_startSet() + { + return array_key_exists('time_start', $this->values); + } + + /** + * 设置订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则 + * @param string $value + * */ + public function SetTime_expire($value) + { + $this->values['time_expire'] = $value; + } + + /** + * 获取订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则的值 + * @return 值 + * */ + public function GetTime_expire() + { + return $this->values['time_expire']; + } + + /** + * 判断订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则是否存在 + * @return true 或 false + * */ + public function IsTime_expireSet() + { + return array_key_exists('time_expire', $this->values); + } + + /** + * 设置商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠 + * @param string $value + * */ + public function SetGoods_tag($value) + { + $this->values['goods_tag'] = $value; + } + + /** + * 获取商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠的值 + * @return 值 + * */ + public function GetGoods_tag() + { + return $this->values['goods_tag']; + } + + /** + * 判断商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠是否存在 + * @return true 或 false + * */ + public function IsGoods_tagSet() + { + return array_key_exists('goods_tag', $this->values); + } + + /** + * 设置接收微信支付异步通知回调地址 + * @param string $value + * */ + public function SetNotify_url($value) + { + $this->values['notify_url'] = $value; + } + + /** + * 获取接收微信支付异步通知回调地址的值 + * @return 值 + * */ + public function GetNotify_url() + { + return $this->values['notify_url']; + } + + /** + * 判断接收微信支付异步通知回调地址是否存在 + * @return true 或 false + * */ + public function IsNotify_urlSet() + { + return array_key_exists('notify_url', $this->values); + } + + /** + * 设置取值如下:JSAPI,NATIVE,APP,详细说明见参数规定 + * @param string $value + * */ + public function SetTrade_type($value) + { + $this->values['trade_type'] = $value; + } + + /** + * 获取取值如下:JSAPI,NATIVE,APP,详细说明见参数规定的值 + * @return 值 + * */ + public function GetTrade_type() + { + return $this->values['trade_type']; + } + + /** + * 判断取值如下:JSAPI,NATIVE,APP,详细说明见参数规定是否存在 + * @return true 或 false + * */ + public function IsTrade_typeSet() + { + return array_key_exists('trade_type', $this->values); + } + + /** + * @param string $value + * */ + public function SetProduct_id($value) + { + $this->values['product_id'] = $value; + } + + /** + * 获取trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。的值 + * @return 值 + * */ + public function GetProduct_id() + { + return $this->values['product_id']; + } + + /** + * 判断trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。是否存在 + * @return true 或 false + * */ + public function IsProduct_idSet() + { + return array_key_exists('product_id', $this->values); + } + + /** + * 设置trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 + * @param string $value + * */ + public function SetOpenid($value) + { + $this->values['openid'] = $value; + } + + /** + * 获取trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 的值 + * @return 值 + * */ + public function GetOpenid() + { + return $this->values['openid']; + } + + /** + * 判断trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 是否存在 + * @return true 或 false + * */ + public function IsOpenidSet() + { + return array_key_exists('openid', $this->values); + } + +} diff --git a/template/www.yohobuy.com/actions/guang/index/editor.phtml b/template/www.yohobuy.com/actions/guang/index/editor.phtml new file mode 100644 index 0000000..a156714 --- /dev/null +++ b/template/www.yohobuy.com/actions/guang/index/editor.phtml @@ -0,0 +1,32 @@ +{{> layout/header}} +<div class="guang-editor-page guang-page yoho-page clearfix"> + {{# guang}} + {{> layout/path-nav}} + + {{# editor}} + <div class="editor-info clearfix"> + <div class="author-avatar"> + <img src="{{avatar}}" alt=""> + </div> + <div class="author-info"> + <p class="author-name">{{name}}</p> + <p class="author-introduce">{{intro}}</p> + </div> + </div> + {{/ editor}} + <div class="left-side"> + <div id="msg-list" class="msg-list"> + {{# msgs}} + {{> guang/msg}} + {{/ msgs}} + </div> + <div class="msg-pager pager"> + {{{msgPager}}} + </div> + </div> + <div class="right-side"> + {{> guang/right-side}} + </div> + {{/ guang}} +</div> +{{> layout/footer}} \ No newline at end of file diff --git a/template/www.yohobuy.com/actions/guang/index/index.phtml b/template/www.yohobuy.com/actions/guang/index/index.phtml new file mode 100644 index 0000000..e799a6d --- /dev/null +++ b/template/www.yohobuy.com/actions/guang/index/index.phtml @@ -0,0 +1,44 @@ +{{> layout/header}} +<div class="guang-index-page guang-page yoho-page clearfix"> + {{# guang}} + {{> layout/path-nav}} + <div class="left-side"> + <div id="slider" class="slider"> + <ul class="slide-wrapper"> + {{#each slider}} + <li> + <a href="{{url}}" target="_blank"> + {{#if @first}} + <img src="{{img}}"> + {{^}} + <img class="lazy" data-original="{{img}}"> + {{/if}} + </a> + </li> + {{/each}} + </ul> + </div> + <div id="pjax-container" class="msg"> + <ul class="msg-nav"> + {{# msgTypes}} + <li data-type="{{typeId}}" {{#if isActive}}class="actived"{{/if}}> + <a class="pjax-link" href="{{navUrl}}">{{type}}</a> + </li> + {{/ msgTypes}} + </ul> + <div id="msg-list" class="msg-list"> + {{# msgs}} + {{> guang/msg}} + {{/ msgs}} + </div> + <div class="msg-pager pager"> + {{{msgPager}}} + </div> + </div> + </div> + <div class="right-side"> + {{> guang/right-side}} + </div> + {{/ guang}} +</div> +{{> layout/footer}} \ No newline at end of file diff --git a/template/www.yohobuy.com/actions/guang/info/comment.phtml b/template/www.yohobuy.com/actions/guang/info/comment.phtml new file mode 100644 index 0000000..d83a822 --- /dev/null +++ b/template/www.yohobuy.com/actions/guang/info/comment.phtml @@ -0,0 +1 @@ +{{> guang/comment}} diff --git a/template/www.yohobuy.com/actions/guang/info/info.phtml b/template/www.yohobuy.com/actions/guang/info/info.phtml new file mode 100644 index 0000000..e3f23d8 --- /dev/null +++ b/template/www.yohobuy.com/actions/guang/info/info.phtml @@ -0,0 +1,152 @@ +{{> layout/header}} +<div class="guang-detail-page guang-page yoho-page clearfix"> + {{# guang}} + {{> layout/path-nav}} + <div class="left-side detail-body" data-id="{{id}}"> + {{# header}} + <div class="detail-title">{{title}}</div> + <div class="article-info clearfix"> + <div class="article-author"> + <div class="author-avatar"> + <a href="{{authorUrl}}" target="_blank"> + <img src="{{avatar}}"> + </a> + </div> + </div> + <div class="author-info"> + <a class="author-name" href="{{authorUrl}}">{{name}}</a> + </div> + <div class="article-status clearfix"> + <span class="article-time">{{time}}</span> + <span class="article-click">点击:{{click}}</span> + <a href="#comment-info" id="article-comment" class="article-comment"><em class="comment-num">{{commentNum}}</em>条评论</a> + </div> + </div> + {{/ header}} + + <div class="article-main"> + {{# content}} + {{# pic}} + <div class="article-pic block"> + <img class="lazy" data-original="{{.}}"> + </div> + {{/ pic}} + {{# text}} + <div class="article-text block"> + <p>{{{.}}}</p> + </div> + {{/ text}} + {{#if smallPic}} + <div class="article-small-pic block clearfix"> + {{# smallPic}} + <img class="lazy" data-original="{{.}}"> + {{/ smallPic}} + </div> + {{/if}} + {{# relatedReco}} + <div class="related-reco block clearfix"> + <div class="block-header"> + 相关推荐 + {{# moreReco}} + <a class="more-reco" href="{{.}}">MORE ></a> + {{/ moreReco}} + </div> + <div class="recos clearfix"> + {{# recos}} + {{> product/good}} + {{/ recos}} + </div> + </div> + {{/ relatedReco}} + {{/ content}} + </div> + {{#if brands}} + <div class="related-brand block clearfix"> + <div class="block-header">相关品牌</div> + <div class="brands"> + {{# brands}} + <div class="brand"> + <a class="thumb" href="{{url}}" target="_blank"> + <img class="lazy" data-original="{{thumb}}"> + </a> + <p class="brand-name">{{name}}</p> + </div> + {{/ brands}} + </div> + </div> + {{/if}} + {{# userInfo}} + <div class="user-handle"> + <ul class="clearfix"> + <li id="prise-btn" class="like-status{{#isLike}} liked{{/isLike}}"> + <a href="javascript:;"> + <i class="iconfont"></i> + <span class="like-num">{{likeNum}}</span> + </a> + </li> + <li id="collect-btn" class="sort-collect{{#isCollected}} collected{{/isCollected}}"> + <a href="javascript:;"> + <i class="iconfont"></i> + <span>收藏</span> + <span class="cancel-collect">取消收藏</span> + </a> + </li> + </ul> + </div> + {{/ userInfo}} + <div class="article-bottom-info clearfix"> + {{#if tag}} + <div class="article-tag clearfix"> + <i class="tag-icon iconfont"></i> + <ul class="clearfix"> + {{# tag}} + <li> + <a href="{{url}}" target="_blank">{{name}}</a> + </li> + {{/ tag}} + </ul> + </div> + {{/if}} + <div class="article-share"> + <span class="title pull-left">分享至:</span> + {{> share}} + </div> + </div> + {{#if relatedPost}} + <div class="detail-related-posts"> + <ul class="clearfix"> + {{# relatedPost}} + <li> + <a href="{{url}}" target="_blank"> + <span class="bg-img"> + <img src="{{thumb}}" alt=""> + </span> + <div class="post-title"> + <h2>{{title}}</h2> + </div> + </a> + </li> + {{/ relatedPost}} + </ul> + </div> + {{/if}} + + <div id="comment-area" class="comment-area"> + <div class="comment-textarea"> + <textarea id="comment-info" placeholder="我有话要说。。。">{{commentInfo}}</textarea> + </div> + <div class="comment-publish clearfix"> + <span id="word-count-tip" class="word-count-tip"></span> + <a id="comment-btn" class="publish-btn disable">评论</a> + </div> + <div id="pjax-container" class="comments-wrap"> + {{> guang/comment}} + </div> + </div> + </div> + <div class="right-side detail-side"> + {{> guang/right-side}} + </div> + {{/ guang}} +</div> +{{> layout/footer}} diff --git a/template/www.yohobuy.com/actions/guang/tags/list.phtml b/template/www.yohobuy.com/actions/guang/tags/list.phtml new file mode 100644 index 0000000..f2d523e --- /dev/null +++ b/template/www.yohobuy.com/actions/guang/tags/list.phtml @@ -0,0 +1,24 @@ +{{> layout/header}} +<div class="guang-list-page guang-page yoho-page clearfix"> + {{# guang}} + {{> layout/path-nav}} + <div class="left-side"> + <div class="tag-header"> + <span>{{tag}}</span> + 关联的文章 + </div> + <div id="msg-list" class="msg-list"> + {{# msgs}} + {{> guang/msg}} + {{/ msgs}} + </div> + <div class="msg-pager pager"> + {{{msgPager}}} + </div> + </div> + <div class="right-side"> + {{> guang/right-side}} + </div> + {{/ guang}} +</div> +{{> layout/footer}} \ No newline at end of file diff --git a/template/www.yohobuy.com/actions/pay/index/index.phtml b/template/www.yohobuy.com/actions/pay/index/index.phtml new file mode 100644 index 0000000..61f5d77 --- /dev/null +++ b/template/www.yohobuy.com/actions/pay/index/index.phtml @@ -0,0 +1,18 @@ +<html> + <head> + </head> + <body> + {{#reqPars}} + <form action="{{pay_url}}" method="post" id="payForm"> + {{#each pars}} + <input type="hidden" name="{{@key}}" value="{{.}}"/> + {{/each}} + </form> + {{/reqPars}} + + <script type="text/javascript"> + document.getElementById('payForm').submit(); + </script> + + </body> +</html> \ No newline at end of file diff --git a/template/www.yohobuy.com/actions/pay/notice/index.phtml b/template/www.yohobuy.com/actions/pay/notice/index.phtml new file mode 100644 index 0000000..766c925 --- /dev/null +++ b/template/www.yohobuy.com/actions/pay/notice/index.phtml @@ -0,0 +1,58 @@ +{{> layout/header}} +<div class="pay-notice-page yoho-page"> + {{# payNotice}} + <h1> + <i class="ok-icon"></i> + <span class="font-red">恭喜您,购买完成!</span> + 您已成功支付 + <span class="font-red">{{pay}}</span> + 元! + </h1> + + <div class="order-info"> + <ul class="order-table-header table-row"> + <li class="order-num">订单号</li> + <li>实际支付金额</li> + <li>支付方式</li> + <li>获得YOHO币</li> + <li>获得VIP累计金额</li> + </ul> + <ul class="table-row"> + <li class="order-num"> + <a class="notice-link" href="{{checkOrderUrl}}">{{orderNum}}</a> + </li> + <li class="pay font-red">{{pay}}</li> + <li class="pay-mode">{{payMode}}</li> + <li class="yoho-coin"> + <em class="font-red">{{currency}}</em> + <a class="notice-link" href="{{yohoCoinUrl}}">YOHO币能做什么</a> + </li> + <li class="vip"> + <em class="font-red">{{vipSum}}</em> + <a class="notice-link" href="{{vipUrl}}">查看VIP特权</a> + </li> + </ul> + </div> + + <div class="notice-tip"> + 1.每天15:00以前成功付款的订单将在当天发货,15:00-00:00成功付款的订单将在第二天发货。<br> + 2.当订单发货后,您可以登录<a href="{{ordersUrl}}" class="notice-link" target="_blank">订单中心</a>查询快递发货详情。<br> + 3.有货网支持"开箱验货"和"15天退换货保障"收货后请当面验货,如果发现商品有任何问题请致电客服电话400-889-9646,<a href="{{returnGoodsUrl}}" class="notice-link" target="_blank">退换货政策</a><br> + 4.VIP金额的累计,将在您订单签收15天后积累到您的账户,请您知悉。<br> + 5.购买商品及参与促销活动赠送的YOHO币,将在您订单签收7天后积累到您的账户,您可以在个人中心-我的YOHO币中查看。<br> + <b style="color:#c00;">6.尊敬的用户:近期为网络诈骗高发期,有货郑重声明,不会以任何形式索取客户的账户信息或引导转账,敬请提高警惕,谨防诈骗。</b> + </div> + + <p class="btns"> + <a class="check-order" href="{{checkOrderUrl}}">查看订单</a> + <a class="return-home" href="{{returnHomeUrl}}">返回首页</a> + </p> + + {{#if devEnv}} + <img class="notice-img" src="http://webstatic.dev.yohobuy.com/img/pay/notice.jpg"> + {{^}} + <img class="notice-img" src="http://cdn.yoho.cn/yohobuy/assets/img/pay/notice.jpg"> + {{/if}} + {{/ payNotice}} +</div> +{{> layout/footer}} \ No newline at end of file diff --git a/template/www.yohobuy.com/actions/pay/notice/wechatqrcodereturn.phtml b/template/www.yohobuy.com/actions/pay/notice/wechatqrcodereturn.phtml new file mode 100644 index 0000000..613d4a4 --- /dev/null +++ b/template/www.yohobuy.com/actions/pay/notice/wechatqrcodereturn.phtml @@ -0,0 +1,38 @@ +{{> layout/header}} +<div class="pay-notice-wechatqrcodereturn-page yoho-page clearfix"> + {{# payData}} + <div class="wechatqrcodereturn"> + <div class="pay-title"> + <div class="step5"></div> + <ul> + <li><span>查看购物车</span></li> + <li><span>填写订单</span></li> + <li class="end"><span>付款,完成购买</span></li> + </ul> + </div> + + <div class="pay-wechat-return"> + <p class="payerror"> + 很抱歉,订单支付失败,请立即联系客服! + </p> + <p class="arrival-time"> + 客服电话: + <b class="tell-phone"> + 400-889-9646 + </b> + </p> + </div> + + <div class="cart-bigbtns"> + <span class="btn-type"> + <a href="/">返回首页</a> + </span> + </div> + + <div class="we-alert"> + <span class="we-font">感谢您选择{{payWay}}的方式,我们的客服随后会和您确认订单。</span> + </div> + </div> + {{/ payData}} +</div> +{{> layout/footer}} \ No newline at end of file diff --git a/template/www.yohobuy.com/actions/pay/wechatqrcode/index.phtml b/template/www.yohobuy.com/actions/pay/wechatqrcode/index.phtml new file mode 100644 index 0000000..4f482e0 --- /dev/null +++ b/template/www.yohobuy.com/actions/pay/wechatqrcode/index.phtml @@ -0,0 +1,67 @@ +{{> layout/header}} +<div class="pay-wechatqrcode-page yoho-page clearfix"> + {{# wechatqrcode}} + <div class="pay-title"> + <div class="step4"></div> + <ul> + <li><span>查看购物车</span></li> + <li><span>填写订单</span></li> + <li class="end"><span>付款,完成购买</span></li> + </ul> + </div> + + <div class="w-title"> + <div class="w-left"> + <h3>请您及时付款,以便订单尽快处理!订单号:{{orderNum}}</h3> + <p> + 请您提交订单 + <span>2小时</span> + 内完成,否则订单会自动取消。 + </p> + </div> + + <div class="w-right"> + <p>应付金额 + <strong>{{amount}}</strong> + 元 + </p> + <a href="#" class="w-odetail">订单详情 + <i class="up"></i> + </a> + </div> + </div> + + <div class="w-addrinfo"> + <p> + 收货地址: {{address}} + <span>收货人:{{name}}</span> + {{tellphoneNum}} + </p> + <p> + 商品名称:{{tradeName}} + </p> + </div> + + <div class="w-payment"> + <h2>微信支付</h2> + <div class="w-p-weixin"> + <div class="w-p-erm" data-url="{{wechatqrcode.qrcodeUrl}}"></div> + <div class="w-p-word"> + <p>请使用微信扫一扫</p> + <p>扫描二维码支付</p> + </div> + </div> + <a href="{{choosePayUrl}}" class="w-pay-change"> + <i><</i> + 选择其他支付方式 + </a> + </div> + + <!-- 判断是否支付成功的轮训地址 --> + <input type="hidden" id="payHost" value="{{payHost}}"> + <!-- 支付成功跳转地址 --> + <input type="hidden" id="paySuccessUrl" value="{{paySuccessUrl}}"> + + {{/ wechatqrcode}} +</div> +{{> layout/footer}} \ No newline at end of file diff --git a/template/www.yohobuy.com/actions/shopping/pay/cashondelivery.phtml b/template/www.yohobuy.com/actions/shopping/pay/cashondelivery.phtml new file mode 100644 index 0000000..c3da1b2 --- /dev/null +++ b/template/www.yohobuy.com/actions/shopping/pay/cashondelivery.phtml @@ -0,0 +1,61 @@ +{{> layout/header}} +<div class="shopping-cashondelivery-page yoho-page clearfix"> + {{# shoppingpay}} + <div class="cart-order"> + <h1> + <span class="ok-br"></span> + <span class="f-r">订单提交成功!</span> + 您需要在收货时向送货员支付 + <span class="f-a">{{count}}</span> + 元! + </h1> + </div> + <div class="list-box"> + <div class="list-t"> + <div class="li-1">订单号</div> + <div class="li-2">实际支付金额</div> + <div class="li-3">支付方式</div> + <div class="li-4">获得YOHO币</div> + <div class="li-5">获得VIP累计金额</div> + </div> + <div class="list"> + <div class="li-1"> + <a href="{{checkOrderUrl}}" class="f-e" target="_blank"> + {{orderNum}} + </a> + </div> + <div class="li-2"> + <strong class="f-rz">{{count}}</strong> + </div> + <div class="li-3 pay-mode">货到付款</div> + <div class="li-4"> + <strong class="f-rz">{{yohoCoin}}</strong> + <a href="{{yohoCoinUrl}}" class="f-e" target="_blank">YOHO币能做什么</a> + </div> + <div class="li-5"> + <strong class="f-rz">{{count}}</strong> + <a href="{{vipUrl}}" class="f-e" target="_blank">查看VIP特权</a> + </div> + </div> + </div> + + <div class="list-b"> + <span class="f-r">1.我们将在您的"货到付款"订单提交后24小时内安排快递发货,如订单有疑问需和您电话联系,请您保持电话畅通。</span><br> + 2.当订单发货后,您可以登录 + <a href="{{ordersUrl}}" class="f-e" target="_blank">订单中心</a>查询快递发货详情。<br> + 3.有货网支持"开箱验货"和"15天退换货保障"收货后请当面验货,如果发现商品有任何问题请致电客服电话400-889-9646, + <a href="{{backGoodsUrl}}" class="f-e" target="_blank">退换货政策</a><br> + 4.VIP金额的累计,将在您订单签收15天后积累到您的账户,请您知悉。<br> + 5.购买商品及参与促销活动赠送的YOHO币,将在您订单签收7天后积累到您的账户,您可以在个人中心-我的YOHO币中查看。<br> + <b>6.尊敬的用户:近期为网络诈骗高发期,有货郑重声明,不会以任何形式索取客户的账户信息或引导转账,敬请提高警惕,谨防诈骗。 + </b> + </div> + + <p class="btns"> + <a class="check-order" href="{{checkOrderUrl}}">查看订单</a> + <a class="return-home" href="{{returnHomeUrl}}">返回首页</a> + </p> + + {{/ shoppingpay}} +</div> +{{> layout/footer}} \ No newline at end of file diff --git a/template/www.yohobuy.com/actions/shopping/pay/index.phtml b/template/www.yohobuy.com/actions/shopping/pay/index.phtml new file mode 100644 index 0000000..43d75e0 --- /dev/null +++ b/template/www.yohobuy.com/actions/shopping/pay/index.phtml @@ -0,0 +1,156 @@ +{{> layout/header}} +<div class="shopping-pay-page yoho-page clearfix"> + {{# shoppingpay}} + <div class="pay-page"> + + <div class="pay-title"> + <div class="step4"></div> + <ul> + <li><span>查看购物车</span></li> + <li><span>填写订单</span></li> + <li class="end"><span>付款,完成购买</span></li> + </ul> + </div> + + <div class="cart-pay"> + <h2>您的订单已成功,现在就去付款吧~</h2> + <h3>您的订单号:<strong class="order-num">{{orderNum}}</strong> 应付金额:<strong>{{count}}</strong>元 + 支付方式:{{paymentType}} 送货时间:{{deliveryType}}</h3> + <h4>{{userName}},如果2小时内您无法完成付款,系统会将您的订单取消。</h4> + </div> + + <div class="wrapper"> + <div class="pay-way"> + <span class="word">使用:</span> + <img src="" class="pay-type-img" id="show-pay-img"> + </div> + + <div id="tab-box"> + <ul class="tabs" id="tabs"> + <li class="thistab"><a href="#" tab="tab1">支付宝等平台</a></li> + <li><a href="#" tab="tab2">使用银行卡</a></li> + </ul> + + <ul class="tab-conbox"> + <li id="tab1" class="tab-con"> + <div class="count"> + {{# each list}} + <div class="mode" data-id="{{dataId}}" data-value="{{dataVal}}"> + <div id="{{idNum}}"></div> + <img src="{{ico}}" alt="{{name}}" id="{{imgId}}"> + </div> + {{/each}} + + </div> + </li> + + <li id="tab2" class="tab-con" style="display:none;"> + <div class="count"> + {{# each entry}} + <div class="mode" data-id="{{dataId}}" data-value="{{dataVal}}"> + <div id="{{idNum}}"></div> + <img src="{{ico}}" alt="{{name}}" id="{{imgId}}"> + </div> + {{/each}} + </div> + </li> + </ul> + </div> + + <div class="btn-wrapper"> + <input type="hidden" id="payUrl" value="{{payUrl}}"> + <input type="hidden" id="choosePay" value="{{payRecord}}"> + <input type="submit" value="" class="btnby" id="btnby"> + </div> + </div> + <div class="light-box"> + <div class="opacity" id="fade"></div> + <div class="content" id="light"> + <h2>请您在新打开的页面上完成付款</h2> + <div class="notice"> + <p>付款完成前请不要关闭此窗口</p> + <p>完成付款后请根据您的情况点击下面的按钮</p> + </div> + <div class="btns"> + <a href="{{ordersUrl}}" class="over">已完成付款</a> + <a href="#" class="change">更换支付方式</a> + </div> + <a href="#" class="close">x</a> + </div> + </div> + + {{/ shoppingpay}} + + </div> + + {{# shoppingpay}} + <!-- Google Code for 下单成功 Conversion Page --> + <script type="text/javascript"> + /* <![CDATA[ */ + var google_conversion_id = 959290965; + var google_conversion_language = "zh_CN"; + var google_conversion_format = "2"; + var google_conversion_color = "ff0000"; + var google_conversion_label = "n6GICNu3-AIQ1by2yQM"; + var google_conversion_value = 0; + if (100) { + google_conversion_value = 100; + } + /* ]]> */ + </script> + <script type="text/javascript" + src="http://www.googleadservices.com/pagead/conversion.js"> + </script> + <noscript> + <div style="display: inline;"> + <img height="1" width="1" style="border-style: none;" alt="" + src="http://www.googleadservices.com/pagead/conversion/959290965/?value=100&label=n6GICNu3-AIQ1by2yQM&guid=ON&script=0"/> + </div> + </noscript> + + <iframe name="StatPage" src="http://www.yohobuy.com/shopping/cart/stat?step=end&order_code={{orderNum}}" width=0 + height=0 style="display:none"></iframe> + + <!-- Google Code for 订单完成页-搜索 Conversion Page --> + <script type="text/javascript"> + /* <![CDATA[ */ + var google_conversion_id = 991392201; + var google_conversion_language = "en"; + var google_conversion_format = "2"; + var google_conversion_color = "ffffff"; + var google_conversion_label = "asUdCK_i0AQQyePd2AM"; + var google_conversion_value = 0; + /* ]]> */ + </script> + <script type="text/javascript" + src="http://www.googleadservices.com/pagead/conversion.js"> + </script> + <script type="text/javascript"> + _ozprm = "orderid={{orderNum}}"; + </script> + <noscript> + <div style="display:inline;"> + <img height="1" width="1" style="border-style:none;" alt="" + src="http://www.googleadservices.com/pagead/conversion/991392201/?value=0&label=asUdCK_i0AQQyePd2AM&guid=ON&script=0"/> + </div> + </noscript> + + <script type="text/javascript"> + <!-- + (function (d) { + window.bd_cpro_rtid = "P1fsP10"; + var s = d.createElement("script"); + s.type = "text/javascript"; + s.async = true; + s.src = location.protocol + "//cpro.baidu.com/cpro/ui/rt.js"; + var s0 = d.getElementsByTagName("script")[0]; + s0.parentNode.insertBefore(s, s0); + })(document); + //--> + </script> + + {{> shopping/box-analysis}} + {{> shopping/box-buy-analysis}} + {{/ shoppingpay}} + + {{> layout/footer}} diff --git a/template/www.yohobuy.com/actions/shopping/pay/notneedpay.phtml b/template/www.yohobuy.com/actions/shopping/pay/notneedpay.phtml new file mode 100644 index 0000000..37ccd09 --- /dev/null +++ b/template/www.yohobuy.com/actions/shopping/pay/notneedpay.phtml @@ -0,0 +1,28 @@ +{{> layout/header}} +<div class="shopping-pay-page yoho-page clearfix"> + <div class="pay-page"> + + <div class="pay-title"> + <div class="step5"></div> + <ul> + <li><span>查看购物车</span></li> + <li><span>填写订单</span></li> + <li class="end"><span>完成订单</span></li> + </ul> + </div> + <div class="not-pay"> + <p class="success">恭喜你,购买完成,我们会尽快发货!</p> + <p>当订单发货后,你可以登录订单中心查询快递发货详情。</p> + <a href="http://www.yohobuy.com/">返回首页</a> + </div> + + </div> +</div> +{{#shoppingpay}} +<script> + __custom['order_code'] = {{orderNum}}; + __custom['skn_list'] = '{{sknList}}'; + __custom['sku_list'] = '{{skuList}}'; +</script> +{{/shoppingpay}} +{{> layout/footer}} diff --git a/template/www.yohobuy.com/partials/guang/comment.phtml b/template/www.yohobuy.com/partials/guang/comment.phtml new file mode 100644 index 0000000..2242e1c --- /dev/null +++ b/template/www.yohobuy.com/partials/guang/comment.phtml @@ -0,0 +1,23 @@ +{{# comment}} + <h4> + <span class="comment-num">{{commentNum}}</span> + 条评论 <i></i> + </h4> + <p class="comments-empty">还没有评论,快抢沙发吧</p> + <div class="commnets-resultwrapper"> + <ul class="comments-list"> + {{# list}} + <li class="clearfix"> + <div class="avatar"> + <img class="comment-user-avatar" src="{{avatar}}" alt=""></div> + <div class="comment-info"> + <p class="comment-user-name">{{name}}</p> + <p class="comment-content">{{content}}</p> + <p class="comment-time">{{time}}</p> + </div> + </li> + {{/ list}} + </ul> + <div class="comment-pager pager">{{{commentPager}}}</div> + </div> +{{/ comment}} diff --git a/template/www.yohobuy.com/partials/guang/msg.phtml b/template/www.yohobuy.com/partials/guang/msg.phtml index fc086a6..1bb14c1 100644 --- a/template/www.yohobuy.com/partials/guang/msg.phtml +++ b/template/www.yohobuy.com/partials/guang/msg.phtml @@ -1,49 +1,49 @@ -<div class="msg-content clearfix" data-id="{{id}}"> - <div class="msg-img"> - <div class="classification"> - {{classification}} - </div> - {{#if isReco}} - <div class="reco"></div> - {{/if}} - <a href="{{url}}"> - <img class="lazy{{#if isSquareImg}} square{{/if}}" data-original="{{img}}"> - </a> - </div> - <div class="msg-info"> - <a class="msg-title" href="{{url}}">{{title}}</a> - <p class="msg-app"> - <a href="{{editorUrl}}"> - <span class="author">{{author}}</span> - </a> - <span class="publish-time"> - <i class="iconfont"></i> - {{pTime}} - </span> - <span class="page-view"> - <i class="iconfont"></i> - {{pView}} - </span> - </p> - <p class="content">{{content}}</p> - <div class="footer"> - <div class="tags"> - {{# tags}} - <a class="msg-tag" href="{{url}}" target="_blank">{{tag}}</a> - {{/ tags}} - </div> - <div class="like-comment"> - <span class="like"> - <i class="iconfont like-icon{{#if liked}} liked{{/if}}"></i> - {{#if like}}<b class="like-num">(<em class="num">{{like}}</em>)</b>{{/if}} - </span> - <span class="comment"> - <i class="iconfont"></i> - {{# comment}} - ({{.}}) - {{/ comment}} - </span> - </div> - </div> - </div> +<div class="msg-content clearfix" data-id="{{id}}"> + <div class="msg-img"> + <div class="classification"> + {{classification}} + </div> + {{#if isReco}} + <div class="reco"></div> + {{/if}} + <a href="{{url}}" target="_blank"> + <img class="lazy{{#if isSquareImg}} square{{/if}}" data-original="{{img}}"> + </a> + </div> + <div class="msg-info"> + <a class="msg-title" href="{{url}}" target="_blank">{{title}}</a> + <p class="msg-app"> + <a href="{{editorUrl}}" target="_blank"> + <span class="author">{{author}}</span> + </a> + <span class="publish-time"> + <i class="iconfont"></i> + {{pTime}} + </span> + <span class="page-view"> + <i class="iconfont"></i> + {{pView}} + </span> + </p> + <p class="content">{{content}}</p> + <div class="footer"> + <div class="tags"> + {{# tags}} + <a class="msg-tag" href="{{url}}" target="_blank">{{tag}}</a> + {{/ tags}} + </div> + <div class="like-comment"> + <span class="like"> + <i class="iconfont like-icon{{#if liked}} liked{{/if}}"></i> + {{#if like}}<b class="like-num">(<em class="num">{{like}}</em>)</b>{{/if}} + </span> + <span class="comment"> + <i class="iconfont"></i> + {{# comment}} + ({{.}}) + {{/ comment}} + </span> + </div> + </div> + </div> </div> \ No newline at end of file diff --git a/template/www.yohobuy.com/partials/guang/right-side.phtml b/template/www.yohobuy.com/partials/guang/right-side.phtml index ae43ec6..7b94da1 100644 --- a/template/www.yohobuy.com/partials/guang/right-side.phtml +++ b/template/www.yohobuy.com/partials/guang/right-side.phtml @@ -1,34 +1,34 @@ -<div class="ex-reco"> - <h1 class="ex-reco-title">精彩推荐</h1> - <div id="ex-reco-list" class="ex-reco-list"> - {{# exRecos}} - <div class="ex-reco-item clearfix"> - <a class="ex-reco-img" href="{{url}}" target="_blank"> - <span class="bg-img" style="background-image:url({{img}})"></span> - </a> - <a href="{{url}}" target="_blank"> - <p class="ex-reco-context">{{title}}</p> - </a> - </div> - {{/ exRecos}} - </div> -</div> - -<div class="hot"> - <h1 class="hot-title">热门标签</h1> - <div class="hot-tag-list"> - {{#hotTags}} - <a class="hot-tag" href="{{url}}"> - {{tagName}} - </a> - {{/hotTags}} - </div> -</div> - -<div class="ads"> - {{# ads}} - <a class="ad" href="{{url}}"> - <img class="lazy" data-original="{{img}}"> - </a> - {{/ ads}} +<div class="ex-reco"> + <h1 class="ex-reco-title">精彩推荐</h1> + <div id="ex-reco-list" class="ex-reco-list"> + {{# exRecos}} + <div class="ex-reco-item clearfix"> + <a class="ex-reco-img" href="{{url}}" target="_blank"> + <span class="bg-img" style="background-image:url({{img}})"></span> + </a> + <a href="{{url}}" target="_blank"> + <p class="ex-reco-context">{{title}}</p> + </a> + </div> + {{/ exRecos}} + </div> +</div> + +<div class="hot"> + <h1 class="hot-title">热门标签</h1> + <div class="hot-tag-list"> + {{#hotTags}} + <a class="hot-tag" href="{{url}}" target="_blank"> + {{tagName}} + </a> + {{/hotTags}} + </div> +</div> + +<div class="ads"> + {{# ads}} + <a class="ad" href="{{url}}" target="_blank"> + <img class="lazy" data-original="{{img}}"> + </a> + {{/ ads}} </div> \ No newline at end of file diff --git a/template/www.yohobuy.com/partials/shopping/box-analysis.phtml b/template/www.yohobuy.com/partials/shopping/box-analysis.phtml new file mode 100644 index 0000000..c451db5 --- /dev/null +++ b/template/www.yohobuy.com/partials/shopping/box-analysis.phtml @@ -0,0 +1,10 @@ +<script type="text/javascript"> + var dataLayer = dataLayer || []; + dataLayer.push({userid: '{{uid}}'}) + dataLayer.push({orderid: '{{orderNum}}'}) + dataLayer.push({ordersum: '{{count}}'}) + dataLayer.push({ordercount: '{{ordersGoodsNums}}'}) + /*单条订单中包含的真实订单数目*/ + dataLayer.push({ordernew: {{#if isOldUser}}0{{else}}1{{/if}} }) + /*是否新客单,是为1,不是为0*/ +</script> \ No newline at end of file diff --git a/template/www.yohobuy.com/partials/shopping/box-buy-analysis.phtml b/template/www.yohobuy.com/partials/shopping/box-buy-analysis.phtml new file mode 100644 index 0000000..a3b13bc --- /dev/null +++ b/template/www.yohobuy.com/partials/shopping/box-buy-analysis.phtml @@ -0,0 +1,57 @@ +{{#if orderGoods}} + <script type="text/javascript"> + var ga = ga || function () { + (ga.q = ga.q || []).push(arguments) + }; + ga('require', 'ecommerce', 'ecommerce.js'); //固定引用ecommerce.js + ga('ecommerce:addTransaction', { //收集订单数据 + 'id': '{{orderNum}}', // Transaction ID. Required. + 'affiliation': 'YOHOBUY', // Affiliation or store name. + 'revenue': '{{count}}', // Grand Total. + 'shipping': '1.0', // Shipping. + 'tax': '0' // Tax. + }); + {{#orderGoods}} + ga('ecommerce:addItem', { //收集商品数据 + 'id': '{{../orderNum}}', // Transaction ID. Required. + 'name': '{{product_name}}', // Product name. Required. + 'sku': '{{product_sku}}', // SKU/code. + 'category': 'Olive Medium', // Category or variation. + 'price': '{{goods_price}}', // Unit price. + 'quantity': '{{buy_number}}' // Quantity. + }); + {{/orderGoods}} + ga('ecommerce:send'); //发送电子商务跟踪数据 + ga('myTracker.ecommerce:send'); + </script> + + <script src="http://static.yohobuy.com/js/AG_Tracking.js?v=20121102"></script> + <script type="text/javascript"> + //请将js代码嵌入到html中body标签结束之前。(整个body部分最后边) + var _agq = _agq || []; + _agq.push(['_cid', '415']); //生成value + _agq.push(['_eid', '102']); //生成value + //以下参数需要客户配合填写。**为需要替代内容 + _agq.push(['_orderSum', '{{count}}']);//订单金额,客户在页面填写 + _agq.push(['_orderNo', '{{orderNum}}']);//订单号,客户在页面填写 + _agq.push(['_orderNew','{{#if isOldUser}}false{{else}}true{{/if}}']);//是否新客单,客户标记是为true否为false + _agq.push(['_orderCount', '{{ordersGoodsNums}}']);//订单货品数目,客户填写 + ag_send(_agq); + + var __order_code = '{{orderNum}}'; + var __order_amount = '{{count}}'; + var __order_user = '{{#if isOldUser}}old{{else}}new{{/if}}'; + var __order_uid = '{{uid}}'; + var __order_goods_num = {{ordersGoodsNums}}; + var __order_goods = JSON.stringify({{goodsData}}); + </script> + <script type="text/javascript"> + var _mvq = window._mvq || []; + window._mvq = _mvq; + _mvq.push(['$setAccount', 'm-23428-1']); + _mvq.push(['$setGeneral', 'ordercreate', '', /*用户名*/ '', /*用户id*/ '{{uid}}']); + _mvq.push(['$logConversion']); + _mvq.push(['$addOrder', /*订单号*/ '{{orderNum}}', /*订单金额*/ '{{count}}']); + _mvq.push(['$logData']); + </script> +{{/if}} diff --git a/web-static/js/pay/wechatqrcode.js b/web-static/js/pay/wechatqrcode.js index a2dd6ee..d2b42bb 100644 --- a/web-static/js/pay/wechatqrcode.js +++ b/web-static/js/pay/wechatqrcode.js @@ -20,15 +20,7 @@ $wOdetail.click(function() { } }); -$.ajax({ - url: $wPerm.data('url'), - dataType: 'jsonp', - success: function(res) { - if (res.code === '200') { - $wPerm.qrcode(res.qrcode_url); - } - } -}); +$wPerm.qrcode($wPerm.data('url')); function checkPayStatus() { console.log('ll'); @@ -36,7 +28,7 @@ function checkPayStatus() { url: $payHost, dataType: 'jsonp', success: function(data) { - if (data.status === 'success') { + if (data.message === 'success') { window.location.href = $paySuccessUrl; } } diff --git a/web-static/js/shopping/pay.js b/web-static/js/shopping/pay.js index bbce271..c66ea86 100644 --- a/web-static/js/shopping/pay.js +++ b/web-static/js/shopping/pay.js @@ -10,8 +10,8 @@ var $ = require('yoho.jquery'), $btnty = $('#btnby'), $lightBox = $('.light-box'), $choosePay = $('#choosePay').val(), - $chooseMoid = $('.mode div[id="' + $choosePay + '"]').parent().data().value, - $showValue = $choosePay ? $chooseMoid : $('.mode').eq(0).data().value, + $chooseMoid = $('.mode div[id="' + $choosePay + '"]').parent().data('value'), + $showValue = $choosePay ? $chooseMoid : $('.mode').eq(0).data('value'), $payUrl = $('#payUrl').val(), $modeData, activeTab, diff --git a/web-static/package.json b/web-static/package.json index acb09b5..767f028 100644 --- a/web-static/package.json +++ b/web-static/package.json @@ -1,6 +1,6 @@ { "name": "web-yohobuy", - "version": "0.0.20", + "version": "0.0.21", "description": "web yohobuy static", "keywords": [], "homepage": "", diff --git a/web-static/sass/pay/_notice.css b/web-static/sass/pay/_notice.css index ac6e75a..2f83974 100644 --- a/web-static/sass/pay/_notice.css +++ b/web-static/sass/pay/_notice.css @@ -80,8 +80,8 @@ a { display: inline-block; - height: 34px; - line-height: 34px; + height: 33px; + line-height: 33px; text-align: center; font-size: 14px; font-weight: bold; diff --git a/web-static/sass/shopping/_cashondelivery.css b/web-static/sass/shopping/_cashondelivery.css index bca7b71..e9f768f 100644 --- a/web-static/sass/shopping/_cashondelivery.css +++ b/web-static/sass/shopping/_cashondelivery.css @@ -33,6 +33,7 @@ border-top: 10px #000 solid; border-bottom: 0px; margin-bottom: 20px; + font-size: 14px; } .list-t { @@ -48,13 +49,12 @@ width: 170px; height: 36px; border-right: 1px #dadada solid; - font-size: 14px; font-weight: bold; float: left; a{ text-decoration: none; - color: #666; + color: #468fa2; outline: none; } } @@ -92,11 +92,21 @@ background: #fff; text-align: center; border-bottom: 1px #dadada solid; + font-size: 14px; } .f-rz { font-weight: bold; - font-size: 14px; + font-size: 14px; + color: #e8044f; + } + + .f-e { + color: #468fa2; + } + + .f-a { + color: #e8044f; } .list-b { @@ -106,55 +116,53 @@ padding: 20px; line-height: 1.8; margin-bottom: 20px; + font-family: Arial,helvetica,sans-serif; a { text-decoration: none; - color: #666; + color: #468fa2; outline: none; } b { color:#c00; - font-weight: bold; } } - .submit { + .pay-mode{ + color: #666; + } + + .btns { text-align: center; - padding: 20px 0px; + padding: 20px 0; margin-bottom: 150px; a { - vertical-align: middle; - cursor: auto; + display: inline-block; + height: 33px; + line-height: 33px; + text-align: center; + font-size: 14px; + font-weight: bold; + cursor: pointer; + border-radius: 4px; } - } - .btn-sbr { - width: 135px; - height: 33px; - line-height: 33px; - color: #fff; - text-align: center; - font-size: 14px; - font-weight: bold; - background: resolve(/pay/cashondelivery-ri.png) no-repeat; - display: inline-block; - cursor: pointer; - margin-right: 10px; - } + .check-order { + background: #da034a; + color: #fff; + border: 1px solid #9d0134; + width: 134px; + margin-right: 15px; + } - .btn-sbh { - width: 94px; - height: 33px; - line-height: 33px; - color: #333; - text-align: center; - font-size: 14px; - font-weight: bold; - background: resolve(/pay/cashondelivery-le.png) no-repeat; - display: inline-block; - cursor: pointer; + .return-home { + background: #eee; + color: #000; + border: 1px solid #b0b0b0; + width: 97px; + } } } \ No newline at end of file diff --git a/yohobuy/www.yohobuy.com/application/controllers/Guang.php b/yohobuy/www.yohobuy.com/application/controllers/Guang.php deleted file mode 100644 index 20368fa..0000000 --- a/yohobuy/www.yohobuy.com/application/controllers/Guang.php +++ /dev/null @@ -1,486 +0,0 @@ -<?php -use Action\AbstractAction; - -/** - * 逛 - */ -class GuangController extends AbstractAction -{ - - /** - * 逛首页 - */ - public function indexAction() - { - $data = array( - 'guangIndexPage' => true, - 'guang' => array( - 'slider' => array( - array( - 'url' => '', - 'img' => 'http://img13.static.yhbimg.com/taobaocms/2015/06/17/07/0240f288725106b408d8c524b4d0fba4b9.jpg' - ), - array( - 'url' => '', - 'img' => 'http://img13.static.yhbimg.com/taobaocms/2015/06/17/07/02934d7696b187d260341d31c084eb93cc.jpg' - ) - ), - 'msgTypes' => array( - array( - 'typeId' => 1, - 'type' => '最新', - 'navUrl' => '/' - ), - array( - 'typeId' => 2, - 'type' => '话题', - 'isActive' => true, - 'navUrl' => '/' - ), - array( - 'typeId' => 3, - 'type' => '搭配', - 'navUrl' => '/' - ), - array( - 'typeId' => 4, - 'type' => '潮人', - 'navUrl' => '/' - ), - array( - 'typeId' => 5, - 'type' => '潮物', - 'navUrl' => '/' - ), - array( - 'typeId' => 6, - 'type' => '小贴士', - 'navUrl' => '/' - ) - ), - 'msgs' => array( - array( - 'id' => 1, - 'classification' => '话题', - 'isReco' => true, - 'url' => '', - 'img' => 'http://img10.static.yhbimg.com/yhb-img01/2015/06/12/17/01437323c88bc61f26721a2ad91a2ba61a.png?imageView/2/w/640/h/640', - 'isSquareImg' => true, - 'title' => '破旧除新!Publish完美释出2015最新春季[TheResistance]系列看看你很长的时候会不会分页啊,奇怪的人类', - 'author' => '大家玩看看作者名字 过长的情况显示是不是有问题呵呵哒哒哒', - 'editorUrl' => '', - 'pTime' => '2015-03-08 15:33', - 'pView' => '225', - 'content' => '该类型 应用于多图形式。虽说洛杉矶街头品牌Publish是凭着设计一炮而红,跃升为近年人气品牌,但是该设计团队却打算你妹啊鬼知道你后面说什么但是要测试文字截取能不能成功,所以必须要把你写很长很长很长很长很长', - 'tags' => array( - array( - 'url' => '', - 'tag' => 'adidas OriginalsQ' - ) - ), - 'like' => 0, // 如果为0,不传 - // 'liked' => false, - 'comment' => 20 - ) - ), - 'exRecos' => array( - array( - 'url' => '', - 'img' => 'http://img10.static.yhbimg.com/yhb-img01/2015/06/12/17/01437323c88bc61f26721a2ad91a2ba61a.png?imageView/2/w/640/h/640', - 'title' => '皇家蓝再现,New Balance 999 Elite文字描述长一点查看文字截取的功能' - ) - ), - 'hotTags' => array( - array( - 'tagName' => 'LEE', - 'url' => '' - ) - ), - 'ads' => array( - array( - 'url' => '', - 'img' => 'http://img13.static.yhbimg.com/taobaocms/2015/06/17/07/0240f288725106b408d8c524b4d0fba4b9.jpg' - ) - ), - 'msgPager' => '<a href="" class="cur"><span>1</span></a><a href=""><span>2</span></a><a href="" title="下一页">下一页<span class="ifont10">></span></a>' - ) - ); - $this->_view->display('index', $data); - } - - /** - * 逛详情页 - */ - public function detailAction() - { - $data = array( - 'guangDetailPage' => true, - 'guang' => array( - 'id' => '1', - 'header' => array( - 'title' => '潮款马甲内搭学院风领结衬衣!休闲学院风走起', - 'avatar' => 'http://rescdn.yohoboys.com/res/new/boys/images/writer-head-icon.png', - 'name' => '潮流主编', - 'authorUrl' => '', - 'intro' => '日本设计界宗师', - 'time' => '2015-03-09 08:26', - 'click' => '1128', - 'commentNum' => '4' - ), - 'content' => array( - array( - 'pic' => 'http://img01.yohoboys.com/contentimg/2015/06/04/14/01245c8a33b89ea1efef161f7de82a8b53.jpg' - ), - array( - 'text' => 'LV的大秀想必是最不容错过的,这个全世界最有实力的品牌,当之无愧的时尚之王,今年会带来什么样的惊喜呢?作为设计总监的Kim Jones,从2011年就负责LV的男装设计,每一季都会有突破性的表现,这一季度,依然带来具有Kim Jones风格的春夏系列。本季的主题融入了旅行风格,打造出一系列轻松舒适的服饰。从T恤到棒球夹克再到西装,都充满了轻松随意感。同时还融入了各式的花纹和图案设计。能够见到有中国特色的仙鹤刺绣等图案,撞色格纹设计也非常亮眼。搭配上剪裁轮廓上的流线感,使整个系列给人感觉非常的轻松自如。虽然Kim Jones一直保持低调的习惯,但是在巴黎这个时装界重要地区,他呈现一季比较有活力的大秀,顶级真的是顶级,这可不是一些标榜独立设计师品牌们能够企及的。' - ), - array( - 'smallPic' => array( - 'http://img02.static.yohobuy.com/cms/2015/06/26/12/027eb72bc880b4fe1aad361296c871c2ea.jpg', - 'http://img02.static.yohobuy.com/cms/2015/06/26/12/027eb72bc880b4fe1aad361296c871c2ea.jpg' - ) - ), - array( - 'relatedReco' => array( - 'recos' => array( - array( - 'thumb' => 'http://img11.static.yhbimg.com/goodsimg/2015/03/02/07/01ebfb219e22770ffb0c2c3a2cbb2b4bef.jpg?imageMogr2/thumbnail/235x314/extent/235x314/background/d2hpdGU=/position/center/quality/90', - 'name' => 'GAWS DIGI 丛林数码印花拼接卫衣', - 'isLike' => false, - 'price' => 1268, - 'salePrice' => 589, - 'tags' => array( - array( - 'isNew' => true - ), - array( - 'isSale' => false - ), - array( - 'isLimit' => true - ), - array( - 'isYohood' => false - ), - array( - 'isReNew' => true - ), - array( - 'isYearEndPromotion' => false - ), - array( - 'isYearMidPromotion' => false - ) - ), - 'isFew' => true, // 单独的即将售罄标志,不显示不写 - 'url' => '' - ), - array( - 'thumb' => 'http://img13.static.yhbimg.com/goodsimg/2015/03/02/08/023f696cf1ae78688bc6c8edeccc480c2c.jpg?imageMogr2/thumbnail/235x314/extent/235x314/background/d2hpdGU=/position/center/quality/90', - 'name' => 'CLOTtee 撞色连帽外套', - 'isLike' => false, - 'price' => 488, - 'salePrice' => 139, - 'tags' => array( - array( - 'isNew' => true - ), - array( - 'isSale' => false - ), - array( - 'isLimit' => true - ), - array( - 'isYohood' => true - ) - ), - 'url' => '' - ), - array( - 'thumb' => 'http://img13.static.yhbimg.com/goodsimg/2015/03/02/08/023f696cf1ae78688bc6c8edeccc480c2c.jpg?imageMogr2/thumbnail/235x314/extent/235x314/background/d2hpdGU=/position/center/quality/90', - 'name' => 'CLOTtee 撞色连帽外套', - 'isLike' => false, - 'price' => 488, - 'salePrice' => 139, - 'tags' => array( - array( - 'isNew' => true - ), - array( - 'isSale' => false - ), - array( - 'isLimit' => true - ), - array( - 'isYohood' => true - ) - ), - 'url' => '' - ), - array( - 'thumb' => 'http://img13.static.yhbimg.com/goodsimg/2015/03/02/08/023f696cf1ae78688bc6c8edeccc480c2c.jpg?imageMogr2/thumbnail/235x314/extent/235x314/background/d2hpdGU=/position/center/quality/90', - 'name' => 'CLOTtee 撞色连帽外套', - 'isLike' => false, - 'price' => 488, - 'salePrice' => 139, - 'tags' => array( - array( - 'isNew' => true - ), - array( - 'isSale' => false - ), - array( - 'isLimit' => true - ), - array( - 'isYohood' => true - ) - ), - 'url' => '' - ) - ), - 'moreReco' => '11' - ) - ) - ), - 'brands' => array( - array( - 'thumb' => 'http://img10.static.yhbimg.com/brandLogo/2011/06/26/19/016f21d6a39d5071e1864943253dcdefde.jpg?imageMogr2/thumbnail/100x100/extent/100x100/background/d2hpdGU=/position/center', - 'name' => '004', - 'url' => '' - ), - array( - 'thumb' => 'http://img12.static.yhbimg.com/brandLogo/2011/06/26/14/02ef4f656cbf6c1ec349b30f07e3347840.jpg?imageMogr2/thumbnail/100x100/extent/100x100/background/d2hpdGU=/position/center', - 'name' => 'MELISSA', - 'url' => '' - ), - array( - 'thumb' => 'http://img10.static.yhbimg.com/brandLogo/2012/08/02/15/01e4740f9f77d0142902face2f3d151109.jpg?imageMogr2/thumbnail/100x100/extent/100x100/background/d2hpdGU=/position/center', - 'name' => '2%', - 'url' => '' - ), - array( - 'thumb' => 'http://img12.static.yhbimg.com/brandLogo/2014/08/28/13/028aa6e10aad8235c0f283e0b26f495a9b.jpg?imageMogr2/thumbnail/100x100/extent/100x100/background/d2hpdGU=/position/center', - 'name' => 'migo', - 'url' => '' - ) - ), - 'userInfo' => array( - 'isLike' => true, - 'likeNum' => 84, - 'isCollected' => true - ), - 'tag' => array( - array( - 'name' => 'LEE', - 'url' => 'www.baidu.com' - ), - array( - 'name' => 'Style', - 'url' => '' - ), - array( - 'name' => '卫衣', - 'url' => 'www.baidu.com' - ), - array( - 'name' => '春季新品', - 'url' => 'www.baidu.com' - ), - array( - 'name' => 'LEE', - 'url' => 'www.baidu.com' - ), - array( - 'name' => 'Style', - 'url' => '' - ), - array( - 'name' => '卫衣', - 'url' => 'www.baidu.com' - ), - array( - 'name' => '春季新品', - 'url' => 'www.baidu.com' - ) - ), - 'relatedPost' => array( - array( - 'url' => 'www.baidu.com', - 'thumb' => 'http://img11.static.yhbimg.com/yhb-img01/2015/07/27/17/015d433e79035f8e04aeb4f1329418f0e7.jpg?imageView/2/w/250/h/200', - 'title' => 'Playboy Special' - ), - array( - 'url' => '', - 'imgUrl' => 'http://img02.yohoboys.com/contentimg/2015/06/03/09/02f9e8208e295f6624ba9eea5f1cdac0fa.jpg', - 'title' => 'Playboy Special' - ), - array( - 'url' => 'www.baidu.com', - 'imgUrl' => 'http://img02.yohoboys.com/contentimg/2015/02/27/10/02b3967610350cff3068dada3435cbff38.jpg', - 'title' => 'Playboy Special' - ) - ), - 'commentInfo' => '初始内容,用于登陆页跳转回来后的内容不丢失', - 'comment' => array( - 'commentNum' => 4, // 如果没有评论,数字为0,list和commentPager可以不传 - 'list' => array( - array( - 'avatar' => 'http://rescdn.yohoboys.com/res/new/boys/images/writer-head-icon.png', - 'name' => 'Nikil', - 'content' => '睡一觉再更', - 'time' => '7小时前' - ) - ) - ), - 'exRecos' => array( - array( - 'url' => '', - 'img' => 'http://img10.static.yhbimg.com/yhb-img01/2015/06/12/17/01437323c88bc61f26721a2ad91a2ba61a.png?imageView/2/w/640/h/640', - 'title' => '皇家蓝再现,New Balance 999 Elite文字描述长一点查看文字截取的功能' - ) - ), - 'hotTags' => array( - array( - 'tagName' => 'LEE', - 'url' => '' - ) - ), - 'ads' => array( - array( - 'url' => '', - 'img' => 'http://img13.static.yhbimg.com/taobaocms/2015/06/17/07/0240f288725106b408d8c524b4d0fba4b9.jpg' - ) - ), - 'msgPager' => '<a href="" class="cur"><span>1</span></a><a href=""><span>2</span></a><a href="" title="下一页">下一页<span class="ifont10">></span></a>' - ) - ); - $this->_view->display('detail', $data); - } - - /** - * 编辑页 - */ - public function editorAction() - { - $data = array( - 'guangListPage' => true, - 'guang' => array( - 'editor' => array( - 'avatar' => 'http://rescdn.yohoboys.com/res/new/boys/images/writer-head-icon.png', - 'name' => '潮流主编', - 'intro' => '日本设计界宗师', - 'info' => '设计理念:时尚,线条流畅' - ), - 'msgs' => array( - array( - 'id' => 1, - 'classification' => '话题', - 'isReco' => true, - 'url' => '', - 'img' => 'http://img10.static.yhbimg.com/yhb-img01/2015/06/12/17/01437323c88bc61f26721a2ad91a2ba61a.png?imageView/2/w/640/h/640', - 'isSquareImg' => true, - 'title' => '破旧除新!Publish完美释出2015最新春季[TheResistance]系列看看你很长的时候会不会分页啊,奇怪的人类', - 'author' => '大家玩看看作者名字 过长的情况显示是不是有问题呵呵哒哒哒', - 'editorUrl' => '', - 'pTime' => '2015-03-08 15:33', - 'pView' => '225', - 'content' => '该类型 应用于多图形式。虽说洛杉矶街头品牌Publish是凭着设计一炮而红,跃升为近年人气品牌,但是该设计团队却打算你妹啊鬼知道你后面说什么但是要测试文字截取能不能成功,所以必须要把你写很长很长很长很长很长', - 'tags' => array( - array( - 'url' => '', - 'tag' => 'adidas OriginalsQ' - ) - ), - 'like' => 0, // 如果为0,不传 - // 'liked' => false, - 'comment' => 20 - ) - ), - 'exRecos' => array( - array( - 'url' => '', - 'img' => 'http://img10.static.yhbimg.com/yhb-img01/2015/06/12/17/01437323c88bc61f26721a2ad91a2ba61a.png?imageView/2/w/640/h/640', - 'title' => '皇家蓝再现,New Balance 999 Elite文字描述长一点查看文字截取的功能' - ) - ), - 'hotTags' => array( - array( - 'tagName' => 'LEE', - 'url' => '' - ) - ), - 'ads' => array( - array( - 'url' => '', - 'img' => 'http://img13.static.yhbimg.com/taobaocms/2015/06/17/07/0240f288725106b408d8c524b4d0fba4b9.jpg' - ) - ), - 'msgPager' => '<a href="" class="cur"><span>1</span></a><a href=""><span>2</span></a><a href="" title="下一页">下一页<span class="ifont10">></span></a>' - ) - ); - $this->_view->display('editor', $data); - } - - /** - * 列表 - */ - public function listAction() - { - $data = array( - 'guangListPage' => true, - 'guang' => array( - 'tag' => '户外', - 'msgs' => array( - array( - 'id' => 1, - 'classification' => '话题', - 'isReco' => true, - 'url' => '', - 'img' => 'http://img10.static.yhbimg.com/yhb-img01/2015/06/12/17/01437323c88bc61f26721a2ad91a2ba61a.png?imageView/2/w/640/h/640', - 'isSquareImg' => true, - 'title' => '破旧除新!Publish完美释出2015最新春季[TheResistance]系列看看你很长的时候会不会分页啊,奇怪的人类', - 'author' => '大家玩看看作者名字 过长的情况显示是不是有问题呵呵哒哒哒', - 'editorUrl' => '', - 'pTime' => '2015-03-08 15:33', - 'pView' => '225', - 'content' => '该类型 应用于多图形式。虽说洛杉矶街头品牌Publish是凭着设计一炮而红,跃升为近年人气品牌,但是该设计团队却打算你妹啊鬼知道你后面说什么但是要测试文字截取能不能成功,所以必须要把你写很长很长很长很长很长', - 'tags' => array( - array( - 'url' => '', - 'tag' => 'adidas OriginalsQ' - ) - ), - 'like' => 0, // 如果为0,不传 - // 'liked' => false, - 'comment' => 20 - ) - ), - 'exRecos' => array( - array( - 'url' => '', - 'img' => 'http://img10.static.yhbimg.com/yhb-img01/2015/06/12/17/01437323c88bc61f26721a2ad91a2ba61a.png?imageView/2/w/640/h/640', - 'title' => '皇家蓝再现,New Balance 999 Elite文字描述长一点查看文字截取的功能' - ) - ), - 'hotTags' => array( - array( - 'tagName' => 'LEE', - 'url' => '' - ) - ), - 'ads' => array( - array( - 'url' => '', - 'img' => 'http://img13.static.yhbimg.com/taobaocms/2015/06/17/07/0240f288725106b408d8c524b4d0fba4b9.jpg' - ) - ), - 'msgPager' => '<a href="" class="cur"><span>1</span></a><a href=""><span>2</span></a><a href="" title="下一页">下一页<span class="ifont10">></span></a>' - ) - ); - $this->_view->display('list', $data); - } -} \ No newline at end of file diff --git a/yohobuy/www.yohobuy.com/application/models/Guang/Index.php b/yohobuy/www.yohobuy.com/application/models/Guang/Index.php new file mode 100644 index 0000000..bfcd499 --- /dev/null +++ b/yohobuy/www.yohobuy.com/application/models/Guang/Index.php @@ -0,0 +1,218 @@ +<?php +namespace Guang; +use LibModels\Web\Home\IndexData; +use WebPlugin\Cache; +use WebPlugin\Images; +use LibModels\Web\Guang\ListData; +use WebPlugin\Helpers; +use LibModels\Web\Guang\InfoData; +use Configs\WebCacheConfig; +class IndexModel +{ + //boys的逛的banner + const CODE_BOYS_GUANG = '15a288635c2ed9f6c807417be90f5d2d'; + //girls的逛的banner + const CODE_GIRLS_GUANG = 'e14e12e35af8626650979f7af8a0de2b'; + //lifestyle + const CODE_LIFESTYLE_GUANG = '1d398e899f759c6d88971be680521a6f'; + //kids + const CODE_KIDS_GUANG = 'ad14ee01ad048ce308aa3ca416133d2a'; + //boys的逛的ads + const CODE_BOYS_GUANG_ADS = '41777aa7ac86347692c5aa0d394b2f59'; + const CODE_GIRLS_GUANG_ADS = '722253573823ebb994e313e71b0a4fb9'; + const CODE_LIFESTYLE_GUANG_ADS = '02568b6042510e4be739cc688dc7d6ae'; + const CODE_KIDS_GUANG_ADS = '1ffdd6ea22c58af52ee6408cd353c2d5'; + + + /** + * 获取各频道的banner + * + * @param string $channel + * @return array + */ + public static function getBanner($channel) + { + $contentCode = self::CODE_BOYS_GUANG; + $channels = array( + 'boys' => self::CODE_BOYS_GUANG, + 'girls'=> self::CODE_GIRLS_GUANG, + 'lifestyle'=> self::CODE_LIFESTYLE_GUANG, + 'kids'=> self::CODE_KIDS_GUANG + ); + if(isset($channels[$channel])) { + $contentCode = $channels[$channel]; + } + $key = WebCacheConfig::KEY_WEB_GUANG_BANNER_DATA.'_'.$contentCode; + $data = Cache::get($key); + if(empty($data)) { + $resource = IndexData::getResourceData($contentCode); + if (isset($resource['data']) && !empty($resource['data']) && $resource['code'] == 200) { + $list = current($resource['data']); + foreach($list['data'] as $val) { + $data [] = array( 'img' => Images::getImageUrl($val['src'], 830, 327, 1), + 'url' => $val['url']); + } + //格式化数据 + Cache::set($key, $data, 3600); + } + } + //master没有数据,资源位没有数据, 取二层缓存 + if(empty($data)) { + $data = Cache::get($key, 'slave'); + } + return $data; + } + + /** + * 获取所有分类 + * + * @param string $currentSortId + * @return array + */ + public static function getCategory($currentSortId = 0) + { + $ret = array(); + $data = ListData::category(); + foreach($data['data'] as $category) + { + $ret[] = array('typeId' => $category['id'],'type' => $category['name'], + 'isActive' => $currentSortId == $category['id'] ? true :false, + 'navUrl' => Helpers::url('/index/index', array('type'=> $category['id']),'guang')); + } + return $ret; + } + + /** + * 获取分类列表 + * + * @param int $sortId + * @param string $gender + * @param string $page + * @param int $limit + * @param string $udid + */ + public static function article($gender, $sortId, $uid = 0, $udid = '', $page = 1, $tag = null, $authorId = null, $limit = null) + { + $total = 0; + $article = ListData::article($gender, $sortId, $uid, $udid, $page, $tag, $authorId, $limit); + $articleList = array(); + if (!empty($article['data']['list']['artList'])) { + foreach ($article['data']['list']['artList'] as $articleItem) { + $articleList[] = Helpers::formatArticle($articleItem, true, false, false, $uid); + } + } + + $adlist = array(); + if (!empty($article['data']['list']['adlist'])) { + foreach ($article['data']['list']['adlist'] as $ad) { + $adlist[] = Helpers::formatAd($ad, true, false, false, $uid); + } + } + + if(!empty($article['data']['total'])) { + $total = intval($article['data']['total']); + } + return array('msgs' => $articleList, 'ads' => $adlist, 'total' => $total); + } + + /** + * 获取热门标签 + * + * @return array + */ + public static function getHotTags($page, $limit) + { + $tags = array(); + $data = InfoData::tagTop($page, $limit); + if(!empty($data['data'])) { + foreach($data['data'] as $tag) { + $tags[] = array('tagName' => $tag['tag_name'], + 'url'=> Helpers::url('/tags/index',array('query' => $tag['tag_name']),'guang'), + ); + } + } + return $tags; + } + + /** + * 获取精彩推荐 + * + * @param string $gender + * @param int $page + * @param int $limit + * @return array + */ + public static function getExcellectRecos($gender, $page, $limit) + { + $list = array(); + $data = InfoData::recommend($gender, $page, $limit); + if(!empty($data['data'])) { + foreach($data['data'] as $key => $article) { + $list[] = array( + 'url' => Helpers::url('/'.$article['id'].'.html', '', 'guang'), + 'title' => $article['title'] + ); + if (isset($article['src']) && !empty($article['src'])) { + $list[$key]['img'] = Images::getImageUrl($article['src'], 90, 60, 1); + } + } + } + return $list; + } + + /** + * 获取广告 + * + * @param string $channel + * @return array + */ + public static function getAds($channel) + { + $contentCode = self::CODE_BOYS_GUANG_ADS; + $channels = array( + 'boys' => self::CODE_BOYS_GUANG_ADS, + 'girls'=> self::CODE_GIRLS_GUANG_ADS, + 'lifestyle'=> self::CODE_LIFESTYLE_GUANG_ADS, + 'kids'=> self::CODE_KIDS_GUANG_ADS + ); + if(isset($channels[$channel])) { + $contentCode = $channels[$channel]; + } + $key = WebCacheConfig::KEY_WEB_GUANG_ADS_DATA.'_'.$contentCode; + $data = Cache::get($key); + if(empty($data)) { + $resource = IndexData::getResourceData($contentCode); + if (isset($resource['data']) && !empty($resource['data']) && $resource['code'] == 200) { + $list = current($resource['data']); + foreach($list['data'] as $val) { + $data [] = array( 'img' => Images::getImageUrl($val['src'], 640,640, 1), + 'url' => $val['url']); + } + //最多取5个 + $data = array_slice($data, 0, 5); + //格式化数据 + Cache::set($key, $data, 3600); + } + } + //master没有数据,资源位没有数据, 取二层缓存 + if(empty($data)) { + $data = Cache::get($key, 'slave'); + } + return $data; + } + + /** + * 获取path导航 + * + * @param string $tag + * @return array + */ + public static function getPathNav($tag = '') + { + $paths[] = array('href' => Helpers::url('/index/index',array(),'guang'), 'name' => '逛','pathTitle' => '逛'); + if(!empty($tag)) { + $paths[] = array('name' => $tag,'pathTitle' => $tag); + } + return $paths; + } +} \ No newline at end of file diff --git a/yohobuy/www.yohobuy.com/application/models/Guang/Info.php b/yohobuy/www.yohobuy.com/application/models/Guang/Info.php new file mode 100644 index 0000000..db58325 --- /dev/null +++ b/yohobuy/www.yohobuy.com/application/models/Guang/Info.php @@ -0,0 +1,343 @@ +<?php + +namespace Guang; + +use Api\Yohobuy; +use LibModels\Web\Guang\InfoData; +use LibModels\Web\Product\SearchData; +use Plugin\Images; +use WebPlugin\Helpers; +use WebPlugin\HelperSearch; + + +/** + * 逛-文章页 + */ +class InfoModel +{ + /** + * 获取详情页数据 + * @param $id 文章id + * @param $uid 用户id + * @param $udid 客户端标示 + * @param $page 评论分页 + * @param $gender 性别 + * @param $channel 频道 + * @param $limit 评论每页显示条数 + * @return array + */ + public static function articleInfo($id, $uid, $udid, $page, $gender, $channel, $limit) + { + $result = array(); + //文章相关信息 + $articleInfo = InfoData::getArticleInfo($id); + if (isset($articleInfo['code']) && $articleInfo['code'] == 200 && isset($articleInfo['data']) && !empty($articleInfo['data'])) { + //作者 + if (isset($articleInfo['data']['author_id']) && !empty($articleInfo['data']['author_id'])) { + $url['author'] = InfoData::author($articleInfo['data']['author_id'], true); + } + //文章内容 + $url['contents'] = InfoData::articleContent($id, true); + //热门标签 + $url['hotTags'] = InfoData::tagTop(1, 20, true); + //评论 + $url['comments'] = InfoData::comment($id, $page, $limit, true); + //基本信息 + $url['baseInfo'] = InfoData::baseInfo($id, $uid, $udid, true); + //相关品牌 + $url['brands'] = InfoData::relateBrand($id, true); + //相关文章 + if (isset($articleInfo['data']['tag']) && !empty($articleInfo['data']['tag'])) { + $url['relate'] = InfoData::relateList($id, $articleInfo['data']['tag'], 3, true); + } + //推荐文章 + $url['recommend'] = InfoData::recommend($gender, 1, 10, true); + $data = Yohobuy::getMulti($url); + $result = self::formatInfo($articleInfo['data'], $data, $channel, $limit); + } + return $result; + } + + /** + * 格式化逛详情页数据 + * @param $article 文章信息 + * @param $data 作者信息、文章内容、热门标签、评论、相关文章、推荐文章 + * @param $channel 频道 + * @param $limit 评论一页显示记录数 + * @return array + */ + public static function formatInfo($article, $data, $channel, $limit) + { + $result = array(); + //推荐商品列表 + $goods = array(); + $result['pathNav'] = self::getCenterCrumb($article['article_title'], $channel); + //文章头部信息 + $result['header']['title'] = $article['article_title']; + $result['header']['avatar'] = isset($data['author']['avatar']) && !empty($data['author']['avatar']) ? $data['author']['avatar'] : ''; + $result['header']['name'] = isset($data['author']['name']) && !empty($data['author']['name']) ? $data['author']['name'] : ''; + $result['header']['authorUrl'] = isset($data['author']['name']) && !empty($data['author']['name']) ? Helpers::url('/Index/editor', array('author_id'=>$article['author_id']), 'guang') : ''; + $result['header']['intro'] = isset($data['author']['author_desc']) && !empty($data['author']['author_desc']) ? $data['author']['author_desc'] : ''; + $result['header']['time'] = date('Y年m月d日 H:i', $article['publish_time']); + $result['header']['click'] = $article['pageViews']; + $result['header']['commentNum'] = $data['comments']['total']; + $result['header']['shareImg'] = Images::getImageUrl($article['cover_image'], 600, 600); + $result['header']['desc'] = $article['article_summary']; + $result['header']['weixinUrl'] = $article['url']; + //文章详细 + if (isset($data['contents']) && !empty($data['contents'])) { + foreach ($data['contents'] as $key => $val) { + foreach ($val as $type => $con) { + if ($type != 'goods') { + $result['content'][] = is_callable("self::$type") ? self::$type($con['data']) : ''; + } else { + $goods = array_merge_recursive($goods, self::goods($con['data'])); + } + } + } + } + if (!empty($goods)) { + $result['content'][] = array('relatedReco'=>array('recos'=>$goods)); + } + //赞、收藏 + if (isset($data['baseInfo']) && !empty($data['baseInfo'])) { + $result['userInfo']['isLike'] = $data['baseInfo']['isPraise'] == 'Y' ? true : false; + $result['userInfo']['likeNum'] = $data['baseInfo']['praise_num']; + $result['userInfo']['isCollected'] = $data['baseInfo']['isFavor'] == 'Y' ? true : false;; + } + //文章tags + if (isset($article['tags']) && !empty($article['tags'])) { + foreach ($article['tags'] as $tagKey => $tagsValue) { + $result['tag'][$tagKey]['name'] = $tagsValue['name']; + $result['tag'][$tagKey]['url'] = Helpers::url('/tags/index', array('query' => $tagsValue['name']),'guang'); + } + } + //相关品牌 + if (isset($data['brands']) && !empty($data['brands'])) { + $result['brands'] = $data['brands']; + } + //相关文章 + if (isset($data['relate']) && !empty($data['relate'])) { + foreach ($data['relate'] as $key => $val) { + $result['relatedPost'][$key]['title'] = $val['title']; + $result['relatedPost'][$key]['thumb'] = Images::getImageUrl($val['thumb'], 264, 173, 1); + $result['relatedPost'][$key]['url'] = Helpers::url('/'.$val['id'].'.html', array(), 'guang'); + } + } + //精彩推荐 + if (isset($data['recommend']) && !empty($data['recommend'])) { + foreach ($data['recommend'] as $key => $val) { + $result['exRecos'][$key]['title'] = $val['title']; + $result['exRecos'][$key]['img'] = isset($val['src']) ? Images::getImageUrl($val['src'], 90, 60) : ''; + $result['exRecos'][$key]['url'] = Helpers::url('/'.$val['id'].'.html', array(), 'guang'); + } + } + //热门标签 + if (isset($data['hotTags']) && !empty($data['hotTags'])) { + foreach ($data['hotTags'] as $key => $val) { + $result['hotTags'][$key]['tagName'] = $val['tag_name']; + $result['hotTags'][$key]['url'] = Helpers::url('/tags/index',array('query'=>$val['tag_name']), 'guang'); + } + } + //评论 + if (isset($data['comments']) && !empty($data['comments']) && isset($data['comments']['total'])) { + $result['comment']['commentNum'] = $data['comments']['total']; + $result['comment']['commentPager'] = HelperSearch::pager($data['comments']['total'], $limit); + if ($data['comments']['total'] > 0 && !empty($data['comments']['list'])){ + foreach ($data['comments']['list'] as $key => $val) { + $result['comment']['list'][$key]['avatar'] = Images::getImageUrl($val['avator'], 100, 100); + $result['comment']['list'][$key]['name'] = $val['username']; + $result['comment']['list'][$key]['content'] = $val['content']; + $result['comment']['list'][$key]['time'] = $val['create_time']; + } + } + } + return $result; + } + + /** + * 逛详情文本 + * @param $con + * @return mixed + */ + public static function text($con) + { + return $con; + } + + /** + * 逛详情单张图片 + * @param $con + * @return array + */ + public static function singleImage($con) + { + return array('pic' => Images::getImageUrl($con[0]['src'], 640, 640)); + } + + /** + * 逛详情商品组 + * @param $goodsGroup + * @return mixed + */ + public static function goodsGroup($goodsGroup) + { + $result = $groupSkn = $productSkn = array(); + foreach ($goodsGroup as $key => $val) { + if (!isset($val['list']) || empty($val['list'])) { + continue; + } + foreach ($val['list'] as $k => $v) { + $groupSkn[$key][] = $v['id']; + $productSkn[] = $v['id']; + } + } + if (!empty($productSkn)) { + $product = SearchData::searchElasticByCondition(array('query' => implode(',', $productSkn))); + if (isset($product['data']['product_list'])) { + $result['relatedReco']['recos'] = array_slice(self::formatProduct($product['data']['product_list']), 0, 4); + } + } + return $result; + } + + /** + * 逛详情商品列表 + * @param $goods + * @return array + */ + public static function goods($goods) + { + $result = $productSkn = array(); + foreach ($goods as $key => $val) { + $productSkn[] = $val['id']; + } + if (!empty($productSkn)) { + $product = SearchData::searchElasticByCondition(array('query'=> implode(',', $productSkn))); + if (isset($product['data']['product_list'])) { + $result = self::formatProduct($product['data']['product_list']); + } + } else { + return array(); + } + return $result; + } + + /** + * 逛详情两张小图 + * @param $pic + * @return array + */ + public static function smallPic($pic) + { + $result = array(); + foreach ($pic as $key => $val) { + if ($key < 2) { + $result['smallPic'][] = Images::getImageUrl($val['src'], 600, 600); + } + } + return $result; + } + + /** + * 逛详情链接 + * @param $link + * @return array + */ + public static function link($link) + { + $result = array(); + return $result; + } + + /** + * 逛-面包屑 + * name 当前停留面包屑名称 + * nav 逛 之后的面包屑 + */ + public static function getCenterCrumb($name, $channel) + { + //根据频道判断home页地址 + switch ($channel) { + case 'boys': + $home = Helpers::url('', '', 'default'); + break; + case 'girls': + $home = Helpers::url('/woman', '', 'new'); + break; + case 'lifestyle': + $home = Helpers::url('/lifestyle', '', 'new'); + break; + case 'kids': + $home = Helpers::url('/kids', '', 'new'); + break; + default: + $home = Helpers::url('', '', 'default'); + break; + } + $retNav = array( + array( + 'name' => strtoupper($channel) . '首页', + 'href' => $home + ), + array( + 'name' => '逛', + 'href' => Helpers::url('', '', 'guang') + ) + ); + $retNav[] = array( + 'name' => $name + ); + return $retNav; + } + + /** + * 文章评论列表 + * @param $id + * @param $page + * @param $limit + * @return array + */ + public static function commentList($id, $page, $limit) + { + $result = array(); + $data = InfoData::comment($id, $page, $limit); + //评论 + if (isset($data['code']) && $data['code'] == 200) { + $result['comment']['commentNum'] = $data['data']['total']; + $result['comment']['commentPager'] = HelperSearch::pager($data['data']['total'], $limit); + if ($data['data']['total'] > 0 && !empty($data['data']['list'])){ + foreach ($data['data']['list'] as $key => $val) { + $result['comment']['list'][$key]['avatar'] = Images::getImageUrl($val['avator'], 100, 100); + $result['comment']['list'][$key]['name'] = $val['username']; + $result['comment']['list'][$key]['content'] = $val['content']; + $result['comment']['list'][$key]['time'] = $val['create_time']; + } + } + } + return $result; + } + + /** + * 格式化推荐商品 + * @param $product + * @return arr + */ + public static function formatProduct($product) + { + $result = array(); + foreach ($product as $key => $val) { + $result[$key]['thumb'] = Images::getImageUrl($val['default_images'],235,314); + $result[$key]['name'] = $val['product_name']; + //市场价不等于售价时显示 + if ($val['market_price'] != $val['sales_price']) { + $result[$key]['marketPrice'] = $val['market_price']; + } + $result[$key]['salePrice'] = $val['sales_price']; + $result[$key]['url'] = Helpers::getUrlBySkc($val['product_id'], $val['goods_list'][0]['goods_id'], $val['cn_alphabet']);; + } + return $result; + } + +} + diff --git a/yohobuy/www.yohobuy.com/application/models/Guang/Plusstar.php b/yohobuy/www.yohobuy.com/application/models/Guang/Plusstar.php index e8b341d..5446295 100644 --- a/yohobuy/www.yohobuy.com/application/models/Guang/Plusstar.php +++ b/yohobuy/www.yohobuy.com/application/models/Guang/Plusstar.php @@ -8,7 +8,6 @@ use WebPlugin\Helpers; use LibModels\Web\Guang\ListData; class PlusstarModel { - const URL_GUANG_ARTICLE = '/guang/service/v1/article'; /** * 获取Plustar列表 * diff --git a/yohobuy/www.yohobuy.com/application/models/Index/Brands.php b/yohobuy/www.yohobuy.com/application/models/Index/Brands.php index 9a10011..044656c 100644 --- a/yohobuy/www.yohobuy.com/application/models/Index/Brands.php +++ b/yohobuy/www.yohobuy.com/application/models/Index/Brands.php @@ -13,6 +13,7 @@ use LibModels\Web\Product\SearchData; use WebPlugin\DataProcess\Channel; use Configs\WebCacheConfig; use Configs\ChannelConfig; +use LibModels\Web\Guang\InfoData; /** * 品牌首页模板数据模型 @@ -27,8 +28,6 @@ class BrandsModel const KIDS_BRAND_CODE = 'c575c6bfdfa4125fae7d24bbec7119c8'; const LIFESTYLE_BRAND_CODE = '84b7926282fdef92f1039bdcf77c18ba'; const BRAND_LIST_CODE = 'f0f72b1e8f30e6ad086dfc4401f3a856'; //品牌列表资源位CODE码 - const URL_PRODUCT_BRAND = '/cmsproduct/service/v1/brands'; - const URL_GUANG_ARTICLE = '/guang/service/v1/article'; const BRAND_PLUSSTAR_BANNER_BOYS = 'd0149783b8dd2adaf083fd10556c39a9'; const BRAND_PLUSSTAR_BANNER_GIRLS = 'aad7a43e9a04ac7c70ae7f0c1acf86ef'; const BRAND_PLUSSTARINDEX_BOYS = 'a833aed63d28457156310e97faa7fa37'; //plusstarindex男首资源位 @@ -297,26 +296,15 @@ class BrandsModel $key = WebCacheConfig::KEY_WEB_INDEX_BRANDS_BRANDINFO . '_' . implode(',', $brandIds); $brandsInfo = Cache::get($key); if (empty($brandsInfo)) { - Yohobuy::yarConcurrentCall(Yohobuy::SERVICE_URL . self::URL_PRODUCT_BRAND, 'getBrandByIds', array(implode(',', $brandIds), 'id,brand_name,brand_intro,brand_domain'), function($data)use(&$brandsInfo) { + $data = BrandData::getBrandInfoByIds($brandIds); + if(!empty($data['data']) && $data['code'] == 200) { foreach ($data['data'] as $k => $val) { $val['desc'] = trim(str_replace(array("\t", "\n", "\r", " "), '', strip_tags($val['brand_intro']))); $val['url'] = Helpers::url('', array(), $val['brand_domain']); unset($val['brand_intro']); $brandsInfo[$k] = $val; } - }); - - /* foreach ($brandIds as $brandId) { - Yohobuy::yarConcurrentCall(Yohobuy::SERVICE_URL . self::URL_PRODUCT_BRAND, 'getOneBrand', array($brandId, 'id,brand_name,brand_intro,brand_domain'), function($data)use(&$brandsInfo) { - if (isset($data['data']['id'])) { - $data['data']['desc'] = trim(str_replace(array("\t", "\n", "\r", " "), '', strip_tags($data['data']['brand_intro']))); - $data['data']['url'] = Helpers::url('', array(), $data['data']['brand_domain']); - unset($data['data']['brand_intro']); - $brandsInfo[$data['data']['id']] = $data['data']; - } - }); - } */ - Yohobuy::yarConcurrentLoop(); + } if (!empty($brandsInfo)) { Cache::set($key, $brandsInfo, 3600); } @@ -390,24 +378,21 @@ class BrandsModel { $key = WebCacheConfig::KEY_WEB_BRAND_PLUSSTARINDEX_ARTICLES_DATA . '_' . implode(',', $newIds); $articles = Cache::get($key); + $url = array(); if (empty($articles)) { foreach ($newIds as $newId) { - Yohobuy::yarConcurrentCall(Yohobuy::SERVICE_URL . self::URL_GUANG_ARTICLE, 'getArticle', array($newId, 'h5'), function($val)use(&$articles) { - if (isset($val['id'])) { - $articles[$val['id']] = array('id' => $val['id'], 'title' => $val['article_title'], - 'url' => Helpers::url('/' . $val['id'] . '.html', array(), 'guang'), 'src' => $val['cover_image'], 'summary' => $val['article_summary']); - } - }); + $url[$newId] = InfoData::getArticleInfo($newId, true); + } + //并发调用数据 + $data = Yohobuy::getMulti($url); + foreach ($newIds as $newId) { + if (isset($data[$newId]) && !empty($data[$newId])) { + $val = $data[$newId]; + $articles[$newId] = array('id' => $val['id'], 'title' => $val['article_title'], + 'url' => Helpers::url('/' . $val['id'] . '.html', array(), 'guang'), 'src' => $val['cover_image'], + 'summary' => $val['article_summary']); + } } -// Yohobuy::yarConcurrentCall(Yohobuy::SERVICE_URL . self::URL_GUANG_ARTICLE, 'getArtilceByIds', array($newIds, 'h5'), function($data)use(&$articles) { -// foreach ($data['data'] as $val) { -// if (isset($val['id'])) { -// $articles[$val['id']] = array('id' => $val['id'], 'title' => $val['title'], -// 'url' => Helpers::getFilterUrl($val['url']), 'src' => $val['src'], 'summary' => $val['intro']); -// } -// } -// }); - Yohobuy::yarConcurrentLoop(); if (!empty($articles)) { //设置master,slave Cache::set($key, $articles, 3600); diff --git a/yohobuy/www.yohobuy.com/application/models/Shopping/Pay.php b/yohobuy/www.yohobuy.com/application/models/Shopping/Pay.php new file mode 100644 index 0000000..6d1d034 --- /dev/null +++ b/yohobuy/www.yohobuy.com/application/models/Shopping/Pay.php @@ -0,0 +1,552 @@ +<?php + +namespace Shopping; + +use LibModels\Web\Home\OrderData; +use LibModels\Web\Product\PayData; +use Plugin\Helpers; +use WebPlugin\Pay\Banks; +use WebPlugin\Pay\PayFactory; +use WebPlugin\Pay\Reqparams; +use WebPlugin\Pay\Rspparams; +use WebPlugin\Pay\weixin\lib\WxPayConfig; +use WebPlugin\Pay\weixin\lib\WxPayNativePay; +use WebPlugin\Pay\weixin\lib\WxPayUnifiedOrder; + +/** + * 支付有关方法 + * + * @package Shopping + * @author Gtskk + * @copyright 2016/3/22 14:19 Gtskk<iamgtskk@gmail.com> + * @version: 0.0.1 + */ +class PayModel +{ + /** + * 获取支付方式选择页面有关信息 + * + * @param int $uid 用户ID + * @param string $orderCode 订单号 + * @return array + */ + public static function getPayTypeData($uid, $orderCode) + { + $result = array(); + + do { + // 订单详情 + $orderDetail = OrderData::getOrderDetail($uid, $orderCode); + if (!$orderDetail || empty($orderDetail['data'])) { + $result['noOrder'] = true; + break; + } + + $order = $orderDetail['data']; + $result['orderNum'] = $orderCode; + $result['count'] = $order['payment_amount']; + $result['paymentType'] = ($order['payment_type'] == 1 ? '在线支付' : '货到付款'); + + // 货到付款的情况 + if ($order['payment_type'] == 2) { + $result['finish'] = true; + // 有货币 + $result['yohoCoin'] = $order['yoho_give_coin']; + // 订单详情链接地址 + $result['checkOrderUrl'] = Helpers::url('/home/orders/detail', array('orderCode' => $orderCode)); + // 有货币地址 + $result['yohoCoinUrl'] = Helpers::url('/help', array('category_id' => 87)); + // vip地址 + $result['vipUrl'] = Helpers::url('/help', array('category_id' => 91)); + // 订单中心地址 + $result['ordersUrl'] = Helpers::url('/home/orders'); + // 退换货地址 + $result['backGoodsUrl'] = Helpers::url('/help', array('category_id' => 121)); + break; + } + + $result['deliveryType'] =isset($order['delivery_time']) ? $order['delivery_time'] : ''; + + //统计成交的skn + $sknList = array(); + $skuList = array(); + $goodsData = array(); + foreach ($order['order_goods'] as $val) { + $sknList[] = $val['product_skn']; + $skuList[] = $val['product_sku']; + $goodsData[] = array( + 'goods_name' => $val['product_name'], + 'product_sku' => $val['product_sku'], + 'price' => $val['goods_price'], + 'number' => $val['buy_number'] + ); + } + $result['goodsData'] = $goodsData; + // skn列表 + $result['sknList'] = implode(',', $sknList); + // sku列表 + $result['skuList'] = implode(',', $skuList); + + // 用户ID + $result['uid'] = $uid; + + // 获取支付途径列表 + $payTypes = PayData::getPaymentList(); + $defaultPayType = 0; + $types = array(); + if (isset($payTypes['data']) && !empty($payTypes['data'])) { + $oneType = array(); + + foreach ($payTypes['data'] as $key => $payType) { + if (empty($payType['payIcon'])) { // 排除图标不存在的支付方式 + continue; + } + + // 获取第一个支付方式 + if ($key === 0) { + $defaultPayType = $payType['id']; + } + + $oneType = array(); + $oneType['name'] = $payType['payName']; + $oneType['ico'] = $payType['payIcon']; + + $types[$payType['id']] = $oneType; + } + $result['list'] = self::procPayType($types); + } + + // 获取银行列表 + $result['entry'] = self::procPayType(Banks::getList(), true); + + // 无需付款 + if (isset($order["payment_amount"]) && $order["payment_amount"] == 0) { + // ERP提交订单状态 + PayData::submitOrderStatus($orderCode, 0, '', '', 0, '', '', ''); + // 更新订单的状态 + PayData::updateOrderStatus($order['order_id'], $uid, 0, 'Y', ''); + $result['notNeedPay'] = true; + break; + } + + // 记录支付方式 + $bankRecord = PayData::getBankByOrder($orderCode); + if (isset($bankRecord['data']['bankCode']) && !empty($bankRecord['data']['bankCode'])) { + $payRecord = $bankRecord['data']['bankCode']; + } else { + $payCode = $order['payment'] ?: $defaultPayType; + //记录app上的支付方式 + $changeCodes = array( + 19 => 21,// app上微信支付 + 22 => 21,// h5微信支付 + 18 => $defaultPayType// h5支付宝支付 + ); + $platformCode = isset($changeCodes[$payCode]) && $changeCodes[$payCode] ? $changeCodes[$payCode] : $payCode; + $platformCodeList = array_keys($types); + $payRecord = in_array($platformCode, $platformCodeList) ? $platformCode : $defaultPayType; + } + $result['payRecord'] = $payRecord; + + // 已完成付款的链接地址 + $result['ordersUrl'] = Helpers::url('/home/orders'); + // 支付地址 + $result['payUrl'] = Helpers::url('/pay/index/index'); + + // 是否是老用户(用于订单统计) + $orderCount = 0; + $orders = PayData::getOrderCountByUid($uid); + if (isset($orders['data']) && !empty($orders['data'])) { + $orderCount = $orders['data']['total']; + } + $result['isOldUser'] = (intval($orderCount) > 1) ? true : false; + // 订单数(用于订单统计) + $result['orderCount'] = $orderCount; + $result['is_advance'] = $order['attribute'] == 5 ? 'Y' : 'N'; + // 订单商品(用于订单统计) + $result['orderGoods'] = $order['order_goods']; + // 订单商品数(用于订单统计) + $result['ordersGoodsNums'] = count($order['order_goods']); + + } while (false); + + return $result; + } + + /** + * 处理支付类型数据 + * + * @param array $pays 支付方式数据 + * @param bool $isBank 是否是银行数据 + * @return array + */ + private static function procPayType($pays, $isBank = false) + { + $result = array(); + + $onePay = array(); + foreach ($pays as $code => $pay) { + $onePay = array(); + $onePay['dataId'] = $code; + $onePay['dataVal'] = $isBank ? '12_' . $code : $code . '_platform'; + $onePay['idNum'] = $code; + $onePay['ico'] = $pay['ico']; + $onePay['name'] = $pay['name']; + $onePay['imgId'] = $onePay['dataVal']; + + $result[] = $onePay; + } + + return $result; + } + + + /** + * 获取支付有关信息 + * + * @param int $uid 用户ID + * @param string $orderCode 订单号 + * @param string $paymentType 支付方式 + * @param string $userName 用户名 + * @param string $alipayToken 支付宝用户token + * @return array + */ + public static function getPayData($uid, $orderCode, $paymentType, $userName, $alipayToken) + { + $result = array(); + + do { + /* 判断是否有订单号参数 */ + if (empty($orderCode)) { + $result['error'] = true; + $result['message'] = '订单号不能为空'; + break; + } + + /* 判断支付方式是否选择 */ + $paymentPars = explode('_', $paymentType); + if (count($paymentPars) != 2) { + $result['error'] = true; + $result['message'] = '请选择一个支付方式'; + break; + } + + /* 判断订单信息是否存在 */ + $orderDetail = OrderData::getOrderDetail($uid, $orderCode); + if (empty($orderDetail['data'])) { + $result['error'] = true; + $result['message'] = '没有找到该订单'; + break; + } + + /* 判断订单是否已取消 */ + if (isset($orderDetail['data']['is_cancel']) && $orderDetail['data']['is_cancel'] === 'Y') { + $result['error'] = true; + $result['message'] = '订单已经取消'; + $result['location'] = 'window.location="' . Helpers::url('/home/orders/detail', array('order_code' => $orderCode)) . '";'; + break; + } + + // 获取支付有关参数 + $payId = $paymentPars[0]; + $paymentParams = self::getPaymentById($payId); + if (empty($paymentParams)) { + $result['error'] = true; + $result['message'] = '支付系统繁忙,请稍后再试'; + break; + } + + $payService = PayFactory::factory($paymentParams); + if ($payService == false) { // 没找到支付方式时 + $result['error'] = true; + $result['message'] = '请选择一个支付方式'; + break; + } + + $totalFee = $orderDetail['data']['payment_amount'] * 100; + $isTest = (APPLICATION_ENV === 'developer' || APPLICATION_ENV === 'testing'); + $paymentParameter = $paymentPars[1]; + // 判断是否传入支付宝token + if ($paymentType == 2 && !empty($alipayToken)) { + + $paymentParameter = $alipayToken; + } + + $reqParams = new Reqparams($orderCode, $totalFee, '有货订单号:' . $orderCode, '', $orderDetail['data']['create_time'], $paymentParameter, $isTest, $uid, $userName); + $reqPars = $payService->getPayRequestPars($reqParams); + if (empty($reqPars)) { + $result['error'] = true; + $result['message'] = '支付系统繁忙,请稍后再试'; + break; + } + + // 记录并更新订单支付方式 + $paymentRecod = OrderData::updateOrderPayment($orderCode, $payId, $uid); + if (empty($paymentRecod) || $paymentRecod['code'] != 200) { + $result['error'] = true; + $result['message'] = '系统繁忙,请稍后再试'; + break; + } + $bankRecord = PayData::getBankByOrder($orderCode); + $bankCode = ($paymentParameter != 'platform' ? $paymentParameter : ''); + if (isset($bankRecord['data']['bankCode']) && !empty($bankRecord['data']['bankCode'])) { + $bankPayRecord = PayData::updateOrderPayBank($orderCode, $payId, $bankCode); + } else { + $bankPayRecord = PayData::setOrderPayBank($orderCode, $payId, $bankCode); + } + if (!isset($bankPayRecord['code']) || $bankPayRecord['code'] != 200) { + $result['error'] = true; + $result['message'] = '支付方式记录失败'; + break; + } + + if ($reqPars['reqType'] == 'get') { + //直接跳转到支付界面 + $result['go'] = true; + $result['payUrl'] = $reqPars['pay_url'] . '?' . $reqPars['pars']; + } else { + //如果是post,去form提交 + $result = array('reqPars' => $reqPars); + } + } while (false); + + return $result; + } + + /** + * 根据支付ID获取支付相关参数 + * + * @param int $payId 支付ID + * @return array + */ + public static function getPaymentById($payId) + { + $result = array(); + + $paymentParams = PayData::getPaymentById($payId); + if (isset($paymentParams['data']) && !empty($paymentParams['data'])) { + $result = array( + 'id' => $payId, + 'pay_code' => $paymentParams['data']['payCode'], + 'pay_params' => isset($paymentParams['data']['payParams']) ? $paymentParams['data']['payParams'] : '' + ); + } + + return $result; + } + + + /** + * 处理微信支付 + * + * @param int $uid 用户ID + * @param string $orderCode 订单号 + * @param int $paymentCode 支付方式ID + * @return array + */ + public static function weixinQrcode($uid, $orderCode, $paymentCode) + { + $result = array(); + + do { + if (empty($orderCode)) { + $result['error'] = true; + $result['message'] = '订单号不能为空'; + break; + } + + /* 判断订单信息是否存在 */ + $orderDetail = OrderData::getOrderDetail($uid, $orderCode); + if (!isset($orderDetail['data']) || empty($orderDetail['data'])) { + $result['error'] = true; + $result['message'] = '没有找到该订单'; + break; + } + + /*$wechatqrcode = new Service(array('id' => $paymentCode)); + $reqPars = $wechatqrcode->pay(array('order_code'=>$orderCode)); + if (empty($reqPars)) { + $result['error'] = true; + $result['message'] = '支付系统繁忙,请稍后再试'; + break; + }*/ + + //统一下单 + $totalFee = strval($orderDetail['data']['payment_amount'] * 100); + $input = new WxPayUnifiedOrder(); + $input->SetBody('有货订单号:' . $orderCode); + $input->SetOut_trade_no('YOHOBuy_' . $orderCode); // 商户订单号 + $input->SetTotal_fee($totalFee); + $input->SetTime_start(date("YmdHis")); + $input->SetTime_expire(date("YmdHis", time() + 600)); + $input->SetNotify_url(WxPayConfig::NOTIFY_URL); + $input->SetTrade_type("NATIVE"); + $input->SetProduct_id($orderCode); + $notify = new WxPayNativePay(); + $payResult = $notify->GetPayUrl($input); + + $orderData = $orderDetail['data']; + $firstGoods = current($orderData['order_goods']); + $result = array( + 'orderNum' => $orderData['order_code'], + 'amount' => $orderData['payment_amount'], + 'address' => $orderData['address'], + 'name' => $orderData['user_name'], + 'tellphoneNum' => $orderData['mobile'], + 'tradeName' => $firstGoods['product_name'], + 'choosePayUrl' => Helpers::url('/shopping/pay', array('order_code' => $orderData['order_code'])), + 'qrcodeUrl' => $payResult['code_url']//$reqPars['pay_url'] // 'http://paysdk.weixin.qq.com/example/qrcode.php?data=' . $result['code_url'] + ); + + } while (false); + + return $result; + } + + + /** + * 处理支付结果数据 + * + * @param int $uid 用户ID + * @param string $orderCode 订单号 + * @return array + */ + public static function getPayDetail($uid, $orderCode) + { + $result = array( + 'code' => 500, + 'message' => '支付失败' + ); + + do { + $orderInfo = OrderData::getOrderDetail($uid, $orderCode); + if (!isset($orderInfo['data']['payment_status']) || $orderInfo['data']['payment_status'] !== 'Y') { + break; + } + $result['code'] = 200; + $result['message'] = '支付成功,请等待发货'; + $orderData = $orderInfo['data']; + $result['data'] = array( + 'pay' => $orderData['payment_amount'], + 'orderNum' => $orderData['order_code'], + 'checkOrderUrl' => Helpers::url('/home/orders/detail', array('order_code' => $orderData['order_code'])), + 'payMode' => ($orderData['payment_type'] == 1 ? '在线支付' : '货到付款'), + 'currency' => $orderData['yoho_give_coin'], + 'yohoCoinUrl' => Helpers::url('/help', array('category_id' => 87)), + 'vipSum' => $orderData['order_code'], + 'returnGoodsUrl' => Helpers::url('/help', array('category_id' => 121)), + 'vipUrl' => Helpers::url('/help', array('category_id' => 91)), + 'returnHomeUrl' => Helpers::url('/') + ); + } while (false); + + return $result; + } + + /** + * 检查微信扫码支付结果 + * + * @param int $uid 用户ID + * @param int $orderCode 订单号 + * @return array 订单支付结果 + */ + public static function checkWechatPayStatus($uid, $orderCode) + { + $result = array( + 'code' => '400', + 'message' => 'fail' + ); + + do { + if (empty($uid) || empty($orderCode)) { + break; + } + + $orderInfo = OrderData::getOrderDetail($uid, $orderCode); + if (!isset($orderInfo['data']) || empty($orderInfo['data'])) { + break; + } + + if ($orderInfo['data']['payment_status'] === 'Y') { + $result = array( + 'code' => '200', + 'message' => 'success' + ); + } + } while (false); + + return $result; + } + + /** + * 订单支付后处理后续数据 + * + * @param int $uid 用户ID + * @param Rspparams $payResult 支付之后返回的结果 + * @param int $payment 支付方式ID + * @return array + */ + public static function procOrderData($uid, $payResult, $payment) + { + $result = array( + 'code' => 500, + 'message' => '支付失败' + ); + + do { + $orderInfo = OrderData::getOrderDetail($uid, $payResult->orderCode); + if (!isset($orderInfo['data']) || empty($orderInfo['data'])) { + break; + } + + $orderData = $orderInfo['data']; + $orderCode = $orderData['order_code']; + $paymentStatus = $orderData['payment_status']; + $amount = $orderData['payment_amount']; + + // 订单已取消 + if ($orderData['is_cancel'] === 'Y' && $paymentStatus === 'N') { + // 给用户发送短信 + PayData::sendMessage($orderData['mobile'], 'error_sms', '支付成功,但订单已取消,订单号为' . $orderCode); + $result['code'] = 417; + $result['message'] = '支付成功,但订单已取消,需联系客服'; + break; + } + + // 支付金额与订单金额不一致 + if (round($amount, 2) != round($payResult->totalFee, 2)) { + $result['code'] = 415; + $result['message'] = '支付金额与订单金额不一致'; + break; + } + + //记录交易号和支付订单号(如果有银行流水号会记录银行流水号) + $payOrderCode = $payResult->payOrderCode ? $payResult->payOrderCode : ""; + $tradeNo = $payResult->tradeNo ? $payResult->tradeNo : ""; + $bankBillNo = $payResult->bankBillNo ? $payResult->bankBillNo : ""; + $bankName = $payResult->bankName; + $bankCode = $payResult->bankCode; + // ERP提交订单状态 + PayData::submitOrderStatus($orderCode, $payment, $bankName, $bankCode, $amount, $payOrderCode, $tradeNo, $bankBillNo); + // 更新订单的状态 + PayData::updateOrderStatus($orderData['order_id'], $uid, $payment, 'Y', $bankCode); + + $result['code'] = 200; + $result['message'] = '支付成功,请等待发货'; + $result['data'] = array( + 'pay' => $amount, + 'orderNum' => $orderData['order_code'], + 'checkOrderUrl' => Helpers::url('/home/orders/detail', array('orderCode' => $orderData['order_code'])), + 'payMode' => ($orderData['payment_type'] == 1 ? '在线支付' : '货到付款'), + 'currency' => $orderData['yoho_give_coin'], + 'yohoCoinUrl' => Helpers::url('/help', array('category_id' => 87)), + 'ordersUrl' => Helpers::url('/home/orders'), + 'returnGoodsUrl' => Helpers::url('/help', array('category_id' => 121)), + 'vipSum' => $amount, + 'vipUrl' => Helpers::url('/help', array('category_id' => 91)), + 'returnHomeUrl' => Helpers::url('/') + ); + } while (false); + + return $result; + } +} \ No newline at end of file diff --git a/yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Index.php b/yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Index.php index b3d9bbc..a98d7d7 100644 --- a/yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Index.php +++ b/yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Index.php @@ -1 +1,106 @@ -<?php +<?php +use Action\WebAction; +use WebPlugin\Helpers; +use LibModels\Web\Guang\ListData; +use Guang\IndexModel; +use WebPlugin\Paging; +use Index\HomeModel; +class IndexController extends WebAction +{ + /** + * 逛的首页 + */ + public function indexAction() + { + $this->setWebNavHeader(); + $paging = new Paging('yoho'); + $type = intval($this->get('type', 0)); + $channel = Helpers::getChannelNameByCookie(); + $gender = Helpers::getGenderByCookie(); + $page = intval($this->get('page', 1)); + $uid = $this->getUid(); + $udid = $this->getUdid(); + $limit = 20; + $article = IndexModel::article($gender, $type, $uid, $udid, $page, '', '', $limit); + $this->setTitle('逛', true); + $total = $article['total']; + $tags = IndexModel::getHotTags(1, 20); + $ads = IndexModel::getAds($channel); + $paging->setTotal($total)->setSize($limit)->setQuery(array('type' => $type)); + $data['guangIndexPage'] = true; + //导航 + $data['pathNav'] = array_merge(array(HomeModel::getHomeChannelNav()), IndexModel::getPathNav()); + $data['guang'] = array( + 'slider' => IndexModel::getBanner($channel), + 'msgTypes' => IndexModel::getCategory($type), + 'msgs' => $article['msgs'], + 'ads'=> $ads, + 'msgPager'=> $paging->view(false), + 'exRecos' => IndexModel::getExcellectRecos($gender, 1, 10), + 'hotTags' => $tags + ); + $this->_view->display('index', $data); + } + + /** + * 作者信息 + */ + public function editorAction() + { + $this->setWebNavHeader(); + //author_id = 7613683 + $author_id = $this->get('author_id'); + $channel = Helpers::getChannelNameByCookie(); + // APP访问时通过频道参数判断性别 + $gender = Helpers::getGenderByCookie(); + + $uid = $this->getUid(); + $udid = $this->getUdid(); + + // 获取作者信息 + $author = ListData::author($author_id); + // 作者信息不存在,则跳到错误页面 + if (!isset($author['data']['name'])) { + $this->error(); + } + + // 设置标签页标题 + $authorName = $author['data']['name']; + $this->setTitle($authorName, true, ''); + + $data = array(); + // 模板中使用JS的标识 + $data['guangList'] = true; + + $page = intval($this->get('page', 1)); + $limit = 20; + // 标签聚合内容列表 + $article = IndexModel::article($gender, null, $uid, $udid, $page, '', $author_id, $limit); + $data['guang']['gender'] = $gender; + + $paging = new Paging('yoho'); + $total = $article['total']; + $tags = IndexModel::getHotTags(1, 20); + $ads = IndexModel::getAds($channel); + $paging->setTotal($total)->setSize($limit)->setQuery(null); + + $data = array( + 'guangListPage' => true, + 'guang' => array( + 'editor' => array( + 'avatar' => Helpers::getImageUrl($author['data']['avatar'], 100, 100), + 'name' => $author['data']['name'], + 'intro' => $author['data']['author_desc'], + 'info' => '设计理念:时尚,线条流畅' + ), + 'msgs' => $article['msgs'], + 'exRecos' => IndexModel::getExcellectRecos($gender, 1, 10), + 'hotTags' => $tags, + 'ads' => $ads, + 'msgPager' => $paging->view(false) + ), + 'pathNav' => array_merge(array(HomeModel::getHomeChannelNav()), IndexModel::getPathNav()) + ); + $this->_view->display('editor', $data); + } +} \ No newline at end of file diff --git a/yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Info.php b/yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Info.php new file mode 100644 index 0000000..e23f034 --- /dev/null +++ b/yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Info.php @@ -0,0 +1,166 @@ +<?php +use Action\WebAction; +use WebPlugin\Helpers; +use Guang\InfoModel; +use Guang\IndexModel; +use LibModels\Web\Guang\InfoData; + +class InfoController extends WebAction +{ + + /** + * 逛详情页 + */ + public function indexAction() + { + $id = $this->param('id',''); + if(empty($id)) { + $id = $this->get('id'); + } + $page = $this->get('page', 1);//评论分页 + $col = $this->get('col', 0);//收藏 + $pjax = $this->get("_pjax"); + $limit = 20; //评论每页显示条数 + + if ($pjax) { + $this->_view->display('comment', InfoModel::commentList($id, $page, $limit)); + exit; + } + $uid = $this->getUid(); + $udid = $this->getUdid(); + //登陆后自动收藏 + if ($col == 1 && $uid > 0) { + InfoData::setFavorite($id, $uid); + } + $gender = Helpers::getGenderByCookie(); + $channel = Helpers::getChannelNameByCookie(); + + $info = InfoModel::articleInfo($id, $uid, $udid, $page, $gender, $channel, $limit); + // 判断参数是否有效, 无效会跳转到错误页面 + if (!is_numeric($id) || !isset($info['header']) ) { + $this->error(); + } + $data = array( + 'guangDetailPage' => true, + 'pathNav' => $info['pathNav'], + 'guang' => array( + 'id' => $id, + 'header' => isset($info['header']) ? $info['header']: array(), + 'content' => isset($info['content']) ? $info['content'] : array(), + 'brands' => isset($info['brands']) ? $info['brands'] : array(), + 'userInfo' => isset($info['userInfo']) ? $info['userInfo'] : array(), + 'tag' => isset($info['tag']) ? $info['tag'] : array(), + //分享 + 'shareImg' => $info['header']['shareImg'], + 'sharedTitle' => $info['header']['title'], + 'shareDesc' => $info['header']['desc'], + 'weixinUrl' => $info['header']['weixinUrl'], + 'relatedPost' => isset($info['relatedPost']) ? $info['relatedPost'] : array(), + 'commentInfo' => $this->getSession('comment_'.$udid), + 'comment' => isset($info['comment']) ? $info['comment'] : array(), + 'exRecos' => isset($info['exRecos']) ? $info['exRecos'] : array(), + 'hotTags' => isset($info['hotTags']) ? $info['hotTags'] : array(), + 'ads' => IndexModel::getAds($channel), + ) + ); + $this->setTitle($info['header']['title'].' | YOHO!BUY有货 | 年轻人潮流购物中心,中国潮流购物风向标,官方授权正品保证'); + $this->setKeywords('Yoho! 有货,潮流,时尚,流行,购物,B2C,正品,购物网站,网上购物,货到付款,品牌服饰,男士护肤,黑框眼镜,匡威,板鞋,i.t,izzue,5cm,eastpak,vans,lylescott,g-shock,new balance,lacoste,melissa,casio,卡西欧手表,舒雅,jasonwood,odm,AAAA,香港购物,日本潮流'); + $this->setDescription('潮流商品搜索,上衣,衬衫,TEE,卫衣,冲锋衣,风衣,羽绒服,裤子,休闲鞋,板鞋,配饰,复古眼镜'); + $this->setWebNavHeader($channel); + $this->_view->display('info', $data); + } + + /** + * 添加评论 + */ + public function commentAction() + { + $id = $this->post('id'); + $uid = $this->getUid(); + $udid = $this->getUdid(); + $comment = $this->post('comment'); + $limit = 20; + if (!$uid) { + //评论内容存session + $this->setSession('comment_'.$udid, $comment); + $this->helpJsonResult(401, '', ''); + } + $result = InfoData::addComment($id, $uid, $comment); + if (isset($result['code']) && $result['code'] == 200) { + if ($this->getSession('comment_'.$udid)) { + $this->setSession('comment_'.$udid, ''); + } + $commentInfo = InfoModel::commentList($id, 1, $limit); + $data['content'] = $this->_view->render('comment', $commentInfo); + $data['count'] = $commentInfo['comment']['commentNum']; + $this->helpJsonResult(200, '评论成功', $data); + + } else { + $this->helpJsonResult(400, '评论失败', ''); + } + } + + /** + * 赞 + */ + public function praiseAction() + { + $id = $this->get('id'); + $udid = $this->getUdid(); + $result = InfoData::setPraise($id, $udid); + if (isset($result['code']) && $result['code'] == 200) { + $this->helpJsonResult(200, '!', $result['data']); + } else { + $this->helpJsonResult(400, '', ''); + } + } + + /** + * 取消赞 + */ + public function cancelPraiseAction() + { + $id = $this->get('id'); + $udid = $this->getUdid(); + $result = InfoData::cancelPraise($id, $udid); + if (isset($result['code']) && $result['code'] == 200) { + $this->helpJsonResult(200, '', $result['data']); + } else { + $this->helpJsonResult(400, '', ''); + } + } + + /** + * 收藏 + */ + public function collectAction() + { + $id = $this->get('id'); + $uid = $this->getUid(); + if (!$uid) { + $this->helpJsonResult(401, '', ''); + } + $result = InfoData::setFavorite($id, $uid); + if (isset($result['code']) && $result['code'] == 200) { + $this->helpJsonResult(200, '', ''); + } else { + $this->helpJsonResult(400, '', ''); + } + } + + /** + * 取消收藏 + */ + public function cancelCollectAction() + { + $id = $this->get('id'); + $uid = $this->getUid(); + $result = InfoData::cancelFavorite($id, $uid); + if (isset($result['code']) && $result['code'] == 200) { + $this->helpJsonResult(200, '', ''); + } else { + $this->helpJsonResult(400, '', ''); + } + } + +} diff --git a/yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Tags.php b/yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Tags.php new file mode 100644 index 0000000..b015a27 --- /dev/null +++ b/yohobuy/www.yohobuy.com/application/modules/Guang/controllers/Tags.php @@ -0,0 +1,44 @@ +<?php +use Action\WebAction; +use WebPlugin\Helpers; +use Guang\IndexModel; +use WebPlugin\Paging; +use Index\HomeModel; +class TagsController extends WebAction +{ + /** + * 标签首页 + */ + public function indexAction() + { + $this->setWebNavHeader(); + $query = urldecode(strip_tags($this->get('query'))); + $page = (int)$this->get('page'); + $uid = $this->getUid(); + $udid = $this->getUdid(); + $gender = Helpers::getGenderByCookie(); + $channel = Helpers::getChannelNameByCookie(); + $paging = new Paging('yoho'); + $limit = 20; + $article = IndexModel::article($gender, 0, $uid, $udid, $page, $query, '', $limit); + $total = $article['total']; + $tags = IndexModel::getHotTags(1, 20); + $ads = IndexModel::getAds($channel); + $paging->setTotal($total)->setSize($limit)->setQuery(array('query' => $query)); + $this->setTitle($query, true); + $data = array(); + $data['guangIndexPage'] = true; + //导航 + $data['pathNav'] = array_merge(array(HomeModel::getHomeChannelNav()), IndexModel::getPathNav($query)); + $data['guang'] = array( + 'slider' => IndexModel::getBanner($channel), + 'tag' => $query, + 'msgs' => $article['msgs'], + 'ads'=> $ads, + 'msgPager'=> $paging->view(false), + 'exRecos' => IndexModel::getExcellectRecos($gender, 1, 10), + 'hotTags' => $tags + ); + $this->_view->display('list', $data); + } +} \ No newline at end of file diff --git a/yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Index.php b/yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Index.php new file mode 100644 index 0000000..81eeda9 --- /dev/null +++ b/yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Index.php @@ -0,0 +1,35 @@ +<?php + +use Action\WebAction; +use Shopping\PayModel; +use WebPlugin\Helpers; + +/** + * 支付 + */ +class IndexController extends WebAction +{ + public function indexAction() + { + /* 判断用户是否登录 */ + $uid = $this->getUid(true); + if (!$uid) { + $this->go( Helpers::url('/signin.html', array('refer' => $this->server('HTTP_REFERER', SITE_MAIN))) ); + } + + $orderCode = $this->get('order_code', $this->get('ordercode')); + $paymentType = $this->get('payment_type'); + $alipayToken = $this->getSession('alipay_user_token'); + $data = PayModel::getPayData($uid, $orderCode, $paymentType, $this->_uname, $alipayToken); + if (isset($data['error'])) { + $this->helpJsRedirect($data['message']); + } + + // GET方式直接跳转到支付界面 + if (isset($data['go'])) { + $this->go($data['payUrl']); + } + + $this->_view->display('index', $data); + } +} diff --git a/yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Notice.php b/yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Notice.php new file mode 100644 index 0000000..a7ed3cd --- /dev/null +++ b/yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Notice.php @@ -0,0 +1,352 @@ +<?php + +use Action\WebAction; +use Shopping\PayModel; +use WebPlugin\Helpers; +use WebPlugin\Pay\PayFactory; +use WebPlugin\Pay\Rspparams; + +/** + * 支付Notice + */ +class NoticeController extends WebAction +{ + /** + * 支付宝后台服务器返回,主要是用于补单 + */ + public function alipaynoticeAction() + { + $payment = PayModel::getPaymentById(2); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_POST); //支付宝通知使用的 + if ($res->payResult != -1) { + $this->payResultProc($res, 2); + echo "success"; + } + exit(); + } + + /** + * 支付宝浏览器端返回 + */ + public function alipayreturnAction() + { + $payment = PayModel::getPaymentById(2); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_GET); + $dealResult = $this->payResultProc($res, 2); + $dealResult['payData'] = array('payWay' => '支付宝'); + $this->commonShowResult($dealResult); + } + + /** + * 支付宝二维码支付 + */ + public function alibarcodenoticeAction() + { + $payment = PayModel::getPaymentById(17); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_POST); //支付宝通知使用的 + if ($res->payResult != -1) { + $this->payResultProc($res, 17); + echo "success"; + } + exit(); + } + + /** + * 支付宝二维码支付浏览器端返回 + */ + public function alibarcodereturnAction() + { + $payment = PayModel::getPaymentById(17); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_GET); + $dealResult = $this->payResultProc($res, 17); + $dealResult['payData'] = array('payWay' => '支付宝'); + $this->commonShowResult($dealResult); + } + + /** + * 通联支付 + */ + public function allinpaynoticeAction() + { + $payment = PayModel::getPaymentById(16); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_POST); + if ($res->payResult != -1) { + $this->payResultProc($res, 16); + echo "success"; + } + exit(); + } + + /** + * 通联支付返回 + */ + public function allinpayreturnAction() + { + $payment = PayModel::getPaymentById(16); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_POST); + $dealResult = $this->payResultProc($res, 16); + $dealResult['payData'] = array('payWay' => '通联支付'); + $this->commonShowResult($dealResult); + } + + /** + * 支付宝快捷网关浏览器回复 + */ + public function aliexpressgatewayreturnAction() + { + $payment = PayModel::getPaymentById(13); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_GET); + $dealResult = $this->payResultProc($res, 13); + $dealResult['payData'] = array('payWay' => '支付宝'); + $this->commonShowResult($dealResult); + } + + /** + * 支付宝快捷网关自动对账回复 + */ + public function aliexpressgatewaynoticeAction() + { + $payment = PayModel::getPaymentById(13); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_POST); //支付宝通知使用的 + if ($res->payResult != -1) { + $this->payResultProc($res, 13); + echo "success"; + } + exit(); + } + + /* + * 支付宝支付回调 + */ + public function alibanknoticeAction() + { + $payment = PayModel::getPaymentById(12); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_POST); + + if ($res->payResult != -1) { + $this->payResultProc($res, 12); + echo "success"; + } + + exit(); + } + + public function alibankreturnAction() + { + $payment = PayModel::getPaymentById(12); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_GET); + $dealResult = $this->payResultProc($res, 12); + $dealResult['payData'] = array('payWay' => '银行卡'); + $this->commonShowResult($dealResult); + } + + /** + * 网银信用卡 + */ + public function chinabankAction() + { + $payment = PayModel::getPaymentById(4); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_POST); + $dealResult = $this->payResultProc($res, 4); + $dealResult['payData'] = array('payWay' => '网银在线'); + $this->commonShowResult($dealResult); + } + + /** + * 网银在线自动接收 + */ + public function chinabankautorevAction() + { + $payment = PayModel::getPaymentById(4); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_POST); + if ($res->payResult != -1) { + $this->payResultProc($res, 4); + echo "ok"; + } else { + echo 'error'; + } + exit(); + } + + /** + * 腾讯财付通的回应 + */ + public function tenpayAction() + { + $payment = PayModel::getPaymentById(1); + $payService = PayFactory::factory($payment); + $rspParams = $payService->parseResponse($_GET); //财付通是以get方式回复的。 + $this->payResultProc($rspParams, 1); + } + + /** + * 盛付通浏览器返回 + * Enter description here ... + */ + public function shengpayreturnAction() + { +// $strData = '{"Amount":"0.01","PayAmount":"0.01","OrderNo":"1070021504","serialno":"B000110726001873577","Status":"01","MerchantNo":"408258","PayChannel":"04","Discount":"1","SignType":"2","PayTime":"20110726162126","CurrencyType":"RMB","ProductNo":"","ProductDesc":"","Remark1":"","Remark2":"","ExInfo":"bankid:SDTBNK","Branch":"SHB","MAC":"8ABC0FBAA3EE3202F16A915B42571B58"}'; + // $pars = json_decode($strData, true); + $payment = PayModel::getPaymentById(11); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_POST); + $dealResult = $this->payResultProc($res, 11); + $dealResult['payData'] = array('payWay' => '盛付通'); + $this->commonShowResult($dealResult); + } + + /** + * 盛付通服务器端返回 + */ + public function shengpaynoticeAction() + { + $payment = PayModel::getPaymentById(11); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_POST); + if ($res->payResult != -1) { + $this->payResultProc($res, 11); + echo "OK"; + } + exit(); + } + + /** + * jsonPcallback响应订单支付状态 + */ + public function wechatcallbackAction() + { + $callback = $this->get('callback'); + $orderCode = $this->get('ordercode'); + + $uid = $this->getUid(true); + $response = PayModel::checkWechatPayStatus($uid, $orderCode); + + $this->helpJsonCallbackResult($callback, $response['code'], $response['message']); + } + + /** + * 微信扫码支付返回返回 + */ + public function wechatqrcodereturnAction() + { + //判断是否登录 + $uid = $this->auditJumpLogin(); + + do { + $orderCode = isset($_GET['order_code']) ? $_GET['order_code'] : 0; + if (empty($orderCode)) { + $dealResult = array( + 'code' => 500, + 'message' => '支付失败' + ); + break; + } + + $dealResult = PayModel::getPayDetail($uid, $orderCode); + $dealResult['payData'] = array('payWay' => '微信扫码支付'); + } while (false); + + $this->commonShowResult($dealResult); + } + + /** + * 银联web支付返回 + */ + public function unionpaywebreturnAction() + { + //判断是否登录 + $uid = $this->auditJumpLogin(); + + do { + $orderCode = isset($_GET['order_code']) ? $_GET['order_code'] : 0; + if (empty($orderCode)) { + $dealResult = array( + 'code' => 500, + 'message' => '支付失败' + ); + break; + } + + $dealResult = PayModel::getPayDetail($uid, $orderCode); + $dealResult['payData'] = array('payWay' => '银联在线支付'); + } while (false); + + $this->commonShowResult($dealResult); + } + + /** + * 银联支付成功后台回调响应 + */ + public function unionpaywebnoticeAction() + { + $payment = PayModel::getPaymentById(25); + $payService = PayFactory::factory($payment); + $res = $payService->parseResponse($_GET); + if ($res->payResult != -1) { + $this->payResultProc($res, 25); + echo "OK"; + } + exit(); + } + + + /** + * 通用显示结果的方法 + * @param array $dealResult + */ + private function commonShowResult($dealResult) + { + $code = $dealResult['code']; + $view = 'wechatqrcodereturn'; + $data = array( + 'headerData' => true, + 'payData' => $dealResult['payData'] + ); + + if ($code == 200) { + $view = 'index'; + $data = array('payNotice' => $dealResult['data']); + } + + //头部导航 + $this->setSimpleHeader(); + $this->_view->display($view, $data); + } + + /** + * 处理支付返回的数据 + * + * @param Rspparams $payResult 支付返回的结果 + * @param $payment 支付方式id + * @return array + */ + private function payResultProc($payResult, $payment) + { + //判断是否登录 + $uid = $this->auditJumpLogin(); + + $result = array( + 'code' => 500, + 'message' => '支付失败' + ); + + if ($payResult->payResult == 200) { + //支付成功 + $result = PayModel::procOrderData($uid, $payResult, $payment); + } + + return $result; + } +} diff --git a/yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Wechatqrcode.php b/yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Wechatqrcode.php new file mode 100644 index 0000000..bc71d75 --- /dev/null +++ b/yohobuy/www.yohobuy.com/application/modules/Pay/controllers/Wechatqrcode.php @@ -0,0 +1,38 @@ +<?php + +use Action\WebAction; +use Shopping\PayModel; +use WebPlugin\Helpers; + +class WechatqrcodeController extends WebAction +{ + /** + * 微信扫码支付 + * + * @param int order_code 订单号 + */ + public function indexAction() + { + $uid = $this->getUid(true); + if (!$uid) { + $this->go(Helpers::url('/signin.html', array('refer' => $this->server('HTTP_REFERER')))); + } + + $orderCode = $this->get('order_code', $this->get('ordercode')); + $paymentCode = $this->get('payment_code'); + $data = PayModel::weixinQrcode($uid, $orderCode, $paymentCode); + if (isset($data['error'])) { + $this->helpJsRedirect($data['message']); + } + + $this->setSimpleHeader(); + // 轮询是否支付成功地址 + $data['payHost'] = Helpers::url('/pay/notice/wechatcallback', array('ordercode' => $orderCode)); + // 支付成功跳转地址 + $data['paySuccessUrl'] = Helpers::url('/pay/notice/wechatqrcodereturn', array('order_code' => $orderCode)); + $this->_view->display('index', array( + 'wechatqrcode' => $data, + 'wechatqrcodePage' => true + )); + } +} diff --git a/yohobuy/www.yohobuy.com/application/modules/Shopping/controllers/Pay.php b/yohobuy/www.yohobuy.com/application/modules/Shopping/controllers/Pay.php new file mode 100644 index 0000000..0ba665a --- /dev/null +++ b/yohobuy/www.yohobuy.com/application/modules/Shopping/controllers/Pay.php @@ -0,0 +1,70 @@ +<?php + +use Action\WebAction; +use Shopping\PayModel; +use WebPlugin\Helpers; +use LibModels\Web\Home\UserData; +/** + * 支付相关的控制器 + * + * @name PayController + * @package shopping + * @copyright yoho.inc + * @version 1.0 (2016-3-21 16:23:19) + * @author fei.hong <fei.hong@yoho.cn> + */ +class PayController extends WebAction +{ + /** + * 订单已完成,跳到支付 + */ + public function indexAction() + { + /* 判断用户是否登录 */ + $uid = $this->getUid(true); + if (!$uid) { + $this->go( Helpers::url('/signin.html', array('refer' => $this->server('HTTP_REFERER', SITE_MAIN))) ); + } + + // 订单号 + $orderCode = $this->get('order_code', $this->get('ordercode')); + + //支付宝快捷支付 + $alipayToken = $this->getSession('alipay_user_token'); + if (!empty($alipayToken)) { + $this->go(Helpers::url('/pay/index/index', array('order_code' => $orderCode, 'payment_type' => '2_platform'))); + } + + $data = PayModel::getPayTypeData($uid, $orderCode); + //不存在订单时 + if (isset($data['noOrder'])) { + $this->helpJsRedirect('没有找到该订单'); + } + + $view = 'index'; + // 无需付款时 + if (isset($data['notNeedPay'])) { + $view = 'notneedpay'; + } + // 是货到付款时 + if (isset($data['finish'])) { + $view = 'cashondelivery'; + } + + // 用户名 + $UserData = UserData::getUserInfo($uid); + $data['userName'] = isset($UserData['code']) && $UserData['code'] === 200 ? $UserData['data']['profile_name'] : $this->_uname; + + $this->setSimpleHeader(); + $this->_view->display($view, array( + 'shoppingpay' =>$data, + 'payPage' => true + )); + } + +} + + + + + diff --git a/yohobuy/www.yohobuy.com/configs/application.developer.ini b/yohobuy/www.yohobuy.com/configs/application.developer.ini index a80b19b..20496cf 100644 --- a/yohobuy/www.yohobuy.com/configs/application.developer.ini +++ b/yohobuy/www.yohobuy.com/configs/application.developer.ini @@ -4,7 +4,7 @@ application.directory = APPLICATION_PATH "/application" ;;website library application.library = ROOT_PATH "/library" ;;模块配置 -application.modules = "Index,Product,Passport,Order,Cart,Home" +application.modules = "Index,Product,Passport,Order,Cart,Home,Guang,Shopping,Pay" ;;加载 application.bootstrap = APPLICATION_PATH "/application/Bootstrap.php" ;;view文件的扩展名 @@ -19,7 +19,7 @@ application.dispatcher.defaultController = "index" application.dispatcher.defaultAction = "index" ;;初始化命名空间 -application.namespaces = "Action,Api,Configs,LibModels,WebPlugin,Plugin,Home" +application.namespaces = "Action,Api,Configs,LibModels,WebPlugin,Plugin,Home,Guang,Shopping,Pay" ;;使用composer composer.autoload = 0 @@ -50,7 +50,7 @@ application.template.ext = ".phtml" application.assets.path = ROOT_PATH "/assets/web" ; 应用的版本号 -application.version = "0.0.20" +application.version = "0.0.21" ; 网站SEO信息 application.seo.title = "YOHO!有货 | 年轻人潮流购物中心,中国潮流购物风向标,官方授权正品保证" diff --git a/yohobuy/www.yohobuy.com/configs/application.preview.ini b/yohobuy/www.yohobuy.com/configs/application.preview.ini index c6e4281..19f65c3 100644 --- a/yohobuy/www.yohobuy.com/configs/application.preview.ini +++ b/yohobuy/www.yohobuy.com/configs/application.preview.ini @@ -4,7 +4,7 @@ application.directory = APPLICATION_PATH "/application" ;;website library application.library = ROOT_PATH "/library" ;;默认模块 -application.modules = "Index,Product,Passport,Order,Cart,Home" +application.modules = "Index,Product,Passport,Order,Cart,Home,Guang,Shopping,Pay" ;;加载 application.bootstrap = APPLICATION_PATH "/application/Bootstrap.php" ;;view文件的扩展名 @@ -19,7 +19,7 @@ application.dispatcher.defaultController = "index" application.dispatcher.defaultAction = "index" ;;初始化命名空间 -application.namespaces = "Action,Api,Configs,LibModels,WebPlugin,Plugin,Home" +application.namespaces = "Action,Api,Configs,LibModels,WebPlugin,Plugin,Home,Guang,Shopping,Pay" ;;使用composer composer.autoload = 0 @@ -50,7 +50,7 @@ application.template.ext = ".phtml" application.assets.path = ROOT_PATH "/assets/web" ; 应用的版本号 -application.version = "0.0.20" +application.version = "0.0.21" ; 网站SEO信息 application.seo.title = "YOHO!有货 | 年轻人潮流购物中心,中国潮流购物风向标,官方授权正品保证" diff --git a/yohobuy/www.yohobuy.com/configs/application.production.ini b/yohobuy/www.yohobuy.com/configs/application.production.ini index 0d6a9d0..453dbab 100644 --- a/yohobuy/www.yohobuy.com/configs/application.production.ini +++ b/yohobuy/www.yohobuy.com/configs/application.production.ini @@ -4,7 +4,7 @@ application.directory = APPLICATION_PATH "/application" ;;website library application.library = ROOT_PATH "/library" ;;默认模块 -application.modules = "Index,Product,Passport,Order,Cart,Home" +application.modules = "Index,Product,Passport,Order,Cart,Home,Guang,Shopping,Pay" ;;加载 application.bootstrap = APPLICATION_PATH "/application/Bootstrap.php" ;;view文件的扩展名 @@ -19,7 +19,7 @@ application.dispatcher.defaultController = "index" application.dispatcher.defaultAction = "index" ;;初始化命名空间 -application.namespaces = "Action,Api,Configs,LibModels,WebPlugin,Plugin,Home" +application.namespaces = "Action,Api,Configs,LibModels,WebPlugin,Plugin,Home,Guang,Shopping,Pay" ;;使用composer composer.autoload = 0 @@ -50,7 +50,7 @@ application.template.ext = ".phtml" application.assets.path = ROOT_PATH "/assets/web" ; 应用的版本号 -application.version = "0.0.20" +application.version = "0.0.21" ; 网站SEO信息 application.seo.title = "YOHO!有货 | 年轻人潮流购物中心,中国潮流购物风向标,官方授权正品保证" diff --git a/yohobuy/www.yohobuy.com/configs/application.testing.ini b/yohobuy/www.yohobuy.com/configs/application.testing.ini index 3eded2b..2e7e3e1 100644 --- a/yohobuy/www.yohobuy.com/configs/application.testing.ini +++ b/yohobuy/www.yohobuy.com/configs/application.testing.ini @@ -4,7 +4,7 @@ application.directory = APPLICATION_PATH "/application" ;;website library application.library = ROOT_PATH "/library" ;;默认模块 -application.modules = "Index,Product,Passport,Order,Cart,Home" +application.modules = "Index,Product,Passport,Order,Cart,Home,Guang,Shopping,Pay" ;;加载 application.bootstrap = APPLICATION_PATH "/application/Bootstrap.php" ;;view文件的扩展名 @@ -19,7 +19,7 @@ application.dispatcher.defaultController = "index" application.dispatcher.defaultAction = "index" ;;初始化命名空间 -application.namespaces = "Action,Api,Configs,LibModels,WebPlugin,Plugin,Home" +application.namespaces = "Action,Api,Configs,LibModels,WebPlugin,Plugin,Home,Guang,Shopping,Pay" ;;使用composer composer.autoload = 0 @@ -50,7 +50,7 @@ application.template.ext = ".phtml" application.assets.path = ROOT_PATH "/assets/web" ; 应用的版本号 -application.version = "0.0.20" +application.version = "0.0.21" ; 网站SEO信息 application.seo.title = "YOHO!有货 | 年轻人潮流购物中心,中国潮流购物风向标,官方授权正品保证" diff --git a/yohobuy/www.yohobuy.com/configs/routes.guang.ini b/yohobuy/www.yohobuy.com/configs/routes.guang.ini index e69de29..fa730e5 100644 --- a/yohobuy/www.yohobuy.com/configs/routes.guang.ini +++ b/yohobuy/www.yohobuy.com/configs/routes.guang.ini @@ -0,0 +1,6 @@ +routes.guanginfo.type = "regex" +routes.guanginfo.match = "#/([0-9]+)\.html#" +routes.guanginfo.route.module = Guang +routes.guanginfo.route.controller = Info +routes.guanginfo.route.action = index +routes.guanginfo.map.1=id \ No newline at end of file -- libgit2 0.24.0