api.class.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <?php
  2. /* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
  3. * Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. use Luracast\Restler\Restler;
  19. use Luracast\Restler\RestException;
  20. use Luracast\Restler\Defaults;
  21. use Luracast\Restler\Format\UploadFormat;
  22. require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
  23. /**
  24. * Class for API REST v1
  25. */
  26. class DolibarrApi
  27. {
  28. /**
  29. * @var DoliDb $db Database object
  30. */
  31. static protected $db;
  32. /**
  33. * @var Restler $r Restler object
  34. */
  35. var $r;
  36. /**
  37. * Constructor
  38. *
  39. * @param DoliDb $db Database handler
  40. * @param string $cachedir Cache dir
  41. * @param boolean $refreshCache Update cache
  42. */
  43. function __construct($db, $cachedir = '', $refreshCache = false)
  44. {
  45. global $conf, $dolibarr_main_url_root;
  46. if (empty($cachedir)) $cachedir = $conf->api->dir_temp;
  47. Defaults::$cacheDirectory = $cachedir;
  48. $this->db = $db;
  49. $production_mode = ( empty($conf->global->API_PRODUCTION_MODE) ? false : true );
  50. $this->r = new Restler($production_mode, $refreshCache);
  51. $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
  52. $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
  53. $urlwithouturlrootautodetect=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim(DOL_MAIN_URL_ROOT));
  54. $urlwithrootautodetect=$urlwithouturlroot.DOL_URL_ROOT; // This is to use local domain autodetected by dolibarr from url
  55. $this->r->setBaseUrls($urlwithouturlroot, $urlwithouturlrootautodetect);
  56. $this->r->setAPIVersion(1);
  57. //$this->r->setSupportedFormats('json');
  58. //$this->r->setSupportedFormats('jsonFormat');
  59. }
  60. /**
  61. * Executed method when API is called without parameter
  62. *
  63. * Display a short message an return a http code 200
  64. *
  65. * @return array
  66. */
  67. /* Disabled, most APIs does not share same signature for method index
  68. function index()
  69. {
  70. return array(
  71. 'success' => array(
  72. 'code' => 200,
  73. 'message' => __class__.' is up and running!'
  74. )
  75. );
  76. }*/
  77. /**
  78. * Clean sensible object datas
  79. *
  80. * @param object $object Object to clean
  81. * @return array Array of cleaned object properties
  82. */
  83. function _cleanObjectDatas($object)
  84. {
  85. // Remove $db object property for object
  86. unset($object->db);
  87. unset($object->isextrafieldmanaged);
  88. unset($object->ismultientitymanaged);
  89. unset($object->restrictiononfksoc);
  90. // Remove linkedObjects. We should already have linkedObjectIds that avoid huge responses
  91. unset($object->linkedObjects);
  92. unset($object->lignes); // we don't want lignes, we want only ->lines
  93. unset($object->fields);
  94. unset($object->oldline);
  95. unset($object->error);
  96. unset($object->errors);
  97. unset($object->ref_previous);
  98. unset($object->ref_next);
  99. unset($object->ref_int);
  100. unset($object->projet); // Should be fk_project
  101. unset($object->project); // Should be fk_project
  102. unset($object->author); // Should be fk_user_author
  103. unset($object->timespent_old_duration);
  104. unset($object->timespent_id);
  105. unset($object->timespent_duration);
  106. unset($object->timespent_date);
  107. unset($object->timespent_datehour);
  108. unset($object->timespent_withhour);
  109. unset($object->timespent_fk_user);
  110. unset($object->timespent_note);
  111. unset($object->statuts);
  112. unset($object->statuts_short);
  113. unset($object->statuts_logo);
  114. unset($object->statuts_long);
  115. unset($object->labelstatut);
  116. unset($object->labelstatut_short);
  117. unset($object->element);
  118. unset($object->fk_element);
  119. unset($object->table_element);
  120. unset($object->table_element_line);
  121. unset($object->class_element_line);
  122. unset($object->picto);
  123. unset($object->fieldsforcombobox);
  124. unset($object->comments);
  125. unset($object->skip_update_total);
  126. unset($object->context);
  127. // Remove the $oldcopy property because it is not supported by the JSON
  128. // encoder. The following error is generated when trying to serialize
  129. // it: "Error encoding/decoding JSON: Type is not supported"
  130. // Note: Event if this property was correctly handled by the JSON
  131. // encoder, it should be ignored because keeping it would let the API
  132. // have a very strange behavior: calling PUT and then GET on the same
  133. // resource would give different results:
  134. // PUT /objects/{id} -> returns object with oldcopy = previous version of the object
  135. // GET /objects/{id} -> returns object with oldcopy empty
  136. unset($object->oldcopy);
  137. // If object has lines, remove $db property
  138. if (isset($object->lines) && is_array($object->lines) && count($object->lines) > 0) {
  139. $nboflines = count($object->lines);
  140. for ($i=0; $i < $nboflines; $i++)
  141. {
  142. $this->_cleanObjectDatas($object->lines[$i]);
  143. unset($object->lines[$i]->contact);
  144. unset($object->lines[$i]->contact_id);
  145. unset($object->lines[$i]->country);
  146. unset($object->lines[$i]->country_id);
  147. unset($object->lines[$i]->country_code);
  148. unset($object->lines[$i]->mode_reglement_id);
  149. unset($object->lines[$i]->mode_reglement_code);
  150. unset($object->lines[$i]->mode_reglement);
  151. unset($object->lines[$i]->cond_reglement_id);
  152. unset($object->lines[$i]->cond_reglement_code);
  153. unset($object->lines[$i]->cond_reglement);
  154. unset($object->lines[$i]->fk_delivery_address);
  155. unset($object->lines[$i]->fk_projet);
  156. unset($object->lines[$i]->thirdparty);
  157. unset($object->lines[$i]->user);
  158. unset($object->lines[$i]->model_pdf);
  159. unset($object->lines[$i]->modelpdf);
  160. unset($object->lines[$i]->note_public);
  161. unset($object->lines[$i]->note_private);
  162. unset($object->lines[$i]->fk_incoterms);
  163. unset($object->lines[$i]->libelle_incoterms);
  164. unset($object->lines[$i]->location_incoterms);
  165. unset($object->lines[$i]->name);
  166. unset($object->lines[$i]->lastname);
  167. unset($object->lines[$i]->firstname);
  168. unset($object->lines[$i]->civility_id);
  169. unset($object->lines[$i]->fk_multicurrency);
  170. unset($object->lines[$i]->multicurrency_code);
  171. unset($object->lines[$i]->shipping_method_id);
  172. }
  173. }
  174. if (! empty($object->thirdparty) && is_object($object->thirdparty))
  175. {
  176. $this->_cleanObjectDatas($object->thirdparty);
  177. }
  178. return $object;
  179. }
  180. /**
  181. * Check user access to a resource
  182. *
  183. * Check access by user to a given resource
  184. *
  185. * @param string $resource element to check
  186. * @param int $resource_id Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional).
  187. * @param type $dbtablename 'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity. Not used if objectid is null (optional)
  188. * @param string $feature2 Feature to check, second level of permission (optional). Can be or check with 'level1|level2'.
  189. * @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional)
  190. * @param string $dbt_select Field name for select if not rowid. Not used if objectid is null (optional)
  191. * @return bool
  192. * @throws RestException
  193. */
  194. static function _checkAccessToResource($resource, $resource_id = 0, $dbtablename = '', $feature2 = '', $dbt_keyfield = 'fk_soc', $dbt_select = 'rowid')
  195. {
  196. // Features/modules to check
  197. $featuresarray = array($resource);
  198. if (preg_match('/&/', $resource)) {
  199. $featuresarray = explode("&", $resource);
  200. }
  201. else if (preg_match('/\|/', $resource)) {
  202. $featuresarray = explode("|", $resource);
  203. }
  204. // More subfeatures to check
  205. if (! empty($feature2)) {
  206. $feature2 = explode("|", $feature2);
  207. }
  208. return checkUserAccessToObject(DolibarrApiAccess::$user, $featuresarray, $resource_id, $dbtablename, $feature2, $dbt_keyfield, $dbt_select);
  209. }
  210. /**
  211. * Return if a $sqlfilters parameter is valid
  212. *
  213. * @param string $sqlfilters sqlfilter string
  214. * @return boolean True if valid, False if not valid
  215. */
  216. function _checkFilters($sqlfilters)
  217. {
  218. //$regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
  219. //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
  220. $tmp=$sqlfilters;
  221. $ok=0;
  222. $i=0; $nb=strlen($tmp);
  223. $counter=0;
  224. while ($i < $nb)
  225. {
  226. if ($tmp[$i]=='(') $counter++;
  227. if ($tmp[$i]==')') $counter--;
  228. if ($counter < 0)
  229. {
  230. $error="Bad sqlfilters=".$sqlfilters;
  231. dol_syslog($error, LOG_WARNING);
  232. return false;
  233. }
  234. $i++;
  235. }
  236. return true;
  237. }
  238. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
  239. /**
  240. * Function to forge a SQL criteria
  241. *
  242. * @param array $matches Array of found string by regex search
  243. * @return string Forged criteria. Example: "t.field like 'abc%'"
  244. */
  245. static function _forge_criteria_callback($matches)
  246. {
  247. // phpcs:enable
  248. global $db;
  249. //dol_syslog("Convert matches ".$matches[1]);
  250. if (empty($matches[1])) return '';
  251. $tmp=explode(':',$matches[1]);
  252. if (count($tmp) < 3) return '';
  253. $tmpescaped=$tmp[2];
  254. if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis))
  255. {
  256. $tmpescaped = "'".$db->escape($regbis[1])."'";
  257. }
  258. else
  259. {
  260. $tmpescaped = $db->escape($tmpescaped);
  261. }
  262. return $db->escape($tmp[0]).' '.strtoupper($db->escape($tmp[1]))." ".$tmpescaped;
  263. }
  264. }