18 require_once SQ_CORE_PACKAGE_PATH.
'/page/page.inc';
39 private $_userAgentPrefix =
'SquizSuite-';
46 private $_suiteSystemUser = FALSE;
53 private $_productCache = Array();
60 private $_opensslEncryptionAlgorithm =
'blowfish';
67 private $_responseCode = Array(
69 304 =>
'Not Modified',
71 401 =>
'Unauthorized',
74 405 =>
'Method Not Allowed',
75 406 =>
'Not Acceptable',
76 420 =>
'Enhance Your Calm',
77 500 =>
'Internal Server Error',
79 503 =>
'Service Unavailable',
91 $this->_ser_attrs = TRUE;
92 parent::__construct($assetid);
108 require_once SQ_CORE_PACKAGE_PATH.
'/system/system_asset_fns.inc';
109 if (!system_asset_fns_create_pre_check($this)) {
112 $GLOBALS[
'SQ_SYSTEM']->changeDatabaseConnection(
'db2');
113 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'BEGIN');
115 if ($linkid = parent::create($link)) {
116 if (!system_asset_fns_create_cleanup($this)) {
122 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'COMMIT');
124 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'ROLLBACK');
127 $GLOBALS[
'SQ_SYSTEM']->restoreDatabaseConnection();
130 if (!create_directory($this->data_path)) {
131 trigger_localised_error(
'SYS0148', E_USER_WARNING, $this->name);
150 return 'Squiz Suite Manager';
192 public function getProducts($includeCurrent=TRUE, $includeDeleted=TRUE, $excludeTypes=array(), $includeStatus=array())
195 foreach ($products as &$p) {
196 $p[
'connection'] = unserialize($p[
'connection']);
199 $suiteid = $p[
'suiteid'];
200 if (array_key_exists($suiteid, $this->_productCache) === FALSE) {
201 $this->_productCache[$suiteid] = $p;
206 foreach ($products as $i => $product) {
207 if ($includeCurrent === FALSE && $product[
'is_current'] == TRUE) {
211 if ($includeDeleted === FALSE && $product[
'sync_status'] ===
'D') {
215 if (empty($excludeTypes) === FALSE && in_array($product[
'type'], $excludeTypes) === TRUE) {
219 if (empty($includeStatus) === FALSE && in_array($product[
'status'], $includeStatus) === FALSE) {
223 $results[] = $product;
240 foreach ($results as &$p) {
241 $p[
'connection'] = unserialize($p[
'connection']);
244 $suiteid = $p[
'suiteid'];
245 if (array_key_exists($suiteid, $this->_productCache) === FALSE) {
246 $this->_productCache[$suiteid] = $p;
265 if ($suiteid === NULL || is_numeric($suiteid) === FALSE) {
269 if (array_key_exists($suiteid, $this->_productCache) === TRUE) {
270 return $this->_productCache[$suiteid];
274 $bind_vars = Array(
'suiteid' => $suiteid);
276 }
catch (PDOException $e) {
277 trigger_localised_error(
'SQS0030', E_USER_ERROR);
281 if (empty($results) === TRUE) {
285 $product = array_pop($results);
286 $product[
'connection'] = unserialize($product[
'connection']);
289 $this->_productCache[$suiteid] = $product;
306 $bind_vars = Array(
'systemid' => $systemid);
308 }
catch (PDOException $e) {
309 trigger_localised_error(
'SQS0030', E_USER_ERROR);
313 foreach ($results as &$p) {
314 $p[
'connection'] = unserialize($p[
'connection']);
334 $bind_vars = Array(
'systemid' => $systemid,
'url' => $url);
336 }
catch (PDOException $e) {
337 trigger_localised_error(
'SQS0030', E_USER_ERROR);
341 if (empty($results) === TRUE) {
344 $product = array_pop($results);
345 $product[
'connection'] = unserialize($product[
'connection']);
365 $bind_vars = Array(
'token' => $token);
367 }
catch (PDOException $e) {
368 trigger_localised_error(
'SQS0030', E_USER_ERROR);
372 if (empty($results) === TRUE) {
375 $product = array_pop($results);
376 $product[
'connection'] = unserialize($product[
'connection']);
392 return $currProduct[
'systemid'];
409 if (empty($product) === FALSE) {
410 if (array_key_exists($attrName, $product) === TRUE) {
411 return $product[$attrName];
412 }
else if (array_key_exists($attrName, $product[
'connection']) === TRUE) {
413 return $product[
'connection'][$attrName];
432 }
catch (PDOException $e) {
433 trigger_localised_error(
'SQS0030', E_USER_ERROR);
437 if (empty($results) === TRUE) {
441 $product = array_pop($results);
442 $product[
'connection'] = unserialize($product[
'connection']);
460 foreach ($result as &$product) {
461 $product[
'connection'] = unserialize($product[
'connection']);
462 $this->_productCache[$product[
'suiteid']] = $product;
481 if ($attrName ===
'connection' && is_array($attrValue) === TRUE) {
482 $attrValue = serialize($attrValue);
485 if ($attrName ==
'is_current' && is_bool($attrValue) === TRUE) {
486 $attrValue = ($attrValue) ?
'1' :
'0';
489 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'BEGIN');
491 $sql =
'UPDATE sq_suite_product SET '.$attrName.
'=:'.$attrName.
' WHERE suiteid=:suiteid';
492 $query = MatrixDAL::preparePDOQuery($sql);
496 }
catch (PDOException $e) {
497 trigger_localised_error(
'SQS0031', E_USER_ERROR);
498 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'ROLLBACK');
501 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'COMMIT');
504 if (isset($this->_productCache[$suiteid]) === TRUE) {
505 unset($this->_productCache[$suiteid]);
526 if (is_array($connection) === TRUE) {
527 $connection = serialize($connection);
530 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'BEGIN');
534 'suiteid' => $suiteid,
535 'systemid' => $systemid,
538 'connection' => $connection,
541 }
catch (PDOException $e) {
542 trigger_localised_error(
'SQS0031', E_USER_ERROR);
543 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'ROLLBACK');
546 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'COMMIT');
564 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'BEGIN');
566 $bind_vars = Array(
'suiteid' => $suiteid,
'is_current'=>(
int) $current);
568 }
catch (PDOException $e) {
569 trigger_localised_error(
'SQS0031', E_USER_ERROR);
570 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'ROLLBACK');
573 $GLOBALS[
'SQ_SYSTEM']->doTransaction(
'COMMIT');
588 $responseContent = Array();
591 if ($this->status != SQ_STATUS_LIVE) {
592 $responseContent[
'exception'] =
'Forbidden';
593 $this->_sendHeader(403);
594 $this->_sendResponse($responseContent);
599 $requestMethod = strtolower($_SERVER[
'REQUEST_METHOD']);
600 if ($requestMethod !==
'post') {
601 $responseContent[
'exception'] =
'The request method is not supported.';
602 $this->_sendHeader(405);
603 header(
'Allow: POST');
604 $this->_sendResponse($responseContent);
613 $request[
'_enc'] = array_get_index($_POST,
'_enc', NULL);
614 $request[
'system'] = array_get_index($_POST,
'_system', NULL);
615 $request[
'action'] = array_get_index($_POST,
'_action', NULL);
616 $request[
'format'] = array_get_index($_POST,
'_format',
'xml');
617 $request[
'assetid'] = NULL;
618 if ($request[
'system'] === NULL && $request[
'_enc'] !== NULL) {
620 $request[
'system'] = array_get_index($request[
'_enc'],
'_system', NULL);
621 $request[
'action'] = array_get_index($request[
'_enc'],
'_action', NULL);
622 $request[
'format'] = array_get_index($request[
'_enc'],
'_format',
'xml');
625 if ($request[
'system'] === NULL || $request[
'action'] === NULL) {
626 $responseContent[
'exception'] =
'Failed to get system and action from the request';
627 $this->_sendHeader(400);
628 $this->_sendResponse($responseContent, $request[
'format']);
633 if ($this->_checkPermission($request) === FALSE) {
634 $responseContent[
'exception'] =
'Forbidden';
635 $this->_sendHeader(403);
636 $this->_sendResponse($responseContent, $request[
'format']);
641 $api = $this->
getAPI($request[
'system'], $request[
'action']);
642 $responseContent[
'system'] = $request[
'system'];
643 $responseContent[
'action'] = $request[
'action'];
644 if ($api === FALSE) {
646 $responseContent[
'exception'] =
'Requested service is not found.';
647 $this->_sendHeader(404);
648 $this->_sendResponse($responseContent, $request[
'format']);
653 $responseContent[
'system'] = $api[
'system'];
654 $responseContent[
'action'] = $api[
'action'];
657 $params = $this->_getActionParameters($requestMethod,$api[
'system'],$api[
'action'],$request[
'assetid']);
659 if ($params === FALSE) {
661 $responseContent[
'exception'] =
'Provided parameters are not sufficient';
662 $this->_sendHeader(400);
663 $this->_sendResponse($responseContent, $request[
'format']);
667 $system = $api[
'system'];
668 $action = $api[
'action'];
669 $assetid = $request[
'assetid'];
672 if ($system !=
'squizsuite') {
673 $class =
'Squiz_Suite_System_'.$system;
675 $class =
'Squiz_Suite_System_Suite';
677 $GLOBALS[
'SQ_SYSTEM']->am->includeAsset($class);
682 $responseContent[
'result'] = call_user_func_array($callback, $params);
684 }
catch (Exception $e) {
685 $responseContent[
'exception'] = $e->getMessage();
689 $this->_sendHeader($response);
690 $this->_sendResponse($responseContent, $request[
'format']);
704 private function _checkPermission($request)
707 if (isset($request[
'system']) && isset($request[
'action'])) {
708 if ($request[
'system'] ===
'SquizSuite' && strpos($request[
'action'],
'suiteConnect') === 0) {
711 }
else if ($this->_suiteSystemUser === TRUE) {
712 if (isset($request[
'_enc'][
'matrix'][
'username']) && isset($request[
'_enc'][
'matrix'][
'password'])) {
713 $username = trim($request[
'_enc'][
'matrix'][
'username']);
714 $password = trim($request[
'_enc'][
'matrix'][
'password']);
716 $auth_folder = $GLOBALS[
'SQ_SYSTEM']->am->getSystemAsset(
'authentication_folder');
717 $auth_systems = $auth_folder->getAuthSystems();
720 foreach ($auth_systems as $systemid) {
721 $system = $GLOBALS[
'SQ_SYSTEM']->am->getAsset($systemid);
722 if (is_null($system))
continue;
723 $user = $system->authenticateUser($username, $password);
724 if (!is_null($user)) {
725 $GLOBALS[
'SQ_SYSTEM']->loginUser($user);
726 $GLOBALS[
'SQ_SYSTEM']->am->forgetAsset($system, TRUE);
727 if ($this->_suiteSystemUser === TRUE) {
732 $GLOBALS[
'SQ_SYSTEM']->am->forgetAsset($system, TRUE);
754 $system = strtolower($system);
756 $systemName = (($system ==
'squizsuite') ?
'suite' : $system);
759 $class =
'Squiz_Suite_System_'.ucwords($systemName);
760 $path = SQ_PACKAGES_PATH.
'/squiz_suite/systems/'.strtolower($class).
'/'.strtolower($class).
'.inc';
761 if (file_exists($path)) {
763 if (method_exists($class, $method)) {
764 $api[
'system'] = $system;
765 $api[
'action'] = $method;
784 if (!function_exists(
'json_encode')) {
785 require_once
'Services/JSON.php';
786 $json =
new Services_JSON();
787 $output = $json->encode($data);
789 $output = json_encode($data);
807 if (strtolower($data) ===
'null') {
810 if (!function_exists(
'json_decode')) {
811 require_once
'Services/JSON.php';
812 $json =
new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
813 $output = $json->decode($data);
815 $output = json_decode($data, TRUE);
819 if ($output === NULL) {
845 private function _getActionParameters($requestMethod, $system, $action, $assetid=NULL)
847 $requiredParams = Array();
848 $system = strtolower($system);
850 if ($system ==
'squizsuite') {
851 $systemName =
'suite';
853 $systemName = $system;
857 $system =
'Squiz_Suite_System_'.ucwords($systemName);
858 $GLOBALS[
'SQ_SYSTEM']->am->includeAsset($system);
859 $method =
new ReflectionMethod($system, $action);
860 $parameters = $method->getParameters();
861 foreach ($parameters as $parameter) {
862 $requiredParams[] = Array(
863 'name' => $parameter->getName(),
864 'optional' => $parameter->isOptional(),
869 $encrypted = array_get_index($_POST,
'_enc', NULL);
870 foreach ($requiredParams as $param) {
871 $value = array_get_index($_POST, $param[
'name'], NULL);
873 $value = htmlentities_array($value);
875 if ($value === NULL && $encrypted !== NULL && array_key_exists($param[
'name'], $encrypted) === TRUE) {
876 $value = $this->
decodeJson($encrypted[$param[
'name']]);
879 if ($value === NULL && $param[
'optional'] === FALSE) {
908 'private_key_bits' => 2048,
909 'private_key_type' => OPENSSL_KEYTYPE_RSA,
912 $keyGenerated = openssl_pkey_new($keyInfo);
915 $dataDir = $this->data_path;
916 openssl_pkey_export_to_file($keyGenerated, $dataDir.
'/privatekey.pem');
919 'countryName' =>
'AU',
920 'stateOrProvinceName' =>
'NSW',
921 'localityName' =>
'Sydney',
922 'organizationName' =>
'Squiz Suite',
923 'organizationalUnitName' => $currProduct[
'type'],
924 'commonName' => $currProduct[
'systemid'],
925 'emailAddress' => $currProduct[
'systemid'].
'@squizsuite.com',
927 $csr = openssl_csr_new($info, $keyGenerated);
928 openssl_csr_export_to_file($csr, $dataDir.
'/system.csr');
930 $cert = openssl_csr_sign($csr, NULL, $keyGenerated, (365 * 10));
931 openssl_x509_export_to_file($cert, $dataDir.
'/system.crt');
932 openssl_x509_export($cert, $certStr);
935 $currProduct[
'connection'][
'cert'] = $certStr;
936 $this->
updateProduct($currProduct[
'suiteid'],
'connection', $currProduct[
'connection']);
951 public function sendMessage($targetid, $msgType, array $options=array())
953 if ($msgType !==
'suiteConnect') {
955 if (empty($productInfo) === TRUE) {
956 $errMsg = $targetid.
' is not known. Cannot send '.$msgType.
' to it.';
957 throw new Exception($errMsg);
962 $this->_createSuiteMessageDOM($dom, $msgType, $options);
963 $xml = $dom->saveXML();
967 $system =
'SquizSuite';
972 if ($msgType ===
'suiteConnect') {
974 $msg[
'con_request'] = 1;
976 $msg[
'_enc'] = array(
'xml' => $xml);
977 $msg[
'_pubKeySystemid'] = $targetid;
988 if ($result[
'curlInfo'][
'http_code'] !== 200) {
989 $errMsg =
'HTTP Response '.$result[
'curlInfo'][
'http_code'].
"\n";
990 $errMsg .= var_export($result, 1).
"\n";
1006 private function _isMatrixSystem($targetid)
1011 if (empty($product) === FALSE) {
1012 if ($product[
'type'] ===
'Squiz Matrix') {
1019 if (strpos($targetid,
'http') === 0 && strpos($targetid,
'__api') === FALSE) {
1041 public function sendRequest($targetid, $format, $system, $action, $message=Array())
1044 $userAgentStr = $this->_userAgentPrefix.array_get_index($currProductInfo,
'type',
'Squiz Matrix').
'/4.0';
1045 $productInfo = array();
1048 if ($action ===
'suiteConnect') {
1049 $apiURL = $targetid;
1052 $apiURL = $productInfo[
'url'];
1055 if ($this->_isMatrixSystem($targetid)) {
1056 $message[
'_format'] = $format;
1057 $message[
'_system'] = $system;
1058 $message[
'_action'] = $action;
1059 if ($action !==
'suiteConnect') {
1061 if (!isset($message[
'_enc']) || is_array($message[
'_enc'])) {
1062 if (!isset($message[
'_pubKeySystemid'])) {
1063 $message[
'_pubKeySystemid'] = $targetid;
1066 if (isset($productInfo[
'connection'][
'username'])) {
1067 if (!isset($message[
'_enc'][
'matrix'])) {
1068 $message[
'_enc'][
'matrix'] = array();
1071 $message[
'_enc'][
'matrix'][
'username'] = $productInfo[
'connection'][
'username'];
1074 if (isset($productInfo[
'connection'][
'password'])) {
1075 $message[
'_enc'][
'matrix'][
'password'] = $productInfo[
'connection'][
'password'];
1080 $apiURL = rtrim($apiURL,
'/');
1082 if (strpos($apiURL,
'?') !== FALSE) {
1083 $getVars = substr($apiURL, strpos($apiURL,
'?'));
1084 $apiURL = substr($apiURL, 0, strpos($apiURL,
'?'));
1085 $getVars = str_replace(
'/__api',
'', $getVars);
1088 $apiURL .=
'/'.$format;
1089 $apiURL .=
'/'.$system;
1090 $apiURL .=
'/'.$action;
1091 $apiURL .= $getVars;
1092 if ($action !==
'suiteConnect') {
1095 if (!isset($message[
'_enc'])) {
1096 $message[
'_enc'] = array();
1097 $message[
'_pubKeySystemid'] = $targetid;
1100 if (!isset($message[
'_enc'][
'_systemid'])) {
1101 $message[
'_enc'][
'_systemid'] = $currProductInfo[
'systemid'];
1125 $moreEntropy = TRUE;
1126 $uniqid = uniqid($prefix, $moreEntropy);
1144 $all_products = $this->
getProducts(FALSE, TRUE, array(
'Squiz Update'));
1151 $markedForDeletion = array();
1152 $markedForAddition = array();
1153 foreach ($all_products as $product) {
1154 if ($product[
'sync_status'] ===
'D') {
1155 $markedForDeletion[$product[
'suiteid']] = TRUE;
1158 if ($product[
'sync_status'] ===
'A') {
1159 $markedForAddition[$product[
'suiteid']] = TRUE;
1166 $connection_failed = FALSE;
1168 foreach ($all_products as $product) {
1169 if ($product[
'status'] !==
'live' || $product[
'sync_status'] ===
'D') {
1174 $current_prod_info[
'token'] = $product[
'token'];
1177 $target_excluded = array();
1178 foreach ($current_prod_info[
'connected'] as $p) {
1179 if ($p[
'suiteid'] !== $product[
'suiteid']) {
1180 $target_excluded[] = $p;
1184 $current_prod_info[
'connected'] = $target_excluded;
1186 $response = $this->
sendMessage($product[
'suiteid'],
'suiteSyncProduct', $current_prod_info);
1189 if ($response === FALSE) {
1190 $connection_failed = TRUE;
1197 $this->
syncConnectedProducts($product[
'suiteid'], $response[
'connected'], $markedForDeletion, $markedForAddition);
1201 if ($connection_failed === FALSE) {
1202 foreach ($markedForDeletion as $suiteid => $canBeRemoved) {
1203 if ($canBeRemoved === TRUE) {
1208 foreach ($markedForAddition as $suiteid => $canBeAdded) {
1209 if ($canBeAdded === TRUE) {
1230 if ($product_info[
'connection'][
'cert'] !== $new_product_info[
'cert'] || $product_info[
'connection'][
'name'] !== $new_product_info[
'name']) {
1231 $product_info[
'connection'][
'cert'] = $new_product_info[
'cert'];
1232 $product_info[
'connection'][
'name'] = $new_product_info[
'name'];
1233 $this->
updateProduct($product_info[
'suiteid'],
'connection', $product_info[
'connection']);
1237 if ($product_info[
'url'] !== $new_product_info[
'apiurl']) {
1238 $product_info[
'url'] = $new_product_info[
'apiurl'];
1239 $this->
updateProduct($product_info[
'suiteid'],
'url', $product_info[
'url']);
1257 foreach ($deleted as $p) {
1259 if (empty($res) === TRUE) {
1262 }
else if ($res[
'sync_status'] ===
'D') {
1265 }
else if ($res[
'status'] ===
'live') {
1270 if (empty($markedForAddition) === FALSE && isset($markedForAddition[$p[
'suiteid']]) === TRUE) {
1271 unset($markedForAddition[$p[
'suiteid']]);
1290 public function syncConnectedProducts($requesterSuiteid, array $connected, array &$markedForDeletion, array &$markedForAddtion)
1292 $connectedIds = array();
1293 foreach ($connected as $p) {
1297 if (isset($p[
'url']) === TRUE) {
1299 }
else if (isset($p[
'connection'][
'url']) === TRUE) {
1300 $url = $p[
'connection'][
'url'];
1304 if (empty($res) === TRUE) {
1306 $suiteid = $this->
registerProduct($p[
'systemid'], $p[
'type'], $url, $p[
'connection']);
1309 $suiteid = $res[
'suiteid'];
1310 if ($res[
'sync_status'] ===
'D') {
1313 $markedForDeletion[$suiteid] = FALSE;
1314 }
else if ($res[
'status'] !==
'live') {
1320 $connectedIds[] = $suiteid;
1325 if (empty($markedForAddition) === FALSE) {
1326 $notAddedYet = array_diff(array_keys($markedForAddition), $connectedIds);
1327 foreach ($notAddedYet as $notAddedId) {
1328 if ((
int) $requesterSuiteid !== (
int) $notAddedId) {
1329 $markedForAddition[$notAddedId] = FALSE;
1348 'systemid' => $current_product[
'systemid'],
1349 'type' => $current_product[
'type'],
1350 'apiurl' => $current_product[
'url'],
1351 'name' => $current_product[
'connection'][
'name'],
1352 'cert' => $current_product[
'connection'][
'cert'],
1354 'deleted' => array(),
1355 'connected' => array(),
1359 $suite_manager = $GLOBALS[
'SQ_SYSTEM']->am->getSystemAsset(
'suite_manager');
1360 $products = $suite_manager->getProducts(FALSE, TRUE, array(
'Squiz Update'));
1361 foreach ($products as $p) {
1362 if ($p[
'status'] !==
'live') {
1367 if ($p[
'sync_status'] ===
'D') {
1368 $result[
'deleted'][] = $p;
1370 $result[
'connected'][] = $p;
1389 if ($response[
'curlInfo'][
'http_code'] !== 200) {
1393 $result = $response[
'result'];
1394 if (strpos($result,
'<?xml') !== 0) {
1397 $dom =
new DOMDocument(
'1.0');
1398 $dom->loadXML($result);
1400 $responseDOM = $dom->getElementsByTagName(
'result')->item(0);
1427 'POSTFIELDS' => $msg,
1428 'RETURNTRANSFER' => 1,
1430 if (empty($userAgent) === FALSE) {
1431 $options[
'USERAGENT'] = $userAgent;
1434 $headers = array(
'Expect:');
1435 $url = rtrim($url,
'/');
1436 $details = fetch_url($url, $options, $headers, FALSE);
1437 if ($details[
'response'] === FALSE) {
1438 $errMsg =
'cURL failed:'.$details[
'errorstring'];
1443 'result' => $details[
'response'],
1444 'curlInfo' => $details[
'curlinfo'],
1464 $dom =
new DomDocument(
'1.0',
'utf-8');
1465 $msgElem = $dom->createElement(
'message');
1466 $dom->appendChild($msgElem);
1472 $sysidEl = $dom->createElement(
'system_id');
1473 $systypeEl = $dom->createElement(
'system_type');
1474 $sysurlEl = $dom->createElement(
'system_url');
1475 $sysnameEl = $dom->createElement(
'system_name');
1477 if (!empty($productInfo)) {
1485 $msgElem->appendChild($sysidEl);
1486 $msgElem->appendChild($systypeEl);
1487 $msgElem->appendChild($sysurlEl);
1488 $msgElem->appendChild($sysnameEl);
1491 if (is_numeric($targetid)) {
1493 $conTokenEl = $dom->createElement(
'conn_token');
1495 $msgElem->appendChild($conTokenEl);
1513 private function _createSuiteMessageDOM(&$dom, $msgType, array $options=array())
1515 $msgEl = $dom->getElementsByTagName(
'message')->item(0);
1516 $msgTypeEl = $dom->createElement(
'message_type');
1520 $msgEl->appendChild($msgTypeEl);
1523 case 'suiteConnect':
1524 case 'suiteConnectAck':
1525 case 'suiteConnectAckAck':
1529 if (!empty($currProduct)) {
1530 $pubKey = $currProduct[
'connection'][
'cert'];
1531 $pubkeyEl = $dom->createElement(
'cert');
1533 $msgEl->appendChild($pubkeyEl);
1542 if (empty($options) === FALSE) {
1543 $optionsEl = $dom->createElement(
'options');
1545 $msgEl->appendChild($optionsEl);
1564 $doc =
new DomDocument();
1565 $result = $doc->loadXML($xml);
1566 if ($result === FALSE) {
1567 $errMsg =
'Failed to load the message XML.';
1568 throw new Exception($errMsg);
1572 if (empty($fields)) {
1582 foreach ($fields as $field) {
1583 $fieldEl = $doc->getElementsByTagName($field)->item(0);
1584 if ($fieldEl === NULL) {
1585 $result[$field] = NULL;
1587 if ($fieldEl->nodeType === XML_ELEMENT_NODE) {
1590 'getResponseFromXMLDom',
1592 $params = Array($fieldEl);
1596 $result[$field] = $fieldEl->nodeValue;
1623 include_once SQ_FUDGE_PATH.
'/general/datetime.inc';
1624 $log =
'[RECEIVED '.readable_datetime(time()).
'] '.$msgType;
1625 $log .=
' from '.$systemid;
1628 if (empty($productInfo) === FALSE) {
1629 $log .=
' ('.$productInfo[0][
'url'].
')';
1630 if (isset($_SERVER[
'REMOTE_ADDR']) === TRUE) {
1631 $log .=
' ('.$_SERVER[
'REMOTE_ADDR'].
')';
1637 file_put_contents($this->_getLogFilePath(), $log, FILE_APPEND);
1659 include_once SQ_FUDGE_PATH.
'/general/datetime.inc';
1660 $log =
'[SENT '.readable_datetime(time()).
'] '.$msgType;
1661 $log .=
' to '.$systemid;
1663 if (empty($productInfo) === FALSE) {
1664 $log .=
' ('.$productInfo[0][
'url'].
')';
1669 file_put_contents($this->_getLogFilePath(), $log, FILE_APPEND);
1690 include_once SQ_FUDGE_PATH.
'/general/datetime.inc';
1691 $log =
'[ERROR '.readable_datetime(time()).
'] '.$errorMessage;
1694 file_put_contents($this->_getLogFilePath(), $log, FILE_APPEND);
1705 private function _getLogFilePath()
1707 $logFilePath = $this->data_path;
1708 $logFilePath .=
'/message_log.txt';
1709 return $logFilePath;
1730 if (isset($msg[
'_enc']) === TRUE && isset($msg[
'_pubKeySystemid']) === TRUE) {
1731 $destProduct = $this->
getProduct($msg[
'_pubKeySystemid']);
1732 if (empty($destProduct) === TRUE) {
1736 if ($destProduct[
'status'] ===
'live' && $destProduct[
'sync_status'] !==
'D' && empty($destProduct[
'token']) === FALSE) {
1738 $msg[
'_enc'] = array(
1739 '_token' => $destProduct[
'token'],
1740 '_data' => $msg[
'_enc'],
1745 $msg[
'_enc'] = $this->
encodeJson($msg[
'_enc']);
1746 $enc = $this->
encryptData($msg[
'_pubKeySystemid'], $msg[
'_enc']);
1748 $msg[
'_enc'] = $enc[
'encrypted'];
1749 $msg[
'_password'] = $enc[
'password'];
1765 $encrypted = array_get_index($_POST,
'_enc', NULL);
1766 $password = array_get_index($_POST,
'_password', NULL);
1767 if ($encrypted === NULL || $password === NULL) {
1771 $encrypted = $this->
decryptData($encrypted, $password);
1772 if ($encrypted === FALSE) {
1773 $_POST[
'_enc'] = FALSE;
1776 $tokenFound = FALSE;
1779 if (array_key_exists(
'_token', $encrypted) === TRUE && array_key_exists(
'_data', $encrypted) === TRUE) {
1780 $_POST[
'_enc'] = $encrypted[
'_data'];
1781 $token = $encrypted[
'_token'];
1784 $_POST[
'_enc'] = $encrypted;
1787 if ($tokenFound === TRUE && empty($token) === FALSE) {
1793 if (is_array($encrypted) === TRUE) {
1794 $systemid = $encrypted[
'_systemid'];
1795 }
else if (strpos($encrypted,
'<?xml') === 0) {
1796 $systemid = $this->_getSystemidFromXML($xml);
1799 if ($systemid !== NULL) {
1801 if (isset($products[0]) === TRUE) {
1802 $product = array_pop($products);
1807 if (empty($product) === FALSE && $product[
'status'] ===
'live' && $product[
'sync_status'] !==
'D') {
1809 $this->_suiteSystemUser = TRUE;
1823 private function _getSystemidFromXML($xml)
1826 if (strpos($xml,
'<?xml') === 0) {
1827 $dom =
new DomDocument();
1828 $dom->loadXML($xml);
1829 $systemidDom = $dom->getElementsByTagName(
'system_id')->item(0);
1856 if (isset($product[
'connection'][
'cert']) === TRUE) {
1857 $certStr = $product[
'connection'][
'cert'];
1858 $pubKey = openssl_pkey_get_public($certStr);
1859 $password = sha1(microtime(TRUE));
1860 $encryptedMsg = $this->_opensslEncrypt($data, $this->_opensslEncryptionAlgorithm, $password);
1861 if ($encryptedMsg === FALSE) {
1865 $success = openssl_public_encrypt($password, $encryptedPass, $pubKey);
1866 $encryptedPass = base64_encode($encryptedPass);
1867 if ($success === FALSE) {
1872 'encrypted' => $encryptedMsg,
1873 'password' => $encryptedPass,
1900 $priKeyPath = $this->data_path.
'/privatekey.pem';
1901 $priKey = openssl_pkey_get_private(
'file://'.$priKeyPath);
1902 $password = base64_decode($password);
1905 $result = openssl_private_decrypt(
1911 if ($result === FALSE) {
1915 $decrypted = $this->_opensslDecrypt($data, $this->_opensslEncryptionAlgorithm, $passdec);
1916 if ($decrypted === FALSE) {
1941 private function _opensslEncrypt($data, $algorithm, $password)
1943 $filename = uniqid().
'.txt';
1944 $filePath = $this->data_path.
'/'.$filename;
1945 file_put_contents($filePath, $data);
1947 $command =
'/usr/bin/openssl enc -'.$algorithm.
' -a -salt -in '.$filePath;
1948 $command .=
' -out '.$filePath.
'.enc -pass pass:'.$password;
1949 exec($command, $output, $returnVal);
1950 if ($returnVal === 0 && file_exists($filePath.
'.enc') === TRUE) {
1951 $encrypted = file_get_contents($filePath.
'.enc');
1953 unlink($filePath.
'.enc');
1978 private function _opensslDecrypt($data, $algorithm, $password)
1980 $filename = uniqid().
'.txt';
1981 $filePath = $this->data_path.
'/'.$filename;
1982 file_put_contents($filePath, $data);
1984 $command =
'/usr/bin/openssl enc -d -'.$algorithm.
' -a -salt -in '.$filePath;
1985 $command .=
' -out '.$filePath.
'.dec -pass pass:'.$password;
1986 exec($command, $output, $returnVal);
1987 if ($returnVal === 0 && file_exists($filePath.
'.dec') === TRUE) {
1988 $encrypted = file_get_contents($filePath.
'.dec');
1990 unlink($filePath.
'.dec');
2014 if (is_scalar($content) === TRUE) {
2015 if (is_integer($content) === TRUE) {
2017 $textVal = $content.
'';
2018 }
else if (is_bool($content) === TRUE) {
2020 $textVal = json_encode($content);
2021 }
else if (is_string($content) === TRUE) {
2023 $textVal = $content;
2024 }
else if (is_float($content) === TRUE) {
2026 $textVal = $content.
'';
2029 $parentNode->setAttribute(
'type', $type);
2030 $this->_addTextToNode($parentNode, $textVal);
2031 }
else if (is_array($content) === TRUE) {
2034 $keys = array_keys($content);
2035 $diff = array_diff_key($content, $keys);
2036 if (count($diff) !== 0) {
2041 if (isset($content[
'_base64']) === TRUE) {
2045 $parentNode->setAttribute(
'type', $type);
2048 foreach ($content as $val) {
2049 $valueElem = $parentNode->ownerDocument->createElement(
'value');
2050 $parentNode->appendChild($valueElem);
2056 foreach ($content as $key => $val) {
2058 if (is_numeric($key) === TRUE) {
2059 $keyElemTag =
'_'.$key;
2062 $keyElem = $parentNode->ownerDocument->createElement($keyElemTag);
2063 $parentNode->appendChild($keyElem);
2069 foreach ($content as $key => $val) {
2070 if ($key ===
'_base64') {
2074 $parentNode->setAttribute($key, $val);
2076 $this->_addTextToNode($parentNode, $content[
'_base64'], TRUE);
2098 if ($parentNode->hasAttribute(
'type') === TRUE) {
2099 $type = $parentNode->getAttribute(
'type');
2100 $func =
'_get'.ucwords($type).
'Response';
2105 if (is_callable($callback) === TRUE) {
2106 $params = Array($parentNode);
2107 $response = call_user_func_array($callback, $params);
2109 $response = $parentNode->nodeValue;
2110 settype($response, $type);
2126 private static function _getArrayResponse($parentNode)
2128 $response = Array();
2129 if ($parentNode->hasChildNodes() === TRUE) {
2130 foreach ($parentNode->childNodes as $child) {
2131 if ($child->nodeType === XML_ELEMENT_NODE) {
2149 private static function _getStructResponse($parentNode)
2151 $response = Array();
2152 if ($parentNode->hasChildNodes() === TRUE) {
2153 foreach ($parentNode->childNodes as $child) {
2154 $key = $child->nodeName;
2155 if ($child->nodeType === XML_ELEMENT_NODE) {
2175 private static function _getBase64Response($parentNode)
2177 $response = Array();
2178 if ($parentNode->hasAttributes() === TRUE) {
2179 foreach ($parentNode->attributes as $attribute) {
2180 $name = $attribute->name;
2181 $value = $attribute->value;
2182 if ($name !==
'type') {
2183 $response[$name] = $value;
2189 $response[
'_base64'] = $parentNode->nodeValue;
2210 private function _addTextToNode(&$node, $text, $force=FALSE)
2213 $node->appendChild($node->ownerDocument->createCDATASection($text));
2215 $invalidXMLChars = preg_match(
'/[&<>"\']/', $text);
2216 if ($invalidXMLChars === 1) {
2217 $node->appendChild($node->ownerDocument->createCDATASection($text));
2219 $node->appendChild($node->ownerDocument->createTextNode($text));
2233 private function _sendHeader($response)
2235 $headerString =
'HTTP/1.0 '.$response.
' '.$this->_responseCode[$response];
2237 header($headerString, $replace, $response);
2254 private function _sendResponse(array $responseContent, $outputFormat=
'xml')
2256 $outputFormat = (string) $outputFormat;
2257 switch ($outputFormat) {
2259 header(
'Content-type: application/json');
2260 $json = $this->_buildJsonString($responseContent);
2267 header(
'Content-Type: text/xml; charset=utf-8');
2268 $dom =
new DomDocument(
'1.0',
'utf-8');
2269 $rspElem = $dom->createElement(
'rsp');
2270 $dom->appendChild($rspElem);
2281 foreach ($fields as $field) {
2282 if (array_key_exists($field, $responseContent) === TRUE) {
2283 $fieldElem = $dom->createElement($field);
2285 $rspElem->appendChild($fieldElem);
2289 if (array_key_exists(
'result', $responseContent) === TRUE) {
2290 $resultElem = $dom->createElement(
'result');
2292 $rspElem->appendChild($resultElem);
2295 $xml = $dom->saveXML();
2311 private function _buildJsonString($content)
2315 if (is_scalar($content) === TRUE) {
2317 }
else if ($content === NULL) {
2319 }
else if (is_array($content) === TRUE) {
2321 $keys = array_keys($content);
2322 $diff = array_diff_key($content, $keys);
2323 if (count($diff) !== 0) {
2330 foreach ($content as $key => $val) {
2331 $arr[] = $this->
encodeJson((
string) $key).
':'.$this->_buildJsonString($val);
2334 $result =
'{'.implode(
',', $arr).
'}';
2339 foreach ($content as $val) {
2340 $arr[] = $this->_buildJsonString($val);
2343 $result =
'['.implode(
',', $arr).
']';