php - 使用 QuickBooks PHP Dev Kit/QuickBooks Web Connector 从 QuickBooks 导入项目

标签 php mysql sql import quickbooks

我在使用 QuickBooks PHP Dev Kit 导入我的项目时遇到问题。 QuickBooks Web 连接器日志显示

Error message: Response is not well-formed XML.

我现在唯一真正的线索是:

  • 请求无效
  • 解析不正确

Web 连接器日志文件中的相关片段:

20161227.23:47:12 UTC   : QBWebConnector.SOAPWebService.do_receiveResponseXML() : hresult=""
20161227.23:47:12 UTC   : QBWebConnector.SOAPWebService.do_receiveResponseXML() : message=""
20161227.23:47:12 UTC   : QBWebConnector.SOAPWebService.do_receiveResponseXML() : QBWC1042: ReceiveResponseXML failed
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.receiveResponseXML(String ticket, String response, String hresult, String message)
   at QBWebConnector.localhost.WCWebService.receiveResponseXML(String ticket, String response, String hresult, String message)
   at QBWebConnector.SOAPWebService.receiveResponseXML(String wcTicket, String response, String hresult, String message)
   at QBWebConnector.WebService.do_receiveResponseXML(String wcTicket, String response, String hresult, String message, Boolean& success, Boolean& timeout)
Source = System.Web.Services
20161227.23:47:12 UTC   : QBWebConnector.CompanyFileLock.Send_CompanyQueryRqXML() : XML dump follows: -

inventory_manager.php(基于 example_web_connector_import.php)

<?php
// I always program in E_STRICT error mode... 
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);
// We need to make sure the correct timezone is set, or some PHP installations will complain
if (function_exists('date_default_timezone_set'))
{
    date_default_timezone_set('America/Los_Angeles');
}
// If you're having trouble with performance or memory usage, you can tell the 
//  framework to only include certain chunks of itself:
// require_once 'QuickBooks/Frameworks.php';
// define('QUICKBOOKS_FRAMEWORKS', QUICKBOOKS_FRAMEWORK_WEBCONNECTOR);
// Require the framework
require_once '../../QuickBooks.php';
// User & pass for QWC
$user = 'removed';
$pass = 'removed';
// Globals
define('QB_QUICKBOOKS_CONFIG_LAST', 'last');
define('QB_QUICKBOOKS_CONFIG_CURR', 'curr');
define('QB_QUICKBOOKS_MAILTO', 'removed');
define('QB_QUICKBOOKS_MAX_RETURNED', 10);
define('QB_PRIORITY_ITEM', 3);
// Map QuickBooks actions to handler functions
$map = array(
    QUICKBOOKS_IMPORT_ITEM => array( '_quickbooks_item_import_request', '_quickbooks_item_import_response' ),
    QUICKBOOKS_ADD_INVENTORYADJUSTMENT => array( '_quickbooks_inventoryadjustment_add_request', '_quickbooks_inventoryadjustment_add_response' ),
);
// Trigger actions when errors are returned by QuickBooks
$errmap = array(
    3070 => '_quickbooks_error_stringtoolong',              // Whenever a string is too long to fit in a field, call this function: _quickbooks_error_stringtolong()
    // 'CustomerAdd' => '_quickbooks_error_customeradd',    // Whenever an error occurs while trying to perform an 'AddCustomer' action, call this function: _quickbooks_error_customeradd()
    1 => '_quickbooks_error_e500_notfound',
    '*' => '_quickbooks_error_catchall',                // Using a key value of '*' will catch any errors which were not caught by another error handler
    // ... more error handlers here ...
);
// An array of callback hooks
$hooks = array(
    QuickBooks_WebConnector_Handlers::HOOK_LOGINSUCCESS => '_quickbooks_hook_loginsuccess',     // call this whenever a successful login occurs
);
// Logging level
//$log_level = QUICKBOOKS_LOG_NORMAL;               
$log_level = QUICKBOOKS_LOG_DEVELOP;        // Use this level until you're sure everything works!!!
$soapserver = QUICKBOOKS_SOAPSERVER_BUILTIN;
$soap_options = array(      // 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. )
    //'max_log_history' => 1024,    // Limit the number of quickbooks_log entries to 1024
    //'max_queue_history' => 64,    // Limit the number of *successfully processed* quickbooks_queue entries to 64
);
$callback_options = array(
);
$dsn = 'mysqli://:@localhost/'; // User/pass removed
/**
 * Constant for the connection string (because we'll use it in other places in the script)
 */
define('QB_QUICKBOOKS_DSN', $dsn);
$qb = new mysqli('127.0.0.1', 'removed', 'removed', 'removed');
if (!QuickBooks_Utilities::initialized($dsn))
{
    // Create the tables
    $file = dirname(__FILE__) . '/import.sql';
    if (file_exists($file))
    {
        $contents = file_get_contents($file);   
        foreach (explode(';', $contents) as $sql)
        {
            if (!trim($sql))
            {
                continue;
            }
            mysqli_query($qb, $sql) or die(trigger_error(mysqli_error($qb)));
        }
    }
    else
    {
        die('Could not locate "./import.sql" to create the SQL schema!');
    }
    // Initialize creates the neccessary database schema for queueing up requests and logging
    QuickBooks_Utilities::initialize($dsn);
    // This creates a username and password which is used by the Web Connector to authenticate
    QuickBooks_Utilities::createUser($dsn, $user, $pass);
}
// Initialize the queue
QuickBooks_WebConnector_Queue_Singleton::initialize($dsn);
// Create a new server and tell it to handle the requests
$Server = new QuickBooks_WebConnector_Server($dsn, $map, $errmap, $hooks, $log_level, $soapserver, QUICKBOOKS_WSDL, $soap_options, $handler_options, $driver_options, $callback_options);
$response = $Server->handle(true, true);
function _quickbooks_hook_loginsuccess($requestID, $user, $hook, &$err, $hook_data, $callback_config)
{
    // Fetch the queue instance
    $Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
    $date = '1983-01-02 12:01:01';
    // Set up the item imports
    if (!_quickbooks_get_last_run($user, QUICKBOOKS_IMPORT_ITEM))
    {
        _quickbooks_set_last_run($user, QUICKBOOKS_IMPORT_ITEM, $date);
    }
    // Make sure the requests get queued up
    $Queue->enqueue(QUICKBOOKS_IMPORT_ITEM, 1, QB_PRIORITY_ITEM);
}
/**
 * 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));
    }
    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);   
}

/**
 * Build a request to import items already in QuickBooks into our application
 */
function _quickbooks_item_import_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{
    // Iterator support (break the result set into small chunks)
    $attr_iteratorID = '';
    $attr_iterator = ' iterator="Start" ';
    if (empty($extra['iteratorID']))
    {
        // This is the first request in a new batch
        $last = _quickbooks_get_last_run($user, $action);
        _quickbooks_set_last_run($user, $action);           // Update the last run time to NOW()
        // Set the current run to $last
        _quickbooks_set_current_run($user, $action, $last);
    }
    else
    {
        // This is a continuation of a batch
        $attr_iteratorID = ' iteratorID="' . $extra['iteratorID'] . '" ';
        $attr_iterator = ' iterator="Continue" ';
        $last = _quickbooks_get_current_run($user, $action);
    }
    // Build the request
    $xml = '<?xml version="1.0" encoding="utf-8"?>
        <?qbxml version="' . $version . '"?>
        <QBXML>
            <QBXMLMsgsRq onError="stopOnError">
                <ItemQueryRq ' . $attr_iterator . ' ' . $attr_iteratorID . ' requestID="' . $requestID . '">
                    <MaxReturned>' . QB_QUICKBOOKS_MAX_RETURNED . '</MaxReturned>
                    <FromModifiedDate>' . $last . '</FromModifiedDate>
                    <OwnerID>0</OwnerID>
                </ItemQueryRq>  
            </QBXMLMsgsRq>
        </QBXML>';
    return $xml;
}
/** 
 * Handle a response from QuickBooks 
 */
function _quickbooks_item_import_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
    $Driver = QuickBooks_Driver_Singleton::getInstance();
    if (!empty($idents['iteratorRemainingCount']))
    {
        // Queue up another request
        $Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
        $Queue->enqueue(QUICKBOOKS_IMPORT_ITEM, null, QB_PRIORITY_ITEM, array( 'iteratorID' => $idents['iteratorID'] ));
    }
    // Import all of the records
    $errnum = 0;
    $errmsg = '';
    $Parser = new QuickBooks_XML_Parser($xml);
    if ($Doc = $Parser->parse($errnum, $errmsg))
    {
        $Root = $Doc->getRoot();
        $List = $Root->getChildAt('QBXML/QBXMLMsgsRs/ItemQueryRs');
        foreach ($List->children() as $Item)
        {
            $type = substr(substr($Item->name(), 0, -3), 4);
            $ret = $Item->name();
            $arr = array(
                'ListID' => $Item->getChildDataAt($ret . ' ListID'),
                'TimeCreated' => $Item->getChildDataAt($ret . ' TimeCreated'),
                'TimeModified' => $Item->getChildDataAt($ret . ' TimeModified'),
                'Name' => $Item->getChildDataAt($ret . ' Name'),
                'FullName' => $Item->getChildDataAt($ret . ' FullName'),
                'Type' => $type, 
                'Parent_ListID' => $Item->getChildDataAt($ret . ' ParentRef ListID'),
                'Parent_FullName' => $Item->getChildDataAt($ret . ' ParentRef FullName'),
                'ManufacturerPartNumber' => $Item->getChildDataAt($ret . ' ManufacturerPartNumber'), 
                'SalesTaxCode_ListID' => $Item->getChildDataAt($ret . ' SalesTaxCodeRef ListID'), 
                'SalesTaxCode_FullName' => $Item->getChildDataAt($ret . ' SalesTaxCodeRef FullName'), 
                'BuildPoint' => $Item->getChildDataAt($ret . ' BuildPoint'), 
                'ReorderPoint' => $Item->getChildDataAt($ret . ' ReorderPoint'), 
                'QuantityOnHand' => $Item->getChildDataAt($ret . ' QuantityOnHand'), 
                'AverageCost' => $Item->getChildDataAt($ret . ' AverageCost'), 
                'QuantityOnOrder' => $Item->getChildDataAt($ret . ' QuantityOnOrder'), 
                'QuantityOnSalesOrder' => $Item->getChildDataAt($ret . ' QuantityOnSalesOrder'),  
                'TaxRate' => $Item->getChildDataAt($ret . ' TaxRate'),  
                );
            $look_for = array(
                'SalesPrice' => array( 'SalesOrPurchase Price', 'SalesAndPurchase SalesPrice', 'SalesPrice' ),
                'SalesDesc' => array( 'SalesOrPurchase Desc', 'SalesAndPurchase SalesDesc', 'SalesDesc' ),
                'PurchaseCost' => array( 'SalesOrPurchase Price', 'SalesAndPurchase PurchaseCost', 'PurchaseCost' ),
                'PurchaseDesc' => array( 'SalesOrPurchase Desc', 'SalesAndPurchase PurchaseDesc', 'PurchaseDesc' ),
                'PrefVendor_ListID' => array( 'SalesAndPurchase PrefVendorRef ListID', 'PrefVendorRef ListID' ), 
                'PrefVendor_FullName' => array( 'SalesAndPurchase PrefVendorRef FullName', 'PrefVendorRef FullName' ),
                ); 
            foreach ($look_for as $field => $look_here)
            {
                if (!empty($arr[$field]))
                {
                    break;
                }
                foreach ($look_here as $look)
                {
                    $arr[$field] = $Item->getChildDataAt($ret . ' ' . $look);
                }
            }
            QuickBooks_Utilities::log(QB_QUICKBOOKS_DSN, 'Importing ' . $type . ' Item ' . $arr['FullName'] . ': ' . print_r($arr, true));
            foreach ($arr as $key => $value)
            {
                $arr[$key] = mysqli_real_escape_string($con, $value);
            }

            //print_r(array_keys($arr));
            //trigger_error(print_r(array_keys($arr), true));
            // Store the customers in MySQL
            $Driver->query("
                REPLACE INTO
                    qb_item
                (
                    " . implode(", ", array_keys($arr)) . "
                ) VALUES (
                    '" . implode("', '", array_values($arr)) . "'
                )");
        }
    }
    return true;
}
/**
 * Generate a qbXML response to add a particular inventory adjustment to QuickBooks
 * 
 * @return string                           A valid qbXML request
 */
function _quickbooks_inventoryadjustment_add_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale, $callback_config)
{
    $Driver = QuickBooks_Driver_Singleton::getInstance();
    $errnum = null;
    $errmsg = null;
    $data = $Driver->fetch($Driver->query("SELECT * FROM qb_inventoryadjustment WHERE qbsql_id = %d", $errnum, $errmsg, 0, 1, array( $ID )));
    $res_lines = $Driver->query("SELECT * FROM qb_inventoryadjustment_inventoryadjustmentline WHERE InventoryAdjustment_TxnID = '%s' ORDER BY SortOrder ASC", $errnum, $errmsg, null, null, array( $data['TxnID'] ));
    /*foreach ($data as $key => $value)
    {
        $data[$key] = QuickBooks_Cast::cast(QUICKBOOKS_OBJECT_CUSTOMER, str_replace('_', ' ', $key), $value);
    }*/
    $str_action = 'InventoryAdjustmentAdd';
    $TxnID = '';
    $EditSequence = '';
    if ($action == 'InventoryAdjustmentMod')
    {
        $str_action = 'InventoryAdjustmentMod';
        $TxnID = '<TxnID>' . $data['TxnID'] . '</TxnID>';
        $EditSequence = '<EditSequence>' . $data['EditSequence'] . '</EditSequence>';
    }
    $xml = '<?xml version="1.0" encoding="utf-8"?>
        <?qbxml version="' . $version . '"?>
        <QBXML>
            <QBXMLMsgsRq onError="stopOnError">
                <' . $str_action . 'Rq requestID="' . $requestID . '">
                    <' . $str_action . '>
                        ' . $TxnID . '
                        ' . $EditSequence . '

                        <AccountRef>
                            <FullName>' . $data['Account_FullName'] . '</FullName>
                        </AccountRef>

                        <TxnDate>' . $data['TxnDate'] . '</TxnDate>
                        <!--<RefNumber>' . $data['RefNumber'] . '</RefNumber>-->

                        <Memo>' . $data['Memo'] . '</Memo>
                        ';

    while ($line = $Driver->fetch($res_lines))
    {
        $xml .= '
                        <InventoryAdjustmentLineAdd>
                            <ItemRef>';

        if ($line['Item_ListID'])
        {
            $xml .= '
                                <ListID>' . $line['Item_ListID'] . '</ListID>';
        }
        else
        {
            $xml .= '
                                <FullName>' . $line['Item_FullName'] . '</FullName>';
        }

        $xml .= '
                            </ItemRef>

                            <QuantityAdjustment>';

        if ($line['QuantityDifference'])
        {
            $xml .= '
                                <QuantityDifference>' . $line['QuantityDifference'] . '</QuantityDifference>';
        }
        else
        {
            $xml .= '
                                <NewQuantity>' . $line['NewQuantity'] . '</NewQuantity>';
        }

        $xml .= '
                            </QuantityAdjustment>
                        </InventoryAdjustmentLineAdd>
                ';
    }

    $xml .= '

                    </' . $str_action . '>
                </' . $str_action . 'Rq>
            </QBXMLMsgsRq>
        </QBXML>';

    return $xml;
}

/**
 * Receive a response from QuickBooks 
 */
function _quickbooks_inventoryadjustment_add_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents, $callback_config)
{   
    $Driver = QuickBooks_Driver_Singleton::getInstance();

    $datetime = date('Y-m-d H:i:s');

    $errnum = null;
    $errmsg = null;
    $data = $Driver->fetch($Driver->query("SELECT * FROM qb_inventoryadjustment WHERE qbsql_id = %d", $errnum, $errmsg, 0, 1, array( $ID )));

    if ($data)
    {
        // Get the existing lines 
        $res_lines = $Driver->query("SELECT * FROM qb_inventoryadjustment_inventoryadjustmentline WHERE InventoryAdjustment_TxnID = '%s' ORDER BY qbsql_id ASC ", $errnum, $errmsg, null, null, array( $data['TxnID'] ));

        // Update ListID/EditSequence
        $errnum = null;
        $errmsg = null;
        $Driver->query("
            UPDATE 
                qb_inventoryadjustment
            SET 
                TxnID = '%s', 
                EditSequence = '%s', 
                TimeCreated = '%s', 
                TimeModified = '%s', 
                RefNumber = '%s', 
                qbsql_discov_datetime = '%s', 
                qbsql_resync_datetime = '%s', 
                qbsql_modify_timestamp = '%s'
            WHERE 
                qbsql_id = %d ", $errnum, $errmsg, 0, 1, 
            array( 
                $idents['TxnID'], 
                $idents['EditSequence'], 
                date('Y-m-d H:i:s'), 
                date('Y-m-d H:i:s'), 
                $idents['RefNumber'],
                $datetime, 
                $datetime, 
                $datetime,
                $ID ));

        // Parse the XML we got back 
        // Import all of the records
        $errnum = 0;
        $errmsg = '';
        $Parser = new QuickBooks_XML_Parser($xml);
        if ($Doc = $Parser->parse($errnum, $errmsg))
        {
            $Root = $Doc->getRoot();
            $List = $Root->getChildAt('QBXML/QBXMLMsgsRs/InventoryAdjustmentAddRs');

            $TxnLineIDs = array();

            foreach ($List->children() as $InventoryAdjustment)
            {
                // Process the line items
                foreach ($InventoryAdjustment->children() as $Child)
                {
                    if ($Child->name() == 'InventoryAdjustmentLineRet')
                    {
                        // Store the TxnLineID
                        $TxnLineIDs[] = $Child->getChildDataAt('InventoryAdjustmentLineRet TxnLineID');
                    }
                }
            }

            reset($TxnLineIDs);
            while ($line = $Driver->fetch($res_lines))
            {
                $TxnLineID = current($TxnLineIDs);
                next($TxnLineIDs);

                // Update each line item with the TxnID and the TxnLineID 
                $Driver->query("
                    UPDATE 
                        qb_inventoryadjustment_inventoryadjustmentline
                    SET 
                        InventoryAdjustment_TxnID = '%s', 
                        TxnLineID = '%s', 
                        qbsql_discov_datetime = '%s', 
                        qbsql_resync_datetime = '%s', 
                        qbsql_modify_timestamp = '%s'
                    WHERE 
                        qbsql_id = %d ", $errnum, $errmsg, null, null,  
                    array( 
                        $idents['TxnID'], 
                        $TxnLineID, 
                        $datetime, 
                        $datetime, 
                        $datetime,
                        $line['qbsql_id'] ));
            }
        }

    }
}

/**
 * Catch and handle a "that string is too long for that field" error (err no. 3070) from QuickBooks
 * 
 * @param string $requestID         
 * @param string $action
 * @param mixed $ID
 * @param mixed $extra
 * @param string $err
 * @param string $xml
 * @param mixed $errnum
 * @param string $errmsg
 * @return void
 */
function _quickbooks_error_stringtoolong($requestID, $user, $action, $ID, $extra, &$err, $xml, $errnum, $errmsg)
{
    mail(QB_QUICKBOOKS_MAILTO, 
        'QuickBooks error occured!', 
        'QuickBooks thinks that ' . $action . ': ' . $ID . ' has a value which will not fit in a QuickBooks field...');
}

/**
 * Handle a 500 not found error from QuickBooks
 * 
 * Instead of returning empty result sets for queries that don't find any 
 * records, QuickBooks returns an error message. This handles those error 
 * messages, and acts on them by adding the missing item to QuickBooks. 
 */
function _quickbooks_error_e500_notfound($requestID, $user, $action, $ID, $extra, &$err, $xml, $errnum, $errmsg)
{
    //$Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();

    if ($action == QUICKBOOKS_IMPORT_ITEM) {
        return true;
    } elseif ($action == QUICKBOOKS_ADD_INVENTORYADJUSTMENT) {
        return true;
    }

    return false;
}


/**
 * Catch any errors that occur
 * 
 * @param string $requestID         
 * @param string $action
 * @param mixed $ID
 * @param mixed $extra
 * @param string $err
 * @param string $xml
 * @param mixed $errnum
 * @param string $errmsg
 * @return void
 */
function _quickbooks_error_catchall($requestID, $user, $action, $ID, $extra, &$err, $xml, $errnum, $errmsg)
{
    $message = '';
    $message .= 'Request ID: ' . $requestID . "\r\n";
    $message .= 'User: ' . $user . "\r\n";
    $message .= 'Action: ' . $action . "\r\n";
    $message .= 'ID: ' . $ID . "\r\n";
    $message .= 'Extra: ' . print_r($extra, true) . "\r\n";
    $message .= 'Error: ' . $err . "\r\n";
    $message .= 'Error number: ' . $errnum . "\r\n";
    $message .= 'Error message: ' . $errmsg . "\r\n";

    mail(QB_QUICKBOOKS_MAILTO, 
        'QuickBooks error occured!', 
        $message);
}

PHP error_log

[27-Dec-2016 17:46:12 America/Chicago] PHP Deprecated:  Automatically populating $HTTP_RAW_POST_DATA is deprecated and will be removed in a future version. To avoid this warning set 'always_populate_raw_post_data' to '-1' in php.ini and use the php://input stream instead. in Unknown on line 0
[27-Dec-2016 15:46:12 America/Los_Angeles] PHP Warning:  require_once(/home2/spray/public_html/qb/QuickBooks/Driver/.php): failed to open stream: No such file or directory in /home2/spray/public_html/qb/QuickBooks/Loader.php on line 56
[27-Dec-2016 15:46:12 America/Los_Angeles] PHP Fatal error:  require_once(): Failed opening required '/home2/spray/public_html/qb/QuickBooks/Driver/.php' (include_path='.:/opt/php56/lib/php:/home2/spray/public_html/qb') in /home2/spray/public_html/qb/QuickBooks/Loader.php on line 56

最佳答案

任何时候你看到这样的东西:

20161227.23:47:12 UTC   : QBWebConnector.SOAPWebService.do_receiveResponseXML() : QBWC1042: ReceiveResponseXML failed
Error message: Response is not well-formed XML.

大约有 99% 的可能性您的 PHP 或 SQL 中有错误。

根据您在日志中看到的这些错误:

[27-Dec-2016 15:46:12 America/Los_Angeles] PHP Warning:  require_once(/home2/spray/public_html/qb/QuickBooks/Driver/.php): failed to open stream: No such file or directory in /home2/spray/public_html/qb/QuickBooks/Loader.php on line 56
[27-Dec-2016 15:46:12 America/Los_Angeles] PHP Fatal error:  require_once(): Failed opening required '/home2/spray/public_html/qb/QuickBooks/Driver/.php' (include_path='.:/opt/php56/lib/php:/home2/spray/public_html/qb') in /home2/spray/public_html/qb/QuickBooks/Loader.php on line 56

您可能没有初始化您正在使用的数据库单例。这将获取单例实例:

$Driver = QuickBooks_Driver_Singleton::getInstance();

但您必须先初始化它(在创建 QuickBooks_WebConnector_Server 类之前):

QuickBooks_Driver_Singleton::initialize('mysqli://user:pass@host/db');

或者只使用 mysqli_* 函数,如示例所示。

我看到另一个潜在的问题,那就是这一行:

$arr[$key] = mysqli_real_escape_string($con, $value);

使用名为$con的 undefined variable 。确保检查代码并确保代码正确并且定义了变量。

关于php - 使用 QuickBooks PHP Dev Kit/QuickBooks Web Connector 从 QuickBooks 导入项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41353756/

相关文章:

php - php如何将图片上传到数据库?

php - 如何将用户提供的数量未知的库存商品选择添加到购物车?

sql - PostgreSQL - 选择一列和两列中唯一值的计数

php - 无法加载请求的类 : Pdf

php - Web 表单生成器教程

php - 如何删除 mysql 中计数大于 1 的货币?

mysql 触发器 for 循环

mysql - 无需日复一日地检测日期重叠

sql - Oracle LIMIT 和 1000 列限制

mysql - 我在我的 SQL 查询中没有看到错误