2121use Bitrix24 \Exceptions \Bitrix24PaymentRequiredException ;
2222use Bitrix24 \Exceptions \Bitrix24PortalDeletedException ;
2323use Bitrix24 \Exceptions \Bitrix24PortalRenamedException ;
24+ use Bitrix24 \Exceptions \Bitrix24RestApiUnavailableOnFreeTariffException ;
2425use Bitrix24 \Exceptions \Bitrix24SecurityException ;
2526use Bitrix24 \Exceptions \Bitrix24TokenIsExpiredException ;
2627use Bitrix24 \Exceptions \Bitrix24TokenIsInvalidException ;
@@ -143,11 +144,25 @@ class Bitrix24 implements iBitrix24
143144 */
144145 protected $ _onExpiredToken ;
145146
147+ /**
148+ * @var callable callback after api method called
149+ */
150+ protected $ _onCallApiMethod ;
151+
146152 /**
147153 * @var bool ssl verify for checking CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST
148154 */
149155 protected $ sslVerify = true ;
150156
157+ /**
158+ * @var bool if true - webhook will be used in API calls (without access_token)
159+ */
160+ protected $ webhook_usage ;
161+
162+ /**
163+ * @var string webhook secret identifier
164+ */
165+ protected $ webhook_secret ;
151166
152167 /**
153168 * Create a object to work with Bitrix24 REST API service
@@ -195,6 +210,16 @@ public function setOnExpiredToken(callable $callback)
195210 $ this ->_onExpiredToken = $ callback ;
196211 }
197212
213+ /**
214+ * Set function called after api method executed. Callback receives instance as first parameter, method name as second.
215+ *
216+ * @param callable $callback
217+ */
218+ public function setOnCallApiMethod (callable $ callback )
219+ {
220+ $ this ->_onCallApiMethod = $ callback ;
221+ }
222+
198223 /**
199224 * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call
200225 * random string is a result of mt_rand function
@@ -504,14 +529,14 @@ protected function executeRequest($url, array $additionalParameters = array())
504529 $ curlOptions = array (
505530 CURLOPT_FOLLOWLOCATION => true ,
506531 CURLOPT_RETURNTRANSFER => true ,
507- CURLINFO_HEADER_OUT => true ,
508- CURLOPT_VERBOSE => true ,
532+ CURLINFO_HEADER_OUT => true ,
533+ CURLOPT_VERBOSE => true ,
509534 CURLOPT_CONNECTTIMEOUT => 65 ,
510- CURLOPT_TIMEOUT => 70 ,
511- CURLOPT_USERAGENT => strtolower (__CLASS__ . '-PHP-SDK/v ' . self ::VERSION ),
512- CURLOPT_POST => true ,
513- CURLOPT_POSTFIELDS => http_build_query ($ additionalParameters ),
514- CURLOPT_URL => $ url ,
535+ CURLOPT_TIMEOUT => 70 ,
536+ CURLOPT_USERAGENT => strtolower (__CLASS__ . '-PHP-SDK/v ' . self ::VERSION ),
537+ CURLOPT_POST => true ,
538+ CURLOPT_POSTFIELDS => http_build_query ($ additionalParameters ),
539+ CURLOPT_URL => $ url ,
515540 );
516541
517542 if (!$ this ->sslVerify ) {
@@ -537,8 +562,12 @@ protected function executeRequest($url, array $additionalParameters = array())
537562 // handling network I/O errors
538563 if (false === $ curlResult ) {
539564 $ curlErrorNumber = curl_errno ($ curl );
540- $ errorMsg = sprintf ('in try[%s] cURL error (code %s): %s ' . PHP_EOL , $ retriesCnt , $ curlErrorNumber ,
541- curl_error ($ curl ));
565+ $ errorMsg = sprintf (
566+ 'in try[%s] cURL error (code %s): %s ' . PHP_EOL ,
567+ $ retriesCnt ,
568+ $ curlErrorNumber ,
569+ curl_error ($ curl )
570+ );
542571 if (false === in_array ($ curlErrorNumber , $ retryableErrorCodes , true ) || !$ retriesCnt ) {
543572 $ this ->log ->error ($ errorMsg , $ this ->getErrorContext ());
544573 curl_close ($ curl );
@@ -603,19 +632,19 @@ protected function getErrorContext()
603632 {
604633 return array (
605634 // portal specific settings
606- 'B24_DOMAIN ' => $ this ->getDomain (),
607- 'B24_MEMBER_ID ' => $ this ->getMemberId (),
608- 'B24_ACCESS_TOKEN ' => $ this ->getAccessToken (),
609- 'B24_REFRESH_TOKEN ' => $ this ->getRefreshToken (),
635+ 'B24_DOMAIN ' => $ this ->getDomain (),
636+ 'B24_MEMBER_ID ' => $ this ->getMemberId (),
637+ 'B24_ACCESS_TOKEN ' => $ this ->getAccessToken (),
638+ 'B24_REFRESH_TOKEN ' => $ this ->getRefreshToken (),
610639 // application settings
611- 'APPLICATION_SCOPE ' => $ this ->getApplicationScope (),
612- 'APPLICATION_ID ' => $ this ->getApplicationId (),
640+ 'APPLICATION_SCOPE ' => $ this ->getApplicationScope (),
641+ 'APPLICATION_ID ' => $ this ->getApplicationId (),
613642 'APPLICATION_SECRET ' => $ this ->getApplicationSecret (),
614- 'REDIRECT_URI ' => $ this ->getRedirectUri (),
643+ 'REDIRECT_URI ' => $ this ->getRedirectUri (),
615644 // network
616- 'RAW_REQUEST ' => $ this ->getRawRequest (),
617- 'CURL_REQUEST_INFO ' => $ this ->getRequestInfo (),
618- 'RAW_RESPONSE ' => $ this ->getRawResponse (),
645+ 'RAW_REQUEST ' => $ this ->getRawRequest (),
646+ 'CURL_REQUEST_INFO ' => $ this ->getRequestInfo (),
647+ 'RAW_RESPONSE ' => $ this ->getRawResponse (),
619648 );
620649 }
621650
@@ -762,14 +791,15 @@ protected function handleBitrix24APILevelErrors(
762791 $ arRequestResult ,
763792 $ methodName ,
764793 array $ additionalParameters = array ()
765- )
766- {
794+ ) {
767795 if (array_key_exists ('error ' , $ arRequestResult )) {
768- $ errorMsg = sprintf ('%s - %s in call [%s] for domain [%s] ' ,
796+ $ errorMsg = sprintf (
797+ '%s - %s in call [%s] for domain [%s] ' ,
769798 $ arRequestResult ['error ' ],
770799 (array_key_exists ('error_description ' , $ arRequestResult ) ? $ arRequestResult ['error_description ' ] : '' ),
771800 $ methodName ,
772- $ this ->getDomain ());
801+ $ this ->getDomain ()
802+ );
773803 // throw specific API-level exceptions
774804 switch (strtoupper (trim ($ arRequestResult ['error ' ]))) {
775805 case 'WRONG_CLIENT ' :
@@ -795,6 +825,9 @@ protected function handleBitrix24APILevelErrors(
795825 case 'INSUFFICIENT_SCOPE ' :
796826 $ this ->log ->error ($ errorMsg , $ this ->getErrorContext ());
797827 throw new Bitrix24InsufficientScope ($ errorMsg );
828+ case 'ACCESS_DENIED ' :
829+ $ this ->log ->error ($ errorMsg , $ this ->getErrorContext ());
830+ throw new Bitrix24RestApiUnavailableOnFreeTariffException ($ errorMsg );
798831 default :
799832 $ this ->log ->error ($ errorMsg , $ this ->getErrorContext ());
800833 throw new Bitrix24ApiException ($ errorMsg );
@@ -1016,9 +1049,9 @@ public function addBatchCall($method, array $parameters = array(), callable $cal
10161049 {
10171050 $ id = uniqid ();
10181051 $ this ->_batch [$ id ] = array (
1019- 'method ' => $ method ,
1052+ 'method ' => $ method ,
10201053 'parameters ' => $ parameters ,
1021- 'callback ' => $ callback ,
1054+ 'callback ' => $ callback ,
10221055 );
10231056
10241057 return $ id ;
@@ -1070,9 +1103,9 @@ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY)
10701103
10711104 call_user_func ($ call ['callback ' ], array (
10721105 'result ' => isset ($ results ['result ' ][$ idx ]) ? $ results ['result ' ][$ idx ] : null ,
1073- 'error ' => isset ($ results ['result_error ' ][$ idx ]) ? $ results ['result_error ' ][$ idx ] : null ,
1074- 'total ' => isset ($ results ['result_total ' ][$ idx ]) ? $ results ['result_total ' ][$ idx ] : null ,
1075- 'next ' => isset ($ results ['result_next ' ][$ idx ]) ? $ results ['result_next ' ][$ idx ] : null ,
1106+ 'error ' => isset ($ results ['result_error ' ][$ idx ]) ? $ results ['result_error ' ][$ idx ] : null ,
1107+ 'total ' => isset ($ results ['result_total ' ][$ idx ]) ? $ results ['result_total ' ][$ idx ] : null ,
1108+ 'next ' => isset ($ results ['result_next ' ][$ idx ]) ? $ results ['result_next ' ][$ idx ] : null ,
10761109 ));
10771110 }
10781111 if (count ($ this ->_batch ) && $ delay ) {
@@ -1105,7 +1138,12 @@ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY)
11051138 public function call ($ methodName , array $ additionalParameters = array ())
11061139 {
11071140 try {
1108- $ result = $ this ->_call ($ methodName , $ additionalParameters );
1141+ $ result = $ this ->getWebhookUsage () ? $ this ->_call_webhook ($ methodName , $ additionalParameters )
1142+ : $ this ->_call ($ methodName , $ additionalParameters );
1143+
1144+ if (is_callable ($ this ->_onCallApiMethod )) {
1145+ call_user_func ($ this ->_onCallApiMethod , $ this , $ methodName );
1146+ }
11091147 } catch (Bitrix24TokenIsExpiredException $ e ) {
11101148 if (!is_callable ($ this ->_onExpiredToken )) {
11111149 throw $ e ;
@@ -1115,7 +1153,9 @@ public function call($methodName, array $additionalParameters = array())
11151153 if (!$ retry ) {
11161154 throw $ e ;
11171155 }
1118- $ result = $ this ->_call ($ methodName , $ additionalParameters );
1156+
1157+ $ result = $ this ->getWebhookUsage () ? $ this ->_call_webhook ($ methodName , $ additionalParameters )
1158+ : $ this ->_call ($ methodName , $ additionalParameters );
11191159 }
11201160
11211161 return $ result ;
@@ -1166,8 +1206,8 @@ protected function _call($methodName, array $additionalParameters = array())
11661206
11671207 // execute request
11681208 $ this ->log ->info ('call bitrix24 method ' , array (
1169- 'BITRIX24_DOMAIN ' => $ this ->domain ,
1170- 'METHOD_NAME ' => $ methodName ,
1209+ 'BITRIX24_DOMAIN ' => $ this ->domain ,
1210+ 'METHOD_NAME ' => $ methodName ,
11711211 'METHOD_PARAMETERS ' => $ additionalParameters ,
11721212 ));
11731213 $ requestResult = $ this ->executeRequest ($ url , $ additionalParameters );
@@ -1219,4 +1259,107 @@ protected function _call($methodName, array $additionalParameters = array())
12191259
12201260 return $ requestResult ;
12211261 }
1262+
1263+ /**
1264+ * Set whether we using webhook or application in API calls
1265+ * If true - use webhook in API call
1266+ *
1267+ * @param bool $webhook_usage_boolean
1268+ *
1269+ * @return bool
1270+ */
1271+ public function setWebhookUsage ($ webhook_usage_boolean )
1272+ {
1273+ $ this ->webhook_usage = $ webhook_usage_boolean ;
1274+
1275+ return true ;
1276+ }
1277+
1278+ /**
1279+ * Return whether we using webhook or application in API calls
1280+ *
1281+ * @return bool
1282+ */
1283+ public function getWebhookUsage ()
1284+ {
1285+ return $ this ->webhook_usage ;
1286+ }
1287+
1288+ /**
1289+ * Set webhook secret to use in API calls
1290+ *
1291+ * @param string $webhook_secret
1292+ *
1293+ * @return bool
1294+ */
1295+ public function setWebhookSecret ($ webhook_secret )
1296+ {
1297+ $ this ->webhook_secret = $ webhook_secret ;
1298+
1299+ return true ;
1300+ }
1301+
1302+ /**
1303+ * Return string with webhook secret
1304+ *
1305+ * @return string
1306+ */
1307+ public function getWebhookSecret ()
1308+ {
1309+ return $ this ->webhook_secret ;
1310+ }
1311+
1312+ /**
1313+ * Execute Bitrix24 REST API method using webhook
1314+ *
1315+ * @param string $methodName
1316+ * @param array $additionalParameters
1317+ *
1318+ * @return array
1319+ * @throws Bitrix24Exception
1320+ * @throws Bitrix24ApiException
1321+ * @throws Bitrix24TokenIsInvalidException
1322+ * @throws Bitrix24TokenIsExpiredException
1323+ * @throws Bitrix24WrongClientException
1324+ * @throws Bitrix24MethodNotFoundException
1325+ * @throws Bitrix24PaymentRequiredException
1326+ * @throws Bitrix24SecurityException
1327+ * @throws Bitrix24PortalDeletedException
1328+ * @throws Bitrix24IoException
1329+ * @throws Bitrix24EmptyResponseException
1330+ * @throws Bitrix24PortalRenamedException
1331+ */
1332+ protected function _call_webhook ($ methodName , array $ additionalParameters = array ())
1333+ {
1334+ if (null === $ this ->getDomain ()) {
1335+ throw new Bitrix24Exception ('domain not found, you must call setDomain method before ' );
1336+ }
1337+
1338+ if ('' === $ methodName ) {
1339+ throw new Bitrix24Exception ('method name not found, you must set method name ' );
1340+ }
1341+
1342+ if (null === $ this ->getWebhookSecret ()) {
1343+ throw new Bitrix24Exception ('no webhook secret provided, you must call setWebhookSecret method before ' );
1344+ }
1345+
1346+ $ url = 'https:// ' . $ this ->domain . '/rest/ ' . $ this ->getWebhookSecret () . '/ ' . $ methodName ;
1347+
1348+ // save method parameters for debug
1349+ $ this ->methodParameters = $ additionalParameters ;
1350+
1351+ // execute request
1352+ $ this ->log ->info ('call bitrix24 method ' , array (
1353+ 'BITRIX24_WEBHOOK_URL ' => $ url ,
1354+ 'BITRIX24_DOMAIN ' => $ this ->domain ,
1355+ 'METHOD_NAME ' => $ methodName ,
1356+ 'METHOD_PARAMETERS ' => $ additionalParameters ,
1357+ ));
1358+ $ requestResult = $ this ->executeRequest ($ url , $ additionalParameters );
1359+
1360+ // check errors and throw exception if errors exists
1361+ $ this ->handleBitrix24APILevelErrors ($ requestResult , $ methodName , $ additionalParameters );
1362+
1363+ return $ requestResult ;
1364+ }
12221365}
0 commit comments