我为laravel项目实现了consolibyte/quickbooks-php。除了用于成功登录的钩子处理程序之外,其他一切都很好。我的大部分代码都基于this repo
我想在登录成功钩子上与Quickbooks交流。现在,我得到“ QBWC1012:由于以下错误消息,身份验证失败。 当我添加此处理程序以成功登录时,响应不是格式正确的XML 。 当我在"addCustomer" on this repo.
之类的路线上排队操作时,一切工作正常我正在使用Laravel V5.8。 以下是Quickbooks逻辑的一些文件:
-app / Quickbooks / Quickbooks.php (自定义quickbooks类)
<?php
namespace App\Quickbooks;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Log;
class Quickbooks
{
/**
* User Configuration File Array
*/
protected $dsn;
protected $config;
protected $map = [];
public function __construct()
{
$this->config = config('quickbooks');
$this->dsn = $this->config['qb_dsn'];
}
public function connect()
{
// error_reporting(E_ALL | E_STRICT);
date_default_timezone_set($this->config['qb_timezone']);
// error_log(\QuickBooks_WebConnector_Handlers::HOOK_LOGINSUCCESS);
// error_log(QuickBooks_WebConnector_Handlers::HOOK_LOGINSUCCESS);
if(!$this->config['qb_dsn'])
{
$dbconf = config('database');
$db = $dbconf['connections'][$dbconf['default']];
if($db['driver'] == 'mysql')
{
$db['driver'] = 'mysqli';
}
$this->dsn = $db['driver'] . '://' . $db['username'] . ':' .$db['password'] . '@' . $db['host'] . ':' . $db['port'] .'/'. $db['database'];
}
// Check to make sure our database is set up
if (!\QuickBooks_Utilities::initialized($this->dsn))
{
// Initialize creates the neccessary database schema for queueing up requests and logging
\QuickBooks_Utilities::initialize($this->dsn);
// This creates a username and password which is used by the Web Connector to authenticate
\QuickBooks_Utilities::createUser($this->dsn, $this->config['qb_username'], $this->config['qb_password']);
}
// Set up our queue singleton
\QuickBooks_WebConnector_Queue_Singleton::initialize($this->dsn);
//
return \QuickBooks_Utilities::initialized($this->dsn);
}
public function initServer($return = true, $debug = false)
{
// Create a new server and tell it to handle the requests
$Server = new \QuickBooks_WebConnector_Server(
$this->dsn,
$this->config['actions'],
$this->config['error_map'],
$this->config['hooks'],
$this->config['qb_log_level'],
$this->config['soap']['server'],
QUICKBOOKS_WSDL,
$this->config['soap']['options'],
$this->config['handler_options'],
$this->config['driver_options'],
$this->config['callback_options']
);
return $Server->handle($return, $debug);
// if $return is turned-on, there is an error "Response is not well-formed XML". Probably because of whitespaces somewhere. I haven't figured out this yet
}
// Generate and return a .QWC Web Connector configuration file
public function generateQWC()
{
$name = 'Metrony Admin'; // A name for your server (make it whatever you want)
$descrip = 'Schwartz & Company'; // A description of your server
$appurl = 'https://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['REQUEST_URI']) . '/qbwc'; // This *must* be httpS:// (path to your QuickBooks SOAP server)
$appsupport = $appurl; // This *must* be httpS:// and the domain name must match the domain name above
$username = $this->config['qb_username']; // This is the username you stored in the 'quickbooks_user' table by using QuickBooks_Utilities::createUser()
$fileid = \QuickBooks_WebConnector_QWC::fileID(); // Just make this up, but make sure it keeps that format
$ownerid = \QuickBooks_WebConnector_QWC::ownerID(); // Just make this up, but make sure it keeps that format
$qbtype = QUICKBOOKS_TYPE_QBFS; // You can leave this as-is unless you're using QuickBooks POS
$readonly = false; // No, we want to write data to QuickBooks
$run_every_n_seconds = 600; // Run every 600 seconds (10 minutes)
// Generate the XML file
$QWC = new \QuickBooks_WebConnector_QWC($name, $descrip, $appurl, $appsupport, $username, $fileid, $ownerid, $qbtype, $readonly, $run_every_n_seconds);
$xml = $QWC->generate();
return $xml;
}
// Queue up a request for the Web Connector to process
public function enqueue($action, $ident, $priority = 0, $extra = null, $user = null)
{
$Queue = new \QuickBooks_WebConnector_Queue($this->dsn);
Log::alert(print_r(array($action, $ident, $priority, $extra, $user), true));
return $Queue->enqueue($action, $ident, $priority, $extra, $user);
}
//
// public function
/**
* Get the last date/time the QuickBooks sync ran
*
* @param string $user The web connector username
* @return string A date/time in this format: "yyyy-mm-dd hh:ii:ss"
*/
function _quickbooks_get_last_run($user, $action)
{
$type = null;
$opts = null;
return \QuickBooks_Utilities::configRead(QB_QUICKBOOKS_DSN, $user, md5(__FILE__), QB_QUICKBOOKS_CONFIG_LAST . '-' . $action, $type, $opts);
}
/**
* Set the last date/time the QuickBooks sync ran to NOW
*
* @param string $user
* @return boolean
*/
function _quickbooks_set_last_run($user, $action, $force = null)
{
$value = date('Y-m-d') . 'T' . date('H:i:s');
if ($force)
{
$value = date('Y-m-d', strtotime($force)) . 'T' . date('H:i:s', strtotime($force));
}
// error_log($action . ": " . $value);
return \QuickBooks_Utilities::configWrite(QB_QUICKBOOKS_DSN, $user, md5(__FILE__), QB_QUICKBOOKS_CONFIG_LAST . '-' . $action, $value);
}
/**
*
*
*/
function _quickbooks_get_current_run($user, $action)
{
$type = null;
$opts = null;
return \QuickBooks_Utilities::configRead(QB_QUICKBOOKS_DSN, $user, md5(__FILE__), QB_QUICKBOOKS_CONFIG_CURR . '-' . $action, $type, $opts);
}
/**
*
*
*/
function _quickbooks_set_current_run($user, $action, $force = null)
{
$value = date('Y-m-d') . 'T' . date('H:i:s');
if ($force)
{
$value = date('Y-m-d', strtotime($force)) . 'T' . date('H:i:s', strtotime($force));
}
return \QuickBooks_Utilities::configWrite(QB_QUICKBOOKS_DSN, $user, md5(__FILE__), QB_QUICKBOOKS_CONFIG_CURR . '-' . $action, $value);
}
}
-app / Http / Controllers / QuickbooksController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Quickbooks\Quickbooks;
use Log;
class QuickbooksController extends Controller
{
protected $qbd;
public function __construct()
{
$this->qbd = new Quickbooks;
$this->qbd->connect();
}
//
public function initQBWC(Request $request)
{
$response = $this->qbd->initServer(true, true); //$return,$debug
$contentType = 'text/plain';
if($request->isMethod('post'))
{
$contentType = 'text/xml';
}
else if($request->input('wsdl') !== null or $request->input('WSDL') !== null)
{
$contentType = 'text/xml';
}
if($contentType == 'text/xml')
{
$tidy = new \tidy();
$response = $tidy->repairString($response, ['input-xml'=> 1, 'indent' => 0, 'wrap' => 0]);
}
// Uncomment log if you want to see the request headers submitted from WebConnector
return response($response,200)->header('Content-Type', $contentType);
}
public function generateQWC()
{
$xml = $this->qbd->generateQWC();
// header('Content-type: text/xml');
// print($xml);
// exit;
return response($xml,200)
->header('Content-Type', 'text/xml')
->header('Content-Disposition', 'attachment; filename="my-quickbooks-wc-file.qwc"'); // Send as a file download
}
}
-config / quickbooks.php
<?php
return [
'qb_dsn' => env('QB_DSN'),
'qb_username' => env('QB_USERNAME'),
'qb_password' => env('QB_PASSWORD'),
'qb_timezone' => env('QB_TIMEZONE'),
'qb_log_level' => constant(env('QB_LOGLEVEL')),
'qb_mem_limit' => env('QB_MEMLIMIT'),
'error_map' => array(
'*' => array(App\Quickbooks\ErrorHandler::class, '_quickbooks_error_catchall')
),
'hooks' => array(
\QuickBooks_WebConnector_Handlers::HOOK_LOGINSUCCESS => array(App\Quickbooks\HooksHandler::class, '_quickbooks_hook_loginsuccess')
), // An array of callback hooks
'soap' => array(
'server' => constant(env('QB_SOAPSERVER')), // A pure-PHP SOAP server (no PHP ext/soap extension required, also makes debugging easier)
'options' => [] // See http://www.php.net/soap
),
'handler_options'=> array(
'deny_concurrent_logins' => false,
'deny_reallyfast_logins' => false
), // See the comments in the QuickBooks/Server/Handlers.php file
'driver_options' => array(), // See the comments in the QuickBooks/Driver/<YOUR DRIVER HERE>.php file ( i.e. 'Mysql.php', etc. )
'callback_options'=> array(),
// Map QuickBooks actions to handle functions
'actions' => [
QUICKBOOKS_IMPORT_ACCOUNT => [
[ App\Quickbooks\AccountImport::class, 'xmlRequest' ],
[ App\Quickbooks\AccountImport::class, 'xmlResponse' ]
]
// QUICKBOOKS_ADD_EMPLOYEE => [
// [ App\Quickbooks\EmployeeAdd::class, 'xmlRequest' ],
// [ App\Quickbooks\EmployeeAdd::class, 'xmlResponse' ]
// ],
// QUICKBOOKS_ADD_CUSTOMER => [
// [ App\Quickbooks\CustomerAdd::class, 'xmlRequest' ],
// [ App\Quickbooks\CustomerAdd::class, 'xmlResponse' ]
// ],
]
];
...
-Web连接器日志
20190619.18:17:12 UTC : QBWebConnector.WebServiceManager.DoUpdateSelected() : updateWS() for application = 'Metrony Admin' has STARTED
20190619.18:17:12 UTC : QBWebConnector.RegistryManager.getUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock = FALSE
20190619.18:17:12 UTC : QBWebConnector.RegistryManager.setUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock has been set to True
20190619.18:17:12 UTC : QBWebConnector.RegistryManager.setUpdateLock() : ********************* Update session locked *********************
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : Initiated connection to the following application.
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : AppName: Metrony Admin
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : AppUniqueName (if available): Metrony Admin
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : AppURL: http://localhost/schwartz/public/qbd-connector/qbwc
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.do_serverVersion() : *** Calling serverVersion().
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.do_serverVersion() : Actual error received from web service for serverVersion call: <Response is not well-formed XML.>. For backward compatibility of all webservers, QBWC will catch all errors under app-not-supporting-serverVersion.
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.do_serverVersion() : This application does not contain support for serverVersion. Allowing update operation for backward compatibility.
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.do_clientVersion() : *** Calling clientVersion() with following parameter:<productVersion="2.3.0.25">
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.updateWS() : Actual error received from web service for clientVersion call: <Response is not well-formed XML.>. For backward compatibility of all webservers, QBWC will catch all errors under app-not-supporting-clientVersion.
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.do_clientVersion() : This application does not contain support for clientVersion. Allowing update operation for backward compatibility.
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.do_authenticate() : Authenticating to application 'Metrony Admin', username = 'quickbooks'
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.do_authenticate() : *** Calling authenticate() with following parameters:<userName="quickbooks"><password=<MaskedForSecurity>
20190619.18:17:12 UTC : QBWebConnector.SOAPWebService.do_authenticate() : QBWC1012: Authentication failed due to following error message.
Response is not well-formed XML.
More info:
StackTrace = at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at QBWebConnector.localhost.WCWebServiceDoc.authenticate(String strUserName, String strPassword)
at QBWebConnector.localhost.WCWebService.authenticate(String strUserName, String strPassword)
at QBWebConnector.SOAPWebService.authenticate(String UserName, String Password)
at QBWebConnector.WebService.do_authenticate(String& ticket, String& companyFileName)
Source = System.Web.Services
20190619.18:17:12 UTC : QBWebConnector.RegistryManager.setUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock has been set to False
20190619.18:17:12 UTC : QBWebConnector.RegistryManager.setUpdateLock() : ********************* Update session unlocked *********************
20190619.18:17:12 UTC : QBWebConnector.WebServiceManager.DoUpdateSelected() : Update completed with errors. See log (QWClog.txt) for details.
-Laravel错误日志
[2019-06-19 15:05:39] local.ERROR: Array
(
[0] =>
[1] => -4
[2] => Callback does not exist: [function] App\Quickbooks\HooksHandler(...)
)