src/Services/Base/CRest.php line 139

Open in your IDE?
  1. <?php
  2. namespace App\Services\Base;
  3. /**
  4.  *  @version 1.3
  5.  *  define:
  6.  *      C_REST_WEB_HOOK_URL = 'https://rest-api.bitrix24.com/rest/1/doutwqkjxgc3mgc1/'  //url on creat Webhook
  7.  *      or
  8.  *      C_REST_CLIENT_ID = 'local.5c8bb1b0891cf2.87252039' //Application ID
  9.  *      C_REST_CLIENT_SECRET = 'SakeVG5mbRdcQet45UUrt6q72AMTo7fkwXSO7Y5LYFYNCRsA6f'//Application key
  10.  *
  11.  *        C_REST_CURRENT_ENCODING = 'windows-1251'//set current encoding site if encoding unequal UTF-8 to use iconv()
  12.  *      C_REST_BLOCK_LOG = true //turn off default logs
  13.  *      C_REST_LOGS_DIR = __DIR__ .'/logs/' //directory path to save the log
  14.  *      C_REST_LOG_TYPE_DUMP = true //logs save var_export for viewing convenience
  15.  *      C_REST_IGNORE_SSL = true //turn off validate ssl by curl
  16.  */
  17. class CRest
  18. {
  19.     private static $web_hook;
  20.     const BATCH_COUNT 50//count batch 1 query
  21.     const TYPE_TRANSPORT 'json'// json or xml
  22. //    const C_REST_WEB_HOOK_URL = 'https://b24-5zbws3.bitrix24.by/rest/1/8ot5ilkbxup82264/';
  23.     const C_REST_BLOCK_LOG true;
  24.     public static function setWebhook($web_hook)
  25.     {
  26.         self::$web_hook $web_hook;
  27.     }
  28.     /**
  29.      * call where install application even url
  30.      * only for rest application, not webhook
  31.      */
  32.     public static function installApp()
  33.     {
  34.         $result = [
  35.             'rest_only' => true,
  36.             'install' => false
  37.         ];
  38.         if($_REQUEST'event' ] == 'ONAPPINSTALL' && !empty($_REQUEST'auth' ]))
  39.         {
  40.             $result['install'] = static::setAppSettings($_REQUEST'auth' ], true);
  41.         }
  42.         elseif($_REQUEST['PLACEMENT'] == 'DEFAULT')
  43.         {
  44.             $result['rest_only'] = false;
  45.             $result['install'] = static::setAppSettings(
  46.                 [
  47.                     'access_token' => htmlspecialchars($_REQUEST['AUTH_ID']),
  48.                     'expires_in' => htmlspecialchars($_REQUEST['AUTH_EXPIRES']),
  49.                     'application_token' => htmlspecialchars($_REQUEST['APP_SID']),
  50.                     'refresh_token' => htmlspecialchars($_REQUEST['REFRESH_ID']),
  51.                     'domain' => htmlspecialchars($_REQUEST['DOMAIN']),
  52.                     'client_endpoint' => 'https://' htmlspecialchars($_REQUEST['DOMAIN']) . '/rest/',
  53.                 ],
  54.                 true
  55.             );
  56.         }
  57.         static::setLog(
  58.             [
  59.                 'request' => $_REQUEST,
  60.                 'result' => $result
  61.             ],
  62.             'installApp'
  63.         );
  64.         return $result;
  65.     }
  66.     /**
  67.      * @var $arParams array
  68.      * $arParams = [
  69.      *      'method'    => 'some rest method',
  70.      *      'params'    => []//array params of method
  71.      * ];
  72.      * @return mixed array|string|boolean curl-return or error
  73.      *
  74.      */
  75.     protected static function callCurl($arParams)
  76.     {
  77.         if(!function_exists('curl_init'))
  78.         {
  79.             return [
  80.                 'error'             => 'error_php_lib_curl',
  81.                 'error_information' => 'need install curl lib'
  82.             ];
  83.         }
  84.         $arSettings = static::getAppSettings();
  85.         if($arSettings !== false)
  86.         {
  87.             if(@$arParams'this_auth' ] == 'Y')
  88.             {
  89.                 $url 'https://oauth.bitrix.info/oauth/token/';
  90.             }
  91.             else
  92.             {
  93.                 $url $arSettings"client_endpoint" ] . $arParams'method' ] . '.' . static::TYPE_TRANSPORT;
  94.                 if(empty($arSettings'is_web_hook' ]) || $arSettings'is_web_hook' ] != 'Y')
  95.                 {
  96.                     $arParams'params' ][ 'auth' ] = $arSettings'access_token' ];
  97.                 }
  98.             }
  99.             $sPostFields http_build_query($arParams'params' ]);
  100.             try
  101.             {
  102.                 $obCurl curl_init();
  103.                 curl_setopt($obCurlCURLOPT_URL$url);
  104.                 curl_setopt($obCurlCURLOPT_RETURNTRANSFERtrue);
  105.                 if($sPostFields)
  106.                 {
  107.                     curl_setopt($obCurlCURLOPT_POSTtrue);
  108.                     curl_setopt($obCurlCURLOPT_POSTFIELDS$sPostFields);
  109.                 }
  110.                 curl_setopt(
  111.                     $obCurlCURLOPT_FOLLOWLOCATION, (isset($arParams'followlocation' ]))
  112.                     ? $arParams'followlocation' ] : 1
  113.                 );
  114.                 if(defined("C_REST_IGNORE_SSL") && C_REST_IGNORE_SSL === true)
  115.                 {
  116.                     curl_setopt($obCurlCURLOPT_SSL_VERIFYPEERfalse);
  117.                     curl_setopt($obCurlCURLOPT_SSL_VERIFYHOSTfalse);
  118.                 }
  119. //                var_dump(curl_getinfo($obCurl));
  120.                 $out curl_exec($obCurl);
  121.                 $info curl_getinfo($obCurl);
  122. //                var_dump($info);
  123. //                var_dump(curl_error($obCurl));
  124. //                var_dump(json_decode($out,1));
  125.                 if(curl_errno($obCurl))
  126.                 {
  127.                     $info'curl_error' ] = curl_error($obCurl);
  128.                 }
  129.                 if(@$arParams'this_auth' ] != 'Y' && static::TYPE_TRANSPORT == 'xml')//auth only json support
  130.                 {
  131.                     $result $out;
  132.                 }
  133.                 else
  134.                 {
  135.                     $result = static::expandData($out);
  136.                 }
  137.                 curl_close($obCurl);
  138.                 if(!empty($result'error' ]))
  139.                 {
  140.                     if($result'error' ] == 'expired_token' && empty($arParams'this_auth' ]))
  141.                     {
  142.                         $result = static::GetNewAuth($arParams);
  143.                     }
  144.                     else
  145.                     {
  146.                         $arErrorInform = [
  147.                             'expired_token'          => 'expired token, cant get new auth? Check access oauth server.',
  148.                             'invalid_token'          => 'invalid token, need reinstall application',
  149.                             'invalid_grant'          => 'invalid grant, check out define C_REST_CLIENT_SECRET or C_REST_CLIENT_ID',
  150.                             'invalid_client'         => 'invalid client, check out define C_REST_CLIENT_SECRET or C_REST_CLIENT_ID',
  151.                             'QUERY_LIMIT_EXCEEDED'   => 'Too many requests, maximum 2 query by second',
  152.                             'ERROR_METHOD_NOT_FOUND' => 'Method not found! You can see the permissions of the application: CRest::call(\'scope\')',
  153.                             'NO_AUTH_FOUND'          => 'Some setup error b24, check in table "b_module_to_module" event "OnRestCheckAuth"',
  154.                             'INTERNAL_SERVER_ERROR'  => 'Server down, try later'
  155.                         ];
  156.                         if(!empty($arErrorInform$result'error' ] ]))
  157.                         {
  158.                             $result'error_information' ] = $arErrorInform$result'error' ] ];
  159.                         }
  160.                     }
  161.                 }
  162.                 if(!empty($info'curl_error' ]))
  163.                 {
  164.                     $result'error' ] = 'curl_error';
  165.                     $result'error_information' ] = $info'curl_error' ];
  166.                 }
  167.                 static::setLog(
  168.                     [
  169.                         'url'    => $url,
  170.                         'info'   => $info,
  171.                         'params' => $arParams,
  172.                         'result' => $result
  173.                     ],
  174.                     'callCurl'
  175.                 );
  176.                 return $result;
  177.             }
  178.             catch(Exception $e)
  179.             {
  180.                 return [
  181.                     'error'             => 'exception',
  182.                     'error_information' => $e -> getMessage(),
  183.                 ];
  184.             }
  185.         }
  186.         return [
  187.             'error'             => 'no_install_app',
  188.             'error_information' => 'error install app, pls install local application '
  189.         ];
  190.     }
  191.     /**
  192.      * Generate a request for callCurl()
  193.      *
  194.      * @var $method string
  195.      * @var $params array method params
  196.      * @return mixed array|string|boolean curl-return or error
  197.      */
  198.     public static function call($method$params = [])
  199.     {
  200.         $arPost = [
  201.             'method' => $method,
  202.             'params' => $params
  203.         ];
  204.         if(defined('C_REST_CURRENT_ENCODING'))
  205.         {
  206.             $arPost'params' ] = static::changeEncoding($arPost'params' ]);
  207.         }
  208.         $result = static::callCurl($arPost);
  209. //        file_put_contents(__DIR__.'/ttt.txt', print_r($result,1), FILE_APPEND);
  210.         return $result;
  211.     }
  212.     /**
  213.      * @example $arData:
  214.      * $arData = [
  215.      *      'find_contact' => [
  216.      *          'method' => 'crm.duplicate.findbycomm',
  217.      *          'params' => [ "entity_type" => "CONTACT",  "type" => "EMAIL", "values" => array("info@bitrix24.com") ]
  218.      *      ],
  219.      *      'get_contact' => [
  220.      *          'method' => 'crm.contact.get',
  221.      *          'params' => [ "id" => '$result[find_contact][CONTACT][0]' ]
  222.      *      ],
  223.      *      'get_company' => [
  224.      *          'method' => 'crm.company.get',
  225.      *          'params' => [ "id" => '$result[get_contact][COMPANY_ID]', "select" => ["*"],]
  226.      *      ]
  227.      * ];
  228.      *
  229.      * @var $arData array
  230.      * @var $halt   integer 0 or 1 stop batch on error
  231.      * @return array
  232.      *
  233.      */
  234.     public static function  callBatch($arData$halt 0)
  235.     {
  236.         $arResult = [];
  237.         if(is_array($arData))
  238.         {
  239.             if(defined('C_REST_CURRENT_ENCODING'))
  240.             {
  241.                 $arData = static::changeEncoding($arData);
  242.             }
  243.             $arDataRest = [];
  244.             $i 0;
  245.             foreach($arData as $key => $data)
  246.             {
  247.                 if(!empty($data'method' ]))
  248.                 {
  249.                     $i++;
  250.                     if (static::BATCH_COUNT >= $i)
  251.                     {
  252.                         $arDataRest'cmd' ][ $key ] = $data'method' ];
  253.                         if(!empty($data'params' ]))
  254.                         {
  255.                             $arDataRest'cmd' ][ $key ] .= '?' http_build_query($data'params' ]);
  256.                         }
  257.                     }
  258.                 }
  259.             }
  260.             if(!empty($arDataRest))
  261.             {
  262.                 $arDataRest'halt' ] = $halt;
  263.                 $arPost = [
  264.                     'method' => 'batch',
  265.                     'params' => $arDataRest
  266.                 ];
  267.                 $arResult = static::callCurl($arPost);
  268.             }
  269.         }
  270.         return $arResult;
  271.     }
  272.     /**
  273.      * Getting a new authorization and sending a request for the 2nd time
  274.      *
  275.      * @var $arParams array request when authorization error returned
  276.      * @return array query result from $arParams
  277.      *
  278.      */
  279.     private static function GetNewAuth($arParams)
  280.     {
  281.         $result = [];
  282.         $arSettings = static::getAppSettings();
  283.         if($arSettings !== false)
  284.         {
  285.             $arParamsAuth = [
  286.                 'this_auth' => 'Y',
  287.                 'params'    =>
  288.                     [
  289.                         'client_id'     => $arSettings'C_REST_CLIENT_ID' ],
  290.                         'grant_type'    => 'refresh_token',
  291.                         'client_secret' => $arSettings'C_REST_CLIENT_SECRET' ],
  292.                         'refresh_token' => $arSettings"refresh_token" ],
  293.                     ]
  294.             ];
  295.             $newData = static::callCurl($arParamsAuth);
  296.             if(isset($newData'C_REST_CLIENT_ID' ]))
  297.             {
  298.                 unset($newData'C_REST_CLIENT_ID' ]);
  299.             }
  300.             if(isset($newData'C_REST_CLIENT_SECRET' ]))
  301.             {
  302.                 unset($newData'C_REST_CLIENT_SECRET' ]);
  303.             }
  304.             if(isset($newData'error' ]))
  305.             {
  306.                 unset($newData'error' ]);
  307.             }
  308.             if(static::setAppSettings($newData))
  309.             {
  310.                 $arParams'this_auth' ] = 'N';
  311.                 $result = static::callCurl($arParams);
  312.             }
  313.         }
  314.         return $result;
  315.     }
  316.     /**
  317.      * @var $arSettings array settings application
  318.      * @var $isInstall  boolean true if install app by installApp()
  319.      * @return boolean
  320.      */
  321.     private static function setAppSettings($arSettings$isInstall false)
  322.     {
  323.         $return false;
  324.         if(is_array($arSettings))
  325.         {
  326.             $oldData = static::getAppSettings();
  327.             if($isInstall != true && !empty($oldData) && is_array($oldData))
  328.             {
  329.                 $arSettings array_merge($oldData$arSettings);
  330.             }
  331.             $return = static::setSettingData($arSettings);
  332.         }
  333.         return $return;
  334.     }
  335.     /**
  336.      * @return mixed setting application for query
  337.      */
  338.     private static function getAppSettings()
  339.     {
  340.         if(self::$web_hook && !empty(self::$web_hook))
  341.         {
  342.             $arData = [
  343.                 'client_endpoint' => self::$web_hook,
  344.                 'is_web_hook'     => 'Y'
  345.             ];
  346.             $isCurrData true;
  347.         }
  348.         else
  349.         {
  350.             $arData = static::getSettingData();
  351.             $isCurrData false;
  352.             if(
  353.                 !empty($arData'access_token' ]) &&
  354.                 !empty($arData'domain' ]) &&
  355.                 !empty($arData'refresh_token' ]) &&
  356.                 !empty($arData'application_token' ]) &&
  357.                 !empty($arData'client_endpoint' ])
  358.             )
  359.             {
  360.                 $isCurrData true;
  361.             }
  362.         }
  363.         return ($isCurrData) ? $arData false;
  364.     }
  365.     /**
  366.      * Can overridden this method to change the data storage location.
  367.      *
  368.      * @return array setting for getAppSettings()
  369.      */
  370.     protected static function getSettingData()
  371.     {
  372.         $return = [];
  373.         if(file_exists(__DIR__ '/settings.json'))
  374.         {
  375.             $return = static::expandData(file_get_contents(__DIR__ '/settings.json'));
  376.             if(defined("C_REST_CLIENT_ID") && !empty(C_REST_CLIENT_ID))
  377.             {
  378.                 $return['C_REST_CLIENT_ID'] = C_REST_CLIENT_ID;
  379.             }
  380.             if(defined("C_REST_CLIENT_SECRET") && !empty(C_REST_CLIENT_SECRET))
  381.             {
  382.                 $return['C_REST_CLIENT_SECRET'] = C_REST_CLIENT_SECRET;
  383.             }
  384.         }
  385.         return $return;
  386.     }
  387.     /**
  388.      * @var $data mixed
  389.      * @var $encoding boolean true - encoding to utf8, false - decoding
  390.      *
  391.      * @return string json_encode with encoding
  392.      */
  393.     protected static function changeEncoding($data$encoding true)
  394.     {
  395.         if(is_array($data))
  396.         {
  397.             $result = [];
  398.             foreach ($data as $k => $item)
  399.             {
  400.                 $k = static::changeEncoding($k$encoding);
  401.                 $result[$k] = static::changeEncoding($item$encoding);
  402.             }
  403.         }
  404.         else
  405.         {
  406.             if($encoding)
  407.             {
  408.                 $result iconv(C_REST_CURRENT_ENCODING"UTF-8//TRANSLIT"$data);
  409.             }
  410.             else
  411.             {
  412.                 $result iconv"UTF-8",C_REST_CURRENT_ENCODING$data);
  413.             }
  414.         }
  415.         return $result;
  416.     }
  417.     /**
  418.      * @var $data mixed
  419.      * @var $debag boolean
  420.      *
  421.      * @return string json_encode with encoding
  422.      */
  423.     protected static function wrapData($data$debag false)
  424.     {
  425.         if(defined('C_REST_CURRENT_ENCODING'))
  426.         {
  427.             $data = static::changeEncoding($datatrue);
  428.         }
  429.         $return json_encode($dataJSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT);
  430.         if($debag)
  431.         {
  432.             $e json_last_error();
  433.             if ($e != JSON_ERROR_NONE)
  434.             {
  435.                 if ($e == JSON_ERROR_UTF8)
  436.                 {
  437.                     return 'Failed encoding! Recommended \'UTF - 8\' or set define C_REST_CURRENT_ENCODING = current site encoding for function iconv()';
  438.                 }
  439.             }
  440.         }
  441.         return $return;
  442.     }
  443.     /**
  444.      * @var $data mixed
  445.      * @var $debag boolean
  446.      *
  447.      * @return string json_decode with encoding
  448.      */
  449.     protected static function expandData($data)
  450.     {
  451.         $return json_decode($datatrue);
  452.         if(defined('C_REST_CURRENT_ENCODING'))
  453.         {
  454.             $return = static::changeEncoding($returnfalse);
  455.         }
  456.         return $return;
  457.     }
  458.     /**
  459.      * Can overridden this method to change the data storage location.
  460.      *
  461.      * @var $arSettings array settings application
  462.      * @return boolean is successes save data for setSettingData()
  463.      */
  464.     protected static function setSettingData($arSettings)
  465.     {
  466.         return  (boolean)file_put_contents(__DIR__ '/settings.json', static::wrapData($arSettings));
  467.     }
  468.     /**
  469.      * Can overridden this method to change the log data storage location.
  470.      *
  471.      * @var $arData array of logs data
  472.      * @var $type   string to more identification log data
  473.      * @return boolean is successes save log data
  474.      */
  475.     public static function setLog($arData$type '')
  476.     {
  477.         $return false;
  478.         if(!self::C_REST_BLOCK_LOG || self::C_REST_BLOCK_LOG !== true)
  479.         {
  480.             if(defined("C_REST_LOGS_DIR"))
  481.             {
  482.                 $path C_REST_LOGS_DIR;
  483.             }
  484.             else
  485.             {
  486.                 $path __DIR__ '/logs/';
  487.             }
  488.             $path .= date("Y-m-d/H") . '/';
  489.             @mkdir($path0775true);
  490.             $path .= time() . '_' $type '_' rand(19999999) . 'log';
  491.             if(!defined("C_REST_LOG_TYPE_DUMP") || C_REST_LOG_TYPE_DUMP !== true)
  492.             {
  493.                 $return file_put_contents($path '.json', static::wrapData($arData));
  494.             }
  495.             else
  496.             {
  497.                 $return file_put_contents($path '.txt'var_export($arDatatrue));
  498.             }
  499.         }
  500.         return $return;
  501.     }
  502.     /**
  503.      * check minimal settings server to work CRest
  504.      * @var $print boolean
  505.      * @return array of errors
  506.      */
  507.     public static function checkServer($print true)
  508.     {
  509.         $return = [];
  510.         //check curl lib install
  511.         if(!function_exists('curl_init'))
  512.         {
  513.             $return['curl_error'] = 'Need install curl lib.';
  514.         }
  515.         //creat setting file
  516.         file_put_contents(__DIR__ '/settings_check.json', static::wrapData(['test'=>'data']));
  517.         if(!file_exists(__DIR__ '/settings_check.json'))
  518.         {
  519.             $return['setting_creat_error'] = 'Check permission! Recommended: folders: 775, files: 664';
  520.         }
  521.         unlink(__DIR__ '/settings_check.json');
  522.         //creat logs folder and files
  523.         $path __DIR__ '/logs/'.date("Y-m-d/H") . '/';
  524.         if(!mkdir($path0775true) && !file_exists($path))
  525.         {
  526.             $return['logs_folder_creat_error'] = 'Check permission! Recommended: folders: 775, files: 664';
  527.         }
  528.         else
  529.         {
  530.             file_put_contents($path 'test.txt'var_export(['test'=>'data'], true));
  531.             if(!file_exists($path 'test.txt'))
  532.             {
  533.                 $return['logs_file_creat_error'] = 'check permission! recommended: folders: 775, files: 664';
  534.             }
  535.             unlink($path 'test.txt');
  536.         }
  537.         if($print === true)
  538.         {
  539.             if(empty($return))
  540.             {
  541.                 $return['success'] = 'Success!';
  542.             }
  543.             echo '<pre>';
  544.             print_r($return);
  545.             echo '</pre>';
  546.         }
  547.         return $return;
  548.     }
  549. }