QuickBooks/WebConnector/Handlers.php
public function sendRequestXML($obj)
	{
		//$this->_driver->log('sendRequestXML()', $obj->ticket, QUICKBOOKS_LOG_VERBOSE);
		$this->_log('sendRequestXML()', $obj->ticket, QUICKBOOKS_LOG_VERBOSE);

		if ($this->_driver->authCheck($obj->ticket))
		{
			$user = $this->_driver->authResolve($obj->ticket);

			$hookdata = array(
				'username' => 			$user,
				'ticket' => 			$obj->ticket,
				'strHCPResponse' => 	$obj->strHCPResponse,
				'strCompanyFileName' => $obj->strCompanyFileName,
				'qbXMLCountry' => 		$obj->qbXMLCountry,
				'qbXMLMajorVers' => 	$obj->qbXMLMajorVers,
				'qbXMLMinorVers' => 	$obj->qbXMLMinorVers,
				);
			$hookerr = '';
			$this->_callHook($obj->ticket, QUICKBOOKS_HANDLERS_HOOK_SENDREQUESTXML, null, null, null, null, $hookerr, null, array(), $hookdata);
			// _callHook($ticket, $hook, $requestID, $action, $ident, $extra, &$err, $xml = '', $qb_identifiers = array(), $hook_data = array())

			// Move recurring events which are due to run to the queue table
			// 	We *CAN'T* re-register recurring events here, otherwise, we run
			//	the risk of re-adding an event which has occured, *before* the
			//	entire session has finishing running. Thus, we'd create an
			//	infinite loop of web connector that would never end.
			//$this->_handleRecurringEvents($obj->ticket);

			if ($next = $this->_driver->queueDequeue($user, true)) // Fetch the next action/command from the queue
			{
				//$this->_driver->log('Dequeued: ( ' . $next['qb_action'] . ', ' . $next['ident'] . ' ) ', $obj->ticket, QUICKBOOKS_LOG_DEBUG);
				$this->_log('Dequeued: ( ' . $next['qb_action'] . ', ' . $next['ident'] . ' ) ', $obj->ticket, QUICKBOOKS_LOG_DEBUG);
				//$this->_driver->queueStatus($obj->ticket, $next['qb_action'], $next['ident'], QUICKBOOKS_STATUS_PROCESSING);
				$this->_driver->queueStatus($obj->ticket, $next['quickbooks_queue_id'], QUICKBOOKS_STATUS_PROCESSING);

				/*
				// Here's a strange case, interactive mode handler
				if ($next['qb_action'] == QUICKBOOKS_INTERACTIVE_MODE)
				{
					// Set the error to "Interactive mode"
					$this->_driver->errorLog($obj->ticket, QUICKBOOKS_ERROR_OK, QUICKBOOKS_INTERACTIVE_MODE);

					// This will cause ->getLastError() to be called, and ->getLastError() will then return the string "Interactive mode" which will cause QuickBooks to call ->getInteractiveURL() and start an interactive session... I think...?
					return new QuickBooks_Result_SendRequestXML('');
				}
				*/

				$extra = '';
				if ($next['extra'])
				{
					$extra = unserialize($next['extra']);
				}

				$err = '';
				$xml = '';

				//$last_action_time = $this->_driver->queueActionLast($user, $next['qb_action']);
				//$last_actionident_time = $this->_driver->queueActionIdentLast($user, $next['qb_action'], $next['ident']);
				$last_action_time = null;
				$last_actionident_time = null;

				// Call the mapped function that should generate an appropriate qbXML request
				$xml = $this->_callMappedFunction(0, $user, $next['quickbooks_queue_id'], $next['qb_action'], $next['ident'], $extra, $err, $last_action_time, $last_actionident_time, $obj->qbXMLMajorVers . '.' . $obj->qbXMLMinorVers, $obj->qbXMLCountry, $next['qbxml']);

				// Make sure there's no whitespace around it
				$xml = trim($xml);

				// NoOp can be returned to skip this current operation. This will cause getLastError
				//	to be called, at which point NoOp should be returned to tell the Web
				//	Connector to then pause for 5 seconds before asking for another request.
				if ($xml == QUICKBOOKS_NOOP)
				{
					$this->_driver->errorLog($obj->ticket, 0, QUICKBOOKS_NOOP);

					// Mark it as a NoOp to remove it from the queue
					//$this->_driver->queueStatus($obj->ticket, $next['qb_action'], $next['ident'], QUICKBOOKS_STATUS_NOOP, 'Handler function returned: ' . QUICKBOOKS_NOOP);
					$this->_driver->queueStatus($obj->ticket, $next['quickbooks_queue_id'], QUICKBOOKS_STATUS_NOOP, 'Handler function returned: ' . QUICKBOOKS_NOOP);

					return new QuickBooks_WebConnector_Result_SendRequestXML('');
				}

				// If the requestID="..." attribute was not specified, we can try to automatically add it to the request
				$requestID = null;
				if (!($requestID = $this->_extractRequestID($xml)) and
					$this->_config['autoadd_missing_requestid'])
				{
					// Find the <DoSomethingRq tag

					foreach (QuickBooks_Utilities::listActions() as $action)
					{
						$request = QuickBooks_Utilities::actionToRequest($action);
						if (false !== strpos($xml, '<' . $request . ' '))
						{
							//$xml = str_replace('<' . $request . ' ', '<' . $request . ' requestID="' . $this->_constructRequestID($next['qb_action'], $next['ident']) . '" ', $xml);
							$xml = str_replace('<' . $request . ' ', '<' . $request . ' requestID="' . $next['quickbooks_queue_id'] . '" ', $xml);
							break;
						}
						else if (false !== strpos($xml, '<' . $request . '>'))
						{
							//$xml = str_replace('<' . $request . '>', '<' . $request . ' requestID="' . $this->_constructRequestID($next['qb_action'], $next['ident']) . '">', $xml);
							$xml = str_replace('<' . $request . '>', '<' . $request . ' requestID="' . $next['quickbooks_queue_id'] . '">', $xml);
							break;
						}
					}
				}
				else if ($this->_config['check_valid_requestid'])
				{
					// They embedded a requestID="..." attribute, let's make sure it's valid

					//$embedded_action = null;
					//$embedded_ident = null;
					//$this->_parseRequestID($requestID, $embedded_action, $embedded_ident);

					//if ($embedded_action != $next['qb_action'] or $embedded_ident != $next['ident'])
					if ($next['quickbooks_queue_id'] != $requestID)
					{
						// They are sending this request with an INVALID requestID! Error this out and warn them!

						$err = 'This request contains an invalid embedded requestID="..." attribute; either embed the $requestID parameter, or leave out the requestID="..." attribute entirely, found [' . $requestID . ' vs. expected ' . $next['quickbooks_queue_id'] . ']!';
					}
				}

				/*
				if ($this->_config['convert_unix_newlines'] and
					false === strpos($xml, "\r") and 				// there are currently no Windows newlines...
					false !== strpos($xml, "\n"))					// ... but there *are* Unix newlines!
				{
					; // (this is currently broken/unimplemented)
				}
				*/

				if ($err) // The function encountered an error when generating the qbXML request
				{
					//$this->_driver->errorLog($obj->ticket, QUICKBOOKS_ERROR_HANDLER, $err);
					//$this->_driver->log('ERROR: ' . $err, $obj->ticket, QUICKBOOKS_LOG_NORMAL);
					//$this->_driver->queueStatus($obj->ticket, $next['qb_action'], $next['ident'], QUICKBOOKS_STATUS_ERROR, 'Registered handler returned error: ' . $err);

					$errerr = '';
					//$this->_handleError($obj->ticket, QUICKBOOKS_ERROR_HANDLER, $err, $this->_constructRequestID($next['qb_action'], $next['ident']), $next['qb_action'], $next['ident'], $extra, $errerr, $xml);
					$this->_handleError($obj->ticket, QUICKBOOKS_ERROR_HANDLER, $err, $next['quickbooks_queue_id'], $next['qb_action'], $next['ident'], $extra, $errerr, $xml);

					return new QuickBooks_WebConnector_Result_SendRequestXML('');
				}
				else
				{
					//$this->_driver->log('Outgoing XML request: ' . $xml, $obj->ticket, QUICKBOOKS_LOG_DEBUG);
					$this->_log('Outgoing XML request: ' . $xml, $obj->ticket, QUICKBOOKS_LOG_DEBUG);

					if (strlen($xml) and  // Returned XML AND
						!$this->_extractRequestID($xml)) // Does not have a requestID in the request
					{
						// Mark it as successful right now
						//$this->_driver->queueStatus($obj->ticket, $next['qb_action'], $next['ident'], QUICKBOOKS_STATUS_SUCCESS, 'Unverified... no requestID attribute in XML stream.');
						$this->_driver->queueStatus($obj->ticket, $next['quickbooks_queue_id'], QUICKBOOKS_STATUS_SUCCESS, 'Unverified... no requestID attribute in XML stream.');
					}

					return new QuickBooks_WebConnector_Result_SendRequestXML($xml);
				}
			}
		}

		// Reporting an error, this will cause the QBWC to call ->getLastError()
		return new QuickBooks_WebConnector_Result_SendRequestXML('');
	}
public function sendRequestXML($obj)
	{
		//$this->_driver->log('sendRequestXML()', $obj->ticket, QUICKBOOKS_LOG_VERBOSE);
		$this->_log('sendRequestXML()', $obj->ticket, QUICKBOOKS_LOG_VERBOSE);

		if ($this->_driver->authCheck($obj->ticket))
		{
			$user = $this->_driver->authResolve($obj->ticket);

			$hookdata = array(
				'username' => 			$user,
				'ticket' => 			$obj->ticket,
				'strHCPResponse' => 	$obj->strHCPResponse,
				'strCompanyFileName' => $obj->strCompanyFileName,
				'qbXMLCountry' => 		$obj->qbXMLCountry,
				'qbXMLMajorVers' => 	$obj->qbXMLMajorVers,
				'qbXMLMinorVers' => 	$obj->qbXMLMinorVers,
				);
			$hookerr = '';
			$this->_callHook($obj->ticket, QUICKBOOKS_HANDLERS_HOOK_SENDREQUESTXML, null, null, null, null, $hookerr, null, array(), $hookdata);
			// _callHook($ticket, $hook, $requestID, $action, $ident, $extra, &$err, $xml = '', $qb_identifiers = array(), $hook_data = array())

			// Move recurring events which are due to run to the queue table
			// 	We *CAN'T* re-register recurring events here, otherwise, we run
			//	the risk of re-adding an event which has occured, *before* the
			//	entire session has finishing running. Thus, we'd create an
			//	infinite loop of web connector that would never end.
			//$this->_handleRecurringEvents($obj->ticket);

			if ($next = $this->_driver->queueDequeue($user, true)) // Fetch the next action/command from the queue
			{
				//$this->_driver->log('Dequeued: ( ' . $next['qb_action'] . ', ' . $next['ident'] . ' ) ', $obj->ticket, QUICKBOOKS_LOG_DEBUG);
				$this->_log('Dequeued: ( ' . $next['qb_action'] . ', ' . $next['ident'] . ' ) ', $obj->ticket, QUICKBOOKS_LOG_DEBUG);
				//$this->_driver->queueStatus($obj->ticket, $next['qb_action'], $next['ident'], QUICKBOOKS_STATUS_PROCESSING);
				$this->_driver->queueStatus($obj->ticket, $next['quickbooks_queue_id'], QUICKBOOKS_STATUS_PROCESSING);

				/*
				// Here's a strange case, interactive mode handler
				if ($next['qb_action'] == QUICKBOOKS_INTERACTIVE_MODE)
				{
					// Set the error to "Interactive mode"
					$this->_driver->errorLog($obj->ticket, QUICKBOOKS_ERROR_OK, QUICKBOOKS_INTERACTIVE_MODE);

					// This will cause ->getLastError() to be called, and ->getLastError() will then return the string "Interactive mode" which will cause QuickBooks to call ->getInteractiveURL() and start an interactive session... I think...?
					return new QuickBooks_Result_SendRequestXML('');
				}
				*/

				$extra = '';
				if ($next['extra'])
				{
					$extra = unserialize($next['extra']);
				}

				$err = '';
				$xml = '';

				//$last_action_time = $this->_driver->queueActionLast($user, $next['qb_action']);
				//$last_actionident_time = $this->_driver->queueActionIdentLast($user, $next['qb_action'], $next['ident']);
				$last_action_time = null;
				$last_actionident_time = null;

				// Call the mapped function that should generate an appropriate qbXML request
				$xml = $this->_callMappedFunction(0, $user, $next['quickbooks_queue_id'], $next['qb_action'], $next['ident'], $extra, $err, $last_action_time, $last_actionident_time, $obj->qbXMLMajorVers . '.' . $obj->qbXMLMinorVers, $obj->qbXMLCountry, $next['qbxml']);

				// Make sure there's no whitespace around it
				$xml = trim($xml);

				// NoOp can be returned to skip this current operation. This will cause getLastError
				//	to be called, at which point NoOp should be returned to tell the Web
				//	Connector to then pause for 5 seconds before asking for another request.
				if ($xml == QUICKBOOKS_NOOP)
				{
					$this->_driver->errorLog($obj->ticket, 0, QUICKBOOKS_NOOP);

					// Mark it as a NoOp to remove it from the queue
					//$this->_driver->queueStatus($obj->ticket, $next['qb_action'], $next['ident'], QUICKBOOKS_STATUS_NOOP, 'Handler function returned: ' . QUICKBOOKS_NOOP);
					$this->_driver->queueStatus($obj->ticket, $next['quickbooks_queue_id'], QUICKBOOKS_STATUS_NOOP, 'Handler function returned: ' . QUICKBOOKS_NOOP);

					return new QuickBooks_WebConnector_Result_SendRequestXML('');
				}

				// If the requestID="..." attribute was not specified, we can try to automatically add it to the request
				$requestID = null;
				if (!($requestID = $this->_extractRequestID($xml)) and
					$this->_config['autoadd_missing_requestid'])
				{
					// Find the <DoSomethingRq tag

					foreach (QuickBooks_Utilities::listActions() as $action)
					{
						$request = QuickBooks_Utilities::actionToRequest($action);
						if (false !== strpos($xml, '<' . $request . ' '))
						{
							//$xml = str_replace('<' . $request . ' ', '<' . $request . ' requestID="' . $this->_constructRequestID($next['qb_action'], $next['ident']) . '" ', $xml);
							$xml = str_replace('<' . $request . ' ', '<' . $request . ' requestID="' . $next['quickbooks_queue_id'] . '" ', $xml);
							break;
						}
						else if (false !== strpos($xml, '<' . $request . '>'))
						{
							//$xml = str_replace('<' . $request . '>', '<' . $request . ' requestID="' . $this->_constructRequestID($next['qb_action'], $next['ident']) . '">', $xml);
							$xml = str_replace('<' . $request . '>', '<' . $request . ' requestID="' . $next['quickbooks_queue_id'] . '">', $xml);
							break;
						}
					}
				}
				else if ($this->_config['check_valid_requestid'])
				{
					// They embedded a requestID="..." attribute, let's make sure it's valid

					//$embedded_action = null;
					//$embedded_ident = null;
					//$this->_parseRequestID($requestID, $embedded_action, $embedded_ident);

					//if ($embedded_action != $next['qb_action'] or $embedded_ident != $next['ident'])
					if ($next['quickbooks_queue_id'] != $requestID)
					{
						// They are sending this request with an INVALID requestID! Error this out and warn them!

						$err = 'This request contains an invalid embedded requestID="..." attribute; either embed the $requestID parameter, or leave out the requestID="..." attribute entirely, found [' . $requestID . ' vs. expected ' . $next['quickbooks_queue_id'] . ']!';
					}
				}

				/*
				if ($this->_config['convert_unix_newlines'] and
					false === strpos($xml, "\r") and 				// there are currently no Windows newlines...
					false !== strpos($xml, "\n"))					// ... but there *are* Unix newlines!
				{
					; // (this is currently broken/unimplemented)
				}
				*/

				if ($err) // The function encountered an error when generating the qbXML request
				{
					//$this->_driver->errorLog($obj->ticket, QUICKBOOKS_ERROR_HANDLER, $err);
					//$this->_driver->log('ERROR: ' . $err, $obj->ticket, QUICKBOOKS_LOG_NORMAL);
					//$this->_driver->queueStatus($obj->ticket, $next['qb_action'], $next['ident'], QUICKBOOKS_STATUS_ERROR, 'Registered handler returned error: ' . $err);

					$errerr = '';
					//$this->_handleError($obj->ticket, QUICKBOOKS_ERROR_HANDLER, $err, $this->_constructRequestID($next['qb_action'], $next['ident']), $next['qb_action'], $next['ident'], $extra, $errerr, $xml);
					$this->_handleError($obj->ticket, QUICKBOOKS_ERROR_HANDLER, $err, $next['quickbooks_queue_id'], $next['qb_action'], $next['ident'], $extra, $errerr, $xml);

					return new QuickBooks_WebConnector_Result_SendRequestXML('');
				}
				else
				{
					//$this->_driver->log('Outgoing XML request: ' . $xml, $obj->ticket, QUICKBOOKS_LOG_DEBUG);
					$this->_log('Outgoing XML request: ' . $xml, $obj->ticket, QUICKBOOKS_LOG_DEBUG);

					if (strlen($xml) and  // Returned XML AND
						!$this->_extractRequestID($xml)) // Does not have a requestID in the request
					{
						// Mark it as successful right now
						//$this->_driver->queueStatus($obj->ticket, $next['qb_action'], $next['ident'], QUICKBOOKS_STATUS_SUCCESS, 'Unverified... no requestID attribute in XML stream.');
						$this->_driver->queueStatus($obj->ticket, $next['quickbooks_queue_id'], QUICKBOOKS_STATUS_SUCCESS, 'Unverified... no requestID attribute in XML stream.');
					}

					return new QuickBooks_WebConnector_Result_SendRequestXML($xml);
				}
			}
		}

		// Reporting an error, this will cause the QBWC to call ->getLastError()
		return new QuickBooks_WebConnector_Result_SendRequestXML('');
	}
SendRequestXML method for the QuickBooks Web Connector SOAP server - Generate and send a request to QuickBooks

The QuickBooks Web Connector calls this method to ask for things to do.
So, calling this method is the Web Connectors way of saying: "Please
send me a command so that I can pass that command on to QuickBooks."
After it passes the command to QuickBooks, it will pass the response
back via a call to receiveResponseXML().

The stdClass object passed as a parameter should contain these members:
- ticket				The login session ticket
- strHCPResponse
- strCompanyFileName
- qbXMLCountry			The country code for whatever version of QuickBooks is sitting behind the Web Connector
- qbXMLMajorVers		The major version code of the QuickBooks web connector
- qbXMLMinorVers 		The minor version code of the QuickBooks web connector

You should return either an empty string "" to signal an error state, or
a valid qbXML or qbposXML request.

The following user-defined hooks are invoked by this method:
- QUICKBOOKS_HANDLERS_HOOK_SENDREQUESTXML

@param stdClass $obj
@return QuickBooks_Result_SendRequestXML