diff --git a/api_objDef.php b/api_objDef.php
index 7eeb7f0..6408aad 100644
--- a/api_objDef.php
+++ b/api_objDef.php
@@ -24,12 +24,21 @@ public function __construct(simpleXmlElement $simpleXml) {
$this->Description = (string)$simpleXml->Attributes->Description;
$fields = $simpleXml->Fields;
-
$this->Fields = array();
+
foreach($fields->Field as $field) {
$fieldDef = new api_fieldDef($field);
$this->Fields[$fieldDef->Name] = $fieldDef;
}
}
-}
\ No newline at end of file
+ public function get_field_array()
+ {
+ $array = array();
+ foreach ($this->Fields as $field) {
+ $array[] = (string)$field->Name;
+ }
+ return $array;
+ }
+
+}
diff --git a/api_post.php b/api_post.php
index 16a3c66..23c0b9b 100755
--- a/api_post.php
+++ b/api_post.php
@@ -1,4 +1,4 @@
-
+$id$fields$response_type";
+ $response = api_post::post($readXml, $session);
+ api_post::validateReadResults($response);
+ switch ($response_type) {
+ case 'xml':
+ $resultRecallsArr = new SimpleXMLElement($response);
+ $result = $resultRecallsArr->operation->result->data;
+ break;
+ case 'csv':
+ $objAry = api_util::csvToPhp($response);
+ if (count(explode(",",$id)) > 1) {
+ $result = $objAry;
+ }
+ else {
+ $result = $objAry[0];
+ }
+ break;
+ default:
+ $result = false;
+ break;
+ }
+ return $result;
+ }
+
+ /**
+ * ReadDocument one or more records by their key. For platform objects, the key is the 'id' field.
+ * For standard objects, the key is the 'recordno' field. Results are returned as a php structured array
* @param String $object the integration name for the object
+ * @param String $docparid the transaction type
* @param String $id a comma separated list of keys for each record you wish to read
* @param String $fields a comma separated list of fields to return
* @param \api_session|Object $session an instance of the php_session object
* @return Array of records
*/
- public static function read($object, $id, $fields, api_session $session) {
+ public static function readDocument($object, $docparid, $id, $fields, api_session $session) {
- $readXml = "$id$fieldscsv";
+ $readXml = "$id$fieldscsv$docparid";
$objCsv = api_post::post($readXml, $session);
api_post::validateReadResults($objCsv);
$objAry = api_util::csvToPhp($objCsv);
@@ -49,7 +88,7 @@ public static function read($object, $id, $fields, api_session $session) {
* @throws Exception
* @return Array array of keys to the objects created
*/
- public static function create($records, api_session $session) {
+ public static function create($records, api_session $session,$policy=null) {
if (count($records) > 100) throw new Exception("Attempting to create more than 100 records. (" . count($records) . ") ");
@@ -63,9 +102,11 @@ public static function create($records, api_session $session) {
$createXml = $createXml . $objXml;
}
$createXml = $createXml . "";
- $res = api_post::post($createXml, $session);
+ $res = api_post::post($createXml, $session, "3.0", false, $policy);
+ if ($policy !== null) {
+ return $res;
+ }
$records = api_post::processUpdateResults($res, $node);
-
return $records;
}
@@ -82,7 +123,7 @@ public static function create($records, api_session $session) {
* @return array An array of 'ids' updated in the method invocation
*/
public static function update($records, api_session $session) {
- if (count($records) > 100) throw new Exception("Attempting to update more than 100 records.");
+ if (count($records) > 10000) throw new Exception("Attempting to update more than 10000 records.");
// convert the $records array into an xml structure
$updateXml = "";
@@ -167,7 +208,7 @@ public static function upsert($object, $records, $nameField, $keyField, api_sess
unset($toCreate[$key][$object][$nameField]);
}
}
- api_post::create($toCreate, $session);
+ return api_post::create($toCreate, $session);
}
if (count($toUpdate) > 0) {
foreach ($toUpdate as $updateKey => $updateRec) {
@@ -176,7 +217,7 @@ public static function upsert($object, $records, $nameField, $keyField, api_sess
unset($toUpdate[$updateKey][$object][$nameField]);
}
}
- api_post::update($toUpdate, $session);
+ return api_post::update($toUpdate, $session);
}
}
}
@@ -188,9 +229,9 @@ public static function upsert($object, $records, $nameField, $keyField, api_sess
* objects and 'recordno' values for standard objects
* @param api_session $session instance of api_session object
*/
- public static function delete($object, $ids, api_session $session) {
+ public static function delete($object, $ids, api_session $session,$policy=null) {
$deleteXml = "$ids";
- api_post::post($deleteXml, $session);
+ api_post::post($deleteXml, $session,"3.0",false,$policy);
}
/**
@@ -205,6 +246,15 @@ public static function otherMethod($xml, api_session $session, $dtdVersion="3.0"
return api_post::post($xml, $session,$dtdVersion);
}
+ public static function send_xml($xml, api_session $session) {
+ return api_post::post("$xml", $session,"3.0",true);
+ }
+
+ public static function get_xml($obj) {
+ $xml = api_util::phpToXml('content',array($obj));
+ return $xml;
+ }
+
/**
* Run any Intacct API method not directly implemented in this class. You must pass
* valid XML for the method you wish to invoke.
@@ -221,16 +271,98 @@ public static function call21Method($function, $phpObj, api_session $session) {
/**
* Run any Intacct API method not directly implemented in this class. You must pass
* valid XML for the method you wish to invoke.
- * @param Array $phpObj an array for all the functions .
+ * @param Array $phpObj an array for all the functions .
* @param api_session $session an api_session instance with a valid connection
* @param string $dtdVersion DTD Version. Either "2.1" or "3.0". Defaults to "2.1"
* @return String the XML response from Intacct
*/
- public static function sendFunctions($phpObj, api_session $session, $dtdVersion="2.1") {
+ public static function sendFunctions($phpObj, api_session $session, $dtdVersion="3.0", $returnFormat = api_returnFormat::XML,$policy = null) {
$xml = api_util::phpToXml('content',array($phpObj));
- return api_post::post($xml, $session,$dtdVersion, true);
+ $res = api_post::post($xml, $session,$dtdVersion, true, $policy);
+ if ($returnFormat == api_returnFormat::PHPOBJ) {
+ $res_xml = simplexml_load_string($res);
+ $json = json_encode($res_xml->operation->result->data,JSON_FORCE_OBJECT);
+ $array = json_decode($json,TRUE);
+ return $array;
+ } else {
+ return $res;
+ }
+ }
+
+ public static function prune_empty_element($a) {
+ foreach ($a as $k => $v) {
+ if (is_array($v) && empty($v)) {
+ $a[$k] = "";
+ }
+ }
+ return $a;
}
+ /**
+ * Run any Intacct API method not directly implemented in this class. You must pass
+ * valid XML for the method you wish to invoke.
+ * @param Array $phpObj an array for all the functions .
+ * @param api_session $session an api_session instance with a valid connection
+ * @param string $dtdVersion DTD Version. Either "2.1" or "3.0". Defaults to "2.1"
+ * @return String the XML response from Intacct
+ */
+ public static function query(api_session $session, $call, int $limit = null, $returnFormat = api_returnFormat::PHPOBJ) {
+ $obj = $call['object'];
+ $call['offset'] = $call['offset'] ?? '0';
+ $call['pagesize'] = $call['pagesize'] ?? '100';
+ if ($limit !== null) {
+ $call['pagesize'] = min($limit,$call['pagesize']);
+ }
+
+ $phpObj = array (
+ 'function' => array (
+ '@controlid' => uniqid(),
+ 'query' => $call,
+ )
+ );
+ $rows = array();
+ dbg("**RBQ**: (QUERY) " . $obj );
+
+ do {
+ $xml = api_util::phpToXml('content',array($phpObj));
+ $res = api_post::post($xml, $session,'3.0', true);
+ //dbg($res);
+ $res_xml = simplexml_load_string($res);
+ $json = json_encode($res_xml->operation->result->data,JSON_FORCE_OBJECT);
+ $array = json_decode($json,TRUE);
+ if (!isset($array[$obj])) {
+ $array[$obj] = array();
+ } else if (!is_numeric(key($array[$obj]))) {
+ $array[$obj] = array(
+ $array[$obj]
+ );
+ }
+
+ $row = array_map(array('api_post','prune_empty_element'),$array[$obj]);
+ //dbg("READ this many rows" . count($row));
+ $rows = array_merge($rows,$row);
+ $num_remaining = $array['@attributes']['numremaining'];
+ $total = count($rows);
+ if ($num_remaining > 0 && $limit !== null) {
+ $num_remaining = min($limit - $total,$num_remaining);
+ }
+
+ $phpObj['function']['query']['offset'] += $phpObj['function']['query']['pagesize'] ;
+ dbg("REMAINING: $num_remaining. OFFSET is now : " . $phpObj['function']['query']['offset']);
+
+ if ($limit !== null && $phpObj['function']['query']['offset'] >= $limit) {
+ $num_remaining = 0;
+ }
+ dbg(" **NUM REMAINING**: " . $num_remaining);
+
+ } while ($num_remaining > 0);
+
+ if ($returnFormat == api_returnFormat::PHPOBJ) {
+ return $rows;
+ } else {
+ die("only php return format supported");
+ }
+ }
/**
* Run any Intacct API method not directly implemented in this class. You must pass
* valid XML for the method you wish to invoke.
@@ -240,9 +372,12 @@ public static function sendFunctions($phpObj, api_session $session, $dtdVersion=
* @param string $dtdVersion DTD Version. Either "2.1" or "3.0". Defaults to "2.1"
* @return String the XML response from Intacct
*/
- public static function get_list($object, $filter, $sorts, $fields, api_session $session, $dtdVersion="2.1") {
+ public static function get_list($object, $filter, $sorts, $fields, api_session $session, $dtdVersion="2.1", $max_desired = null) {
$get_list = array();
$get_list['@object'] = $object;
+ $get_list['@start'] = 0;
+ $get_list['@maxitems'] = min(1000,$max_desired);
+
if ($filter != null) {
$get_list['filter'] = $filter;
}
@@ -259,15 +394,67 @@ public static function get_list($object, $filter, $sorts, $fields, api_session $
);
$xml = api_util::phpToXml('content',array($func));
- $res = api_post::post($xml, $session,$dtdVersion, true);
+ $res = api_post::post($xml, $session,$dtdVersion, true);
+ if (self::$dryRun == true) {
+ return;
+ }
$ret = api_post::processListResults($res, api_returnFormat::PHPOBJ, $count);
- $toReturn = $ret[$object];
+ $toReturn = null;
+ if (array_key_exists($object,$ret)) {
+ $toReturn = $ret[$object];
+ } else {
+ return array();
+ }
if (is_array($toReturn)) {
$keys = array_keys($toReturn);
if (!is_numeric($keys[0])) {
$toReturn = array ($toReturn);
}
}
+
+ // now get more if there are any
+ $xml = simplexml_load_string($res);
+ $total = $xml->operation->result->listtype;
+ $attrs = $total->attributes();
+ $total = $attrs['total'];
+ $c = count($toReturn);
+
+ if ($c < $total && ($max_desired == null || $c < $max_desired )) {
+
+ do {
+ dbg("FETCH MORE " . count($toReturn) . " of $total ($max_desired)");
+ // we need to fetch more
+ $get_list['@start'] = count($toReturn);
+ $func['function'] = array();
+
+ $func['function'][] = array (
+ '@controlid' => 'control1',
+ 'get_list' => $get_list
+ );
+
+ $xml = api_util::phpToXml('content',array($func));
+ $res = api_post::post($xml, $session,$dtdVersion, true);
+ $ret = api_post::processListResults($res, api_returnFormat::PHPOBJ, $count);
+
+ if (!is_array($ret) || empty($ret)) {
+ break;
+ }
+
+ $nextBatch = null;
+ if (array_key_exists($object,$ret)) {
+ $nextBatch = $ret[$object];
+ }
+ if (is_array($nextBatch)) {
+ $keys = array_keys($nextBatch);
+ if (!is_numeric($keys[0])) {
+ $nextBatch = array ($nextBatch);
+ }
+ }
+ $toReturn = array_merge($toReturn,$nextBatch);
+
+ } while ( count($toReturn) < $total) ;
+ }
+
return $toReturn;
}
@@ -349,7 +536,7 @@ public static function readView($viewName, api_session $session, api_viewFilters
// append all but the first row to the CSV file
$page = explode("\n", $page);
array_shift($page);
- $csv .= implode($page, "\n");
+ $csv .= implode("\n",$page);
}
elseif ($returnFormat == api_returnFormat::XML) {
// just add the xml string
@@ -377,6 +564,7 @@ public static function readView($viewName, api_session $session, api_viewFilters
* @return mixed either string or array of objects depending on returnFormat argument
*/
public static function readByQuery($object, $query, $fields, api_session $session, $maxRecords=self::DEFAULT_MAXRETURN, $returnFormat=api_returnFormat::PHPOBJ) {
+ dbg("RBQ: $object -> $query with $fields");
$pageSize = ($maxRecords <= self::DEFAULT_PAGESIZE) ? $maxRecords : self::DEFAULT_PAGESIZE;
@@ -393,6 +581,205 @@ public static function readByQuery($object, $query, $fields, api_session $sessio
$readXml = "$query$fields$returnFormatArg";
$readXml .= "$pageSize";
$readXml .= "";
+ //dbg($readXml);
+
+ $response = api_post::post($readXml,$session);
+ if ($returnFormatArg == api_returnFormat::CSV && trim($response) == "") {
+ // csv with no records will have no response, so avoid the error from validate and just return
+ return '';
+ }
+ if ($object == 'PROJECT') {
+ dbg(api_post::getLastRequest());
+ dbg($response);
+ }
+ api_post::validateReadResults($response);
+
+
+ $phpobj = array(); $csv = ''; $json = ''; $xml = ''; $count = 0; $thiscount = 0;
+ $$returnFormat = self::processReadResults($response, $returnFormat, $thiscount);
+
+ $totalcount = $thiscount;
+ //dbg("$thiscount == $pageSize && $totalcount <= $maxRecords");
+
+ // we have no idea if there are more if CSV is returned, so just check
+ // if the last count returned was $pageSize
+ while($thiscount == $pageSize && $totalcount < $maxRecords) {
+ $readXml = "";
+ try {
+ $response = api_post::post($readXml, $session);
+ if ($object == 'PROJECT') {
+ dbg("READMORE PROJECT");
+ dbg(api_post::getLastRequest());
+ dbg($response);
+ }
+ api_post::validateReadResults($response);
+ $page = self::processReadResults($response, $returnFormat, $pageCount);
+ $totalcount += $pageCount;
+ $thiscount = $pageCount;
+
+ switch($returnFormat) {
+ case api_returnFormat::PHPOBJ:
+ foreach($page as $objRec) {
+ $phpobj[] = $objRec;
+ }
+ break;
+ case api_returnFormat::CSV:
+ $page = explode("\n", $page);
+ array_shift($page);
+ $csv .= implode("\n",$page);
+ break;
+ case api_returnFormat::XML:
+ $xml .= $page;
+ break;
+ default:
+ throw new Exception("Invalid return format: " . $returnFormat);
+ break;
+ }
+ dbg("READMORE GOT: $thiscount, Total now: $totalcount");
+
+ }
+ catch (Exception $ex) {
+ // we've probably exceeded the limit
+ break;
+ }
+ }
+ return $$returnFormat;
+ }
+ /**
+ * Read records using a query. Specify the object you want to query and something like a "where" clause"
+ * @param api_session $session An instance of the api_session object with a valid connection
+ * @param String $object the object upon which to run the query
+ * @param String $fields A comma separated list of fields to return
+ * @param String $query the query string to execute. Use SQL operators
+ * @param int $maxRecords number of records to return. Defaults to 100000
+ * @param string $returnFormat defaults to php object. Pass one of the valid constants from api_returnFormat class
+ * @return mixed either string or array of objects depending on returnFormat argument
+ */
+ public static function query_bad(api_session $session, $object, $fields=null, $query=null, $maxRecords=self::DEFAULT_MAXRETURN, $returnFormat=api_returnFormat::PHPOBJ) {
+
+ $pageSize = ($maxRecords <= self::DEFAULT_PAGESIZE) ? $maxRecords : self::DEFAULT_PAGESIZE;
+
+ if ($returnFormat == api_returnFormat::PHPOBJ) {
+ $returnFormatArg = api_returnFormat::CSV;
+ }
+ else {
+ $returnFormatArg = $returnFormat;
+ }
+
+ $field_xml = "";
+ if ($fields !== null) {
+ $field_xml = "" . str_replace(",","",$fields) . "";
+ }
+ if ($query !== NULL) {
+ $query_xml = api_util::phpToXml($query);
+
+ }
+
+ // TODO: Implement returnFormat. Today we only support PHPOBJ
+// $query = HTMLSpecialChars($query);
+
+ $readXml = "$query_xml";
+ $readXml .= "$pageSize";
+ $readXml .= "";
+ //dbg($readXml);
+
+ $response = api_post::post($readXml,$session);
+ //dbg($response);
+ die();
+ if ($returnFormatArg == api_returnFormat::CSV && trim($response) == "") {
+ // csv with no records will have no response, so avoid the error from validate and just return
+ return '';
+ }
+ api_post::validateReadResults($response);
+
+
+ $phpobj = array(); $xml = ''; $count = 0; $thiscount = 0;
+
+ $simpleXml = simplexml_load_string($response);
+ $data = $simpleXml->xpath("/response/operation/result/data");
+ $thiscount = $data[0]['count'];
+ $rows = $simpleXml->xpath("/response/operation/result/data/$object");
+ foreach ($rows as $row) {
+ $phpobj[] = (array)$row;
+ }
+
+ if ($data[0]['numremaining'])
+
+// $thiscount = $data->
+
+ //$$returnFormat = self::processReadResults($response, $returnFormat, $thiscount);
+
+ $totalcount = $thiscount;
+ //dbg("$thiscount == $pageSize && $totalcount <= $maxRecords");
+
+ // we have no idea if there are more if CSV is returned, so just check
+ // if the last count returned was $pageSize
+ while($thiscount == $pageSize && $totalcount < $maxRecords) {
+ $readXml = "";
+ try {
+ $response = api_post::post($readXml, $session);
+ //dbg($response);
+ //dbg(api_post::getLastRequest());
+ api_post::validateReadResults($response);
+ $page = self::processReadResults($response, $returnFormat, $pageCount);
+ $totalcount += $pageCount;
+ $thiscount = $pageCount;
+
+ switch($returnFormat) {
+ case api_returnFormat::PHPOBJ:
+ foreach($page as $objRec) {
+ $phpobj[] = $objRec;
+ }
+ break;
+ case api_returnFormat::CSV:
+ $page = explode("\n", $page);
+ array_shift($page);
+ $csv .= implode($page, "\n");
+ break;
+ case api_returnFormat::XML:
+ $xml .= $page;
+ break;
+ default:
+ throw new Exception("Invalid return format: " . $returnFormat);
+ break;
+ }
+
+ }
+ catch (Exception $ex) {
+ // we've probably exceeded the limit
+ break;
+ }
+ }
+ return $$returnFormat;
+ }
+ /**
+ * Read records using a query. Specify the object you want to query and something like a "where" clause"
+ * @param String $object the object upon which to run the query
+ * @param String $query the query string to execute. Use SQL operators
+ * @param String $fields A comma separated list of fields to return
+ * @param api_session $session An instance of the api_session object with a valid connection
+ * @param int $maxRecords number of records to return. Defaults to 100000
+ * @param string $returnFormat defaults to php object. Pass one of the valid constants from api_returnFormat class
+ * @return mixed either string or array of objects depending on returnFormat argument
+ */
+ public static function readDocumentByQuery($object, $docparid, $query, $fields, api_session $session, $maxRecords=self::DEFAULT_MAXRETURN, $returnFormat=api_returnFormat::PHPOBJ) {
+
+ $pageSize = ($maxRecords <= self::DEFAULT_PAGESIZE) ? $maxRecords : self::DEFAULT_PAGESIZE;
+
+ if ($returnFormat == api_returnFormat::PHPOBJ) {
+ $returnFormatArg = api_returnFormat::CSV;
+ }
+ else {
+ $returnFormatArg = $returnFormat;
+ }
+
+ // TODO: Implement returnFormat. Today we only support PHPOBJ
+ $query = HTMLSpecialChars($query);
+
+ $readXml = "$query$fields$returnFormatArg";
+ $readXml .= "$docparid";
+ $readXml .= "$pageSize";
+ $readXml .= "";
$response = api_post::post($readXml,$session);
if ($returnFormatArg == api_returnFormat::CSV && trim($response) == "") {
@@ -409,7 +796,7 @@ public static function readByQuery($object, $query, $fields, api_session $sessio
// we have no idea if there are more if CSV is returned, so just check
// if the last count returned was $pageSize
- while($thiscount == $pageSize && $totalcount <= $maxRecords) {
+ while($thiscount == $pageSize && $totalcount < $maxRecords) {
$readXml = "";
try {
$response = api_post::post($readXml, $session);
@@ -446,6 +833,7 @@ public static function readByQuery($object, $query, $fields, api_session $sessio
return $$returnFormat;
}
+
/**
* Inspect an object to get a list of its fields
*
@@ -504,8 +892,90 @@ public static function readByName($object, $name, $fields, api_session $session)
public static function readRelated($object, $keys, $relation, $fields, api_session $session) {
$readXml = "$keys$relation$fieldscsv";
$objCsv = api_post::post($readXml, $session);
+ //if we receive an empty response we return it
+ if (trim($objCsv) == "") {
+ return '';
+ }
+ api_post::validateReadResults($objCsv);
+ $objAry = api_util::csvToPhp($objCsv);
+ return $objAry;
+ }
+
+ /**
+ * Reads all the records related to a source record through a named relationship.
+ * @param String $object the integration name of the object
+ * @param String $keys a comma separated list of 'id' values of the source records from which you want to read related records
+ * @param String $relation the name of the relationship. This will determine the type of object you are reading
+ * @param String $fields a comma separated list of fields to return
+ * @param api_session $session
+ * @return Array of objects
+ */
+ public static function readReport($report, api_session $session, $arguments=null, $waitTime=0, $pageSize=100) {
+ $maxRecords = self::DEFAULT_MAXRETURN;
+ $max_try = 1000;
+ $try = 0;
+
+ if (is_array($arguments) ) {
+ $argxml= "";
+ foreach ($arguments as $key => $arg) {
+ $argxml.= "<$key>$arg$key>";
+ }
+ $argxml .= "";
+ }
+ $readXml = "$reportcsv$waitTime$argxml$pagesize";
+ $objCsv = api_post::post($readXml, $session);
api_post::validateReadResults($objCsv);
$objAry = api_util::csvToPhp($objCsv);
+
+ if (is_array($objAry) && count($objAry) == 1) {
+ $id = $objAry[0]['REPORTID'];
+ do {
+ $readXml = "$id";
+ try {
+ $response = api_post::post($readXml, $session);
+ //dbg("READMORE:");
+ //dbg($response);
+ //dbg("TRIMMED:");
+ //dbg(trim($response));
+ if (trim($response) == "") {
+ return array();
+ }
+ api_post::validateReadResults($response);
+ $_obj = api_util::csvToPhp($response);
+ if (isset($_obj[0]['STATUS']) && $_obj[0]['STATUS'] == 'PENDING') {
+ //dbg("Sleeping 10, try = $try");
+ sleep("10");
+ $try++;
+ continue;
+ }
+
+ $page = self::processReadResults($response, $returnFormat, $pageCount);
+ $count += $pageCount;
+ if ($returnFormat == api_returnFormat::PHPOBJ) {
+ foreach($page as $objRec) {
+ $phpobj[] = $objRec;
+ }
+ }
+ elseif ($returnFormat == api_returnFormat::CSV) {
+ // append all but the first row to the CSV file
+ $page = explode("\n", $page);
+ array_shift($page);
+ $csv .= implode($page, "\n");
+ }
+ elseif ($returnFormat == api_returnFormat::XML) {
+ // just add the xml string
+ $xml .= $page;
+ }
+ }
+ catch (Exception $ex) {
+ // for now, pass the exception on
+ Throw new Exception($ex);
+ }
+ if ($pageCount < $pageSize || $count >= $maxRecords) break;
+ } while ($try < $max_try);
+
+ //dbg("FINISHED LOOP");
+ }
return $objAry;
}
@@ -554,22 +1024,39 @@ public static function deleteAll($object, api_session $session, $max=10000) {
* @param Integer $max [optional] Maximum number of records to delete. Default is 10000
* @return Integer count of records deleted
*/
- public static function deleteByQuery($object, $query, api_session $session, $max=10000) {
+ public static function deleteByQuery($object, $query, $key_field, api_session $session, $max=100000) {
+ $num_per_func= 100;
// read all the record ids for the given object
- $ids = api_post::readByQuery($object, "id > 0 and $query", "id", $session, $max);
+ $ids = api_post::readByQuery($object, "$key_field > 0 and $query", $key_field, $session, $max);
+ if (!is_array($ids)) {
+ $ids = array();
+ }
if ((!is_array($ids) && trim($ids) == '') || !count($ids) > 0) {
return 0;
}
+ dbg("COUNT of things to delete: " . count($ids));
+
$count = 0;
$delIds = array();
+ $_count = count($ids);
+
foreach($ids as $rec) {
- $delIds[] = $rec['id'];
- if (count($delIds) == 100) {
- api_post::delete($object, implode(",", $delIds), $session);
- $count += 100;
+ $delIds[] = $rec[$key_field];
+ if (count($delIds) == $num_per_func) {
+ try {
+ $_count -= $num_per_func;
+ dbg($_count);
+ api_post::delete($object, implode(",", $delIds), $session);
+ }
+ catch (Exception $ex) {
+ $delIds = array();
+ print_r($ex);
+ continue;
+ }
+ $count += $num_per_func;
$delIds = array();
}
}
@@ -590,7 +1077,7 @@ public static function deleteByQuery($object, $query, api_session $session, $max
* @throws Exception
* @return String the XML response document
*/
- private static function post($xml, api_session $session, $dtdVersion="3.0",$multiFunc=false) {
+ private static function post($xml, api_session $session, $dtdVersion="3.0",$multiFunc=false, $policy=null) {
$sessionId = $session->sessionId;
$endPoint = $session->endPoint;
@@ -599,7 +1086,7 @@ private static function post($xml, api_session $session, $dtdVersion="3.0",$mult
$transaction = ( $session->transaction ) ? 'true' : 'false' ;
- /*
+ /*
$templateHead =
"
@@ -632,16 +1119,26 @@ private static function post($xml, api_session $session, $dtdVersion="3.0",$mult
*/
- $templateHead =
-"
+
+ // if self::$sage_appid is not empty we want to pass above senderid.
+
+ $templateHead = "
-
+ ";
+if (!empty(self::$sage_appid)) {
+ $templateHead .= "
+ " . self::$sage_appid . "";
+}
+$templateHead .= "
{$senderId}
{$senderPassword}
- foobar
+ ".uniqid()."
false
- {$dtdVersion}
-
+ {$dtdVersion}";
+ if ($policy !== null) {
+ $templateHead .= "$policy";
+ }
+ $templateHead .= "
{$sessionId}
@@ -651,7 +1148,7 @@ private static function post($xml, api_session $session, $dtdVersion="3.0",$mult
"
";
- $contentFoot =
+ $contentFoot =
"
";
@@ -669,6 +1166,7 @@ private static function post($xml, api_session $session, $dtdVersion="3.0",$mult
if (self::$dryRun == true) {
self::$lastRequest = $xml;
+ self::$lastResponse= null;
return;
}
@@ -677,20 +1175,40 @@ private static function post($xml, api_session $session, $dtdVersion="3.0",$mult
$res = "";
while (true) {
$res = api_post::execute($xml, $endPoint);
+ if ( strpos($res, "520 Origin") !== FALSE || strpos($res, "502 Bad Gateway") !== FALSE) {
+ $count++;
+ if ($count <= 5) {
+ dbg("RETRYING due to 520 or 502 error");
+ dbg("===REQUEST==============================");
+ dbg(api_post::getLastRequest());
+ dbg("===RESPONSE==============================");
+ dbg($res);
+ continue;
+ }
+ }
// If we didn't get a response, we had a poorly constructed XML request.
try {
api_post::validateResponse($res, $xml);
break;
- }
- catch (Exception $ex) {
+ } catch (Exception $ex) {
+ dbg("JPC EXCEPTION");
+ if ($count >= 5) {
+ throw new Exception($ex->getMessage(),$ex->getCode(),$ex);
+ }
+ dbg("EX getMessage");
+ dbg($ex->getMessage());
if (strpos($ex->getMessage(), "too many operations") !== false) {
$count++;
- if ($count >= 5) {
- throw new Exception($ex);
- }
+ } else if (strpos($ex->getMessage(), "UJPP0007") !== false) {
+ $count++;
+ dbg("Got UJPP007. Sleeping one minute and trying again.");
+ dbg("RESPONSE HEADER:");
+ dbg(self::$lastResponseHeader);
+ dbg("END RESPONSE HEADER:");
+ sleep(60);
} else {
- throw new Exception($ex);
+ throw new Exception($ex->getMessage(),$ex->getCode(),$ex);
}
}
}
@@ -708,29 +1226,55 @@ private static function post($xml, api_session $session, $dtdVersion="3.0",$mult
public static function execute($body, $endPoint) {
self::$lastRequest = $body;
+ self::$lastResponse = null;
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $endPoint );
- curl_setopt( $ch, CURLOPT_HEADER, 0 );
+ curl_setopt( $ch, CURLOPT_HEADER, true );
+ curl_setopt( $ch, CURLINFO_HEADER_OUT, true );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
- curl_setopt( $ch, CURLOPT_TIMEOUT, 3000 ); //Seconds until timeout
+ curl_setopt( $ch, CURLOPT_TIMEOUT, 6000 ); //Seconds until timeout
curl_setopt( $ch, CURLOPT_POST, 1 );
+ curl_setopt( $ch, CURLOPT_VERBOSE, 0);
// TODO: Research and correct the problem with CURLOPT_SSL_VERIFYPEER
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false); // yahoo doesn't like the api.intacct.com CA
$body = "xmlrequest=" . urlencode( $body );
- curl_setopt( $ch, CURLOPT_POSTFIELDS, $body );
+ curl_setopt( $ch, CURLOPT_POSTFIELDS, $body );
$response = curl_exec( $ch );
$error = curl_error($ch);
+ $code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
+
+ $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
+ $response_header = substr($response, 0, $header_size);
+ $response_body = substr($response, $header_size);
+ self::$lastResponse = $response_body;
+ self::$lastResponseHeader = $response_header;
+
+ if ($code != "200" || strpos($response,"UJPP00") !== FALSE ||
+ strpos($error,"transfer closed") !== FALSE ||
+ strpos($response,"cloudflare-nginx") !== FALSE ||
+ strpos($error,"cloudflare-nginx") !== FALSE ||
+ strpos($response,"") !== FALSE) {
+
+ dbg("SAGE ERROR FULL RESPONSE with header");
+ dbg($response);
+ dbg("RESPONSE BODY");
+ dbg($response_body);
+ dbg("SAGE ERROR REQUEST WAS");
+ dbg("SAGE ERROR " . self::$lastRequest);
+ }
+
if ($error != "") {
+ dbg("FULL RESPONSE with header");
+ dbg($response);
throw new exception($error);
}
curl_close( $ch );
- self::$lastResponse = $response;
- return $response;
+ return $response_body;
}
@@ -739,7 +1283,7 @@ public static function execute($body, $endPoint) {
* @param String $response The XML response document
* @throws Exception
*/
- public static function findResponseErrors($response) {
+ public static function findResponseErrors($response,$multi=false) {
$errorArray = array();
@@ -756,7 +1300,7 @@ public static function findResponseErrors($response) {
// look for a failure in the operation, but not the result
if (isset($simpleXml->operation->errormessage)) {
$error = $simpleXml->operation->errormessage->error[0];
- $errorArray[] = array ( 'desc' => api_util::xmlErrorToString($simpleXml->operation->errormessage));
+ $errorArray[] = array ( 'desc' => api_util::xmlErrorToString($simpleXml->operation->errormessage,$multi));
}
// if we didn't get an operation, the request failed and we should raise an exception
@@ -764,14 +1308,14 @@ public static function findResponseErrors($response) {
// did the method invocation fail?
if (!isset($simpleXml->operation)) {
if (isset($simpleXml->errormessage)) {
- $errorArray[] = array ( 'desc' => api_util::xmlErrorToString($simpleXml->errormessage));
+ $errorArray[] = array ( 'desc' => api_util::xmlErrorToString($simpleXml->errormessage,$multi));
}
}
else {
$results = $simpleXml->xpath('/response/operation/result');
foreach ($results as $result) {
- if ((string)$result->status == "failure") {
- $errorArray[] = array ( 'controlid' => (string)$result->controlid, 'desc' => api_util::xmlErrorToString($result->errormessage));
+ if ((string)$result->status == "failure" || (string)$result->status == "aborted") {
+ $errorArray[] = array ( 'controlid' => (string)$result->controlid, 'desc' => api_util::xmlErrorToString($result->errormessage,$multi));
}
}
}
@@ -808,11 +1352,12 @@ private static function validateResponse($response) {
throw new Exception("[Error] " . api_util::xmlErrorToString($simpleXml->errormessage));
}
}
- else {
+ else {
$results = $simpleXml->operation->result;
foreach ($results as $res) {
- if ($res->status == "failure") {
- throw new Exception("[Error] " . api_util::xmlErrorToString($res->errormessage));
+ if ($res->status == "failure" || $res->status == "aborted") {
+ $msg = api_util::xmlErrorToString($res->errormessage);
+ throw new Exception("[Error] " . $msg);
}
}
}
@@ -827,6 +1372,8 @@ private static function validateResponse($response) {
* @throws Exception
*/
private static function processUpdateResults($response, $objectName) {
+ //Fix Intacct bug, by trim spaces from the returned xml response string
+ $response = trim($response);
$simpleXml = simplexml_load_string($response);
if ($simpleXml === false) {
throw new Exception("Invalid XML response: \n " . var_export($response, true));
@@ -900,7 +1447,8 @@ private static function validateReadResults($response) {
* @throws Exception
* @return Mixed string or object depending on return format
*/
- public static function processListResults($response, $returnFormat = api_returnFormat::PHPOBJ, &$count) {
+ public static function processListResults($response, $returnFormat, &$count) {
+ //dbg($response);
$xml = simplexml_load_string($response);
@@ -909,14 +1457,59 @@ public static function processListResults($response, $returnFormat = api_returnF
throw new Exception("Get List failed");
return;
}
-
+
if ($returnFormat != api_returnFormat::PHPOBJ) {
throw new Exception("Only PHPOBJ is supported for returnFormat currently.");
return;
}
- $json = json_encode($xml->operation->result->data);
+ $json = json_encode($xml->operation->result->data,JSON_FORCE_OBJECT);
+ if ($json == "{}") {
+ return array();
+ }
+
$array = json_decode($json,TRUE);
+
+ $obj = key($array);
+
+ if (!is_numeric(key($array[$obj]))) {
+ $array[$obj] = array ( $array[$obj] );
+ }
+
+ // check for known line item issues
+ // lame, but not sure how else to fix this. the json_decode removes the level from a single line item and it needs to be restored
+ // make this generic if it works
+ if (isset($array['sotransaction'])) {
+ foreach ($array['sotransaction'] as $key => $txn) {
+ if (isset($txn['sotransitems']['sotransitem'])) {
+ if (!is_numeric(key($txn['sotransitems']['sotransitem']))) {
+ $array['sotransaction'][$key]['sotransitems']['sotransitem'] = array ($txn['sotransitems']['sotransitem']);
+ }
+ }
+ }
+ }
+ if (isset($array['dimensions'])) {
+ $array['dimensions'] = $array['dimensions'][0]['dimension'];
+ }
+ if (isset($array['arpayment'])) {
+ foreach ($array['arpayment'] as $key => $txn) {
+ if (isset($txn['lineitems']['lineitem'])) {
+ if (!is_numeric(key($txn['lineitems']['lineitem']))) {
+ $array['arpayment'][$key]['lineitems']['lineitem'] = array ($txn['lineitems']['lineitem']);
+ }
+ }
+ }
+ }
+
+ if (isset($array['recursotransaction'])) {
+ foreach ($array['recursotransaction'] as $key => $txn) {
+ if (isset($txn['recursotransitems']['recursotransitem'])) {
+ if (!is_numeric(key($txn['recursotransitems']['recursotransitem']))) {
+ $array['recursotransaction'][$key]['recursotransitems']['recursotransitem'] = array ($txn['recursotransitems']['recursotransitem']);
+ }
+ }
+ }
+ }
return $array;
}
@@ -928,7 +1521,7 @@ public static function processListResults($response, $returnFormat = api_returnF
* @throws Exception
* @return Mixed string or object depending on return format
*/
- private static function processReadResults($response, $returnFormat = api_returnFormat::PHPOBJ, &$count) {
+ private static function processReadResults($response, $returnFormat, &$count) {
$objAry = array(); $csv = ''; $json = ''; $xml = '';
if ($returnFormat == api_returnFormat::PHPOBJ) {
$objAry = api_util::csvToPhp($response);
@@ -980,9 +1573,18 @@ public static function getLastResponse() {
return self::$lastResponse;
}
+ public static function getLastResponseHeader() {
+ return self::$lastResponseHeader;
+ }
+
public static function setDryRun($tf=true)
{
self::$dryRun = $tf;
}
-
+
+ public static function setAppID($id)
+ {
+ self::$sage_appid = $id;
+ }
+
}
diff --git a/api_returnFormat.php b/api_returnFormat.php
index 1f2fbb0..6272530 100755
--- a/api_returnFormat.php
+++ b/api_returnFormat.php
@@ -1,4 +1,4 @@
-
+
";
+ const XML_FOOTER_2 = "
+
+ {6%}
+
+
+";
const XML_LOGIN = "
{1%}
@@ -40,7 +47,22 @@ class api_session {
const XML_SESSIONID = "{1%}";
const DEFAULT_LOGIN_URL = "https://api.intacct.com/ia/xml/xmlgw.phtml";
-
+ const PRV_LOGIN_URL = "https://preview.intacct.com/ia/xml/xmlgw.phtml";
+
+ public function __toString() {
+ $temp = array (
+ 'sessionId' => $this->sessionId,
+ 'endPoint' => $this->endPoint,
+ 'companyId' => $this->companyId,
+ 'entityId' => $this->entityId,
+ 'userId' => $this->userId,
+ 'senderId' => $this->senderId,
+ 'entityId' => $this->entityId,
+ 'senderPassword' => 'REDACTED',
+ 'transaction' => $this->transaction
+ );
+ return json_encode($temp);
+ }
/**
* Connect to the Intacct Web Service using a set of user credntials for a subentity
@@ -53,7 +75,7 @@ class api_session {
* @param String $entityId The sub entity id
* @throws Exception this method returns no value, but will raise any connection exceptions
*/
- private function buildHeaderXML($companyId, $userId, $password, $senderId, $senderPassword, $entityType = null, $entityId = null )
+ private function buildHeaderXML($companyId, $userId, $password, $senderId, $senderPassword, $entityType = null, $entityId = null )
{
$xml = self::XML_HEADER . self::XML_LOGIN . self::XML_FOOTER;
@@ -62,15 +84,16 @@ private function buildHeaderXML($companyId, $userId, $password, $senderId, $send
$xml = str_replace("{2%}", $companyId, $xml);
$xml = str_replace("{3%}", $password, $xml);
$xml = str_replace("{4%}", $senderId, $xml);
- $xml = str_replace("{5%}", $senderPassword, $xml);
+ $xml = str_replace("{5%}", htmlspecialchars($senderPassword), $xml);
- if ($entityType == 'location') {
+ // hack for backward compat
+ if ($entityType == 'location' || $entityType === null) {
$xml = str_replace("{%entityid%}", "$entityId", $xml);
- }
- else if ($entityType == 'client') {
+ } else if ($entityType == 'client') {
$xml = str_replace("{%entityid%}", "$entityId", $xml);
- }
- else {
+ } else if (!empty($entityType) || !empty($entityId)) {
+ $xml = str_replace("{%entityid%}", "$entityType$entityId", $xml);
+ } else {
$xml = str_replace("{%entityid%}", "", $xml);
}
@@ -88,9 +111,10 @@ private function buildHeaderXML($companyId, $userId, $password, $senderId, $send
*/
public function connectCredentials($companyId, $userId, $password, $senderId, $senderPassword, $entityType=null, $entityId=null) {
- $xml = $this->buildHeaderXML($companyId, $userId, $password, $senderId, $senderPassword, $entityType, $entityId);
+ $xml = $this->buildHeaderXML($companyId, $userId, $password, $senderId, $senderPassword, $entityType, $entityId);
- $response = api_post::execute($xml, self::DEFAULT_LOGIN_URL);
+ $endpoint = strpos($companyId,"-prv") === FALSE ? self::DEFAULT_LOGIN_URL : self::PRV_LOGIN_URL;
+ $response = api_post::execute($xml, $endpoint);
self::validateConnection($response);
@@ -98,6 +122,7 @@ public function connectCredentials($companyId, $userId, $password, $senderId, $s
$this->sessionId = (string)$responseObj->operation->result->data->api->sessionid;
$this->endPoint = (string)$responseObj->operation->result->data->api->endpoint;
+ $this->entityId = (string)$responseObj->operation->authentication->locationid;
$this->companyId = $companyId;
$this->userId = $userId;
$this->senderId = $senderId;
@@ -118,9 +143,10 @@ public function connectCredentials($companyId, $userId, $password, $senderId, $s
*/
public function connectCredentialsEntity($companyId, $userId, $password, $senderId, $senderPassword,$entityType, $entityId) {
- $xml = $this->buildHeaderXML($companyId, $userId, $password, $senderId, $senderPassword,$entityType, $entityId);
+ $xml = $this->buildHeaderXML($companyId, $userId, $password, $senderId, $senderPassword,$entityType, $entityId);
- $response = api_post::execute($xml, self::DEFAULT_LOGIN_URL);
+ $endpoint = strpos($companyId,"-prv") === FALSE ? self::DEFAULT_LOGIN_URL : self::PRV_LOGIN_URL;
+ $response = api_post::execute($xml, $endpoint);
self::validateConnection($response);
@@ -128,6 +154,7 @@ public function connectCredentialsEntity($companyId, $userId, $password, $sender
$this->sessionId = (string)$responseObj->operation->result->data->api->sessionid;
$this->endPoint = (string)$responseObj->operation->result->data->api->endpoint;
+ $this->entityId = (string)$responseObj->operation->authentication->locationid;
$this->companyId = $companyId;
$this->userId = $userId;
$this->senderId = $senderId;
@@ -143,14 +170,25 @@ public function connectCredentialsEntity($companyId, $userId, $password, $sender
* @param String $senderPassword Your Intacct partner password
* @throws Exception This method returns no values, but will raise an exception if there's a connection error
*/
- public function connectSessionId($sessionId, $senderId, $senderPassword) {
-
- $xml = self::XML_HEADER . self::XML_SESSIONID . self::XML_FOOTER;
+ public function connectSessionId($sessionId, $senderId, $senderPassword, $entityId = null) {
+
+ if ($entityId === null) {
+ // we are passing NO entity/location. do not add locationid to the XML
+ $xml = self::XML_HEADER . self::XML_SESSIONID . self::XML_FOOTER;
+ } else {
+ // we are passing entity/location ('' for top-level flip from entity). add locationid to the XML
+ $xml = self::XML_HEADER . self::XML_SESSIONID . self::XML_FOOTER_2;
+ }
+
$xml = str_replace("{1%}", $sessionId, $xml);
$xml = str_replace("{4%}", $senderId, $xml);
$xml = str_replace("{5%}", $senderPassword, $xml);
+ if ($entityId !== null) {
+ $xml = str_replace("{6%}", $entityId, $xml);
+ }
- $response = api_post::execute($xml, self::DEFAULT_LOGIN_URL);
+ $endpoint = ($this->companyId === null || strpos($this->companyId,"-prv") === FALSE) ? self::DEFAULT_LOGIN_URL : self::PRV_LOGIN_URL;
+ $response = api_post::execute($xml, $endpoint);
self::validateConnection($response);
@@ -159,6 +197,7 @@ public function connectSessionId($sessionId, $senderId, $senderPassword) {
$this->companyId = (string)$responseObj->operation->authentication->companyid;
$this->userId = (string)$responseObj->operation->authentication->userid;
$this->endPoint = (string)$responseObj->operation->result->data->api->endpoint;
+ $this->entityId = (string)$responseObj->operation->authentication->locationid;
$this->senderId = $senderId;
$this->senderPassword = $senderPassword;
}
@@ -181,8 +220,10 @@ private static function validateConnection($response) {
if (isset($simpleXml->operation->authentication->status)) {
if ($simpleXml->operation->authentication->status != 'success') {
+ print_r($simpleXml);
$error = $simpleXml->operation->errormessage;
- throw new Exception(" [Error] " . (string)$error->error[0]->description2);
+ $desc2 = (string)$error->error[0]->description2 ?? '';
+ throw new Exception(" [Error] " . $desc2);
}
}
diff --git a/api_util.php b/api_util.php
index 97b898b..c133ab5 100755
--- a/api_util.php
+++ b/api_util.php
@@ -1,4 +1,4 @@
-
+modify("-1 day");
$dates = array($dateTime->format("Y-m-d"));
- // now, iterate $count - 1 times adding one month to each
+ // now, iterate $count - 1 times adding one month to each
for ($x=1; $x < $count; $x++) {
$dateTime->modify("+1 day");
$dateTime->modify("+1 month");
@@ -91,11 +91,11 @@ public static function getRangeOfDates($date, $count) {
return $dates;
}
- /**
- * Convert a php structure to an XML element
+ /**
+ * Convert a php structure to an XML element
* @param String $key element name
* @param Array $values element values
- * @return string xml
+ * @return string xml
*/
public static function phpToXml($key, $values) {
$xml = "";
@@ -103,13 +103,15 @@ public static function phpToXml($key, $values) {
return "<$key>$values$key>";
}
- if (!is_numeric(array_shift(array_keys($values)))) {
+ $temp1 = array_keys($values);
+ $temp2 = array_shift($temp1);
+ if (!is_numeric($temp2)) {
$xml = "<" . $key . ">";
}
foreach($values as $node => $value) {
$attrString = "";
$_xml = "";
- if (is_array($value)) {
+ if (is_array($value) && count($value) > 0) {
if (is_numeric($node)) {
$node = $key;
}
@@ -119,7 +121,7 @@ public static function phpToXml($key, $values) {
if (substr($_k,0,1) == '@') {
$pad = ($attrString == "") ? " " : "";
$aname = substr($_k,1);
- $aval = $v;
+ $aval = htmlspecialchars($v);
//$attrs = explode(':', substr($v,1));
//$attrString .= $pad . $attrs[0].'="'.$attrs[1].'" ';
$attrString .= $pad . $aname.'="'.$aval.'" ';
@@ -128,13 +130,17 @@ public static function phpToXml($key, $values) {
}
}
- $firstKey = array_shift(array_keys($value));
- if (is_array($value[$firstKey]) || count($value) > 1 ) {
- $_xml = self::phpToXml($node,$value) ;
+ $valuekeys = array_keys($value);
+ $firstKey = array_shift($valuekeys);
+ if (is_array($value) && (( isset($value[$firstKey]) && is_array($value[$firstKey])) || count($value) > 0)) {
+ $_xml = self::phpToXml($node,$value) ;
}
else {
- $v = $value[$firstKey];
- $_xml .= "<$node>" . htmlspecialchars($v) . "$node>";
+ $_xml = self::phpToXml($node,$value) ;
+ $v = $value[$firstKey] ?? '';
+ if (!empty($v)) {
+ $_xml .= "<$node>" . htmlspecialchars($v) . "$node>";
+ }
}
if ($attrString != "") {
@@ -142,36 +148,48 @@ public static function phpToXml($key, $values) {
}
$xml .= $_xml;
+// dbg("XML now is $xml");
}
else {
- $xml .= "<" . $node . $attrString . ">" . htmlspecialchars($value) . "" . $node . ">";
+ if (is_numeric($node)) {
+ $xml .= "<" . $key. $attrString . ">" . htmlspecialchars($value) . "" . $key. ">";
+ }
+ else {
+ $_v = ($value != "0" && empty($value)) ? '' : htmlspecialchars($value);
+ $xml .= "<" . $node . $attrString . ">" .$_v . "" . $node . ">";
+ }
}
}
- if (!is_numeric(array_shift(array_keys($values)))) {
+ $temp1 = array_keys($values);
+ $temp2 = array_shift($temp1);
+ if (!is_numeric($temp2)) {
$xml .= "" . $key . ">";
}
return $xml;
}
- /**
- * Convert a CSV string result into a php array.
- * This work for Intacct API results. Not a generic method
+ /**
+ * Convert a CSV string result into a php array.
+ * This work for Intacct API results. Not a generic method
*/
public static function csvToPhp($csv) {
$fp = fopen('php://temp', 'r+');
+ $csv = str_replace("\,",",",$csv);
+ $csv = str_replace('\",','",',$csv);
fwrite($fp, trim($csv));
+
rewind($fp);
$table = array();
- // get the header row
+ // get the header row
$header = fgetcsv($fp, 10000, ',','"');
if (is_null($header) || is_null($header[0])) {
- throw new exception ("Unable to determine header. Is there garbage in the file?");
+ throw new \Exception ("Unable to determine header. Is there garbage in the file?");
}
- // get the rows
+ // get the rows
while (($data = fgetcsv($fp, 10000, ',','"')) !== false) {
$row = array();
foreach($header as $key => $value) {
@@ -181,30 +199,40 @@ public static function csvToPhp($csv) {
}
return $table;
- }
-
+ }
+
/**
* Convert a error object into nice text
* @param Object $error simpleXmlObject
* @return string formatted error message
*/
- public static function xmlErrorToString($error) {
-
+ public static function xmlErrorToString($error,$multi=false) {
if (!is_object($error)) {
return "Malformed error: " . var_export($error, true);
}
-
- $error = $error->error[0];
- if (!is_object($error)) {
+ // show just the first error
+ //$error = $error->error[0];
+ $error_string = "";
+ if (!isset($error->error)) {
return "Malformed error: " . var_export($error, true);
}
+ foreach ($error->error as $error) {
+ if (!is_object($error)) {
+ return "Malformed error: " . var_export($error, true);
+ }
- $errorno = is_object($error->errorno) ? (string)$error->errorno : ' ';
- $description = is_object($error->description) ? (string)$error->description : ' ';
- $description2 = is_object($error->description2) ? (string)$error->description2 : ' ';
- $correction = is_object($error->correction) ? (string)$error->correction : ' ';
- return "$errorno: $description: $description2: $correction";
+ $errorno = is_object($error->errorno) ? (string)$error->errorno : ' ';
+ $description = is_object($error->description) ? (string)$error->description : ' ';
+ $description2 = is_object($error->description2) ? (string)$error->description2 : ' ';
+ $correction = is_object($error->correction) ? (string)$error->correction : ' ';
+ $error_string .= "$errorno: $description: $description2: $correction\n";
+ if ($multi === false) {
+ break;
+ }
+ }
+ return $error_string;
}
+
}
diff --git a/api_viewFilter.php b/api_viewFilter.php
index 585d963..93f083c 100755
--- a/api_viewFilter.php
+++ b/api_viewFilter.php
@@ -1,4 +1,4 @@
-
+operator = $operator;
$this->value = HTMLSpecialChars($value);
}
-}
\ No newline at end of file
+}
diff --git a/api_viewFilters.php b/api_viewFilters.php
index df66178..3950e3c 100755
--- a/api_viewFilters.php
+++ b/api_viewFilters.php
@@ -1,4 +1,4 @@
-
+filters = $filters;
$this->operator = $operator;
}
-}
\ No newline at end of file
+}