2015-05-01 16:12:30 +02:00
< ? php
2017-05-25 13:48:30 +02:00
/* Copyright ( C ) 2015 Jean - François Ferry < jfefe @ aternatik . fr >
2016-09-26 02:18:11 +02:00
* Copyright ( C ) 2016 Laurent Destailleur < eldy @ users . sourceforge . net >
2018-10-27 14:43:12 +02:00
* Copyright ( C ) 2017 Regis Houssin < regis . houssin @ inodbox . com >
2021-03-22 09:37:25 +01:00
* Copyright ( C ) 2021 Alexis LAURIER < contact @ alexislaurier . fr >
2024-03-14 21:59:15 +01:00
* Copyright ( C ) 2024 MDW < mdeweerd @ users . noreply . github . com >
2024-11-04 23:53:20 +01:00
* Copyright ( C ) 2024 Frédéric France < frederic . france @ free . fr >
2015-11-22 17:17:06 +01:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2019-09-23 21:55:30 +02:00
* along with this program . If not , see < https :// www . gnu . org / licenses />.
2015-11-22 17:17:06 +01:00
*/
2015-05-01 16:12:30 +02:00
2015-11-22 17:17:06 +01:00
/**
* \defgroup api Module DolibarrApi
* \brief API loader
* Search files htdocs /< module >/ class / api_ < module >. class . php
2017-06-25 17:09:08 +02:00
* \file htdocs / api / index . php
2015-05-01 16:12:30 +02:00
*/
2016-09-08 12:12:00 +02:00
2019-08-25 16:40:21 +02:00
use Luracast\Restler\Format\UploadFormat ;
2021-02-23 17:44:43 +01:00
if ( ! defined ( 'NOCSRFCHECK' )) {
define ( 'NOCSRFCHECK' , '1' ); // Do not check anti CSRF attack test
}
if ( ! defined ( 'NOTOKENRENEWAL' )) {
define ( 'NOTOKENRENEWAL' , '1' ); // Do not check anti POST attack test
}
if ( ! defined ( 'NOREQUIREMENU' )) {
define ( 'NOREQUIREMENU' , '1' ); // If there is no need to load and show top and left menu
}
if ( ! defined ( 'NOREQUIREHTML' )) {
define ( 'NOREQUIREHTML' , '1' ); // If we don't need to load the html.form.class.php
}
if ( ! defined ( 'NOREQUIREAJAX' )) {
define ( 'NOREQUIREAJAX' , '1' ); // Do not load ajax.lib.php library
}
if ( ! defined ( " NOLOGIN " )) {
define ( " NOLOGIN " , '1' ); // If this page is public (can be called outside logged session)
}
if ( ! defined ( " NOSESSION " )) {
define ( " NOSESSION " , '1' );
}
2023-07-19 04:14:49 +02:00
if ( ! defined ( " NODEFAULTVALUES " )) {
define ( " NODEFAULTVALUES " , '1' );
}
2015-11-22 17:17:06 +01:00
2017-10-19 17:30:08 +02:00
// Force entity if a value is provided into HTTP header. Otherwise, will use the entity of user of token used.
2021-02-23 17:44:43 +01:00
if ( ! empty ( $_SERVER [ 'HTTP_DOLAPIENTITY' ])) {
define ( " DOLENTITY " , ( int ) $_SERVER [ 'HTTP_DOLAPIENTITY' ]);
}
2017-09-16 03:54:23 +02:00
2022-02-09 21:12:06 +01:00
// Response for preflight requests (used by browser when into a CORS context)
if ( ! empty ( $_SERVER [ 'REQUEST_METHOD' ]) && $_SERVER [ 'REQUEST_METHOD' ] == 'OPTIONS' && ! empty ( $_SERVER [ 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' ])) {
header ( 'Access-Control-Allow-Origin: *' );
header ( 'Access-Control-Allow-Methods: GET, POST, PUT, DELETE' );
header ( 'Access-Control-Allow-Headers: Content-Type, Authorization, api_key, DOLAPIKEY' );
http_response_code ( 204 );
exit ;
}
2021-03-26 14:30:47 +01:00
// When we request url to get the json file, we accept Cross site so we can include the descriptor into an external tool.
if ( preg_match ( '/\/explorer\/swagger\.json/' , $_SERVER [ " PHP_SELF " ])) {
header ( 'Access-Control-Allow-Origin: *' );
header ( 'Access-Control-Allow-Methods: GET, POST, PUT, DELETE' );
header ( 'Access-Control-Allow-Headers: Content-Type, Authorization, api_key, DOLAPIKEY' );
}
2022-02-09 18:10:21 +01:00
// When we request url to get an API, we accept Cross site so we can make js API call inside another website
if ( preg_match ( '/\/api\/index\.php/' , $_SERVER [ " PHP_SELF " ])) {
header ( 'Access-Control-Allow-Origin: *' );
header ( 'Access-Control-Allow-Methods: GET, POST, PUT, DELETE' );
header ( 'Access-Control-Allow-Headers: Content-Type, Authorization, api_key, DOLAPIKEY' );
}
2022-09-09 13:58:54 +02:00
header ( 'X-Frame-Options: SAMEORIGIN' );
2022-02-09 18:10:21 +01:00
2020-04-10 10:59:32 +02:00
$res = 0 ;
2021-02-23 17:44:43 +01:00
if ( ! $res && file_exists ( " ../main.inc.php " )) {
$res = include '../main.inc.php' ;
}
if ( ! $res ) {
die ( " Include of main fails " );
}
2015-11-22 17:17:06 +01:00
require_once DOL_DOCUMENT_ROOT . '/includes/restler/framework/Luracast/Restler/AutoLoader.php' ;
2024-03-14 21:59:15 +01:00
call_user_func (
/**
* @ return Luracast\Restler\AutoLoader
*/
static function () {
$loader = Luracast\Restler\AutoLoader :: instance ();
spl_autoload_register ( $loader );
return $loader ;
}
);
2015-11-22 17:17:06 +01:00
require_once DOL_DOCUMENT_ROOT . '/api/class/api.class.php' ;
require_once DOL_DOCUMENT_ROOT . '/api/class/api_access.class.php' ;
require_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php' ;
2024-11-04 23:53:20 +01:00
/**
* @ var Conf $conf
* @ var DoliDB $db
* @ var HookManager $hookmanager
* @ var Translate $langs
* @ var User $user
*/
2015-11-22 17:17:06 +01:00
2019-11-02 13:52:24 +01:00
$url = $_SERVER [ 'PHP_SELF' ];
2020-03-26 03:32:05 +01:00
if ( preg_match ( '/api\/index\.php$/' , $url )) { // sometimes $_SERVER['PHP_SELF'] is 'api\/index\.php' instead of 'api\/index\.php/explorer.php' or 'api\/index\.php/method'
2022-05-19 21:32:43 +02:00
$url = $_SERVER [ 'PHP_SELF' ] . ( empty ( $_SERVER [ 'PATH_INFO' ]) ? $_SERVER [ 'ORIG_PATH_INFO' ] : $_SERVER [ 'PATH_INFO' ]);
2020-03-25 19:29:54 +01:00
}
2019-11-02 13:52:24 +01:00
// Fix for some NGINX setups (this should not be required even with NGINX, however setup of NGINX are often mysterious and this may help is such cases)
2023-10-24 17:00:13 +02:00
if ( getDolGlobalString ( 'MAIN_NGINX_FIX' )) {
2019-11-02 13:52:24 +01:00
$url = ( isset ( $_SERVER [ 'SCRIPT_URI' ]) && $_SERVER [ " SCRIPT_URI " ] !== null ) ? $_SERVER [ " SCRIPT_URI " ] : $_SERVER [ 'PHP_SELF' ];
}
2019-11-02 13:51:45 +01:00
2015-11-22 17:17:06 +01:00
// Enable and test if module Api is enabled
2023-12-04 11:41:14 +01:00
if ( ! isModEnabled ( 'api' )) {
2020-10-31 14:32:18 +01:00
$langs -> load ( " admin " );
2021-03-26 14:54:12 +01:00
dol_syslog ( " Call of Dolibarr API interfaces with module API REST are disabled " );
2020-10-31 14:32:18 +01:00
print $langs -> trans ( " WarningModuleNotActive " , 'Api' ) . '.<br><br>' ;
print $langs -> trans ( " ToActivateModule " );
//session_destroy();
exit ( 0 );
2015-11-22 17:17:06 +01:00
}
2017-01-22 20:55:26 +01:00
// Test if explorer is not disabled
2023-10-24 17:00:13 +02:00
if ( preg_match ( '/api\/index\.php\/explorer/' , $url ) && getDolGlobalString ( 'API_EXPLORER_DISABLED' )) {
2020-10-31 14:32:18 +01:00
$langs -> load ( " admin " );
2022-10-03 17:30:47 +02:00
dol_syslog ( " Call Dolibarr API interfaces with module API REST disabled " );
2020-10-31 14:32:18 +01:00
print $langs -> trans ( " WarningAPIExplorerDisabled " ) . '.<br><br>' ;
//session_destroy();
exit ( 0 );
2017-01-22 20:55:26 +01:00
}
2024-01-12 20:58:09 +01:00
// This 2 lines are useful only if we want to exclude some Urls from the explorer
2018-01-14 15:58:04 +01:00
//use Luracast\Restler\Explorer;
//Explorer::$excludedPaths = array('/categories');
2016-12-12 15:19:47 +01:00
2015-11-22 17:17:06 +01:00
2017-06-25 17:09:08 +02:00
// Analyze URLs
// index.php/explorer do a redirect to index.php/explorer/
2021-04-26 19:21:23 +02:00
// index.php/explorer/ called by swagger to build explorer page index.php/explorer/index.html
2017-06-25 17:09:08 +02:00
// index.php/explorer/.../....png|.css|.js called by swagger for resources to build explorer page
// index.php/explorer/resources.json called by swagger to get list of all services
// index.php/explorer/resources.json/xxx called by swagger to get detail of services xxx
// index.php/xxx called by any REST client to run API
2020-04-10 10:59:32 +02:00
$reg = array ();
2019-10-10 15:18:24 +02:00
preg_match ( '/index\.php\/([^\/]+)(.*)$/' , $url , $reg );
2017-06-25 17:09:08 +02:00
// .../index.php/categories?sortfield=t.rowid&sortorder=ASC
2024-02-12 05:25:45 +01:00
$hookmanager -> initHooks ( array ( 'api' ));
2019-07-26 13:23:42 +02:00
// When in production mode, a file api/temp/routes.php is created with the API available of current call.
// But, if we set $refreshcache to false, so it may have only one API in the routes.php file if we make a call for one API without
// using the explorer. And when we make another call for another API, the API is not into the api/temp/routes.php and a 404 is returned.
// So we force refresh to each call.
2024-02-12 05:25:45 +01:00
$refreshcache = ( getDolGlobalString ( 'API_PRODUCTION_DO_NOT_ALWAYS_REFRESH_CACHE' ) ? false : true );
2021-02-23 17:44:43 +01:00
if ( ! empty ( $reg [ 1 ]) && $reg [ 1 ] == 'explorer' && ( $reg [ 2 ] == '/swagger.json' || $reg [ 2 ] == '/swagger.json/root' || $reg [ 2 ] == '/resources.json' || $reg [ 2 ] == '/resources.json/root' )) {
2020-10-31 14:32:18 +01:00
$refreshcache = true ;
2022-10-03 17:30:47 +02:00
if ( ! is_writable ( $conf -> api -> dir_temp )) {
2024-12-01 23:18:38 +01:00
dol_syslog ( " ErrorFailedToWriteInApiTempDirectory " . $conf -> api -> dir_temp , LOG_ERR );
2022-10-03 17:30:47 +02:00
print 'Erreur temp dir api/temp not writable' ;
2024-04-02 12:28:55 +02:00
header ( 'HTTP/1.1 500 temp dir api/temp not writable' );
2022-10-03 17:30:47 +02:00
exit ( 0 );
}
2019-07-26 13:23:42 +02:00
}
2017-06-25 18:18:17 +02:00
$api = new DolibarrApi ( $db , '' , $refreshcache );
//var_dump($api->r->apiVersionMap);
2015-11-22 17:17:06 +01:00
2022-03-18 14:09:53 +01:00
// If MAIN_API_DEBUG is set to 1, we save logs into file "dolibarr_api.log"
2023-10-24 17:00:13 +02:00
if ( getDolGlobalString ( 'MAIN_API_DEBUG' )) {
2022-03-18 14:09:53 +01:00
$r = $api -> r ;
$r -> onCall ( function () use ( $r ) {
2024-01-12 20:58:09 +01:00
// Don't log Luracast Restler Explorer resources calls
2022-03-18 14:09:53 +01:00
//if (!preg_match('/^explorer/', $r->url)) {
// 'method' => $api->r->requestMethod,
// 'url' => $api->r->url,
// 'route' => $api->r->apiMethodInfo->className.'::'.$api->r->apiMethodInfo->methodName,
// 'version' => $api->r->getRequestedApiVersion(),
// 'data' => $api->r->getRequestData(),
//dol_syslog("Debug API input ".var_export($r, true), LOG_DEBUG, 0, '_api');
dol_syslog ( " Debug API url " . var_export ( $r -> url , true ), LOG_DEBUG , 0 , '_api' );
dol_syslog ( " Debug API input " . var_export ( $r -> getRequestData (), true ), LOG_DEBUG , 0 , '_api' );
//}
});
}
2016-06-13 14:24:09 +02:00
// Enable the Restler API Explorer.
// See https://github.com/Luracast/Restler-API-Explorer for more info.
$api -> r -> addAPIClass ( 'Luracast\\Restler\\Explorer' );
2020-04-10 10:59:32 +02:00
$api -> r -> setSupportedFormats ( 'JsonFormat' , 'XmlFormat' , 'UploadFormat' ); // 'YamlFormat'
2019-01-27 11:55:16 +01:00
$api -> r -> addAuthenticationClass ( 'DolibarrApiAccess' , '' );
2015-11-22 17:17:06 +01:00
2016-12-12 15:19:47 +01:00
// Define accepted mime types
UploadFormat :: $allowedMimeTypes = array ( 'image/jpeg' , 'image/png' , 'text/plain' , 'application/octet-stream' );
2015-11-22 17:17:06 +01:00
2019-08-25 16:40:21 +02:00
// Restrict API to some IPs
2023-10-24 17:00:13 +02:00
if ( getDolGlobalString ( 'API_RESTRICT_ON_IP' )) {
2023-12-13 15:20:53 +01:00
$allowedip = explode ( ' ' , getDolGlobalString ( 'API_RESTRICT_ON_IP' ));
2019-08-25 16:40:21 +02:00
$ipremote = getUserRemoteIP ();
2021-02-23 17:44:43 +01:00
if ( ! in_array ( $ipremote , $allowedip )) {
2023-10-15 15:32:35 +02:00
dol_syslog ( 'Remote ip is ' . $ipremote . ', not into list ' . getDolGlobalString ( 'API_RESTRICT_ON_IP' ));
2019-08-25 16:40:21 +02:00
print 'APIs are not allowed from the IP ' . $ipremote ;
header ( 'HTTP/1.1 503 API not allowed from your IP ' . $ipremote );
2020-06-17 19:26:17 +02:00
//session_destroy();
2019-08-25 16:40:21 +02:00
exit ( 0 );
}
}
2017-06-25 18:18:17 +02:00
2019-07-26 13:16:49 +02:00
// Call Explorer file for all APIs definitions (this part is slow)
2021-02-23 17:44:43 +01:00
if ( ! empty ( $reg [ 1 ]) && $reg [ 1 ] == 'explorer' && ( $reg [ 2 ] == '/swagger.json' || $reg [ 2 ] == '/swagger.json/root' || $reg [ 2 ] == '/resources.json' || $reg [ 2 ] == '/resources.json/root' )) {
2020-10-31 14:32:18 +01:00
// Scan all API files to load them
$listofapis = array ();
$modulesdir = dolGetModulesDirs ();
2021-02-23 17:44:43 +01:00
foreach ( $modulesdir as $dir ) {
2020-10-31 14:32:18 +01:00
// Search available module
dol_syslog ( " Scan directory " . $dir . " for module descriptor files, then search for API files " );
$handle = @ opendir ( dol_osencode ( $dir ));
2021-02-23 17:44:43 +01:00
if ( is_resource ( $handle )) {
while (( $file = readdir ( $handle )) !== false ) {
2020-10-31 14:32:18 +01:00
$regmod = array ();
2021-02-23 17:44:43 +01:00
if ( is_readable ( $dir . $file ) && preg_match ( " /^mod(.*) \ .class \ .php $ /i " , $file , $regmod )) {
2020-10-31 14:32:18 +01:00
$module = strtolower ( $regmod [ 1 ]);
$moduledirforclass = getModuleDirForApiClass ( $module );
$modulenameforenabled = $module ;
2021-02-23 17:44:43 +01:00
if ( $module == 'propale' ) {
$modulenameforenabled = 'propal' ;
2024-02-27 15:29:58 +01:00
} elseif ( $module == 'supplierproposal' ) {
2021-02-23 17:44:43 +01:00
$modulenameforenabled = 'supplier_proposal' ;
2024-02-27 15:29:58 +01:00
} elseif ( $module == 'ficheinter' ) {
$modulenameforenabled = 'intervention' ;
2021-02-23 17:44:43 +01:00
}
2020-10-31 14:32:18 +01:00
dol_syslog ( " Found module file " . $file . " - module= " . $module . " - modulenameforenabled= " . $modulenameforenabled . " - moduledirforclass= " . $moduledirforclass );
// Defined if module is enabled
$enabled = true ;
2022-09-25 15:27:42 +02:00
if ( ! isModEnabled ( $modulenameforenabled )) {
2021-02-23 17:44:43 +01:00
$enabled = false ;
}
2020-10-31 14:32:18 +01:00
2021-02-23 17:44:43 +01:00
if ( $enabled ) {
2020-10-31 14:32:18 +01:00
// If exists, load the API class for enable module
// Search files named api_<object>.class.php into /htdocs/<module>/class directory
// @todo : use getElementProperties() function ?
$dir_part = dol_buildpath ( '/' . $moduledirforclass . '/class/' );
$handle_part = @ opendir ( dol_osencode ( $dir_part ));
2021-02-23 17:44:43 +01:00
if ( is_resource ( $handle_part )) {
while (( $file_searched = readdir ( $handle_part )) !== false ) {
if ( $file_searched == 'api_access.class.php' ) {
continue ;
}
2020-10-31 14:32:18 +01:00
2024-08-17 16:29:52 +02:00
//$conf->global->API_DISABLE_LOGIN_API = 1;
if ( $file_searched == 'api_login.class.php' && getDolGlobalString ( 'API_DISABLE_LOGIN_API' )) {
2021-04-25 17:41:59 +02:00
continue ;
}
2022-07-15 13:41:02 +02:00
//dol_syslog("We scan to search api file with into ".$dir_part.$file_searched);
2020-10-31 14:32:18 +01:00
$regapi = array ();
2021-02-23 17:44:43 +01:00
if ( is_readable ( $dir_part . $file_searched ) && preg_match ( " /^api_(.*) \ .class \ .php $ /i " , $file_searched , $regapi )) {
2020-10-31 14:32:18 +01:00
$classname = ucwords ( $regapi [ 1 ]);
$classname = str_replace ( '_' , '' , $classname );
require_once $dir_part . $file_searched ;
2021-02-23 17:44:43 +01:00
if ( class_exists ( $classname . 'Api' )) {
2020-10-31 14:32:18 +01:00
//dol_syslog("Found API by index.php: classname=".$classname."Api for module ".$dir." into ".$dir_part.$file_searched);
$listofapis [ strtolower ( $classname . 'Api' )] = $classname . 'Api' ;
2021-02-23 17:44:43 +01:00
} elseif ( class_exists ( $classname )) {
2020-10-31 14:32:18 +01:00
//dol_syslog("Found API by index.php: classname=".$classname." for module ".$dir." into ".$dir_part.$file_searched);
$listofapis [ strtolower ( $classname )] = $classname ;
} else {
dol_syslog ( " We found an api_xxx file ( " . $file_searched . " ) but class " . $classname . " does not exists after loading file " , LOG_WARNING );
}
}
}
}
}
}
}
}
}
// Sort the classes before adding them to Restler.
// The Restler API Explorer shows the classes in the order they are added and it's a mess if they are not sorted.
asort ( $listofapis );
2021-02-23 17:44:43 +01:00
foreach ( $listofapis as $apiname => $classname ) {
2020-10-31 14:32:18 +01:00
$api -> r -> addAPIClass ( $classname , $apiname );
}
//var_dump($api->r);
2015-11-22 17:17:06 +01:00
}
2017-06-25 17:09:08 +02:00
// Call one APIs or one definition of an API
2019-08-25 16:40:21 +02:00
$regbis = array ();
2021-02-23 17:44:43 +01:00
if ( ! empty ( $reg [ 1 ]) && ( $reg [ 1 ] != 'explorer' || ( $reg [ 2 ] != '/swagger.json' && $reg [ 2 ] != '/resources.json' && preg_match ( '/^\/(swagger|resources)\.json\/(.+)$/' , $reg [ 2 ], $regbis ) && $regbis [ 2 ] != 'root' ))) {
2020-10-31 14:32:18 +01:00
$moduleobject = $reg [ 1 ];
2021-02-23 17:44:43 +01:00
if ( $moduleobject == 'explorer' ) { // If we call page to explore details of a service
2020-10-31 14:32:18 +01:00
$moduleobject = $regbis [ 2 ];
}
2017-06-25 17:09:08 +02:00
2020-10-31 14:32:18 +01:00
$moduleobject = strtolower ( $moduleobject );
$moduledirforclass = getModuleDirForApiClass ( $moduleobject );
2017-06-25 17:09:08 +02:00
2020-10-31 14:32:18 +01:00
// Load a dedicated API file
dol_syslog ( " Load a dedicated API file moduleobject= " . $moduleobject . " moduledirforclass= " . $moduledirforclass );
2017-11-05 18:15:59 +01:00
2020-10-31 14:32:18 +01:00
$tmpmodule = $moduleobject ;
2021-02-23 17:44:43 +01:00
if ( $tmpmodule != 'api' ) {
2017-11-25 13:14:28 +01:00
$tmpmodule = preg_replace ( '/api$/i' , '' , $tmpmodule );
2021-02-23 17:44:43 +01:00
}
2017-11-25 13:14:28 +01:00
$classfile = str_replace ( '_' , '' , $tmpmodule );
2020-07-29 12:51:18 +02:00
// Special cases that does not match name rules conventions
2021-02-23 17:44:43 +01:00
if ( $moduleobject == 'supplierproposals' ) {
2017-11-25 13:14:28 +01:00
$classfile = 'supplier_proposals' ;
2021-02-23 17:44:43 +01:00
}
if ( $moduleobject == 'supplierorders' ) {
2017-11-25 13:14:28 +01:00
$classfile = 'supplier_orders' ;
2021-02-23 17:44:43 +01:00
}
if ( $moduleobject == 'supplierinvoices' ) {
2017-11-25 13:14:28 +01:00
$classfile = 'supplier_invoices' ;
2021-02-23 17:44:43 +01:00
}
if ( $moduleobject == 'ficheinter' ) {
2018-02-03 20:58:26 +01:00
$classfile = 'interventions' ;
2021-02-23 17:44:43 +01:00
}
if ( $moduleobject == 'interventions' ) {
2018-02-03 20:58:26 +01:00
$classfile = 'interventions' ;
2021-02-23 17:44:43 +01:00
}
2018-02-03 20:58:26 +01:00
2020-04-10 10:59:32 +02:00
$dir_part_file = dol_buildpath ( '/' . $moduledirforclass . '/class/api_' . $classfile . '.class.php' , 0 , 2 );
2017-11-25 13:14:28 +01:00
2020-06-18 01:09:30 +02:00
$classname = ucwords ( $moduleobject );
2017-11-25 13:14:28 +01:00
2021-04-25 20:23:41 +02:00
// Test rules on endpoints. For example:
// $conf->global->API_ENDPOINT_RULES = 'endpoint1:1,endpoint2:1,...'
2023-10-24 17:00:13 +02:00
if ( getDolGlobalString ( 'API_ENDPOINT_RULES' )) {
2023-12-13 15:20:53 +01:00
$listofendpoints = explode ( ',' , getDolGlobalString ( 'API_ENDPOINT_RULES' ));
2021-04-25 20:23:41 +02:00
$endpointisallowed = false ;
2021-04-25 20:25:32 +02:00
foreach ( $listofendpoints as $endpointrule ) {
2021-04-25 20:23:41 +02:00
$tmparray = explode ( ':' , $endpointrule );
2022-02-09 17:50:26 +01:00
if (( $classfile == $tmparray [ 0 ] || $classfile . 'api' == $tmparray [ 0 ]) && $tmparray [ 1 ] == 1 ) {
2021-04-25 20:23:41 +02:00
$endpointisallowed = true ;
break ;
}
}
if ( ! $endpointisallowed ) {
dol_syslog ( 'The API with endpoint /' . $classfile . ' is forbidden by config API_ENDPOINT_RULES' , LOG_WARNING );
print 'The API with endpoint /' . $classfile . ' is forbidden by config API_ENDPOINT_RULES' ;
header ( 'HTTP/1.1 501 API is forbidden by API_ENDPOINT_RULES' );
//session_destroy();
exit ( 0 );
}
}
2023-10-31 13:31:02 +01:00
dol_syslog ( 'Search api file /' . $moduledirforclass . '/class/api_' . $classfile . '.class.php => dir_part_file=' . $dir_part_file . ', classname=' . $classname );
2017-11-25 13:14:28 +01:00
$res = false ;
2021-02-23 17:44:43 +01:00
if ( $dir_part_file ) {
2017-11-25 13:14:28 +01:00
$res = include_once $dir_part_file ;
2021-02-23 17:44:43 +01:00
}
2020-04-10 10:59:32 +02:00
if ( ! $res ) {
2020-10-31 14:32:18 +01:00
dol_syslog ( 'Failed to make include_once ' . $dir_part_file , LOG_WARNING );
2017-11-25 13:14:28 +01:00
print 'API not found (failed to include API file)' ;
header ( 'HTTP/1.1 501 API not found (failed to include API file)' );
2020-06-17 19:26:17 +02:00
//session_destroy();
2017-11-25 13:14:28 +01:00
exit ( 0 );
}
2021-02-23 17:44:43 +01:00
if ( class_exists ( $classname )) {
2017-11-25 13:14:28 +01:00
$api -> r -> addAPIClass ( $classname );
2021-02-23 17:44:43 +01:00
}
2016-06-15 22:53:05 +02:00
}
2015-11-22 17:17:06 +01:00
2020-06-17 19:26:17 +02:00
2017-06-25 18:18:17 +02:00
//var_dump($api->r->apiVersionMap);
2017-06-25 17:09:08 +02:00
//exit;
2016-04-30 00:00:59 +02:00
2021-04-25 16:15:15 +02:00
// We do not want that restler outputs data if we use native compression (default behaviour) but we want to have it returned into a string.
2021-12-19 17:05:57 +01:00
// If API_DISABLE_COMPRESSION is set, returnResponse is false => It use default handling so output result directly.
2023-10-24 17:00:13 +02:00
$usecompression = ( ! getDolGlobalString ( 'API_DISABLE_COMPRESSION' ) && ! empty ( $_SERVER [ 'HTTP_ACCEPT_ENCODING' ]));
2021-12-19 17:05:57 +01:00
$foundonealgorithm = 0 ;
2021-12-21 14:01:58 +01:00
if ( $usecompression ) {
2023-01-11 17:06:23 +01:00
if ( strpos ( $_SERVER [ 'HTTP_ACCEPT_ENCODING' ], 'br' ) !== false && function_exists ( 'brotli_compress' )) {
2021-12-21 14:01:58 +01:00
$foundonealgorithm ++ ;
}
2023-01-11 17:06:23 +01:00
if ( strpos ( $_SERVER [ 'HTTP_ACCEPT_ENCODING' ], 'bz' ) !== false && function_exists ( 'bzcompress' )) {
2021-12-21 14:01:58 +01:00
$foundonealgorithm ++ ;
}
2023-01-11 17:06:23 +01:00
if ( strpos ( $_SERVER [ 'HTTP_ACCEPT_ENCODING' ], 'gzip' ) !== false && function_exists ( 'gzencode' )) {
2021-12-21 14:01:58 +01:00
$foundonealgorithm ++ ;
}
if ( ! $foundonealgorithm ) {
$usecompression = false ;
}
2021-12-19 17:05:57 +01:00
}
2024-01-12 20:58:09 +01:00
//dol_syslog('We found some compression algorithm: '.$foundonealgorithm.' -> usecompression='.$usecompression, LOG_DEBUG);
2021-12-19 17:05:57 +01:00
Luracast\Restler\Defaults :: $returnResponse = $usecompression ;
2021-03-25 09:20:31 +01:00
2019-07-26 13:16:49 +02:00
// Call API (we suppose we found it).
// The handle will use the file api/temp/routes.php to get data to run the API. If the file exists and the entry for API is not found, it will return 404.
2024-01-17 11:16:43 +01:00
$responsedata = $api -> r -> handle ();
2021-03-25 12:52:35 +01:00
if ( Luracast\Restler\Defaults :: $returnResponse ) {
2021-12-19 17:05:57 +01:00
// We try to compress the data received data
2023-01-11 17:06:23 +01:00
if ( strpos ( $_SERVER [ 'HTTP_ACCEPT_ENCODING' ], 'br' ) !== false && function_exists ( 'brotli_compress' ) && defined ( 'BROTLI_TEXT' )) {
2021-03-22 09:40:06 +01:00
header ( 'Content-Encoding: br' );
2024-01-17 11:16:43 +01:00
$result = brotli_compress ( $responsedata , 11 , constant ( 'BROTLI_TEXT' ));
2023-01-11 17:06:23 +01:00
} elseif ( strpos ( $_SERVER [ 'HTTP_ACCEPT_ENCODING' ], 'bz' ) !== false && function_exists ( 'bzcompress' )) {
2021-03-22 09:40:06 +01:00
header ( 'Content-Encoding: bz' );
2024-01-17 11:16:43 +01:00
$result = bzcompress ( $responsedata , 9 );
2023-01-11 17:06:23 +01:00
} elseif ( strpos ( $_SERVER [ 'HTTP_ACCEPT_ENCODING' ], 'gzip' ) !== false && function_exists ( 'gzencode' )) {
2021-03-22 09:40:06 +01:00
header ( 'Content-Encoding: gzip' );
2024-01-17 11:16:43 +01:00
$result = gzencode ( $responsedata , 9 );
2021-12-19 17:05:57 +01:00
} else {
header ( 'Content-Encoding: text/html' );
print " No compression method found. Try to disable compression by adding API_DISABLE_COMPRESSION=1 " ;
exit ( 0 );
2021-03-22 09:40:06 +01:00
}
2021-03-25 09:20:31 +01:00
2021-03-25 12:52:35 +01:00
// Restler did not output data yet, we return it now
2021-03-25 09:20:31 +01:00
echo $result ;
2021-03-22 09:28:57 +01:00
}
2020-06-17 19:26:17 +02:00
2024-04-11 19:14:10 +02:00
if ( getDolGlobalInt ( " API_ENABLE_COUNT_CALLS " ) && $api -> r -> responseCode == 200 ) {
$error = 0 ;
$db -> begin ();
$userid = DolibarrApiAccess :: $user -> id ;
$sql = " SELECT up.value " ;
$sql .= " FROM " . MAIN_DB_PREFIX . " user_param as up " ;
$sql .= " WHERE up.param = 'API_COUNT_CALL' " ;
$sql .= " AND up.fk_user = " . (( int ) $userid );
$sql .= " AND up.entity = " . (( int ) $conf -> entity );
$result = $db -> query ( $sql );
if ( $result ) {
$updateapi = false ;
$nbrows = $db -> num_rows ( $result );
if ( $nbrows == 0 ) {
$sql2 = " INSERT INTO " . MAIN_DB_PREFIX . " user_param " ;
$sql2 .= " (fk_user, entity, param, value) " ;
$sql2 .= " VALUES ( " . (( int ) $userid ) . " , " . (( int ) $conf -> entity ) . " , 'API_COUNT_CALL', 1) " ;
} else {
$updateapi = true ;
$sql2 = " UPDATE " . MAIN_DB_PREFIX . " user_param as up " ;
$sql2 .= " SET up.value = up.value + 1 " ;
$sql2 .= " WHERE up.param = 'API_COUNT_CALL' " ;
$sql2 .= " AND up.fk_user = " . (( int ) $userid );
$sql2 .= " AND up.entity = " . (( int ) $conf -> entity );
}
$result2 = $db -> query ( $sql2 );
if ( ! $result2 ) {
$modeapicall = $updateapi ? 'updating' : 'inserting' ;
dol_syslog ( 'Error while ' . $modeapicall . ' API_COUNT_CALL for user ' . $userid , LOG_ERR );
$error ++ ;
}
} else {
dol_syslog ( 'Error on select API_COUNT_CALL for user ' . $userid , LOG_ERR );
$error ++ ;
}
if ( $error ) {
$db -> rollback ();
} else {
$db -> commit ();
}
}
2024-01-17 11:37:10 +01:00
// Call API termination method
2024-01-18 10:26:42 +01:00
$apiMethodInfo = & $api -> r -> apiMethodInfo ;
$terminateCall = '_terminate_' . $apiMethodInfo -> methodName . '_' . $api -> r -> responseFormat -> getExtension ();
if ( method_exists ( $apiMethodInfo -> className , $terminateCall )) {
2024-01-18 12:39:45 +01:00
// Now flush output buffers so that response data is sent to the client even if we still have action to do in a termination method.
ob_end_flush ();
// If you're using PHP-FPM, this function will allow you to send the response and then continue processing
if ( function_exists ( 'fastcgi_finish_request' )) {
fastcgi_finish_request ();
}
2024-01-18 15:15:05 +01:00
// Call a termination method. Warning: This method can do I/O, sync but must not make output.
2024-01-18 10:52:39 +01:00
call_user_func ( array ( Luracast\Restler\Scope :: get ( $apiMethodInfo -> className ), $terminateCall ), $responsedata );
2024-01-18 10:26:42 +01:00
}
2024-01-17 11:16:43 +01:00
2020-06-17 19:26:17 +02:00
//session_destroy();